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 */