gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r6049 - Extractor/src/plugins


From: gnunet
Subject: [GNUnet-SVN] r6049 - Extractor/src/plugins
Date: Sat, 29 Dec 2007 04:32:28 -0700 (MST)

Author: holindho
Date: 2007-12-29 04:32:28 -0700 (Sat, 29 Dec 2007)
New Revision: 6049

Added:
   Extractor/src/plugins/amfparser.c
   Extractor/src/plugins/amfparser.h
Modified:
   Extractor/src/plugins/Makefile.am
   Extractor/src/plugins/flvextractor.c
Log:
real metadata parsing to flv extractor


Modified: Extractor/src/plugins/Makefile.am
===================================================================
--- Extractor/src/plugins/Makefile.am   2007-12-28 21:02:03 UTC (rev 6048)
+++ Extractor/src/plugins/Makefile.am   2007-12-29 11:32:28 UTC (rev 6049)
@@ -126,7 +126,8 @@
 noinst_LTLIBRARIES = \
   libpack.la \
   libconvert.la \
-  libconvert_numeric.la
+  libconvert_numeric.la \
+  libamfparser.la
 
 if HAVE_ZLIB
 libextractor_qt_la_LDFLAGS = \
@@ -242,6 +243,12 @@
   convert_numeric.c \
   convert_numeric.h 
 
+libamfparser_la_SOURCES = \
+  amfparser.c \
+  amfparser.h 
+libamfparser_la_LIBADD = \
+  libconvert_numeric.la
+
 libextractor_zip_la_SOURCES = \
   zipextractor.c
 libextractor_zip_la_LDFLAGS = \
@@ -265,6 +272,8 @@
   flvextractor.c
 libextractor_flv_la_LDFLAGS = \
   $(PLUGINFLAGS)  $(retaincommand)
+libextractor_flv_la_LIBADD = \
+  libamfparser.la
 
 libextractor_real_la_SOURCES = \
   realextractor.c 

