libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

asf_extractor.c (16316B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2002, 2003, 2011 Vidyut Samanta and Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 2, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19  */
     20 
     21 /*
     22  * This file is based on demux_asf from the xine project (copyright follows).
     23  *
     24  * Copyright Copyright (C) 2000-2002 the xine project
     25  *
     26  * This file is part of xine, a free video player.
     27  *
     28  * xine is free software; you can redistribute it and/or modify
     29  * it under the terms of the GNU General Public License as published by
     30  * the Free Software Foundation; either version 2 of the License, or
     31  * (at your option) any later version.
     32  *
     33  * xine is distributed in the hope that it will be useful,
     34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     36  * GNU General Public License for more details.
     37  *
     38  * You should have received a copy of the GNU General Public License
     39  * along with this program; if not, write to the Free Software
     40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
     41  *
     42  * $Id: asfextractor.c,v 1.6 2004/10/05 20:02:08 grothoff Exp $
     43  *
     44  * demultiplexer for asf streams
     45  *
     46  * based on ffmpeg's
     47  * ASF compatible encoder and decoder.
     48  * Copyright (c) 2000, 2001 Gerard Lantau.
     49  *
     50  * GUID list from avifile
     51  * some other ideas from MPlayer
     52  */
     53 
     54 #include "platform.h"
     55 #include "extractor.h"
     56 #include "convert.h"
     57 #include <stdint.h>
     58 
     59 #define DEMUX_FINISHED 0
     60 #define DEMUX_START 1
     61 
     62 
     63 /*
     64  * define asf GUIDs (list from avifile)
     65  */
     66 #define GUID_ERROR                              0
     67 #define GUID_ASF_HEADER                         1
     68 #define GUID_ASF_DATA                           2
     69 #define GUID_ASF_SIMPLE_INDEX                   3
     70 #define GUID_ASF_FILE_PROPERTIES                4
     71 #define GUID_ASF_STREAM_PROPERTIES              5
     72 #define GUID_ASF_STREAM_BITRATE_PROPERTIES      6
     73 #define GUID_ASF_CONTENT_DESCRIPTION            7
     74 #define GUID_ASF_EXTENDED_CONTENT_ENCRYPTION    8
     75 #define GUID_ASF_SCRIPT_COMMAND                 9
     76 #define GUID_ASF_MARKER                        10
     77 #define GUID_ASF_HEADER_EXTENSION              11
     78 #define GUID_ASF_BITRATE_MUTUAL_EXCLUSION      12
     79 #define GUID_ASF_CODEC_LIST                    13
     80 #define GUID_ASF_EXTENDED_CONTENT_DESCRIPTION  14
     81 #define GUID_ASF_ERROR_CORRECTION              15
     82 #define GUID_ASF_PADDING                       16
     83 #define GUID_ASF_AUDIO_MEDIA                   17
     84 #define GUID_ASF_VIDEO_MEDIA                   18
     85 #define GUID_ASF_COMMAND_MEDIA                 19
     86 #define GUID_ASF_NO_ERROR_CORRECTION           20
     87 #define GUID_ASF_AUDIO_SPREAD                  21
     88 #define GUID_ASF_MUTEX_BITRATE                 22
     89 #define GUID_ASF_MUTEX_UKNOWN                  23
     90 #define GUID_ASF_RESERVED_1                    24
     91 #define GUID_ASF_RESERVED_SCRIPT_COMMNAND      25
     92 #define GUID_ASF_RESERVED_MARKER               26
     93 #define GUID_ASF_AUDIO_CONCEAL_NONE            27
     94 #define GUID_ASF_CODEC_COMMENT1_HEADER         28
     95 #define GUID_ASF_2_0_HEADER                    29
     96 
     97 #define GUID_END                               30
     98 
     99 
    100 typedef struct
    101 {
    102   uint32_t v1;
    103   uint16_t v2;
    104   uint16_t v3;
    105   uint8_t v4[8];
    106 } LE_GUID;
    107 
    108 
    109 static const struct
    110 {
    111   const char *name;
    112   const LE_GUID guid;
    113 } guids[] = {
    114   {
    115     "error",
    116     {
    117       0x0,
    118     }
    119   },
    120   /* base ASF objects */
    121   {
    122     "header",
    123     {
    124       0x75b22630, 0x668e, 0x11cf,
    125       {
    126         0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
    127       }
    128     }
    129   },
    130   {
    131     "data",
    132     {
    133       0x75b22636, 0x668e, 0x11cf,
    134       {
    135         0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
    136       }
    137     }
    138   },
    139   {
    140     "simple index",
    141     {
    142       0x33000890, 0xe5b1, 0x11cf,
    143       {
    144         0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb
    145       }
    146     }
    147   },
    148   /* header ASF objects */
    149   {
    150     "file properties",
    151     {
    152       0x8cabdca1, 0xa947, 0x11cf,
    153       {
    154         0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
    155       }
    156     }
    157   },
    158   {
    159     "stream header",
    160     {
    161       0xb7dc0791, 0xa9b7, 0x11cf,
    162       {
    163         0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
    164       }
    165     }
    166   },
    167   {
    168     "stream bitrate properties",        /* (http://get.to/sdp) */
    169     {
    170       0x7bf875ce, 0x468d, 0x11d1,
    171       {
    172         0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2
    173       }
    174     }
    175   },
    176   {
    177     "content description",
    178     {
    179       0x75b22633, 0x668e, 0x11cf,
    180       {
    181         0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
    182       }
    183     }
    184   },
    185   {
    186     "extended content encryption",
    187     {
    188       0x298ae614, 0x2622, 0x4c17,
    189       {
    190         0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c
    191       }
    192     }
    193   },
    194   {
    195     "script command",
    196     {
    197       0x1efb1a30, 0x0b62, 0x11d0,
    198       {
    199         0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
    200       }
    201     }
    202   },
    203   {
    204     "marker",
    205     {
    206       0xf487cd01, 0xa951, 0x11cf,
    207       {
    208         0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
    209       }
    210     }
    211   },
    212   {
    213     "header extension",
    214     {
    215       0x5fbf03b5, 0xa92e, 0x11cf,
    216       {
    217         0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
    218       }
    219     }
    220   },
    221   {
    222     "bitrate mutual exclusion",
    223     {
    224       0xd6e229dc, 0x35da, 0x11d1,
    225       {
    226         0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe
    227       }
    228     }
    229   },
    230   {
    231     "codec list",
    232     {
    233       0x86d15240, 0x311d, 0x11d0,
    234       {
    235         0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
    236       }
    237     }
    238   },
    239   {
    240     "extended content description",
    241     {
    242       0xd2d0a440, 0xe307, 0x11d2,
    243       {
    244         0x97, 0xf0, 0x00, 0xa0, 0xc9, 0x5e, 0xa8, 0x50
    245       }
    246     }
    247   },
    248   {
    249     "error correction",
    250     {
    251       0x75b22635, 0x668e, 0x11cf,
    252       {
    253         0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
    254       }
    255     }
    256   },
    257   {
    258     "padding",
    259     {
    260       0x1806d474, 0xcadf, 0x4509,
    261       {
    262         0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8
    263       }
    264     }
    265   },
    266   /* stream properties object stream type */
    267   {
    268     "audio media",
    269     {
    270       0xf8699e40, 0x5b4d, 0x11cf,
    271       {
    272         0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b
    273       }
    274     }
    275   },
    276   {
    277     "video media",
    278     {
    279       0xbc19efc0, 0x5b4d, 0x11cf,
    280       {
    281         0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b
    282       }
    283     }
    284   },
    285   {
    286     "command media",
    287     {
    288       0x59dacfc0, 0x59e6, 0x11d0,
    289       {
    290         0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
    291       }
    292     }
    293   },
    294   /* stream properties object error correction */
    295   {
    296     "no error correction",
    297     {
    298       0x20fb5700, 0x5b55, 0x11cf,
    299       {
    300         0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b
    301       }
    302     }
    303   },
    304   {
    305     "audio spread",
    306     {
    307       0xbfc3cd50, 0x618f, 0x11cf,
    308       {
    309         0x8b, 0xb2, 0x00, 0xaa, 0x00, 0xb4, 0xe2, 0x20
    310       }
    311     }
    312   },
    313   /* mutual exclusion object exlusion type */
    314   {
    315     "mutex bitrate",
    316     {
    317       0xd6e22a01, 0x35da, 0x11d1,
    318       {
    319         0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe
    320       }
    321     }
    322   },
    323   {
    324     "mutex unknown",
    325     {
    326       0xd6e22a02, 0x35da, 0x11d1,
    327       {
    328         0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe
    329       }
    330     }
    331   },
    332   /* header extension */
    333   {
    334     "reserved_1",
    335     {
    336       0xabd3d211, 0xa9ba, 0x11cf,
    337       {
    338         0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65
    339       }
    340     }
    341   },
    342   /* script command */
    343   {
    344     "reserved script command",
    345     {
    346       0x4B1ACBE3, 0x100B, 0x11D0,
    347       {
    348         0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6
    349       }
    350     }
    351   },
    352   /* marker object */
    353   {
    354     "reserved marker",
    355     {
    356       0x4CFEDB20, 0x75F6, 0x11CF,
    357       {
    358         0x9C, 0x0F, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB
    359       }
    360     }
    361   },
    362   /* various */
    363   /* Already defined (reserved_1)
    364      { "head2",
    365      { 0xabd3d211, 0xa9ba, 0x11cf, { 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65 }} },
    366    */
    367   {
    368     "audio conceal none",
    369     {
    370       0x49f1a440, 0x4ece, 0x11d0,
    371       {
    372         0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
    373       }
    374     }
    375   },
    376   {
    377     "codec comment1 header",
    378     {
    379       0x86d15241, 0x311d, 0x11d0,
    380       {
    381         0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6
    382       }
    383     }
    384   },
    385   {
    386     "asf 2.0 header",
    387     {
    388       0xd6e229d1, 0x35da, 0x11d1,
    389       {
    390         0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe
    391       }
    392     }
    393   },
    394 };
    395 
    396 
    397 struct demux_asf_s
    398 {
    399   /* pointer to the stream data */
    400   const char *input;
    401   /* current position in stream */
    402   size_t inputPos;
    403 
    404   size_t inputLen;
    405 
    406   uint32_t length;
    407 
    408   int status;
    409 
    410   char *title;
    411   char *author;
    412   char *copyright;
    413   char *comment;
    414   char *rating;
    415 };
    416 
    417 static int
    418 readBuf (struct demux_asf_s *this, void *buf, int len)
    419 {
    420   int min;
    421 
    422   min = len;
    423   if (this->inputLen - this->inputPos < min)
    424     min = this->inputLen - this->inputPos;
    425   memcpy (buf, &this->input[this->inputPos], min);
    426   this->inputPos += min;
    427   return min;
    428 }
    429 
    430 
    431 static uint8_t
    432 get_byte (struct demux_asf_s *this)
    433 {
    434   uint8_t buf;
    435   int i;
    436 
    437   i = readBuf (this, &buf, 1);
    438   if (i != 1)
    439     this->status = DEMUX_FINISHED;
    440   return buf;
    441 }
    442 
    443 
    444 static uint16_t
    445 get_le16 (struct demux_asf_s *this)
    446 {
    447   uint8_t buf[2];
    448   int i;
    449 
    450   i = readBuf (this, buf, 2);
    451   if (i != 2)
    452     this->status = DEMUX_FINISHED;
    453   return buf[0] | (buf[1] << 8);
    454 }
    455 
    456 
    457 static uint32_t
    458 get_le32 (struct demux_asf_s *this)
    459 {
    460   uint8_t buf[4];
    461   int i;
    462 
    463   i = readBuf (this, buf, 4);
    464   if (i != 4)
    465     this->status = DEMUX_FINISHED;
    466   return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
    467 }
    468 
    469 
    470 static uint64_t
    471 get_le64 (struct demux_asf_s *this)
    472 {
    473   uint8_t buf[8];
    474   int i;
    475 
    476   i = readBuf (this, buf, 8);
    477   if (i != 8)
    478     this->status = DEMUX_FINISHED;
    479   return (uint64_t) buf[0]
    480          | ((uint64_t) buf[1] << 8)
    481          | ((uint64_t) buf[2] << 16)
    482          | ((uint64_t) buf[3] << 24)
    483          | ((uint64_t) buf[4] << 32)
    484          | ((uint64_t) buf[5] << 40)
    485          | ((uint64_t) buf[6] << 48) | ((uint64_t) buf[7] << 54);
    486 }
    487 
    488 
    489 static int
    490 get_guid (struct demux_asf_s *this)
    491 {
    492   int i;
    493   LE_GUID g;
    494 
    495   g.v1 = get_le32 (this);
    496   g.v2 = get_le16 (this);
    497   g.v3 = get_le16 (this);
    498   for (i = 0; i < 8; i++)
    499     g.v4[i] = get_byte (this);
    500   if (this->status == DEMUX_FINISHED)
    501     return GUID_ERROR;
    502   for (i = 1; i < GUID_END; i++)
    503     if (! memcmp (&g, &guids[i].guid, sizeof (LE_GUID)))
    504       return i;
    505 
    506   return GUID_ERROR;
    507 }
    508 
    509 
    510 static int
    511 asf_read_header (struct demux_asf_s *this)
    512 {
    513   int guid;
    514   uint64_t gsize;
    515   uint16_t len1, len2, len3, len4, len5;
    516 
    517   guid = get_guid (this);
    518   if (guid != GUID_ASF_HEADER)
    519     return 0;
    520   get_le64 (this); /* object size */
    521   get_le32 (this); /* number of header objects */
    522   get_byte (this); /* reserved 1 */
    523   get_byte (this); /* reserved 2 */
    524   while (this->status != DEMUX_FINISHED)
    525   {
    526     guid = get_guid (this);   /* object ID */
    527     gsize = get_le64 (this);   /* object size */
    528     if (gsize < 24)
    529       goto fail;
    530     switch (guid)
    531     {
    532     case GUID_ASF_FILE_PROPERTIES:
    533       guid = get_guid (this); /* file ID */
    534       get_le64 (this);  /* file size */
    535       get_le64 (this);  /* creation date */
    536       get_le64 (this);  /* nb_packets */
    537       this->length = get_le64 (this); /* play duration in 100 ns units */
    538       get_le64 (this); /* send duration */
    539       get_le64 (this); /* preroll */
    540       get_le32 (this);  /* flags */
    541       get_le32 (this);  /* min size */
    542       get_le32 (this);      /* max size */
    543       get_le32 (this);  /* max bitrate */
    544       break;
    545     case GUID_ASF_DATA:
    546       goto headers_ok;
    547       break;
    548     case GUID_ASF_CONTENT_DESCRIPTION:
    549       len1 = get_le16 (this);
    550       len2 = get_le16 (this);
    551       len3 = get_le16 (this);
    552       len4 = get_le16 (this);
    553       len5 = get_le16 (this);
    554       this->title = EXTRACTOR_common_convert_to_utf8 (
    555         &this->input[this->inputPos],
    556         len1,
    557         "UTF-16");
    558       this->inputPos += len1;
    559       this->author = EXTRACTOR_common_convert_to_utf8 (
    560         &this->input[this->inputPos],
    561         len2,
    562         "UTF-16");
    563       this->inputPos += len2;
    564       this->copyright = EXTRACTOR_common_convert_to_utf8 (
    565         &this->input[this->inputPos],
    566         len3,
    567         "UTF-16");
    568       this->inputPos += len3;
    569       this->comment = EXTRACTOR_common_convert_to_utf8 (
    570         &this->input[this->inputPos],
    571         len4,
    572         "UTF-16");
    573       this->inputPos += len4;
    574       this->rating = EXTRACTOR_common_convert_to_utf8 (
    575         &this->input[this->inputPos],
    576         len5,
    577         "UTF-16");
    578       this->inputPos += len5;
    579       break;
    580     default:
    581       this->inputPos += gsize - 24;
    582     }
    583   }
    584 
    585 headers_ok:
    586   this->inputPos += sizeof (LE_GUID) + 10;
    587   return 1;
    588 fail:
    589   return 0;
    590 }
    591 
    592 
    593 /* mimetypes:
    594    video/x-ms-asf: asf: ASF stream;
    595    video/x-ms-wmv: wmv: Windows Media Video;
    596    video/x-ms-wma: wma: Windows Media Audio;
    597    application/vnd.ms-asf: asf: ASF stream;
    598    application/x-mplayer2: asf,asx,asp: mplayer2;
    599    video/x-ms-asf-plugin: asf,asx,asp: mms animation;
    600    video/x-ms-wvx: wvx: wmv metafile;
    601    video/x-ms-wax: wva: wma metafile; */
    602 
    603 /* mimetype = application/applefile */
    604 int
    605 EXTRACTOR_asf_extract (const char *data,
    606                        size_t size,
    607                        EXTRACTOR_MetaDataProcessor proc,
    608                        void *proc_cls,
    609                        const char *options)
    610 {
    611   struct demux_asf_s this;
    612   size_t slen;
    613   char duration_str[30];
    614   int ret;
    615 
    616   memset (&this, 0, sizeof (struct demux_asf_s));
    617   this.input = data;
    618   this.inputLen = size;
    619   this.status = DEMUX_START;
    620   ret = 0;
    621   if (1 == asf_read_header (&this))
    622   {
    623     snprintf (duration_str,
    624               sizeof (duration_str),
    625               "%llu ms", (unsigned long long) (this.length / 10000LL));
    626     if ( ( (this.title != NULL) &&
    627            (0 < (slen = strlen (this.title))) &&
    628            (0 != proc (proc_cls,
    629                        "asf",
    630                        EXTRACTOR_METATYPE_TITLE,
    631                        EXTRACTOR_METAFORMAT_C_STRING,
    632                        "text/plain",
    633                        this.title,
    634                        slen + 1)) ) ||
    635          ( (this.author != NULL) &&
    636            (0 < (slen = strlen (this.author))) &&
    637            (0 != proc (proc_cls,
    638                        "asf",
    639                        EXTRACTOR_METATYPE_AUTHOR_NAME,
    640                        EXTRACTOR_METAFORMAT_C_STRING,
    641                        "text/plain",
    642                        this.author,
    643                        slen + 1)) ) ||
    644          ( (this.comment != NULL) &&
    645            (0 < (slen = strlen (this.comment))) &&
    646            (0 != proc (proc_cls,
    647                        "asf",
    648                        EXTRACTOR_METATYPE_COMMENT,
    649                        EXTRACTOR_METAFORMAT_C_STRING,
    650                        "text/plain",
    651                        this.comment,
    652                        slen + 1)) ) ||
    653          ( (this.copyright != NULL) &&
    654            (0 < (slen = strlen (this.copyright))) &&
    655            (0 != proc (proc_cls,
    656                        "asf",
    657                        EXTRACTOR_METATYPE_COPYRIGHT,
    658                        EXTRACTOR_METAFORMAT_C_STRING,
    659                        "text/plain",
    660                        this.copyright,
    661                        slen + 1)) ) ||
    662          (0 != proc (proc_cls,
    663                      "asf",
    664                      EXTRACTOR_METATYPE_MIMETYPE,
    665                      EXTRACTOR_METAFORMAT_C_STRING,
    666                      "text/plain",
    667                      "video/x-ms-asf",
    668                      strlen ("video/x-ms-asf") + 1)) ||
    669          (0 != proc (proc_cls,
    670                      "asf",
    671                      EXTRACTOR_METATYPE_DURATION,
    672                      EXTRACTOR_METAFORMAT_C_STRING,
    673                      "text/plain",
    674                      duration_str,
    675                      strlen (duration_str) + 1)) )
    676       ret = 1;
    677   }
    678   free (this.title);
    679   free (this.author);
    680   free (this.copyright);
    681   free (this.comment);
    682   free (this.rating);
    683   return ret;
    684 }
    685 
    686 
    687 /*  end of asf_extractor.c */