gnunet-svn
[Top][All Lists]
Advanced

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

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


From: gnunet
Subject: [GNUnet-SVN] r9792 - Extractor/src/plugins
Date: Fri, 18 Dec 2009 18:21:02 +0100

Author: grothoff
Date: 2009-12-18 18:21:02 +0100 (Fri, 18 Dec 2009)
New Revision: 9792

Added:
   Extractor/src/plugins/flv_extractor.c
Removed:
   Extractor/src/plugins/flvextractor.c
Modified:
   Extractor/src/plugins/Makefile.am
Log:
flv

Modified: Extractor/src/plugins/Makefile.am
===================================================================
--- Extractor/src/plugins/Makefile.am   2009-12-18 15:38:35 UTC (rev 9791)
+++ Extractor/src/plugins/Makefile.am   2009-12-18 17:21:02 UTC (rev 9792)
@@ -74,6 +74,7 @@
   libextractor_elf.la \
   $(exiv2) \
   $(flac) \
+  libextractor_flv.la \
   libextractor_gif.la \
   libextractor_html.la \
   libextractor_it.la \
@@ -135,6 +136,13 @@
   -lFLAC $(flacoggflag) \
   $(LE_LIBINTL)
 
+libextractor_flv_la_SOURCES = \
+  flv_extractor.c
+libextractor_flv_la_LDFLAGS = \
+  $(PLUGINFLAGS)
+libextractor_flv_la_LIBADD = \
+  $(top_builddir)/src/common/libextractor_common.la
+
 libextractor_gif_la_SOURCES = \
   gif_extractor.c 
 libextractor_gif_la_LDFLAGS = \
@@ -239,7 +247,6 @@
 
 
 OLD_LIBS = \
-  libextractor_flv.la \
   libextractor_id3v2.la \
   libextractor_id3v24.la \
   libextractor_id3v23.la \
@@ -325,13 +332,6 @@
 libextractor_zip_la_LIBADD = \
   $(top_builddir)/src/main/libextractor.la
 
-libextractor_flv_la_SOURCES = \
-  flvextractor.c
-libextractor_flv_la_LDFLAGS = \
-  $(PLUGINFLAGS)
-libextractor_flv_la_LIBADD = \
-  $(top_builddir)/src/common/libextractor_common.la
-
 libextractor_real_la_SOURCES = \
   realextractor.c 
 libextractor_real_la_LDFLAGS = \