Added: Extractor/src/plugins/amfparser.c
===================================================================
--- Extractor/src/plugins/amfparser.c                           (rev 0)
+++ Extractor/src/plugins/amfparser.c   2007-12-29 11:32:28 UTC (rev 6049)
@@ -0,0 +1,373 @@
+/*
+     This file is part of libextractor.
+     Copyright (C) 2007 Heikki Lindholm
+
+     libextractor is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libextractor is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libextractor; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * see http://osflash.org/documentation/amf
+ */
+#include "platform.h"
+#include "convert_numeric.h"
+#include "amfparser.h"
+
+#define DEBUG 0
+
+/* core datatypes */
+
+static inline unsigned long readLong(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  unsigned long val;
+
+  val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+  ptr += 4;
+  *data = ptr;
+  return val;
+}
+
+static inline unsigned long readMediumInt(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  unsigned long val;
+
+  val = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
+  ptr += 3;
+  *data = ptr;
+  return val;
+}
+
+static inline unsigned short readInt(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  unsigned short val;
+
+  val = (ptr[0] << 8) | ptr[1];
+  ptr += 2;
+  *data = ptr;
+  return val;
+}
+
+static inline double readDouble(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  double val;
+
+  floatformat_to_double(&floatformat_ieee_double_big, 
+                        (const void *)ptr, 
+                        &val);
+  ptr += 8;
+  *data = ptr;
+  return val;
+}
+
+
+/* actionscript types */
+
+static int readASNumber(const unsigned char **data,
+                               size_t *len,
+                               double *retval)
+{
+  const unsigned char *ptr = *data;
+  char *ret;
+  double val;
+
+  if (*len < 8)
+    return -1;
+
+  val = readDouble(&ptr);
+  *len -= 8;
+
+  *retval = val;
+  *data = ptr;
+  return 0;
+}
+
+static int readASBoolean(const unsigned char **data,
+                                size_t *len,
+                                int *retval)
+{
+  const unsigned char *ptr = *data;
+  char *ret;
+  int val;
+  
+  if (*len < 1)
+    return -1;
+
+  val = (*ptr != 0x00);
+#if DEBUG
+  printf("asbool: %d\n", val);
+#endif
+  ptr += 1;
+  *len -= 1;
+
+  *retval = val;
+  *data = ptr;
+  return 0;
+}
+
+static int readASDate(const unsigned char **data,
+                             size_t *len,
+                             double *millis,
+                             short *zone)
+{
+  const unsigned char *ptr = *data;
+  char *ret;
+
+  if (*len < 10)
+    return -1;
+
+  *millis = readDouble(&ptr);
+  *len -= 8;
+
+  *zone = readInt(&ptr);
+  len -= 2;
+
+#if DEBUG
+  printf("asdate: %f tz: %d\n", *millis, *zone);
+#endif
+
+  *data = ptr;
+  return 0;
+}
+
+static int readASString(const unsigned char **data,
+                               size_t *len,
+                               char **retval)
+{
+  const unsigned char *ptr = *data;
+  char *ret;
+  int slen;
+ 
+  if (*len < 2)
+    return -1;
+
+  slen = readInt(&ptr);
+
+  if (*len < (2 + slen))
+    return -1;
+
+  ret = malloc(slen+1);
+  if (ret == NULL)
+    return -1;
+  memcpy(ret, ptr, slen);
+  ret[slen] = '\0';
+#if DEBUG
+  printf("asstring: %p %s\n", ret, ret);
+#endif
+  ptr += slen;
+  *len -= (2 + slen);
+
+  *retval = ret;
+  *data = ptr;
+  return 0;
+}
+
+int parse_amf(const unsigned char **data, 
+              size_t *len,
+              AMFParserHandler *handler) 
+{
+  const unsigned char *ptr = *data;
+  unsigned char astype;
+  int ret;
+
+  ret = 0;
+  astype = *ptr++;
+  (*(handler->as_begin_callback))(astype, handler->userdata);
+  switch (astype) {
+    case ASTYPE_NUMBER:
+    {
+      double val;
+      ret = readASNumber(&ptr, len, &val);
+      if (ret == 0)
+        (*(handler->as_end_callback))(astype, 
+                                      &val, 
+                                      handler->userdata);
+      break;
+    }
+    case ASTYPE_BOOLEAN:
+    {
+      int val;
+      ret = readASBoolean(&ptr, len, &val);
+      if (ret == 0)
+        (*(handler->as_end_callback))(astype, 
+                                      &val, 
+                                      handler->userdata);
+      break;
+    }
+    case ASTYPE_STRING:
+    {
+      char *val;
+      ret = readASString(&ptr, len, &val);
+      if (ret == 0) {
+        (*(handler->as_end_callback))(astype, 
+                                      val, 
+                                      handler->userdata);
+        free(val);
+      }
+      break;
+    }
+    case ASTYPE_DATE:
+    {
+      void *tmp[2];
+      double millis;
+      short tz;
+      ret = readASDate(&ptr, len, &millis, &tz);
+      tmp[0] = &millis;
+      tmp[1] = &tz;
+      if (ret == 0)
+        (*(handler->as_end_callback))(astype, 
+                                      &tmp, 
+                                      handler->userdata);
+      break;
+    }
+    case ASTYPE_NULL:
+    case ASTYPE_UNDEFINED:
+    case ASTYPE_UNSUPPORTED:
+      ret = 0;
+      (*(handler->as_end_callback))(astype, NULL, handler->userdata);
+      break;
+    case ASTYPE_ENDOFOBJECT:
+      ret = 0;
+      (*(handler->as_end_callback))(astype, NULL, handler->userdata);
+#if DEBUG
+      printf("asendofboject\n");
+#endif
+      break;
+    case ASTYPE_ARRAY:
+    {
+      long i, alen;
+#if DEBUG
+      printf("asarray:\n");
+#endif
+      if (*len < 4) {
+        ret = -1;
+        break;
+      }
+      alen = readLong(&ptr);
+      *len -= 4;
+#if DEBUG
+      printf(" len: %ld\n", alen);
+#endif
+      for (i = 0; i < alen; i++) {
+        ret = parse_amf(&ptr, len, handler);
+        if (ret == -1)
+         break;
+      }
+      (*(handler->as_end_callback))(ASTYPE_ARRAY, 
+                                    NULL, 
+                                    handler->userdata);
+#if DEBUG
+      printf("asarray: END\n");
+#endif
+      break;
+    }  
+    case ASTYPE_OBJECT:
+    {
+      char *key;
+      unsigned char type;
+#if DEBUG
+      printf("asobject:\n");
+#endif
+      ret = readASString(&ptr, len, &key);
+      if (ret == -1)
+        break;
+      (*(handler->as_key_callback))(key, 
+                                    handler->userdata);
+      free(key);
+      type = *ptr;
+      while (type != ASTYPE_ENDOFOBJECT) {
+        ret = parse_amf(&ptr, len, handler);
+        if (ret == -1)
+          break;
+        ret = readASString(&ptr, len, &key);
+        if (ret == -1)
+          break;
+        (*(handler->as_key_callback))(key, 
+                                      handler->userdata);
+        free(key);
+        type = *ptr;      
+      }
+      if (ret == 0)
+        (*(handler->as_end_callback))(ASTYPE_OBJECT, 
+                                      NULL, 
+                                      handler->userdata);
+#if DEBUG
+      printf("asobject END:\n");
+#endif
+      break;
+    }  
+    case ASTYPE_MIXEDARRAY:
+    {
+      char *key;
+      unsigned char type;
+      long max_index;
+#if DEBUG
+      printf("asmixedarray:\n");
+#endif
+      if (*len < 4) {
+        ret = -1;
+        break;
+      }
+      max_index = readLong(&ptr);
+      *len -= 4;
+#if DEBUG
+      printf(" max index: %ld\n", max_index);
+#endif
+      ret = readASString(&ptr, len, &key);
+      if (ret == -1)
+        break;
+      (*(handler->as_key_callback))(key, 
+                                    handler->userdata);
+      free(key);
+      type = *ptr;
+      while (type != ASTYPE_ENDOFOBJECT) {
+        ret = parse_amf(&ptr, len, handler);
+        if (ret == -1)
+          break;
+        ret = readASString(&ptr, len, &key);
+        if (ret == -1)
+          break;
+        (*(handler->as_key_callback))(key, 
+                                      handler->userdata);
+        free(key);
+        type = *ptr;      
+      }
+      if (ret == 0)
+        (*(handler->as_end_callback))(astype, 
+                                      NULL, 
+                                      handler->userdata);
+#if DEBUG
+      printf("asmixedarray: END\n");
+#endif
+      break;
+    }  
+    default:
+      ret = -1;
+      (*(handler->as_end_callback))(astype, 
+                                    NULL, 
+                                    handler->userdata);
+#if DEBUG
+      printf("asunknown %x\n", astype);
+#endif
+      break;
+  }
+
+  *data = ptr;
+  return ret;
+}
+

