00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 #include "platform.h"
00055 #include "extractor.h"
00056
00057 #define CODEC_TYPE_AUDIO 0
00058 #define CODEC_TYPE_VIDEO 1
00059 #define CODEC_TYPE_CONTROL 2
00060 #define MAX_NUM_STREAMS 23
00061
00062 #define DEFRAG_BUFSIZE 65536
00063 #define DEMUX_START 1
00064 #define DEMUX_FINISHED 0
00065
00066
00067
00068
00069
00070 #define GUID_ERROR 0
00071
00072
00073 #define GUID_ASF_HEADER 1
00074 #define GUID_ASF_DATA 2
00075 #define GUID_ASF_SIMPLE_INDEX 3
00076
00077
00078 #define GUID_ASF_FILE_PROPERTIES 4
00079 #define GUID_ASF_STREAM_PROPERTIES 5
00080 #define GUID_ASF_STREAM_BITRATE_PROPERTIES 6
00081 #define GUID_ASF_CONTENT_DESCRIPTION 7
00082 #define GUID_ASF_EXTENDED_CONTENT_ENCRYPTION 8
00083 #define GUID_ASF_SCRIPT_COMMAND 9
00084 #define GUID_ASF_MARKER 10
00085 #define GUID_ASF_HEADER_EXTENSION 11
00086 #define GUID_ASF_BITRATE_MUTUAL_EXCLUSION 12
00087 #define GUID_ASF_CODEC_LIST 13
00088 #define GUID_ASF_EXTENDED_CONTENT_DESCRIPTION 14
00089 #define GUID_ASF_ERROR_CORRECTION 15
00090 #define GUID_ASF_PADDING 16
00091
00092
00093 #define GUID_ASF_AUDIO_MEDIA 17
00094 #define GUID_ASF_VIDEO_MEDIA 18
00095 #define GUID_ASF_COMMAND_MEDIA 19
00096
00097
00098 #define GUID_ASF_NO_ERROR_CORRECTION 20
00099 #define GUID_ASF_AUDIO_SPREAD 21
00100
00101
00102 #define GUID_ASF_MUTEX_BITRATE 22
00103 #define GUID_ASF_MUTEX_UKNOWN 23
00104
00105
00106 #define GUID_ASF_RESERVED_1 24
00107
00108
00109 #define GUID_ASF_RESERVED_SCRIPT_COMMNAND 25
00110
00111
00112 #define GUID_ASF_RESERVED_MARKER 26
00113
00114
00115
00116
00117
00118 #define GUID_ASF_AUDIO_CONCEAL_NONE 27
00119 #define GUID_ASF_CODEC_COMMENT1_HEADER 28
00120 #define GUID_ASF_2_0_HEADER 29
00121
00122 #define GUID_END 30
00123
00124
00125
00126 #define ASF_STREAM_TYPE_UNKNOWN 0
00127 #define ASF_STREAM_TYPE_AUDIO 1
00128 #define ASF_STREAM_TYPE_VIDEO 2
00129 #define ASF_STREAM_TYPE_CONTROL 3
00130
00131 #define ASF_MAX_NUM_STREAMS 23
00132
00133
00134 typedef unsigned long long ext_uint64_t;
00135 typedef unsigned int ext_uint32_t;
00136 typedef unsigned short ext_uint16_t;
00137 typedef unsigned char ext_uint8_t;
00138
00139 typedef struct
00140 {
00141 ext_uint32_t v1;
00142 ext_uint16_t v2;
00143 ext_uint16_t v3;
00144 ext_uint8_t v4[8];
00145 } LE_GUID;
00146
00147 static const struct
00148 {
00149 const char *name;
00150 const LE_GUID guid;
00151 } guids[] =
00152 {
00153 {
00154 "error",
00155 {
00156 0x0,}},
00157
00158 {
00159 "header",
00160 {
00161 0x75b22630, 0x668e, 0x11cf,
00162 {
00163 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}}},
00164 {
00165 "data",
00166 {
00167 0x75b22636, 0x668e, 0x11cf,
00168 {
00169 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}}},
00170 {
00171 "simple index",
00172 {
00173 0x33000890, 0xe5b1, 0x11cf,
00174 {
00175 0x89, 0xf4, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xcb}}},
00176
00177 {
00178 "file properties",
00179 {
00180 0x8cabdca1, 0xa947, 0x11cf,
00181 {
00182 0x8e, 0xe4, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}}},
00183 {
00184 "stream header",
00185 {
00186 0xb7dc0791, 0xa9b7, 0x11cf,
00187 {
00188 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}}},
00189 {
00190 "stream bitrate properties",
00191 {
00192 0x7bf875ce, 0x468d, 0x11d1,
00193 {
00194 0x8d, 0x82, 0x00, 0x60, 0x97, 0xc9, 0xa2, 0xb2}}},
00195 {
00196 "content description",
00197 {
00198 0x75b22633, 0x668e, 0x11cf,
00199 {
00200 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}}},
00201 {
00202 "extended content encryption",
00203 {
00204 0x298ae614, 0x2622, 0x4c17,
00205 {
00206 0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}}},
00207 {
00208 "script command",
00209 {
00210 0x1efb1a30, 0x0b62, 0x11d0,
00211 {
00212 0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}}},
00213 {
00214 "marker",
00215 {
00216 0xf487cd01, 0xa951, 0x11cf,
00217 {
00218 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}}},
00219 {
00220 "header extension",
00221 {
00222 0x5fbf03b5, 0xa92e, 0x11cf,
00223 {
00224 0x8e, 0xe3, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}}},
00225 {
00226 "bitrate mutual exclusion",
00227 {
00228 0xd6e229dc, 0x35da, 0x11d1,
00229 {
00230 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe}}},
00231 {
00232 "codec list",
00233 {
00234 0x86d15240, 0x311d, 0x11d0,
00235 {
00236 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}}},
00237 {
00238 "extended content description",
00239 {
00240 0xd2d0a440, 0xe307, 0x11d2,
00241 {
00242 0x97, 0xf0, 0x00, 0xa0, 0xc9, 0x5e, 0xa8, 0x50}}},
00243 {
00244 "error correction",
00245 {
00246 0x75b22635, 0x668e, 0x11cf,
00247 {
00248 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}}},
00249 {
00250 "padding",
00251 {
00252 0x1806d474, 0xcadf, 0x4509,
00253 {
00254 0xa4, 0xba, 0x9a, 0xab, 0xcb, 0x96, 0xaa, 0xe8}}},
00255
00256 {
00257 "audio media",
00258 {
00259 0xf8699e40, 0x5b4d, 0x11cf,
00260 {
00261 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}}},
00262 {
00263 "video media",
00264 {
00265 0xbc19efc0, 0x5b4d, 0x11cf,
00266 {
00267 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}}},
00268 {
00269 "command media",
00270 {
00271 0x59dacfc0, 0x59e6, 0x11d0,
00272 {
00273 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}}},
00274
00275 {
00276 "no error correction",
00277 {
00278 0x20fb5700, 0x5b55, 0x11cf,
00279 {
00280 0xa8, 0xfd, 0x00, 0x80, 0x5f, 0x5c, 0x44, 0x2b}}},
00281 {
00282 "audio spread",
00283 {
00284 0xbfc3cd50, 0x618f, 0x11cf,
00285 {
00286 0x8b, 0xb2, 0x00, 0xaa, 0x00, 0xb4, 0xe2, 0x20}}},
00287
00288 {
00289 "mutex bitrate",
00290 {
00291 0xd6e22a01, 0x35da, 0x11d1,
00292 {
00293 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe}}},
00294 {
00295 "mutex unknown",
00296 {
00297 0xd6e22a02, 0x35da, 0x11d1,
00298 {
00299 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe}}},
00300
00301 {
00302 "reserved_1",
00303 {
00304 0xabd3d211, 0xa9ba, 0x11cf,
00305 {
00306 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65}}},
00307
00308 {
00309 "reserved script command",
00310 {
00311 0x4B1ACBE3, 0x100B, 0x11D0,
00312 {
00313 0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}}},
00314
00315 {
00316 "reserved marker",
00317 {
00318 0x4CFEDB20, 0x75F6, 0x11CF,
00319 {
00320 0x9C, 0x0F, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}}},
00321
00322
00323
00324
00325
00326 {
00327 "audio conceal none",
00328 {
00329 0x49f1a440, 0x4ece, 0x11d0,
00330 {
00331 0xa3, 0xac, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}}},
00332 {
00333 "codec comment1 header",
00334 {
00335 0x86d15241, 0x311d, 0x11d0,
00336 {
00337 0xa3, 0xa4, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}}},
00338 {
00339 "asf 2.0 header",
00340 {
00341 0xd6e229d1, 0x35da, 0x11d1,
00342 {
00343 0x90, 0x34, 0x00, 0xa0, 0xc9, 0x03, 0x49, 0xbe}}},};
00344
00345 typedef struct
00346 {
00347 int num;
00348 int seq;
00349
00350 int frag_offset;
00351 int64_t timestamp;
00352 int ts_per_kbyte;
00353 int defrag;
00354
00355 ext_uint32_t buf_type;
00356 int stream_id;
00357
00358 ext_uint8_t *buffer;
00359 } asf_stream_t;
00360
00361 typedef struct demux_asf_s
00362 {
00363
00364 char *input;
00365
00366 size_t inputPos;
00367 size_t inputLen;
00368
00369 int keyframe_found;
00370
00371 int seqno;
00372 ext_uint32_t packet_size;
00373 ext_uint8_t packet_flags;
00374 ext_uint32_t data_size;
00375
00376 ext_uint32_t bitrates[MAX_NUM_STREAMS];
00377 int num_streams;
00378 int num_audio_streams;
00379 int num_video_streams;
00380 int audio_stream;
00381 int video_stream;
00382 int audio_stream_id;
00383 int video_stream_id;
00384 int control_stream_id;
00385
00386 ext_uint16_t wavex[1024];
00387 int wavex_size;
00388
00389 char title[512];
00390 char author[512];
00391 char copyright[512];
00392 char comment[512];
00393
00394 ext_uint32_t length, rate;
00395
00396
00397 int packet_size_left;
00398
00399
00400
00401 int64_t last_pts[2];
00402 int32_t frame_duration;
00403 int send_newpts;
00404 int64_t last_frame_pts;
00405
00406
00407 ext_uint32_t packet_padsize;
00408 int nb_frames;
00409 ext_uint8_t frame_flag;
00410 ext_uint8_t segtype;
00411 int frame;
00412
00413 int status;
00414
00415
00416 int reorder_h;
00417 int reorder_w;
00418 int reorder_b;
00419
00420 off_t header_size;
00421 int buf_flag_seek;
00422
00423
00424 int64_t first_packet_pos;
00425
00426 int reference_mode;
00427 } demux_asf_t;
00428
00429 static int
00430 readBuf (demux_asf_t * this, void *buf, int len)
00431 {
00432 int min;
00433
00434 min = len;
00435 if (this->inputLen - this->inputPos < min)
00436 min = this->inputLen - this->inputPos;
00437 memcpy (buf, &this->input[this->inputPos], min);
00438 this->inputPos += min;
00439 return min;
00440 }
00441
00442 static ext_uint8_t
00443 get_byte (demux_asf_t * this)
00444 {
00445 ext_uint8_t buf;
00446 int i;
00447
00448 i = readBuf (this, &buf, 1);
00449 if (i != 1)
00450 this->status = DEMUX_FINISHED;
00451 return buf;
00452 }
00453
00454 static ext_uint16_t
00455 get_le16 (demux_asf_t * this)
00456 {
00457 ext_uint8_t buf[2];
00458 int i;
00459
00460 i = readBuf (this, buf, 2);
00461 if (i != 2)
00462 this->status = DEMUX_FINISHED;
00463 return buf[0] | (buf[1] << 8);
00464 }
00465
00466 static ext_uint32_t
00467 get_le32 (demux_asf_t * this)
00468 {
00469 ext_uint8_t buf[4];
00470 int i;
00471
00472 i = readBuf (this, buf, 4);
00473 if (i != 4)
00474 this->status = DEMUX_FINISHED;
00475 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
00476 }
00477
00478 static ext_uint64_t
00479 get_le64 (demux_asf_t * this)
00480 {
00481 ext_uint8_t buf[8];
00482 int i;
00483
00484 i = readBuf (this, buf, 8);
00485 if (i != 8)
00486 this->status = DEMUX_FINISHED;
00487 return (ext_uint64_t) buf[0]
00488 | ((ext_uint64_t) buf[1] << 8)
00489 | ((ext_uint64_t) buf[2] << 16)
00490 | ((ext_uint64_t) buf[3] << 24)
00491 | ((ext_uint64_t) buf[4] << 32)
00492 | ((ext_uint64_t) buf[5] << 40)
00493 | ((ext_uint64_t) buf[6] << 48) | ((ext_uint64_t) buf[7] << 54);
00494 }
00495
00496 static int
00497 get_guid (demux_asf_t * this)
00498 {
00499 int i;
00500 LE_GUID g;
00501
00502 g.v1 = get_le32 (this);
00503 g.v2 = get_le16 (this);
00504 g.v3 = get_le16 (this);
00505 for (i = 0; i < 8; i++)
00506 g.v4[i] = get_byte (this);
00507 if (this->status == DEMUX_FINISHED)
00508 return GUID_ERROR;
00509 for (i = 1; i < GUID_END; i++)
00510 if (!memcmp (&g, &guids[i].guid, sizeof (LE_GUID)))
00511 return i;
00512
00513 return GUID_ERROR;
00514 }
00515
00516 static void
00517 get_str16_nolen (demux_asf_t * this, int len, char *buf, int buf_size)
00518 {
00519
00520 int c;
00521 char *q;
00522
00523 q = buf;
00524 while (len > 0)
00525 {
00526 c = get_le16 (this);
00527 if ((q - buf) < buf_size - 1)
00528 *q++ = c;
00529 len -= 2;
00530 }
00531 *q = '\0';
00532 }
00533
00534 static int
00535 asf_read_header (demux_asf_t * this)
00536 {
00537 int guid;
00538 ext_uint64_t gsize;
00539
00540 guid = get_guid (this);
00541 if (guid != GUID_ASF_HEADER)
00542 return 0;
00543 get_le64 (this);
00544 get_le32 (this);
00545 get_byte (this);
00546 get_byte (this);
00547
00548 while (this->status != DEMUX_FINISHED)
00549 {
00550 guid = get_guid (this);
00551 gsize = get_le64 (this);
00552
00553 if (gsize < 24)
00554 goto fail;
00555
00556 switch (guid)
00557 {
00558 case GUID_ASF_FILE_PROPERTIES:
00559 {
00560 ext_uint64_t start_time, end_time;
00561
00562 guid = get_guid (this);
00563 get_le64 (this);
00564 get_le64 (this);
00565 get_le64 (this);
00566
00567 end_time = get_le64 (this);
00568
00569 this->length = get_le64 (this) / 10000;
00570 if (this->length)
00571 this->rate = this->inputLen / (this->length / 1000);
00572 else
00573 this->rate = 0;
00574
00575
00576 start_time = get_le32 (this);
00577
00578 get_le32 (this);
00579 get_le32 (this);
00580 this->packet_size = get_le32 (this);
00581 get_le32 (this);
00582 get_le32 (this);
00583 }
00584 break;
00585
00586 case (GUID_ASF_STREAM_PROPERTIES):
00587 {
00588 int type;
00589 ext_uint32_t total_size, stream_data_size;
00590 ext_uint16_t stream_id;
00591 ext_uint64_t pos1, pos2;
00592 pos1 = this->inputPos;
00593
00594 guid = get_guid (this);
00595 switch (guid)
00596 {
00597 case GUID_ASF_AUDIO_MEDIA:
00598 type = CODEC_TYPE_AUDIO;
00599 break;
00600
00601 case GUID_ASF_VIDEO_MEDIA:
00602 type = CODEC_TYPE_VIDEO;
00603 break;
00604
00605 case GUID_ASF_COMMAND_MEDIA:
00606 type = CODEC_TYPE_CONTROL;
00607 break;
00608
00609 default:
00610 goto fail;
00611 }
00612
00613 guid = get_guid (this);
00614 get_le64 (this);
00615 total_size = get_le32 (this);
00616 if (total_size > sizeof (this->wavex))
00617 goto fail;
00618 stream_data_size = get_le32 (this);
00619 stream_id = get_le16 (this);
00620 get_le32 (this);
00621
00622 if (type == CODEC_TYPE_AUDIO)
00623 {
00624 ext_uint8_t buffer[6];
00625
00626 readBuf (this, (ext_uint8_t *) this->wavex, total_size);
00627 if (guid == GUID_ASF_AUDIO_SPREAD)
00628 {
00629 readBuf (this, buffer, 6);
00630 this->reorder_h = buffer[0];
00631 this->reorder_w = (buffer[2] << 8) | buffer[1];
00632 this->reorder_b = (buffer[4] << 8) | buffer[3];
00633 this->reorder_w /= this->reorder_b;
00634 }
00635 else
00636 {
00637 this->reorder_b = this->reorder_h = this->reorder_w = 1;
00638 }
00639
00640 this->wavex_size = total_size;
00641 this->num_audio_streams++;
00642 }
00643 else if (type == CODEC_TYPE_VIDEO)
00644 {
00645
00646 ext_uint16_t i;
00647
00648 get_le32 (this);
00649 get_le32 (this);
00650 get_byte (this);
00651
00652 i = get_le16 (this);
00653 this->inputPos += i;
00654 this->num_video_streams++;
00655 }
00656 else if (type == CODEC_TYPE_CONTROL)
00657 {
00658 this->control_stream_id = stream_id;
00659 }
00660
00661 this->num_streams++;
00662 pos2 = this->inputPos;
00663 this->inputPos += gsize - (pos2 - pos1 + 24);
00664 }
00665 break;
00666
00667 case GUID_ASF_DATA:
00668 goto headers_ok;
00669 break;
00670 case GUID_ASF_CONTENT_DESCRIPTION:
00671 {
00672 ext_uint16_t len1, len2, len3, len4, len5;
00673
00674 len1 = get_le16 (this);
00675 len2 = get_le16 (this);
00676 len3 = get_le16 (this);
00677 len4 = get_le16 (this);
00678 len5 = get_le16 (this);
00679 get_str16_nolen (this, len1, this->title, sizeof (this->title));
00680 get_str16_nolen (this, len2, this->author, sizeof (this->author));
00681 get_str16_nolen (this, len3, this->copyright,
00682 sizeof (this->copyright));
00683 get_str16_nolen (this, len4, this->comment,
00684 sizeof (this->comment));
00685 this->inputPos += len5;
00686 }
00687 break;
00688
00689 case GUID_ASF_STREAM_BITRATE_PROPERTIES:
00690 {
00691 ext_uint16_t streams, stream_id;
00692 ext_uint16_t i;
00693
00694 streams = get_le16 (this);
00695 for (i = 0; i < streams; i++)
00696 {
00697 stream_id = get_le16 (this);
00698 this->bitrates[stream_id] = get_le32 (this);
00699 }
00700 }
00701 break;
00702
00703 default:
00704 this->inputPos += gsize - 24;
00705 }
00706 }
00707
00708 headers_ok:
00709 this->inputPos += sizeof (LE_GUID) + 10;
00710 this->packet_size_left = 0;
00711 this->first_packet_pos = this->inputPos;
00712 return 1;
00713
00714 fail:
00715 return 0;
00716 }
00717
00718
00719 static struct EXTRACTOR_Keywords *
00720 addKeyword (EXTRACTOR_KeywordType type,
00721 char *keyword, struct EXTRACTOR_Keywords *next)
00722 {
00723 EXTRACTOR_KeywordList *result;
00724
00725 if (keyword == NULL)
00726 return next;
00727 result = malloc (sizeof (EXTRACTOR_KeywordList));
00728 result->next = next;
00729 result->keyword = strdup (keyword);
00730 result->keywordType = type;
00731 return result;
00732 }
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 struct EXTRACTOR_Keywords *
00745 libextractor_asf_extract (char *filename,
00746 char *data,
00747 size_t size, struct EXTRACTOR_Keywords *prev)
00748 {
00749 demux_asf_t *this;
00750
00751 this = malloc (sizeof (demux_asf_t));
00752 memset (this, 0, sizeof (demux_asf_t));
00753 this->input = data;
00754 this->inputPos = 0;
00755 this->inputLen = size;
00756 this->status = DEMUX_START;
00757
00758 if (0 == asf_read_header (this))
00759 {
00760 free (this);
00761 return prev;
00762 }
00763
00764 if (strlen (this->title) > 0)
00765 prev = addKeyword (EXTRACTOR_TITLE, this->title, prev);
00766 if (strlen (this->author) > 0)
00767 prev = addKeyword (EXTRACTOR_AUTHOR, this->author, prev);
00768 if (strlen (this->comment) > 0)
00769 prev = addKeyword (EXTRACTOR_COMMENT, this->comment, prev);
00770 if (strlen (this->copyright) > 0)
00771 prev = addKeyword (EXTRACTOR_COPYRIGHT, this->copyright, prev);
00772 prev = addKeyword (EXTRACTOR_MIMETYPE, "video/x-ms-asf", prev);
00773
00774
00775 if (strlen (this->author) * strlen (this->title) > 0)
00776 {
00777 EXTRACTOR_KeywordList *keyword =
00778 malloc (sizeof (EXTRACTOR_KeywordList));
00779 char *word;
00780 int len = 3 + strlen (this->author) + strlen (this->title);
00781
00782 word = malloc (len);
00783 word[0] = '\0';
00784 strcat (word, this->author);
00785 strcat (word, ": ");
00786 strcat (word, this->title);
00787 keyword->next = prev;
00788 keyword->keyword = word;
00789 keyword->keywordType = EXTRACTOR_DESCRIPTION;
00790 prev = keyword;
00791 }
00792 free (this);
00793 return prev;
00794 }
00795
00796
00797