Copied: Extractor/src/plugins/flv_extractor.c (from rev 9791, 
Extractor/src/plugins/flvextractor.c)
===================================================================
--- Extractor/src/plugins/flv_extractor.c                               (rev 0)
+++ Extractor/src/plugins/flv_extractor.c       2009-12-18 17:21:02 UTC (rev 
9792)
@@ -0,0 +1,1238 @@
+/*
+     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/flv
+ *     http://osflash.org/documentation/amf
+ */
+#include "platform.h"
+#include "extractor.h"
+#include "convert_numeric.h"
+#include <string.h>
+
+#define DEBUG 0
+
+#define FLV_SIGNATURE "FLV"
+
+/*
+ * AMF parser
+ */
+
+/* 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;
+
+/* core datatypes */
+
+static uint32_t readInt32(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  uint32_t val;
+
+  val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
+  ptr += 4;
+  *data = ptr;
+  return val;
+}
+
+static uint32_t readInt24(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  uint32_t val;
+
+  val = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
+  ptr += 3;
+  *data = ptr;
+  return val;
+}
+
+static uint16_t readInt16(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  uint16_t val;
+
+  val = (ptr[0] << 8) | ptr[1];
+  ptr += 2;
+  *data = ptr;
+  return val;
+}
+
+static double readDouble(const unsigned char **data)
+{
+  const unsigned char *ptr = *data;
+  double val;
+
+  
EXTRACTOR_common_floatformat_to_double(&EXTRACTOR_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;
+  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;
+  int val;
+
+  if (*len < 1)
+    return -1;
+
+  val = (*ptr != 0x00);
+  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;
+
+  if (*len < 10)
+    return -1;
+
+  *millis = readDouble(&ptr);
+  *len -= 8;
+
+  *zone = readInt16(&ptr);
+  *len -= 2;
+
+  *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 = readInt16(&ptr);
+
+  if (*len < (2 + slen))
+    return -1;
+
+  ret = malloc(slen+1);
+  if (ret == NULL)
+    return -1;
+  memcpy(ret, ptr, slen);
+  ret[slen] = '\0';
+  ptr += slen;
+  *len -= (2 + slen);
+
+  *retval = ret;
+  *data = ptr;
+  return 0;
+}
+
+static 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:
+    case ASTYPE_ENDOFOBJECT:
+      ret = 0;
+      (*(handler->as_end_callback))(astype, NULL, handler->userdata);
+      break;
+    case ASTYPE_ARRAY:
+    {
+      long i, alen;
+      if (*len < 4) {
+        ret = -1;
+        break;
+      }
+      alen = readInt32(&ptr);
+      *len -= 4;
+      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);
+      break;
+    }
+    case ASTYPE_OBJECT:
+    {
+      char *key;
+      unsigned char type;
+
+      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);
+      break;
+    }
+    case ASTYPE_MIXEDARRAY:
+    {
+      char *key;
+      unsigned char type;
+      long max_index;
+
+      if (*len < 4) {
+        ret = -1;
+        break;
+      }
+      max_index = readInt32(&ptr);
+      *len -= 4;
+      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);
+      break;
+    }
+    default:
+      ret = -1;
+      (*(handler->as_end_callback))(astype,
+                                    NULL,
+                                    handler->userdata);
+#if DEBUG
+      printf("parse_amf: Unknown type %02x", astype);
+#endif
+      break;
+  }
+
+  *data = ptr;
+  return ret;
+}
+
+/*
+ * FLV parser
+ */
+
+/* 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;
+}
+
+typedef struct
+{
+  char signature[3];
+  unsigned char version;
+  unsigned char flags;
+  unsigned long offset;
+} FLVHeader;
+
+#define FLV_HEADER_SIZE 9
+
+#define FLV_TAG_TYPE_AUDIO 0x08
+#define FLV_TAG_TYPE_VIDEO 0x09
+#define FLV_TAG_TYPE_META  0x12
+
+typedef struct
+{
+  unsigned char type;
+  unsigned long bodyLength;
+  uint32_t timestamp;
+  unsigned long streamId;
+} FLVTagHeader;
+
+#define FLV_TAG_HEADER_SIZE 11
+
+static int readFLVHeader(const unsigned char **data,
+                        const unsigned char *end,
+                        FLVHeader *hdr)
+{
+  const unsigned char *ptr = *data;
+
+  if ((ptr + FLV_HEADER_SIZE) > end)
+    return -1;
+
+  memcpy(hdr->signature, ptr, 3);
+  ptr += 3;
+  hdr->version = *ptr++;
+  hdr->flags = *ptr++;
+  hdr->offset = readInt32(&ptr);
+  if (hdr->offset != FLV_HEADER_SIZE)
+    return -1;
+
+  *data = ptr;
+  return 0;
+}
+
+static int readPreviousTagSize(const unsigned char **data,
+                                const unsigned char *end,
+                                unsigned long *prev_size)
+{
+  const unsigned char *ptr = *data;
+
+  if ((ptr + 4) > end)
+    return -1;
+
+  *prev_size = readInt32(&ptr);
+
+  *data = ptr;
+  return 0;
+}
+
+static int readFLVTagHeader(const unsigned char **data,
+                          const unsigned char *end,
+                          FLVTagHeader *hdr)
+{
+  const unsigned char *ptr = *data;
+
+  if ((ptr + FLV_TAG_HEADER_SIZE) > end)
+    return -1;
+
+  hdr->type = *ptr++;
+  hdr->bodyLength = readInt24(&ptr);
+  hdr->timestamp = readInt32(&ptr);
+  hdr->streamId = readInt24(&ptr);
+
+  *data = ptr;
+  return 0;
+}
+
+typedef struct {
+  int videoCodec;
+  char *videoCodecStr;
+  int videoWidth;
+  int videoHeight;
+  double videoDataRate;
+  double videoFrameRate;
+
+  int audioCodec;
+  char *audioCodecStr;
+  double audioDataRate;
+  int audioChannels;
+  int audioSampleBits;
+  int audioRate;
+} FLVStreamInfo;
+
+typedef enum {
+  FLV_NONE = 0,
+  FLV_WIDTH,
+  FLV_HEIGHT,
+  FLV_FRAMERATE,
+  FLV_STEREO,
+  FLV_ACHANNELS,
+  FLV_VDATARATE,
+  FLV_ADATARATE,
+  FLV_VCODECID,
+  FLV_ACODECID
+} FLVStreamAttribute;
+
+typedef struct {
+  const char *key;
+  FLVStreamAttribute attribute;
+} MetaKeyToStreamAttribute;
+
+static MetaKeyToStreamAttribute key_to_attribute_map[] = {
+  { "width", FLV_WIDTH },
+  { "height", FLV_HEIGHT },
+  { "framerate", FLV_FRAMERATE },
+  { "videoframerate", FLV_FRAMERATE },
+  { "stereo", FLV_STEREO },
+  { "audiochannels", FLV_ACHANNELS },
+  { "videodatarate", FLV_VDATARATE },
+  { "audiodatarate", FLV_ADATARATE },
+  { "videocodecid", FLV_VCODECID },
+  { "audiocodecid", FLV_ACODECID },
+  { NULL, FLV_NONE }
+};
+
+typedef struct {
+  const char *key;
+  enum EXTRACTOR_MetaType type;
+} MetaKeyToExtractorItem;
+
+static MetaKeyToExtractorItem key_to_extractor_map[] = {
+  { "duration", EXTRACTOR_METATYPE_DURATION },
+  { "creator", EXTRACTOR_METATYPE_CREATOR },
+  { "metadatacreator", EXTRACTOR_METATYPE_CREATOR },
+  { "creationdate", EXTRACTOR_METATYPE_CREATION_DATE },
+  { "metadatadate", EXTRACTOR_METATYPE_MODIFICATION_DATE },
+  { NULL, EXTRACTOR_METATYPE_RESERVED }
+};
+
+typedef struct {
+  int onMetaData;
+  int parsingDepth;
+  int ret;
+  /* mixed array keys mapped to something readily usable */
+  enum EXTRACTOR_MetaType currentKeyType;
+  FLVStreamAttribute currentAttribute;
+
+  EXTRACTOR_MetaDataProcessor proc;
+  void *proc_cls;
+  FLVStreamInfo *streamInfo;
+} FLVMetaParserState;
+
+static void handleASBegin(unsigned char type, void * userdata)
+{
+  FLVMetaParserState *state = (FLVMetaParserState *)userdata;
+
+  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 (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;
+  const char *s;
+  char tmpstr[30];
+
+  if ((state->parsingDepth == 0) && (type == ASTYPE_STRING)) {
+    s = (const 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_NONE:
+      case FLV_STEREO:
+        break;
+      case FLV_ACHANNELS:
+        state->streamInfo->audioChannels = n;
+        break;
+      case FLV_WIDTH:
+        if (state->streamInfo->videoWidth == -1)
+          state->streamInfo->videoWidth = n;
+        break;
+      case FLV_HEIGHT:
+        if (state->streamInfo->videoHeight == -1)
+          state->streamInfo->videoHeight = n;
+        break;
+      case FLV_FRAMERATE:
+        state->streamInfo->videoFrameRate = n;
+        break;
+      case FLV_VDATARATE:
+        state->streamInfo->videoDataRate = n;
+        break;
+      case FLV_ADATARATE:
+        state->streamInfo->audioDataRate = n;
+        break;
+      case FLV_VCODECID:
+        if (state->streamInfo->videoCodec == -1)
+          state->streamInfo->videoCodec = n;
+        /* prefer codec ids to fourcc codes */
+        if (state->streamInfo->videoCodecStr != NULL) {
+          free(state->streamInfo->videoCodecStr);
+          state->streamInfo->videoCodecStr = NULL;
+        }
+        break;
+      case FLV_ACODECID:
+        if (state->streamInfo->audioCodec == -1)
+          state->streamInfo->audioCodec = n;
+        /* prefer codec ids to fourcc codes */
+        if (state->streamInfo->audioCodecStr != NULL) {
+          free(state->streamInfo->audioCodecStr);
+          state->streamInfo->audioCodecStr = NULL;
+        }
+        break;
+    }
+  }
+
+  /* sometimes a/v codecs are as fourcc strings */
+  if (state->onMetaData && (state->parsingDepth == 1) &&
+      (state->currentAttribute != FLV_NONE) &&
+      (type == ASTYPE_STRING))
+  {
+    s = (const char *)value;
+    switch (state->currentAttribute) {
+      case FLV_VCODECID:
+        if (s != NULL && state->streamInfo->videoCodecStr == NULL &&
+            state->streamInfo->videoCodec == -1)
+          state->streamInfo->videoCodecStr = strdup(s);
+        break;
+      case FLV_ACODECID:
+        if (s != NULL && state->streamInfo->audioCodecStr == NULL &&
+            state->streamInfo->audioCodec == -1)
+          state->streamInfo->audioCodecStr = strdup(s);
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (state->onMetaData && (state->parsingDepth == 1) &&
+      (state->currentAttribute == FLV_STEREO) &&
+      (type == ASTYPE_BOOLEAN))
+  {
+    int n = *((int *)value);
+    if (state->streamInfo->audioChannels == -1)
+      state->streamInfo->audioChannels = (n == 0) ? 1 : 2;
+  }
+
+  /* metadata that maps straight to extractor keys */
+  if (state->onMetaData && (state->parsingDepth == 1) &&
+      (state->currentKeyType != EXTRACTOR_METATYPE_RESERVED))
+  {
+    s = NULL;
+    switch (type) {
+      case ASTYPE_NUMBER:
+      {
+        double n = *((double *)value);
+        s = tmpstr;
+       if (state->currentKeyType == EXTRACTOR_METATYPE_DURATION)
+          snprintf(tmpstr, sizeof(tmpstr), "%.2f s", n);
+       else
+          snprintf(tmpstr, sizeof(tmpstr), "%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 = tmpstr;
+       flv_to_iso_date(*millis, *tz, tmpstr, sizeof(tmpstr));
+        break;
+      }
+    }
+    if ( (s != NULL) &&
+        (state->ret == 0) )
+      state->ret = state->proc (state->proc_cls,
+                               "flv",
+                               state->currentKeyType,
+                               EXTRACTOR_METAFORMAT_UTF8,
+                               "text/plain",
+                               s,
+                               strlen (s) + 1);
+  }
+  state->currentKeyType = EXTRACTOR_METATYPE_RESERVED;
+  state->currentAttribute = FLV_NONE;
+
+  if (type == ASTYPE_ARRAY || type == ASTYPE_MIXEDARRAY ||
+      type == ASTYPE_OBJECT)
+    state->parsingDepth--;
+}
+
+static int
+handleMetaBody(const unsigned char *data, size_t len,
+              FLVStreamInfo *stinfo,
+              EXTRACTOR_MetaDataProcessor proc,
+              void *proc_cls)
+{
+  AMFParserHandler handler;
+  FLVMetaParserState pstate;
+
+  pstate.onMetaData = 0;
+  pstate.currentKeyType = EXTRACTOR_METATYPE_RESERVED;
+  pstate.parsingDepth = 0;
+  pstate.streamInfo = stinfo;
+  pstate.ret = 0;
+  pstate.proc = proc;
+  pstate.proc_cls = proc_cls;
+  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);
+  if (pstate.ret != 0)
+    return 1;
+  return 0;
+}
+
+static char *FLVAudioCodecs[] = {
+  "Uncompressed",
+  "ADPCM",
+  "MP3",
+  NULL,
+  NULL,
+  "Nellymoser 8kHz mono",
+  "Nellymoser",
+  NULL,
+  NULL,
+  NULL,
+  "AAC",
+  "Speex"
+};
+
+static char *FLVAudioChannels[] = {
+  "mono",
+  "stereo"
+};
+
+static char *FLVAudioSampleSizes[] = {
+  "8-bit",
+  "16-bit"
+};
+
+static char *FLVAudioSampleRates[] = {
+  "5512.5",
+  "11025",
+  "22050",
+  "44100"
+};
+
+static void
+handleAudioBody(const unsigned char *data, size_t len,
+                FLVStreamInfo *stinfo)
+{
+  stinfo->audioChannels = (*data & 0x01) + 1;
+  stinfo->audioSampleBits = (*data & 0x02) >> 1;
+  stinfo->audioRate = (*data & 0x0C) >> 2;
+  stinfo->audioCodec = (*data & 0xF0) >> 4;
+  if (stinfo->audioCodecStr != NULL) {
+    free(stinfo->audioCodecStr);
+    stinfo->audioCodecStr = NULL;
+  }
+}
+
+static char *FLVVideoCodecs[] = {
+  NULL,
+  NULL,
+  "Sorenson Spark",
+  "ScreenVideo",
+  "On2 TrueMotion VP6",
+  "On2 TrueMotion VP6 Alpha",
+  "ScreenVideo 2",
+  "H.264" /* XXX not found in docs */
+};
+
+static int sorenson_predefined_res[][2] = {
+  { -1, -1 },
+  { -1, -1 },
+  { 352, 288 },
+  { 176, 144 },
+  { 128, 96 },
+  { 320, 240 },
+  { 160, 120 },
+  { -1, -1 }
+};
+
+static void
+handleVideoBody(const unsigned char *data, size_t len,
+                FLVStreamInfo *stinfo)
+{
+  int codecId, frameType;
+
+  codecId = *data & 0x0F;
+  frameType = (*data & 0xF0) >> 4;
+  data++;
+
+  /* try to get video dimensions */
+  switch (codecId) {
+    case 0x02: /* Sorenson */
+      if (len < 9)
+        break;
+      if (frameType == 1) {
+        int start_code = (data[0] << 9) | (data[1] << 1) | ((data[2] >> 
7)&0x1);
+        int version = (data[2] & 0x7C) >> 2;
+        int frame_size = ((data[3] & 0x03) << 1) | (data[4] >> 7);
+        if (start_code != 0x00000001)
+          break;
+        if (!(version == 0 || version == 1))
+          break;
+        if (frame_size == 0) {
+          stinfo->videoWidth = ((data[4] & 0x7F) >> 1) | (data[5] >> 7);
+          stinfo->videoHeight = ((data[5] & 0x7F) >> 1) | (data[6] >> 7);
+        }
+        else if (frame_size == 1) {
+          stinfo->videoWidth = ((data[4] & 0x7F) << 9) | (data[5] << 1) |
+                               (data[6] >> 7);
+          stinfo->videoHeight = ((data[6] & 0x7F) << 9) | (data[7] << 1) |
+                                (data[8] >> 7);
+        }
+        else {
+          stinfo->videoWidth = sorenson_predefined_res[frame_size][0];
+          stinfo->videoHeight = sorenson_predefined_res[frame_size][1];
+        }
+      }
+      break;
+    case 0x03: /* ScreenVideo */
+      if (len < 5)
+        break;
+      stinfo->videoWidth = readInt16(&data) & 0x0FFF;
+      stinfo->videoHeight = readInt16(&data) & 0x0FFF;
+      break;
+    case 0x04: /* On2 VP6 */
+    case 0x05:
+    {
+      unsigned char dim_adj;
+      if (len < 10)
+        break;
+      dim_adj = *data++;
+      if ((frameType == 1) && ((data[0] & 0x80) == 0)) {
+        /* see ffmpeg vp6 decoder */
+        int separated_coeff = data[0] & 0x01;
+        int filter_header = data[1] & 0x06;
+        /*int interlaced = data[1] & 0x01; TODO: used in flv ever? */
+        if (separated_coeff || !filter_header) {
+          data += 2;
+        }
+        /* XXX encoded/displayed dimensions might vary, but which are the
+         * right ones? */
+        stinfo->videoWidth = (data[3]*16) - (dim_adj>>4);
+        stinfo->videoHeight = (data[2]*16) - (dim_adj&0x0F);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  stinfo->videoCodec = codecId;
+  if (stinfo->videoCodecStr != NULL) {
+    free(stinfo->videoCodecStr);
+    stinfo->videoCodecStr = NULL;
+  }
+}
+
+static int readFLVTag(const unsigned char **data,
+                      const unsigned char *end,
+                      FLVStreamInfo *stinfo,
+                     EXTRACTOR_MetaDataProcessor proc,
+                     void *proc_cls)
+{
+  const unsigned char *ptr = *data;
+  FLVTagHeader header;
+  int ret = 0;
+
+  if (readFLVTagHeader(&ptr, end, &header) == -1)
+    return -1;
+
+  if ((ptr + header.bodyLength) > end)
+    return -1;
+
+  switch (header.type)
+  {
+    case FLV_TAG_TYPE_AUDIO:
+      handleAudioBody(ptr, header.bodyLength, stinfo);
+      break;
+    case FLV_TAG_TYPE_VIDEO:
+      handleVideoBody(ptr, header.bodyLength, stinfo);
+      break;
+    case FLV_TAG_TYPE_META:
+      ret = handleMetaBody(ptr, header.bodyLength, stinfo, proc, proc_cls);
+      break;
+    default:
+      break;
+  }
+
+  ptr += header.bodyLength;
+  *data = ptr;
+  return ret;
+}
+
+#define MAX_FLV_FORMAT_LINE 80
+static char * printVideoFormat(FLVStreamInfo *stinfo)
+{
+  char s[MAX_FLV_FORMAT_LINE+1];
+  int n;
+  size_t len = MAX_FLV_FORMAT_LINE;
+
+  n = 0;
+  /* some files seem to specify only the width or the height, print '?' for
+   * the unknown dimension */
+  if (stinfo->videoWidth != -1 || stinfo->videoHeight != -1) {
+    if (n < len) {
+      if (stinfo->videoWidth != -1)
+        n += snprintf(s+n, len-n, "%d", stinfo->videoWidth);
+      else
+        n += snprintf(s+n, len-n, "?");
+    }
+
+    if (n < len) {
+      if (stinfo->videoHeight != -1)
+        n += snprintf(s+n, len-n, "x%d", stinfo->videoHeight);
+      else
+        n += snprintf(s+n, len-n, "x?");
+    }
+  }
+
+  if (stinfo->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", stinfo->videoFrameRate);
+  }
+
+  if (stinfo->videoCodec > -1 && stinfo->videoCodec < 8 &&
+      FLVVideoCodecs[stinfo->videoCodec] != NULL && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", FLVVideoCodecs[stinfo->videoCodec]);
+  }
+  else if (stinfo->videoCodecStr != NULL && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", stinfo->videoCodecStr);    
+  }
+
+  if (stinfo->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", stinfo->videoDataRate);
+  }
+
+  if (n == 0)
+    return NULL;
+  return strdup(s);
+}
+
+static char * printAudioFormat(FLVStreamInfo *stinfo)
+{
+  char s[MAX_FLV_FORMAT_LINE+1];
+  int n;
+  size_t len = MAX_FLV_FORMAT_LINE;
+
+  n = 0;
+  if (stinfo->audioRate != -1 && n < len) {
+      n += snprintf(s+n, len-n, "%s Hz", 
FLVAudioSampleRates[stinfo->audioRate]);
+  }
+
+  if (stinfo->audioSampleBits != -1 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s",
+                    FLVAudioSampleSizes[stinfo->audioSampleBits]);
+  }
+
+  if (stinfo->audioChannels != -1 && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len) {
+      if (stinfo->audioChannels >= 1 && stinfo->audioChannels <= 2)
+        n += snprintf(s+n, len-n, "%s",
+                      FLVAudioChannels[stinfo->audioChannels-1]);
+      else
+        n += snprintf(s+n, len-n, "%d",
+                      stinfo->audioChannels);
+    }
+  }
+
+  if (stinfo->audioCodec > -1 && stinfo->audioCodec < 12 &&
+      FLVAudioCodecs[stinfo->audioCodec] != NULL && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", FLVAudioCodecs[stinfo->audioCodec]);
+  }
+  else if (stinfo->audioCodecStr != NULL && n < len) {
+    if (n > 0)
+      n += snprintf(s+n, len-n, ", ");
+    if (n < len)
+      n += snprintf(s+n, len-n, "%s", stinfo->audioCodecStr);    
+  }
+
+  if (stinfo->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", stinfo->audioDataRate);
+  }
+
+  if (n == 0)
+    return NULL;
+  return strdup(s);
+}
+
+int 
+EXTRACTOR_flv_extract (const unsigned char *data,
+                      size_t size,
+                      EXTRACTOR_MetaDataProcessor proc,
+                      void *proc_cls,
+                      const char *options)
+{
+  const unsigned char *ptr;
+  const unsigned char *end;
+  FLVStreamInfo stinfo;
+  FLVHeader header;
+  unsigned long prev_tag_size;
+  char *s;
+  int ret;
+
+  ptr = data;
+  end = ptr + size;
+
+  if (readFLVHeader(&ptr, end, &header) == -1)
+    return 0;
+
+  if (memcmp(header.signature, FLV_SIGNATURE, 3) != 0)
+    return 0;
+
+  if (0 != proc (proc_cls,
+                "flv",
+                EXTRACTOR_METATYPE_MIMETYPE, 
+                EXTRACTOR_METAFORMAT_UTF8,
+                "text/plain",
+                "video/x-flv",
+                strlen ("video/x-flv") + 1))
+    return 0;
+  if (header.version != 1)
+    return 0;
+  if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
+    return 0;
+
+  stinfo.videoCodec = -1;
+  stinfo.videoCodecStr = NULL;
+  stinfo.videoWidth = -1;
+  stinfo.videoHeight = -1;
+  stinfo.videoFrameRate = 0.0;
+  stinfo.videoDataRate = 0.0;
+  stinfo.audioCodec = -1;
+  stinfo.audioCodecStr = NULL;
+  stinfo.audioRate = -1;
+  stinfo.audioSampleBits = -1;
+  stinfo.audioChannels = -1;
+  stinfo.audioDataRate = 0.0;
+  ret = 0;
+  while (ptr < end) {
+    if (-1 == (ret = readFLVTag (&ptr, end, &stinfo, proc, proc_cls)))
+      break;
+    if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
+      break;
+  }
+  if (1 == ret)
+    return 1;
+  s = printVideoFormat (&stinfo);
+  if (s != NULL)
+    {
+      if (0 != proc (proc_cls, 
+                    "flv",
+                    EXTRACTOR_METATYPE_RESOURCE_TYPE,
+                    EXTRACTOR_METAFORMAT_UTF8,
+                    "text/plain",
+                    s,
+                    strlen (s)+1))
+       {
+         free (s);
+         return 1;
+       }
+      free (s);
+    }
+  s = printAudioFormat (&stinfo);
+  if (s != NULL)
+    {
+      if (0 != proc (proc_cls, 
+                    "flv",
+                    EXTRACTOR_METATYPE_RESOURCE_TYPE,
+                    EXTRACTOR_METAFORMAT_UTF8,
+                    "text/plain",
+                    s,
+                    strlen (s)+1))
+       {
+         free (s);
+         return 1;
+       }
+      free (s);
+    }
+  return 0;
+}

Deleted: Extractor/src/plugins/flvextractor.c
===================================================================
--- Extractor/src/plugins/flvextractor.c        2009-12-18 15:38:35 UTC (rev 
9791)
+++ Extractor/src/plugins/flvextractor.c        2009-12-18 17:21:02 UTC (rev 
9792)
@@ -1,1220 +0,0 @@
-/*
-     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/flv
- *     http://osflash.org/documentation/amf
- */
-#include "platform.h"
-#include "extractor.h"
-#include "convert_numeric.h"
-#include <string.h>
-
-#define DEBUG 0
-
-#define FLV_SIGNATURE "FLV"
-
-static struct EXTRACTOR_Keywords *
-addKeyword (EXTRACTOR_KeywordType type,
-            char *keyword, struct EXTRACTOR_Keywords *next)
-{
-  EXTRACTOR_KeywordList *result;
-
-  if (keyword == NULL)
-    return next;
-  result = malloc (sizeof (EXTRACTOR_KeywordList));
-  result->next = next;
-  result->keyword = keyword;
-  result->keywordType = type;
-  return result;
-}
-
-/*
- * AMF parser
- */
-
-/* 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;
-
-/* core datatypes */
-
-static uint32_t readInt32(const unsigned char **data)
-{
-  const unsigned char *ptr = *data;
-  uint32_t val;
-
-  val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
-  ptr += 4;
-  *data = ptr;
-  return val;
-}
-
-static uint32_t readInt24(const unsigned char **data)
-{
-  const unsigned char *ptr = *data;
-  uint32_t val;
-
-  val = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2];
-  ptr += 3;
-  *data = ptr;
-  return val;
-}
-
-static uint16_t readInt16(const unsigned char **data)
-{
-  const unsigned char *ptr = *data;
-  uint16_t val;
-
-  val = (ptr[0] << 8) | ptr[1];
-  ptr += 2;
-  *data = ptr;
-  return val;
-}
-
-static double readDouble(const unsigned char **data)
-{
-  const unsigned char *ptr = *data;
-  double val;
-
-  
EXTRACTOR_common_floatformat_to_double(&EXTRACTOR_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;
-  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;
-  int val;
-
-  if (*len < 1)
-    return -1;
-
-  val = (*ptr != 0x00);
-  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;
-
-  if (*len < 10)
-    return -1;
-
-  *millis = readDouble(&ptr);
-  *len -= 8;
-
-  *zone = readInt16(&ptr);
-  *len -= 2;
-
-  *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 = readInt16(&ptr);
-
-  if (*len < (2 + slen))
-    return -1;
-
-  ret = malloc(slen+1);
-  if (ret == NULL)
-    return -1;
-  memcpy(ret, ptr, slen);
-  ret[slen] = '\0';
-  ptr += slen;
-  *len -= (2 + slen);
-
-  *retval = ret;
-  *data = ptr;
-  return 0;
-}
-
-static 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:
-    case ASTYPE_ENDOFOBJECT:
-      ret = 0;
-      (*(handler->as_end_callback))(astype, NULL, handler->userdata);
-      break;
-    case ASTYPE_ARRAY:
-    {
-      long i, alen;
-      if (*len < 4) {
-        ret = -1;
-        break;
-      }
-      alen = readInt32(&ptr);
-      *len -= 4;
-      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);
-      break;
-    }
-    case ASTYPE_OBJECT:
-    {
-      char *key;
-      unsigned char type;
-
-      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);
-      break;
-    }
-    case ASTYPE_MIXEDARRAY:
-    {
-      char *key;
-      unsigned char type;
-      long max_index;
-
-      if (*len < 4) {
-        ret = -1;
-        break;
-      }
-      max_index = readInt32(&ptr);
-      *len -= 4;
-      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);
-      break;
-    }
-    default:
-      ret = -1;
-      (*(handler->as_end_callback))(astype,
-                                    NULL,
-                                    handler->userdata);
-#if DEBUG
-      printf("parse_amf: Unknown type %02x", astype);
-#endif
-      break;
-  }
-
-  *data = ptr;
-  return ret;
-}
-
-/*
- * FLV parser
- */
-
-/* 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;
-}
-
-typedef struct
-{
-  char signature[3];
-  unsigned char version;
-  unsigned char flags;
-  unsigned long offset;
-} FLVHeader;
-
-#define FLV_HEADER_SIZE 9
-
-#define FLV_TAG_TYPE_AUDIO 0x08
-#define FLV_TAG_TYPE_VIDEO 0x09
-#define FLV_TAG_TYPE_META  0x12
-
-typedef struct
-{
-  unsigned char type;
-  unsigned long bodyLength;
-  uint32_t timestamp;
-  unsigned long streamId;
-} FLVTagHeader;
-
-#define FLV_TAG_HEADER_SIZE 11
-
-static int readFLVHeader(const unsigned char **data,
-                        const unsigned char *end,
-                        FLVHeader *hdr)
-{
-  const unsigned char *ptr = *data;
-
-  if ((ptr + FLV_HEADER_SIZE) > end)
-    return -1;
-
-  memcpy(hdr->signature, ptr, 3);
-  ptr += 3;
-  hdr->version = *ptr++;
-  hdr->flags = *ptr++;
-  hdr->offset = readInt32(&ptr);
-  if (hdr->offset != FLV_HEADER_SIZE)
-    return -1;
-
-  *data = ptr;
-  return 0;
-}
-
-static int readPreviousTagSize(const unsigned char **data,
-                                const unsigned char *end,
-                                unsigned long *prev_size)
-{
-  const unsigned char *ptr = *data;
-
-  if ((ptr + 4) > end)
-    return -1;
-
-  *prev_size = readInt32(&ptr);
-
-  *data = ptr;
-  return 0;
-}
-
-static int readFLVTagHeader(const unsigned char **data,
-                          const unsigned char *end,
-                          FLVTagHeader *hdr)
-{
-  const unsigned char *ptr = *data;
-
-  if ((ptr + FLV_TAG_HEADER_SIZE) > end)
-    return -1;
-
-  hdr->type = *ptr++;
-  hdr->bodyLength = readInt24(&ptr);
-  hdr->timestamp = readInt32(&ptr);
-  hdr->streamId = readInt24(&ptr);
-
-  *data = ptr;
-  return 0;
-}
-
-typedef struct {
-  int videoCodec;
-  char *videoCodecStr;
-  int videoWidth;
-  int videoHeight;
-  double videoDataRate;
-  double videoFrameRate;
-
-  int audioCodec;
-  char *audioCodecStr;
-  double audioDataRate;
-  int audioChannels;
-  int audioSampleBits;
-  int audioRate;
-} FLVStreamInfo;
-
-typedef enum {
-  FLV_NONE = 0,
-  FLV_WIDTH,
-  FLV_HEIGHT,
-  FLV_FRAMERATE,
-  FLV_STEREO,
-  FLV_ACHANNELS,
-  FLV_VDATARATE,
-  FLV_ADATARATE,
-  FLV_VCODECID,
-  FLV_ACODECID
-} FLVStreamAttribute;
-
-typedef struct {
-  const char *key;
-  FLVStreamAttribute attribute;
-} MetaKeyToStreamAttribute;
-
-static MetaKeyToStreamAttribute key_to_attribute_map[] = {
-  { "width", FLV_WIDTH },
-  { "height", FLV_HEIGHT },
-  { "framerate", FLV_FRAMERATE },
-  { "videoframerate", FLV_FRAMERATE },
-  { "stereo", FLV_STEREO },
-  { "audiochannels", FLV_ACHANNELS },
-  { "videodatarate", FLV_VDATARATE },
-  { "audiodatarate", FLV_ADATARATE },
-  { "videocodecid", FLV_VCODECID },
-  { "audiocodecid", FLV_ACODECID },
-  { 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;
-  FLVStreamInfo *streamInfo;
-} FLVMetaParserState;
-
-static void handleASBegin(unsigned char type, void * userdata)
-{
-  FLVMetaParserState *state = (FLVMetaParserState *)userdata;
-
-  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 (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 ((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_NONE:
-      case FLV_STEREO:
-        break;
-      case FLV_ACHANNELS:
-        state->streamInfo->audioChannels = n;
-        break;
-      case FLV_WIDTH:
-        if (state->streamInfo->videoWidth == -1)
-          state->streamInfo->videoWidth = n;
-        break;
-      case FLV_HEIGHT:
-        if (state->streamInfo->videoHeight == -1)
-          state->streamInfo->videoHeight = n;
-        break;
-      case FLV_FRAMERATE:
-        state->streamInfo->videoFrameRate = n;
-        break;
-      case FLV_VDATARATE:
-        state->streamInfo->videoDataRate = n;
-        break;
-      case FLV_ADATARATE:
-        state->streamInfo->audioDataRate = n;
-        break;
-      case FLV_VCODECID:
-        if (state->streamInfo->videoCodec == -1)
-          state->streamInfo->videoCodec = n;
-        /* prefer codec ids to fourcc codes */
-        if (state->streamInfo->videoCodecStr != NULL) {
-          free(state->streamInfo->videoCodecStr);
-          state->streamInfo->videoCodecStr = NULL;
-        }
-        break;
-      case FLV_ACODECID:
-        if (state->streamInfo->audioCodec == -1)
-          state->streamInfo->audioCodec = n;
-        /* prefer codec ids to fourcc codes */
-        if (state->streamInfo->audioCodecStr != NULL) {
-          free(state->streamInfo->audioCodecStr);
-          state->streamInfo->audioCodecStr = NULL;
-        }
-        break;
-    }
-  }
-
-  /* sometimes a/v codecs are as fourcc strings */
-  if (state->onMetaData && (state->parsingDepth == 1) &&
-      (state->currentAttribute != FLV_NONE) &&
-      (type == ASTYPE_STRING))
-  {
-    s = (char *)value;
-    switch (state->currentAttribute) {
-      case FLV_VCODECID:
-        if (s != NULL && state->streamInfo->videoCodecStr == NULL &&
-            state->streamInfo->videoCodec == -1)
-          state->streamInfo->videoCodecStr = strdup(s);
-        break;
-      case FLV_ACODECID:
-        if (s != NULL && state->streamInfo->audioCodecStr == NULL &&
-            state->streamInfo->audioCodec == -1)
-          state->streamInfo->audioCodecStr = strdup(s);
-        break;
-      default:
-        break;
-    }
-  }
-
-  if (state->onMetaData && (state->parsingDepth == 1) &&
-      (state->currentAttribute == FLV_STEREO) &&
-      (type == ASTYPE_BOOLEAN))
-  {
-    int n = *((int *)value);
-    if (state->streamInfo->audioChannels == -1)
-      state->streamInfo->audioChannels = (n == 0) ? 1 : 2;
-  }
-
-  /* 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, "%.2f 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,
-                FLVStreamInfo *stinfo,
-                struct EXTRACTOR_Keywords *prev)
-{
-  AMFParserHandler handler;
-  FLVMetaParserState pstate;
-
-  pstate.onMetaData = 0;
-  pstate.currentKeyType = EXTRACTOR_UNKNOWN;
-  pstate.parsingDepth = 0;
-  pstate.keywords = prev;
-  pstate.streamInfo = stinfo;
-  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",
-  "MP3",
-  NULL,
-  NULL,
-  "Nellymoser 8kHz mono",
-  "Nellymoser",
-  NULL,
-  NULL,
-  NULL,
-  "AAC",
-  "Speex"
-};
-
-static char *FLVAudioChannels[] = {
-  "mono",
-  "stereo"
-};
-
-static char *FLVAudioSampleSizes[] = {
-  "8-bit",
-  "16-bit"
-};
-
-static char *FLVAudioSampleRates[] = {
-  "5512.5",
-  "11025",
-  "22050",
-  "44100"
-};
-
-static struct EXTRACTOR_Keywords *
-handleAudioBody(const unsigned char *data, size_t len,
-                FLVStreamInfo *stinfo,
-                struct EXTRACTOR_Keywords *prev)
-{
-  stinfo->audioChannels = (*data & 0x01) + 1;
-  stinfo->audioSampleBits = (*data & 0x02) >> 1;
-  stinfo->audioRate = (*data & 0x0C) >> 2;
-  stinfo->audioCodec = (*data & 0xF0) >> 4;
-  if (stinfo->audioCodecStr != NULL) {
-    free(stinfo->audioCodecStr);
-    stinfo->audioCodecStr = NULL;
-  }
-
-  return prev;
-}
-
-static char *FLVVideoCodecs[] = {
-  NULL,
-  NULL,
-  "Sorenson Spark",
-  "ScreenVideo",
-  "On2 TrueMotion VP6",
-  "On2 TrueMotion VP6 Alpha",
-  "ScreenVideo 2",
-  "H.264" /* XXX not found in docs */
-};
-
-static int sorenson_predefined_res[][2] = {
-  { -1, -1 },
-  { -1, -1 },
-  { 352, 288 },
-  { 176, 144 },
-  { 128, 96 },
-  { 320, 240 },
-  { 160, 120 },
-  { -1, -1 }
-};
-
-static struct EXTRACTOR_Keywords *
-handleVideoBody(const unsigned char *data, size_t len,
-                FLVStreamInfo *stinfo,
-                struct EXTRACTOR_Keywords *prev)
-{
-  int codecId, frameType;
-
-  codecId = *data & 0x0F;
-  frameType = (*data & 0xF0) >> 4;
-  data++;
-
-  /* try to get video dimensions */
-  switch (codecId) {
-    case 0x02: /* Sorenson */
-      if (len < 9)
-        break;
-      if (frameType == 1) {
-        int start_code = (data[0] << 9) | (data[1] << 1) | ((data[2] >> 
7)&0x1);
-        int version = (data[2] & 0x7C) >> 2;
-        int frame_size = ((data[3] & 0x03) << 1) | (data[4] >> 7);
-        if (start_code != 0x00000001)
-          break;
-        if (!(version == 0 || version == 1))
-          break;
-        if (frame_size == 0) {
-          stinfo->videoWidth = ((data[4] & 0x7F) >> 1) | (data[5] >> 7);
-          stinfo->videoHeight = ((data[5] & 0x7F) >> 1) | (data[6] >> 7);
-        }
-        else if (frame_size == 1) {
-          stinfo->videoWidth = ((data[4] & 0x7F) << 9) | (data[5] << 1) |
-                               (data[6] >> 7);
-          stinfo->videoHeight = ((data[6] & 0x7F) << 9) | (data[7] << 1) |
-                                (data[8] >> 7);
-        }
-        else {
-          stinfo->videoWidth = sorenson_predefined_res[frame_size][0];
-          stinfo->videoHeight = sorenson_predefined_res[frame_size][1];
-        }
-      }
-      break;
-    case 0x03: /* ScreenVideo */
-      if (len < 5)
-        break;
-      stinfo->videoWidth = readInt16(&data) & 0x0FFF;
-      stinfo->videoHeight = readInt16(&data) & 0x0FFF;
-      break;
-    case 0x04: /* On2 VP6 */
-    case 0x05:
-    {
-      unsigned char dim_adj;
-      if (len < 10)
-        break;
-      dim_adj = *data++;
-      if ((frameType == 1) && ((data[0] & 0x80) == 0)) {
-        /* see ffmpeg vp6 decoder */
-        int separated_coeff = data[0] & 0x01;
-        int filter_header = data[1] & 0x06;
-        /*int interlaced = data[1] & 0x01; TODO: used in flv ever? */
-        if (separated_coeff || !filter_header) {
-          data += 2;
-        }
-        /* XXX encoded/displayed dimensions might vary, but which are the
-         * right ones? */
-        stinfo->videoWidth = (data[3]*16) - (dim_adj>>4);
-        stinfo->videoHeight = (data[2]*16) - (dim_adj&0x0F);
-      }
-      break;
-    }
-    default:
-      break;
-  }
-
-  stinfo->videoCodec = codecId;
-  if (stinfo->videoCodecStr != NULL) {
-    free(stinfo->videoCodecStr);
-    stinfo->videoCodecStr = NULL;
-  }
-  return prev;
-}
-
-static int readFLVTag(const unsigned char **data,
-                      const unsigned char *end,
-                      FLVStreamInfo *stinfo,
-                      struct EXTRACTOR_Keywords **list)
-{
-  const unsigned char *ptr = *data;
-  struct EXTRACTOR_Keywords *head = *list;
-  FLVTagHeader header;
-
-  if (readFLVTagHeader(&ptr, end, &header) == -1)
-    return -1;
-
-  if ((ptr + header.bodyLength) > end)
-    return -1;
-
-  switch (header.type)
-  {
-    case FLV_TAG_TYPE_AUDIO:
-      head = handleAudioBody(ptr, header.bodyLength, stinfo, head);
-      break;
-    case FLV_TAG_TYPE_VIDEO:
-      head = handleVideoBody(ptr, header.bodyLength, stinfo, head);
-      break;
-    case FLV_TAG_TYPE_META:
-      head = handleMetaBody(ptr, header.bodyLength, stinfo, head);
-      break;
-    default:
-      break;
-  }
-
-  ptr += header.bodyLength;
-
-  *list = head;
-  *data = ptr;
-  return 0;
-}
-
-#define MAX_FLV_FORMAT_LINE 80
-static char * printVideoFormat(FLVStreamInfo *stinfo)
-{
-  char s[MAX_FLV_FORMAT_LINE+1];
-  int n;
-  size_t len = MAX_FLV_FORMAT_LINE;
-
-  n = 0;
-  /* some files seem to specify only the width or the height, print '?' for
-   * the unknown dimension */
-  if (stinfo->videoWidth != -1 || stinfo->videoHeight != -1) {
-    if (n < len) {
-      if (stinfo->videoWidth != -1)
-        n += snprintf(s+n, len-n, "%d", stinfo->videoWidth);
-      else
-        n += snprintf(s+n, len-n, "?");
-    }
-
-    if (n < len) {
-      if (stinfo->videoHeight != -1)
-        n += snprintf(s+n, len-n, "x%d", stinfo->videoHeight);
-      else
-        n += snprintf(s+n, len-n, "x?");
-    }
-  }
-
-  if (stinfo->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", stinfo->videoFrameRate);
-  }
-
-  if (stinfo->videoCodec > -1 && stinfo->videoCodec < 8 &&
-      FLVVideoCodecs[stinfo->videoCodec] != NULL && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len)
-      n += snprintf(s+n, len-n, "%s", FLVVideoCodecs[stinfo->videoCodec]);
-  }
-  else if (stinfo->videoCodecStr != NULL && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len)
-      n += snprintf(s+n, len-n, "%s", stinfo->videoCodecStr);    
-  }
-
-  if (stinfo->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", stinfo->videoDataRate);
-  }
-
-  if (n == 0)
-    return NULL;
-  return strdup(s);
-}
-
-static char * printAudioFormat(FLVStreamInfo *stinfo)
-{
-  char s[MAX_FLV_FORMAT_LINE+1];
-  int n;
-  size_t len = MAX_FLV_FORMAT_LINE;
-
-  n = 0;
-  if (stinfo->audioRate != -1 && n < len) {
-      n += snprintf(s+n, len-n, "%s Hz", 
FLVAudioSampleRates[stinfo->audioRate]);
-  }
-
-  if (stinfo->audioSampleBits != -1 && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len)
-      n += snprintf(s+n, len-n, "%s",
-                    FLVAudioSampleSizes[stinfo->audioSampleBits]);
-  }
-
-  if (stinfo->audioChannels != -1 && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len) {
-      if (stinfo->audioChannels >= 1 && stinfo->audioChannels <= 2)
-        n += snprintf(s+n, len-n, "%s",
-                      FLVAudioChannels[stinfo->audioChannels-1]);
-      else
-        n += snprintf(s+n, len-n, "%d",
-                      stinfo->audioChannels);
-    }
-  }
-
-  if (stinfo->audioCodec > -1 && stinfo->audioCodec < 12 &&
-      FLVAudioCodecs[stinfo->audioCodec] != NULL && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len)
-      n += snprintf(s+n, len-n, "%s", FLVAudioCodecs[stinfo->audioCodec]);
-  }
-  else if (stinfo->audioCodecStr != NULL && n < len) {
-    if (n > 0)
-      n += snprintf(s+n, len-n, ", ");
-    if (n < len)
-      n += snprintf(s+n, len-n, "%s", stinfo->audioCodecStr);    
-  }
-
-  if (stinfo->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", stinfo->audioDataRate);
-  }
-
-  if (n == 0)
-    return NULL;
-  return strdup(s);
-}
-
-struct EXTRACTOR_Keywords *
-libextractor_flv_extract (const char *filename,
-                          const unsigned char *data,
-                          const size_t size, struct EXTRACTOR_Keywords *prev)
-{
-  struct EXTRACTOR_Keywords *result;
-  const unsigned char *ptr;
-  const unsigned char *end;
-
-  FLVStreamInfo stinfo;
-  FLVHeader header;
-  unsigned long prev_tag_size;
-  char *s;
-
-  ptr = data;
-  end = ptr + size;
-
-  if (readFLVHeader(&ptr, end, &header) == -1)
-    return prev;
-
-  if (memcmp(header.signature, FLV_SIGNATURE, 3) != 0)
-    return prev;
-
-  result = prev;
-  result = addKeyword (EXTRACTOR_MIMETYPE, strdup ("video/x-flv"), result);
-
-  if (header.version != 1)
-    return result;
-
-  if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
-    return result;
-
-  stinfo.videoCodec = -1;
-  stinfo.videoCodecStr = NULL;
-  stinfo.videoWidth = -1;
-  stinfo.videoHeight = -1;
-  stinfo.videoFrameRate = 0.0;
-  stinfo.videoDataRate = 0.0;
-  stinfo.audioCodec = -1;
-  stinfo.audioCodecStr = NULL;
-  stinfo.audioRate = -1;
-  stinfo.audioSampleBits = -1;
-  stinfo.audioChannels = -1;
-  stinfo.audioDataRate = 0.0;
-  while (ptr < end) {
-    if (readFLVTag (&ptr, end, &stinfo, &result) == -1)
-      break;
-    if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1)
-      break;
-  }
-
-  s = printVideoFormat (&stinfo);
-  if (s != NULL)
-    result = addKeyword (EXTRACTOR_FORMAT, s, result);
-  s = printAudioFormat (&stinfo);
-  if (s != NULL)
-    result = addKeyword (EXTRACTOR_FORMAT, s, result);
-
-  return result;
-}





reply via email to

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