Added: Extractor/src/plugins/amfparser.h
===================================================================
--- Extractor/src/plugins/amfparser.h                           (rev 0)
+++ Extractor/src/plugins/amfparser.h   2007-12-29 11:32:28 UTC (rev 6049)
@@ -0,0 +1,60 @@
+/*
+     This file is part of libextractor.
+     Copyright (C) 2007 Heikki Lindholm
+
+     libextractor is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libextractor is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libextractor; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * see http://osflash.org/documentation/amf
+ */
+
+#ifndef AMFPARSER_H
+#define AMFPARSER_H
+
+/* Actionscript types */
+#define ASTYPE_NUMBER       0x00
+#define ASTYPE_BOOLEAN      0x01
+#define ASTYPE_STRING       0x02
+#define ASTYPE_OBJECT       0x03
+#define ASTYPE_MOVIECLIP    0x04
+#define ASTYPE_NULL         0x05
+#define ASTYPE_UNDEFINED    0x06
+#define ASTYPE_REFERENCE    0x07
+#define ASTYPE_MIXEDARRAY   0x08
+#define ASTYPE_ENDOFOBJECT  0x09
+#define ASTYPE_ARRAY        0x0a
+#define ASTYPE_DATE         0x0b
+#define ASTYPE_LONGSTRING   0x0c
+#define ASTYPE_UNSUPPORTED  0x0d
+#define ASTYPE_RECORDSET    0x0e
+#define ASTYPE_XML          0x0f
+#define ASTYPE_TYPEDOBJECT  0x10
+#define ASTYPE_AMF3DATA     0x11
+
+typedef struct {
+  void * userdata;
+  void (*as_begin_callback)(unsigned char type, void * userdata);
+  void (*as_key_callback)(char * key, void * userdata);
+  void (*as_end_callback)(unsigned char type, void * value, void * userdata);
+} AMFParserHandler;
+
+extern int parse_amf(const unsigned char **data, 
+                     size_t *len,
+                     AMFParserHandler *handler);
+
+#endif /* AMFPARSER_H */
+

Modified: Extractor/src/plugins/flvextractor.c
===================================================================
--- Extractor/src/plugins/flvextractor.c        2007-12-28 21:02:03 UTC (rev 
6048)
+++ Extractor/src/plugins/flvextractor.c        2007-12-29 11:32:28 UTC (rev 
6049)
@@ -24,6 +24,8 @@
  */
 #include "platform.h"
 #include "extractor.h"
+#include "amfparser.h"
+#include <string.h>
 
 #define DEBUG 0
 
@@ -44,6 +46,118 @@
   return result;
 }
 
+/* from tarextractor, modified to take timezone */
+/* TODO: check that the output date is correct */
+static int
+flv_to_iso_date (double timeval, short timezone,
+                 char *rtime, unsigned int rsize)
+{
+  int retval = 0;
+
+  /*
+   * shift epoch to proleptic times
+   * to make subsequent modulo operations safer.
+   */
+  long long my_timeval = (timeval/1000)
+    + ((long long) ((1970 * 365) + 478) * (long long) 86400);
+
+  unsigned int seconds = (unsigned int) (my_timeval % 60);
+  unsigned int minutes = (unsigned int) ((my_timeval / 60) % 60);
+  unsigned int hours = (unsigned int) ((my_timeval / 3600) % 24);
+
+  int zone_sign;
+  int zone_hours;
+  unsigned int zone_minutes;
+
+  unsigned int year = 0;
+  unsigned int month = 1;
+
+  unsigned int days = (unsigned int) (my_timeval / (24 * 3600));
+
+  unsigned int days_in_month[] =
+    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  unsigned int diff = 0;
+
+  if ((long long) 0 > my_timeval)
+    return EDOM;
+
+  /*
+   * 400-year periods
+   */
+  year += (400 * (days / ((365 * 400) + 97)));
+  days %= ((365 * 400) + 97);
+
+  /*
+   * 100-year periods
+   */
+  diff = (days / ((365 * 100) + 24));
+  if (4 <= diff)
+    {
+      year += 399;
+      days = 364;
+    }
+  else
+    {
+      year += (100 * diff);
+      days %= ((365 * 100) + 24);
+    }
+
+  /*
+   * remaining leap years
+   */
+  year += (4 * (days / ((365 * 4) + 1)));
+  days %= ((365 * 4) + 1);
+
+  while (1)
+    {
+      if ((0 == (year % 400)) || ((0 == (year % 4)) && (0 != (year % 100))))
+        {
+          if (366 > days)
+            {
+              break;
+            }
+          else
+            {
+              days -= 366;
+              year++;
+            }
+        }
+      else
+        {
+          if (365 > days)
+            {
+              break;
+            }
+          else
+            {
+              days -= 365;
+              year++;
+            }
+        }
+    }
+
+  if ((0 == (year % 400)) || ((0 == (year % 4)) && (0 != (year % 100))))
+    days_in_month[1] = 29;
+
+  for (month = 0; (month < 12) && (days >= days_in_month[month]); month += 1)
+    days -= days_in_month[month];
+
+  zone_sign = 0;
+  if (timezone < 0)
+    {
+      zone_sign = -1;
+      timezone = -timezone;
+    }
+  zone_hours = timezone/60;
+  zone_minutes = timezone - zone_hours*60;
+
+  retval = snprintf (rtime, rsize, "%04u-%02u-%02uT%02u:%02u:%02u%c%02d:%02u",
+                     year, month + 1, days + 1, hours, minutes, seconds,
+                     ((zone_sign < 0) ? '-' : '+'), zone_hours, zone_minutes);
+
+  return (retval < rsize) ? 0 : EOVERFLOW;
+}
+
 static inline unsigned long readBEInt32(const unsigned char **data)
 {
   const unsigned char *ptr = *data;
@@ -66,9 +180,6 @@
   return val;
 }
 
-/* AMF parser */
-/*TODO*/
-
 /* FLV parser */
 
 typedef struct
@@ -151,15 +262,227 @@
 }
 
 typedef struct {
-  int videoCodec;;
-  int lastFrameType;
+  int videoCodec;
+  int videoWidth;
+  int videoHeight;
+  double videoDataRate;
+  double videoFrameRate;
 
   int audioCodec;
+  double audioDataRate;
   int audioChannels;
   int audioSampleBits;
   int audioRate;
 } FLVStreamState;
 
+typedef enum {
+  FLV_NONE = 0,
+  FLV_WIDTH,
+  FLV_HEIGHT,
+  FLV_FRAMERATE,
+  FLV_VDATARATE,
+  FLV_ADATARATE,
+} FLVStreamAttribute;
+
+typedef struct {
+  const char *key;
+  FLVStreamAttribute attribute;
+} MetaKeyToStreamAttribute;
+
+static MetaKeyToStreamAttribute key_to_attribute_map[] = {
+  { "width", FLV_WIDTH },
+  { "height", FLV_HEIGHT },
+  { "framerate", FLV_FRAMERATE },
+  { "videodatarate", FLV_VDATARATE },
+  { "audiodatarate", FLV_ADATARATE },
+  { NULL, FLV_NONE }
+};
+
+typedef struct {
+  const char *key;
+  EXTRACTOR_KeywordType type;
+} MetaKeyToExtractorItem;
+
+static MetaKeyToExtractorItem key_to_extractor_map[] = {
+  { "duration", EXTRACTOR_DURATION },
+  { "creator", EXTRACTOR_CREATOR },
+  { "metadatacreator", EXTRACTOR_CREATOR },
+  { "creationdate", EXTRACTOR_CREATION_DATE },
+  { "metadatadate", EXTRACTOR_MODIFICATION_DATE },
+  { NULL, EXTRACTOR_UNKNOWN }
+};
+
+typedef struct {
+  int onMetaData;
+  int parsingDepth;
+  /* mixed array keys mapped to something readily usable */
+  EXTRACTOR_KeywordType currentKeyType;
+  FLVStreamAttribute currentAttribute;
+
+  struct EXTRACTOR_Keywords *keywords;
+  FLVStreamState *streamState;
+} FLVMetaParserState;
+
+static void handleASBegin(unsigned char type, void * userdata)
+{
+  FLVMetaParserState *state = (FLVMetaParserState *)userdata;
+#if DEBUG
+  printf("handleASBeginCallback %p\n", state);
+#endif
+  if (state->onMetaData && state->parsingDepth == 0 && 
+      type != ASTYPE_MIXEDARRAY)
+    state->onMetaData = 0;
+
+  if (type == ASTYPE_ARRAY || type == ASTYPE_MIXEDARRAY || 
+      type == ASTYPE_OBJECT)
+    state->parsingDepth++;
+}
+
+static void handleASKey(char * key, void * userdata)
+{
+  FLVMetaParserState *state = (FLVMetaParserState *)userdata;
+  int i;
+#if DEBUG
+  printf("handleASKeyCallback %p [%s]\n", state, key);
+#endif
+  if (key == NULL)
+    return;
+
+  i = 0;
+  while ((key_to_extractor_map[i].key != NULL) && 
+         (strcasecmp(key, key_to_extractor_map[i].key) != 0))
+    i++;
+  state->currentKeyType = key_to_extractor_map[i].type;
+
+  i = 0;
+  while ((key_to_attribute_map[i].key != NULL) && 
+         (strcasecmp(key, key_to_attribute_map[i].key) != 0))
+    i++;
+  state->currentAttribute = key_to_attribute_map[i].attribute;
+}
+
+static void handleASEnd(unsigned char type, void * value, void * userdata)
+{
+  FLVMetaParserState *state = (FLVMetaParserState *)userdata;
+  char *s;
+#if DEBUG
+  printf("handleASEndCallback %p %p\n", state, value);
+#endif
+  if ((state->parsingDepth == 0) && (type == ASTYPE_STRING)) {
+    s = (char *)value;
+    if (!strcmp(s, "onMetaData"))
+      state->onMetaData = 1;
+  }
+
+  /* we expect usable metadata to reside in a MIXEDARRAY container
+   * right after a "onMetaData" STRING */
+
+  /* stream info related metadata */
+  if (state->onMetaData && (state->parsingDepth == 1) && 
+      (state->currentAttribute != FLV_NONE) && 
+      (type == ASTYPE_NUMBER))
+  {
+    double n = *((double *)value);
+    switch (state->currentAttribute) {
+      case FLV_WIDTH:
+        if (state->streamState->videoWidth == -1)
+          state->streamState->videoWidth = n;
+        break;
+      case FLV_HEIGHT:
+        if (state->streamState->videoHeight == -1)
+          state->streamState->videoHeight = n;
+        break;
+      case FLV_FRAMERATE:
+        state->streamState->videoFrameRate = n;
+        break; 
+      case FLV_VDATARATE:
+        state->streamState->videoDataRate = n;
+        break; 
+      case FLV_ADATARATE:
+        state->streamState->audioDataRate = n;
+        break;
+    }
+  }
+
+  /* metadata that maps straight to extractor keys */
+  if (state->onMetaData && (state->parsingDepth == 1) && 
+      (state->currentKeyType != EXTRACTOR_UNKNOWN))
+  {
+    s = NULL;
+    switch (type) {
+      case ASTYPE_NUMBER:
+      {
+        double n = *((double *)value);
+        s = malloc(30);
+       if (s == NULL)
+         break;
+       if (state->currentKeyType == EXTRACTOR_DURATION)
+          snprintf(s, 30, "%.4f s", n);
+       else
+          snprintf(s, 30, "%f", n);
+       break;
+      }
+      case ASTYPE_STRING:
+      {
+        s = (char *)value;
+       if (s != NULL)
+         s = strdup(s);
+        break;
+      }
+      case ASTYPE_DATE:
+      {
+        void **tmp = (void **)value;
+       double *millis;
+       short *tz;
+        millis = (double *)tmp[0];
+       tz = (short *)tmp[1];
+       s = malloc(30);
+       if (s == NULL)
+         break;
+       flv_to_iso_date(*millis, *tz, s, 30);
+        break;
+      }
+    }
+
+    if (s != NULL)
+      state->keywords = addKeyword (state->currentKeyType, 
+                                    s,
+                                    state->keywords);
+  }
+  state->currentKeyType = EXTRACTOR_UNKNOWN;
+  state->currentAttribute = FLV_NONE;
+
+  if (type == ASTYPE_ARRAY || type == ASTYPE_MIXEDARRAY || 
+      type == ASTYPE_OBJECT)
+    state->parsingDepth--;
+}
+
+static struct EXTRACTOR_Keywords *
+handleMetaBody(const unsigned char *data, size_t len, 
+                FLVStreamState *state,
+                struct EXTRACTOR_Keywords *prev) 
+{
+  AMFParserHandler handler;
+  FLVMetaParserState pstate;
+#if DEBUG
+  printf("handleMetaBody()\n");
+#endif
+
+  pstate.onMetaData = 0;
+  pstate.currentKeyType = EXTRACTOR_UNKNOWN;
+  pstate.parsingDepth = 0;
+  pstate.keywords = prev;
+  pstate.streamState = state;
+  handler.userdata = &pstate;
+  handler.as_begin_callback = &handleASBegin;
+  handler.as_key_callback = &handleASKey;
+  handler.as_end_callback = &handleASEnd;
+
+  while (len > 0 && parse_amf(&data, &len, &handler) == 0);
+
+  return pstate.keywords;
+}
+
 static char *FLVAudioCodecs[] = {
   "Uncompressed",
   "ADPCM",
@@ -200,32 +523,7 @@
   soundRate = (*data & 0x0C) >> 2;
   soundFormat = (*data & 0xF0) >> 4;
 
-  if (state->audioCodec != soundFormat)
-  {
-    if (FLVAudioCodecs[soundFormat] != NULL) 
-    {
-#if DEBUG
-      printf("FLV: New AUDIO Codec: %s\n", FLVAudioCodecs[soundFormat]);
-#endif
-      prev = addKeyword (EXTRACTOR_FORMAT, 
-                         strdup (FLVAudioCodecs[soundFormat]),
-                         prev);
-    }
-  }
   state->audioCodec = soundFormat;
-
-  if (state->audioRate != soundRate ||
-        state->audioChannels != soundType ||
-        state->audioSampleBits != soundSize) {
-    char s[48];
-#if DEBUG
-    printf("FLV: New AUDIO Format\n");
-#endif
-    snprintf (s, 32, "%s Hz, %s, %s", FLVAudioSampleRates[soundRate], 
-                                   FLVAudioSampleSizes[soundSize],
-                                   FLVAudioChannels[soundType]);
-    prev = addKeyword (EXTRACTOR_FORMAT, strdup (s), prev);
-  }
   state->audioRate = soundRate;
   state->audioChannels = soundType;
   state->audioSampleBits = soundSize;
@@ -254,18 +552,6 @@
   codecId = *data & 0x0F;
   frameType = (*data & 0xF0) >> 4;
 
-  if (state->videoCodec != codecId)
-  {
-    if (FLVVideoCodecs[codecId] != NULL)
-    {
-#if DEBUG
-      printf("FLV: New VIDEO Codec: %s\n", FLVVideoCodecs[codecId]);
-#endif
-      prev = addKeyword (EXTRACTOR_FORMAT, 
-                         strdup (FLVVideoCodecs[codecId]),
-                         prev);
-    }
-  }
   state->videoCodec = codecId;
   return prev;
 }
@@ -294,7 +580,10 @@
       head = handleVideoBody(ptr, header.bodyLength, state, head);
       break;
     case FLV_TAG_TYPE_META:
+      head = handleMetaBody(ptr, header.bodyLength, state, head);
       break;
+    default:
+      break;
   }
 
   ptr += header.bodyLength;
@@ -304,6 +593,119 @@
   return 0;
 }
 
+#define MAX_FLV_FORMAT_LINE 80
+static char * printVideoFormat(FLVStreamState *state)
+{
+  char *s;
+  int n;
+  size_t len = MAX_FLV_FORMAT_LINE;
+
+  s = malloc(len);
+  if (s == NULL)
+    return NULL;
+
+  n = 0;
+  if (state->videoWidth != -1 || state->videoHeight != -1) {
+    if (n < len) {
+      if (state->videoWidth != -1)
+        n += snprintf(s+n, len-n, "%dx", state->videoWidth);
+      else
+        n += snprintf(s+n, len-n, "?x", state->videoWidth);
+    }
+
+    if (n < len) {
+      if (state->videoHeight != -1)
+        n += snprintf(s+n, len-n, "%d", state->videoHeight);
+      else
+        n += snprintf(s+n, len-n, "?", state->videoHeight);
+    }
+  }
+
+  if (state->videoFrameRate != 0.0 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%0.2f fps", state->videoFrameRate);
+  }
+
+  if (state->videoCodec != -1 && FLVVideoCodecs[state->videoCodec] != NULL &&
+      n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", FLVVideoCodecs[state->videoCodec]);
+  }
+
+  if (state->videoDataRate != 0.0 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%.4f kbps", state->videoDataRate);
+  }
+
+  if (n == 0) {
+    free(s);
+    s = NULL;
+  }
+
+  return s;
+}
+
+static char * printAudioFormat(FLVStreamState *state)
+{
+  char *s;
+  int n;
+  size_t len = MAX_FLV_FORMAT_LINE;
+
+  s = malloc(len);
+  if (s == NULL)
+    return NULL;
+
+  n = 0;
+
+  if (state->audioRate != -1 && n < len) {
+      n += snprintf(s+n, len-n, "%s Hz", 
FLVAudioSampleRates[state->audioRate]);
+  }
+
+  if (state->audioSampleBits != -1 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", 
+                    FLVAudioSampleSizes[state->audioSampleBits]);
+  }
+
+  if (state->audioChannels != -1 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", 
+                    FLVAudioChannels[state->audioChannels]);
+  }
+
+  if (state->audioCodec != -1 && FLVAudioCodecs[state->audioCodec] != NULL &&
+      n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", FLVAudioCodecs[state->audioCodec]);
+  }
+
+  if (state->audioDataRate != 0.0 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%.4f kbps", state->audioDataRate);
+  }
+
+  if (n == 0) {
+    free(s);
+    s = NULL;
+  }
+
+  return s;
+}
+
 struct EXTRACTOR_Keywords *
 libextractor_flv_extract (const char *filename,
                           const unsigned char *data,
@@ -316,6 +718,7 @@
   FLVStreamState state;
   FLVHeader header;
   unsigned long prev_tag_size;
+  char *s;
 
   ptr = data;
   end = ptr + size;
@@ -332,17 +735,32 @@
   if (header.version != 1)
     return result;
 
-  if (readPreviousTagSize(&ptr, end, &prev_tag_size) == -1)
+  if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
     return result;
 
   state.videoCodec = -1;
+  state.videoWidth = -1;
+  state.videoHeight = -1;
+  state.videoFrameRate = 0.0;
+  state.videoDataRate = 0.0;
   state.audioCodec = -1;
   state.audioRate = -1;
+  state.audioSampleBits = -1;
+  state.audioChannels = -1;
+  state.audioDataRate = 0.0;
   while (ptr < end) {
-    if (readFLVTag(&ptr, end, &state, &result) == -1)
+    if (readFLVTag (&ptr, end, &state, &result) == -1)
       break;
-    if (readPreviousTagSize(&ptr, end, &prev_tag_size) == -1)
+    if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
       break;
   }
+
+  s = printVideoFormat (&state);
+  if (s != NULL)
+    result = addKeyword (EXTRACTOR_FORMAT, s, result);
+  s = printAudioFormat (&state);
+  if (s != NULL)
+    result = addKeyword (EXTRACTOR_FORMAT, s, result);
+
   return result;
 }





reply via email to

[Prev in Thread] Current Thread [Next in Thread]