flv_extractor.c (30724B)
1 /* 2 This file is part of libextractor. 3 Copyright Copyright (C) 2007, 2009 Heikki Lindholm 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 * see http://osflash.org/flv 23 * http://osflash.org/documentation/amf 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include "convert_numeric.h" 28 #include <string.h> 29 30 #define DEBUG 0 31 32 #define FLV_SIGNATURE "FLV" 33 34 /* 35 * AMF parser 36 */ 37 38 /* Actionscript types */ 39 #define ASTYPE_NUMBER 0x00 40 #define ASTYPE_BOOLEAN 0x01 41 #define ASTYPE_STRING 0x02 42 #define ASTYPE_OBJECT 0x03 43 #define ASTYPE_MOVIECLIP 0x04 44 #define ASTYPE_NULL 0x05 45 #define ASTYPE_UNDEFINED 0x06 46 #define ASTYPE_REFERENCE 0x07 47 #define ASTYPE_MIXEDARRAY 0x08 48 #define ASTYPE_ENDOFOBJECT 0x09 49 #define ASTYPE_ARRAY 0x0a 50 #define ASTYPE_DATE 0x0b 51 #define ASTYPE_LONGSTRING 0x0c 52 #define ASTYPE_UNSUPPORTED 0x0d 53 #define ASTYPE_RECORDSET 0x0e 54 #define ASTYPE_XML 0x0f 55 #define ASTYPE_TYPEDOBJECT 0x10 56 #define ASTYPE_AMF3DATA 0x11 57 58 typedef struct 59 { 60 void *userdata; 61 void (*as_begin_callback)(unsigned char type, void *userdata); 62 void (*as_key_callback)(char *key, void *userdata); 63 void (*as_end_callback)(unsigned char type, void *value, void *userdata); 64 } AMFParserHandler; 65 66 /* core datatypes */ 67 68 static uint32_t 69 readInt32 (const unsigned char **data) 70 { 71 const unsigned char *ptr = *data; 72 uint32_t val; 73 74 val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; 75 ptr += 4; 76 *data = ptr; 77 return val; 78 } 79 80 81 static uint32_t 82 readInt24 (const unsigned char **data) 83 { 84 const unsigned char *ptr = *data; 85 uint32_t val; 86 87 val = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]; 88 ptr += 3; 89 *data = ptr; 90 return val; 91 } 92 93 94 static uint16_t 95 readInt16 (const unsigned char **data) 96 { 97 const unsigned char *ptr = *data; 98 uint16_t val; 99 100 val = (ptr[0] << 8) | ptr[1]; 101 ptr += 2; 102 *data = ptr; 103 return val; 104 } 105 106 107 static double 108 readDouble (const unsigned char **data) 109 { 110 const unsigned char *ptr = *data; 111 double val; 112 113 EXTRACTOR_common_floatformat_to_double ( 114 &EXTRACTOR_floatformat_ieee_double_big, 115 (const void *) ptr, 116 &val); 117 ptr += 8; 118 *data = ptr; 119 return val; 120 } 121 122 123 /* actionscript types */ 124 125 static int 126 readASNumber (const unsigned char **data, 127 size_t *len, 128 double *retval) 129 { 130 const unsigned char *ptr = *data; 131 double val; 132 133 if (*len < 8) 134 return -1; 135 136 val = readDouble (&ptr); 137 *len -= 8; 138 139 *retval = val; 140 *data = ptr; 141 return 0; 142 } 143 144 145 static int 146 readASBoolean (const unsigned char **data, 147 size_t *len, 148 int *retval) 149 { 150 const unsigned char *ptr = *data; 151 int val; 152 153 if (*len < 1) 154 return -1; 155 156 val = (*ptr != 0x00); 157 ptr += 1; 158 *len -= 1; 159 160 *retval = val; 161 *data = ptr; 162 return 0; 163 } 164 165 166 static int 167 readASDate (const unsigned char **data, 168 size_t *len, 169 double *millis, 170 short *zone) 171 { 172 const unsigned char *ptr = *data; 173 174 if (*len < 10) 175 return -1; 176 177 *millis = readDouble (&ptr); 178 *len -= 8; 179 180 *zone = readInt16 (&ptr); 181 *len -= 2; 182 183 *data = ptr; 184 return 0; 185 } 186 187 188 static int 189 readASString (const unsigned char **data, 190 size_t *len, 191 char **retval) 192 { 193 const unsigned char *ptr = *data; 194 char *ret; 195 int slen; 196 197 if (*len < 2) 198 return -1; 199 200 slen = readInt16 (&ptr); 201 202 if (*len < (2 + slen)) 203 return -1; 204 205 ret = malloc (slen + 1); 206 if (ret == NULL) 207 return -1; 208 memcpy (ret, ptr, slen); 209 ret[slen] = '\0'; 210 ptr += slen; 211 *len -= (2 + slen); 212 213 *retval = ret; 214 *data = ptr; 215 return 0; 216 } 217 218 219 static int 220 parse_amf (const unsigned char **data, 221 size_t *len, 222 AMFParserHandler *handler) 223 { 224 const unsigned char *ptr = *data; 225 unsigned char astype; 226 int ret; 227 228 ret = 0; 229 astype = *ptr++; 230 (*(handler->as_begin_callback))(astype, handler->userdata); 231 switch (astype) 232 { 233 case ASTYPE_NUMBER: 234 { 235 double val; 236 ret = readASNumber (&ptr, len, &val); 237 if (ret == 0) 238 (*(handler->as_end_callback))(astype, 239 &val, 240 handler->userdata); 241 break; 242 } 243 case ASTYPE_BOOLEAN: 244 { 245 int val; 246 ret = readASBoolean (&ptr, len, &val); 247 if (ret == 0) 248 (*(handler->as_end_callback))(astype, 249 &val, 250 handler->userdata); 251 break; 252 } 253 case ASTYPE_STRING: 254 { 255 char *val; 256 ret = readASString (&ptr, len, &val); 257 if (ret == 0) 258 { 259 (*(handler->as_end_callback))(astype, 260 val, 261 handler->userdata); 262 free (val); 263 } 264 break; 265 } 266 case ASTYPE_DATE: 267 { 268 void *tmp[2]; 269 double millis; 270 short tz; 271 ret = readASDate (&ptr, len, &millis, &tz); 272 tmp[0] = &millis; 273 tmp[1] = &tz; 274 if (ret == 0) 275 (*(handler->as_end_callback))(astype, 276 &tmp, 277 handler->userdata); 278 break; 279 } 280 case ASTYPE_NULL: 281 case ASTYPE_UNDEFINED: 282 case ASTYPE_UNSUPPORTED: 283 case ASTYPE_ENDOFOBJECT: 284 (*(handler->as_end_callback))(astype, NULL, handler->userdata); 285 break; 286 case ASTYPE_ARRAY: 287 { 288 long i, alen; 289 if (*len < 4) 290 { 291 ret = -1; 292 break; 293 } 294 alen = readInt32 (&ptr); 295 *len -= 4; 296 for (i = 0; i < alen; i++) 297 { 298 ret = parse_amf (&ptr, len, handler); 299 if (ret == -1) 300 break; 301 } 302 (*(handler->as_end_callback))(ASTYPE_ARRAY, 303 NULL, 304 handler->userdata); 305 break; 306 } 307 case ASTYPE_OBJECT: 308 { 309 char *key; 310 unsigned char type; 311 312 ret = readASString (&ptr, len, &key); 313 if (ret == -1) 314 break; 315 (*(handler->as_key_callback))(key, 316 handler->userdata); 317 free (key); 318 type = *ptr; 319 while (type != ASTYPE_ENDOFOBJECT) 320 { 321 ret = parse_amf (&ptr, len, handler); 322 if (ret == -1) 323 break; 324 ret = readASString (&ptr, len, &key); 325 if (ret == -1) 326 break; 327 (*(handler->as_key_callback))(key, 328 handler->userdata); 329 free (key); 330 type = *ptr; 331 } 332 if (ret == 0) 333 (*(handler->as_end_callback))(ASTYPE_OBJECT, 334 NULL, 335 handler->userdata); 336 break; 337 } 338 case ASTYPE_MIXEDARRAY: 339 { 340 char *key; 341 unsigned char type; 342 343 if (*len < 4) 344 { 345 ret = -1; 346 break; 347 } 348 /* max_index */ readInt32 (&ptr); 349 *len -= 4; 350 ret = readASString (&ptr, len, &key); 351 if (ret == -1) 352 break; 353 (*(handler->as_key_callback))(key, 354 handler->userdata); 355 free (key); 356 type = *ptr; 357 while (type != ASTYPE_ENDOFOBJECT) 358 { 359 ret = parse_amf (&ptr, len, handler); 360 if (ret == -1) 361 break; 362 ret = readASString (&ptr, len, &key); 363 if (ret == -1) 364 break; 365 (*(handler->as_key_callback))(key, 366 handler->userdata); 367 free (key); 368 type = *ptr; 369 } 370 if (ret == 0) 371 (*(handler->as_end_callback))(astype, 372 NULL, 373 handler->userdata); 374 break; 375 } 376 default: 377 ret = -1; 378 (*(handler->as_end_callback))(astype, 379 NULL, 380 handler->userdata); 381 #if DEBUG 382 printf ("parse_amf: Unknown type %02x", astype); 383 #endif 384 break; 385 } 386 387 *data = ptr; 388 return ret; 389 } 390 391 392 /* 393 * FLV parser 394 */ 395 396 /* from tarextractor, modified to take timezone */ 397 /* TODO: check that the output date is correct */ 398 static int 399 flv_to_iso_date (double timeval, short timezone, 400 char *rtime, unsigned int rsize) 401 { 402 int retval = 0; 403 404 /* 405 * shift epoch to proleptic times 406 * to make subsequent modulo operations safer. 407 */ 408 long long my_timeval = (timeval / 1000) 409 + ((long long) ((1970 * 365) + 478) * (long 410 long) 86400); 411 412 unsigned int seconds = (unsigned int) (my_timeval % 60); 413 unsigned int minutes = (unsigned int) ((my_timeval / 60) % 60); 414 unsigned int hours = (unsigned int) ((my_timeval / 3600) % 24); 415 416 int zone_sign; 417 int zone_hours; 418 unsigned int zone_minutes; 419 420 unsigned int year = 0; 421 unsigned int month = 1; 422 423 unsigned int days = (unsigned int) (my_timeval / (24 * 3600)); 424 425 unsigned int days_in_month[] = 426 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 427 unsigned int diff = 0; 428 429 if ((long long) 0 > my_timeval) 430 return EDOM; 431 432 /* 433 * 400-year periods 434 */ 435 year += (400 * (days / ((365 * 400) + 97))); 436 days %= ((365 * 400) + 97); 437 438 /* 439 * 100-year periods 440 */ 441 diff = (days / ((365 * 100) + 24)); 442 if (4 <= diff) 443 { 444 year += 399; 445 days = 364; 446 } 447 else 448 { 449 year += (100 * diff); 450 days %= ((365 * 100) + 24); 451 } 452 453 /* 454 * remaining leap years 455 */ 456 year += (4 * (days / ((365 * 4) + 1))); 457 days %= ((365 * 4) + 1); 458 459 while (1) 460 { 461 if ((0 == (year % 400)) || ((0 == (year % 4)) && (0 != (year % 100)))) 462 { 463 if (366 > days) 464 { 465 break; 466 } 467 else 468 { 469 days -= 366; 470 year++; 471 } 472 } 473 else 474 { 475 if (365 > days) 476 { 477 break; 478 } 479 else 480 { 481 days -= 365; 482 year++; 483 } 484 } 485 } 486 487 if ((0 == (year % 400)) || ((0 == (year % 4)) && (0 != (year % 100)))) 488 days_in_month[1] = 29; 489 490 for (month = 0; (month < 12) && (days >= days_in_month[month]); month += 1) 491 days -= days_in_month[month]; 492 493 zone_sign = 0; 494 if (timezone < 0) 495 { 496 zone_sign = -1; 497 timezone = -timezone; 498 } 499 zone_hours = timezone / 60; 500 zone_minutes = timezone - zone_hours * 60; 501 502 retval = snprintf (rtime, rsize, "%04u-%02u-%02uT%02u:%02u:%02u%c%02d:%02u", 503 year, month + 1, days + 1, hours, minutes, seconds, 504 ((zone_sign < 0) ? '-' : '+'), zone_hours, zone_minutes); 505 506 return (retval < rsize) ? 0 : EOVERFLOW; 507 } 508 509 510 typedef struct 511 { 512 char signature[3]; 513 unsigned char version; 514 unsigned char flags; 515 unsigned long offset; 516 } FLVHeader; 517 518 #define FLV_HEADER_SIZE 9 519 520 #define FLV_TAG_TYPE_AUDIO 0x08 521 #define FLV_TAG_TYPE_VIDEO 0x09 522 #define FLV_TAG_TYPE_META 0x12 523 524 typedef struct 525 { 526 unsigned char type; 527 unsigned long bodyLength; 528 uint32_t timestamp; 529 unsigned long streamId; 530 } FLVTagHeader; 531 532 #define FLV_TAG_HEADER_SIZE 11 533 534 static int 535 readFLVHeader (const unsigned char **data, 536 const unsigned char *end, 537 FLVHeader *hdr) 538 { 539 const unsigned char *ptr = *data; 540 541 if ((ptr + FLV_HEADER_SIZE) > end) 542 return -1; 543 544 memcpy (hdr->signature, ptr, 3); 545 ptr += 3; 546 hdr->version = *ptr++; 547 hdr->flags = *ptr++; 548 hdr->offset = readInt32 (&ptr); 549 if (hdr->offset != FLV_HEADER_SIZE) 550 return -1; 551 552 *data = ptr; 553 return 0; 554 } 555 556 557 static int 558 readPreviousTagSize (const unsigned char **data, 559 const unsigned char *end, 560 unsigned long *prev_size) 561 { 562 const unsigned char *ptr = *data; 563 564 if ((ptr + 4) > end) 565 return -1; 566 567 *prev_size = readInt32 (&ptr); 568 569 *data = ptr; 570 return 0; 571 } 572 573 574 static int 575 readFLVTagHeader (const unsigned char **data, 576 const unsigned char *end, 577 FLVTagHeader *hdr) 578 { 579 const unsigned char *ptr = *data; 580 581 if ((ptr + FLV_TAG_HEADER_SIZE) > end) 582 return -1; 583 584 hdr->type = *ptr++; 585 hdr->bodyLength = readInt24 (&ptr); 586 hdr->timestamp = readInt32 (&ptr); 587 hdr->streamId = readInt24 (&ptr); 588 589 *data = ptr; 590 return 0; 591 } 592 593 594 typedef struct 595 { 596 int videoCodec; 597 char *videoCodecStr; 598 int videoWidth; 599 int videoHeight; 600 double videoDataRate; 601 double videoFrameRate; 602 603 int audioCodec; 604 char *audioCodecStr; 605 double audioDataRate; 606 int audioChannels; 607 int audioSampleBits; 608 int audioRate; 609 } FLVStreamInfo; 610 611 typedef enum 612 { 613 FLV_NONE = 0, 614 FLV_WIDTH, 615 FLV_HEIGHT, 616 FLV_FRAMERATE, 617 FLV_STEREO, 618 FLV_ACHANNELS, 619 FLV_VDATARATE, 620 FLV_ADATARATE, 621 FLV_VCODECID, 622 FLV_ACODECID 623 } FLVStreamAttribute; 624 625 typedef struct 626 { 627 const char *key; 628 FLVStreamAttribute attribute; 629 } MetaKeyToStreamAttribute; 630 631 static MetaKeyToStreamAttribute key_to_attribute_map[] = { 632 { "width", FLV_WIDTH }, 633 { "height", FLV_HEIGHT }, 634 { "framerate", FLV_FRAMERATE }, 635 { "videoframerate", FLV_FRAMERATE }, 636 { "stereo", FLV_STEREO }, 637 { "audiochannels", FLV_ACHANNELS }, 638 { "videodatarate", FLV_VDATARATE }, 639 { "audiodatarate", FLV_ADATARATE }, 640 { "videocodecid", FLV_VCODECID }, 641 { "audiocodecid", FLV_ACODECID }, 642 { NULL, FLV_NONE } 643 }; 644 645 typedef struct 646 { 647 const char *key; 648 enum EXTRACTOR_MetaType type; 649 } MetaKeyToExtractorItem; 650 651 static MetaKeyToExtractorItem key_to_extractor_map[] = { 652 { "duration", EXTRACTOR_METATYPE_DURATION }, 653 { "creator", EXTRACTOR_METATYPE_CREATOR }, 654 { "metadatacreator", EXTRACTOR_METATYPE_CREATOR }, 655 { "creationdate", EXTRACTOR_METATYPE_CREATION_DATE }, 656 { "metadatadate", EXTRACTOR_METATYPE_MODIFICATION_DATE }, 657 { NULL, EXTRACTOR_METATYPE_RESERVED } 658 }; 659 660 typedef struct 661 { 662 int onMetaData; 663 int parsingDepth; 664 int ret; 665 /* mixed array keys mapped to something readily usable */ 666 enum EXTRACTOR_MetaType currentKeyType; 667 FLVStreamAttribute currentAttribute; 668 669 EXTRACTOR_MetaDataProcessor proc; 670 void *proc_cls; 671 FLVStreamInfo *streamInfo; 672 } FLVMetaParserState; 673 674 static void 675 handleASBegin (unsigned char type, void *userdata) 676 { 677 FLVMetaParserState *state = (FLVMetaParserState *) userdata; 678 679 if (state->onMetaData && (state->parsingDepth == 0) && 680 (type != ASTYPE_MIXEDARRAY) ) 681 state->onMetaData = 0; 682 683 if ((type == ASTYPE_ARRAY) || (type == ASTYPE_MIXEDARRAY) || 684 (type == ASTYPE_OBJECT) ) 685 state->parsingDepth++; 686 } 687 688 689 static void 690 handleASKey (char *key, void *userdata) 691 { 692 FLVMetaParserState *state = (FLVMetaParserState *) userdata; 693 int i; 694 695 if (key == NULL) 696 return; 697 698 i = 0; 699 while ((key_to_extractor_map[i].key != NULL) && 700 (strcasecmp (key, key_to_extractor_map[i].key) != 0)) 701 i++; 702 state->currentKeyType = key_to_extractor_map[i].type; 703 704 i = 0; 705 while ((key_to_attribute_map[i].key != NULL) && 706 (strcasecmp (key, key_to_attribute_map[i].key) != 0)) 707 i++; 708 state->currentAttribute = key_to_attribute_map[i].attribute; 709 } 710 711 712 static void 713 handleASEnd (unsigned char type, void *value, void *userdata) 714 { 715 FLVMetaParserState *state = (FLVMetaParserState *) userdata; 716 const char *s; 717 char tmpstr[30]; 718 719 if ((state->parsingDepth == 0) && (type == ASTYPE_STRING)) 720 { 721 s = (const char *) value; 722 if (! strcmp (s, "onMetaData")) 723 state->onMetaData = 1; 724 } 725 726 /* we expect usable metadata to reside in a MIXEDARRAY container 727 * right after a "onMetaData" STRING */ 728 729 /* stream info related metadata */ 730 if (state->onMetaData && (state->parsingDepth == 1) && 731 (state->currentAttribute != FLV_NONE) && 732 (type == ASTYPE_NUMBER)) 733 { 734 double n = *((double *) value); 735 switch (state->currentAttribute) 736 { 737 case FLV_NONE: /* make gcc happy */ 738 break; 739 case FLV_STEREO: 740 break; 741 case FLV_ACHANNELS: 742 state->streamInfo->audioChannels = n; 743 break; 744 case FLV_WIDTH: 745 if (state->streamInfo->videoWidth == -1) 746 state->streamInfo->videoWidth = n; 747 break; 748 case FLV_HEIGHT: 749 if (state->streamInfo->videoHeight == -1) 750 state->streamInfo->videoHeight = n; 751 break; 752 case FLV_FRAMERATE: 753 state->streamInfo->videoFrameRate = n; 754 break; 755 case FLV_VDATARATE: 756 state->streamInfo->videoDataRate = n; 757 break; 758 case FLV_ADATARATE: 759 state->streamInfo->audioDataRate = n; 760 break; 761 case FLV_VCODECID: 762 if (state->streamInfo->videoCodec == -1) 763 state->streamInfo->videoCodec = n; 764 /* prefer codec ids to fourcc codes */ 765 if (state->streamInfo->videoCodecStr != NULL) 766 { 767 free (state->streamInfo->videoCodecStr); 768 state->streamInfo->videoCodecStr = NULL; 769 } 770 break; 771 case FLV_ACODECID: 772 if (state->streamInfo->audioCodec == -1) 773 state->streamInfo->audioCodec = n; 774 /* prefer codec ids to fourcc codes */ 775 if (state->streamInfo->audioCodecStr != NULL) 776 { 777 free (state->streamInfo->audioCodecStr); 778 state->streamInfo->audioCodecStr = NULL; 779 } 780 break; 781 } 782 } 783 784 /* sometimes a/v codecs are as fourcc strings */ 785 if (state->onMetaData && (state->parsingDepth == 1) && 786 (state->currentAttribute != FLV_NONE) && 787 (type == ASTYPE_STRING)) 788 { 789 s = (const char *) value; 790 switch (state->currentAttribute) 791 { 792 case FLV_VCODECID: 793 if ((s != NULL) && (state->streamInfo->videoCodecStr == NULL) && 794 (state->streamInfo->videoCodec == -1) ) 795 state->streamInfo->videoCodecStr = strdup (s); 796 break; 797 case FLV_ACODECID: 798 if ((s != NULL) && (state->streamInfo->audioCodecStr == NULL) && 799 (state->streamInfo->audioCodec == -1) ) 800 state->streamInfo->audioCodecStr = strdup (s); 801 break; 802 default: 803 break; 804 } 805 } 806 807 if (state->onMetaData && (state->parsingDepth == 1) && 808 (state->currentAttribute == FLV_STEREO) && 809 (type == ASTYPE_BOOLEAN)) 810 { 811 int n = *((int *) value); 812 if (state->streamInfo->audioChannels == -1) 813 state->streamInfo->audioChannels = (n == 0) ? 1 : 2; 814 } 815 816 /* metadata that maps straight to extractor keys */ 817 if (state->onMetaData && (state->parsingDepth == 1) && 818 (state->currentKeyType != EXTRACTOR_METATYPE_RESERVED)) 819 { 820 s = NULL; 821 switch (type) 822 { 823 case ASTYPE_NUMBER: 824 { 825 double n = *((double *) value); 826 s = tmpstr; 827 if (state->currentKeyType == EXTRACTOR_METATYPE_DURATION) 828 snprintf (tmpstr, sizeof(tmpstr), "%.2f s", n); 829 else 830 snprintf (tmpstr, sizeof(tmpstr), "%f", n); 831 break; 832 } 833 case ASTYPE_STRING: 834 { 835 s = (char *) value; 836 break; 837 } 838 case ASTYPE_DATE: 839 { 840 void **tmp = (void **) value; 841 double *millis; 842 short *tz; 843 millis = (double *) tmp[0]; 844 tz = (short *) tmp[1]; 845 if (0 == flv_to_iso_date (*millis, *tz, tmpstr, sizeof(tmpstr))) 846 s = tmpstr; 847 break; 848 } 849 } 850 if ( (s != NULL) && 851 (state->ret == 0) ) 852 state->ret = state->proc (state->proc_cls, 853 "flv", 854 state->currentKeyType, 855 EXTRACTOR_METAFORMAT_UTF8, 856 "text/plain", 857 s, 858 strlen (s) + 1); 859 } 860 state->currentKeyType = EXTRACTOR_METATYPE_RESERVED; 861 state->currentAttribute = FLV_NONE; 862 863 if ((type == ASTYPE_ARRAY) || (type == ASTYPE_MIXEDARRAY) || 864 (type == ASTYPE_OBJECT) ) 865 state->parsingDepth--; 866 } 867 868 869 static int 870 handleMetaBody (const unsigned char *data, size_t len, 871 FLVStreamInfo *stinfo, 872 EXTRACTOR_MetaDataProcessor proc, 873 void *proc_cls) 874 { 875 AMFParserHandler handler; 876 FLVMetaParserState pstate; 877 878 pstate.onMetaData = 0; 879 pstate.currentKeyType = EXTRACTOR_METATYPE_RESERVED; 880 pstate.parsingDepth = 0; 881 pstate.streamInfo = stinfo; 882 pstate.ret = 0; 883 pstate.proc = proc; 884 pstate.proc_cls = proc_cls; 885 handler.userdata = &pstate; 886 handler.as_begin_callback = &handleASBegin; 887 handler.as_key_callback = &handleASKey; 888 handler.as_end_callback = &handleASEnd; 889 890 while (len > 0 && parse_amf (&data, &len, &handler) == 0) 891 ; 892 if (pstate.ret != 0) 893 return 1; 894 return 0; 895 } 896 897 898 static char *FLVAudioCodecs[] = { 899 "Uncompressed", 900 "ADPCM", 901 "MP3", 902 NULL, 903 NULL, 904 "Nellymoser 8kHz mono", 905 "Nellymoser", 906 NULL, 907 NULL, 908 NULL, 909 "AAC", 910 "Speex" 911 }; 912 913 static char *FLVAudioChannels[] = { 914 "mono", 915 "stereo" 916 }; 917 918 static char *FLVAudioSampleSizes[] = { 919 "8-bit", 920 "16-bit" 921 }; 922 923 static char *FLVAudioSampleRates[] = { 924 "5512.5", 925 "11025", 926 "22050", 927 "44100" 928 }; 929 930 static void 931 handleAudioBody (const unsigned char *data, size_t len, 932 FLVStreamInfo *stinfo) 933 { 934 stinfo->audioChannels = (*data & 0x01) + 1; 935 stinfo->audioSampleBits = (*data & 0x02) >> 1; 936 stinfo->audioRate = (*data & 0x0C) >> 2; 937 stinfo->audioCodec = (*data & 0xF0) >> 4; 938 if (stinfo->audioCodecStr != NULL) 939 { 940 free (stinfo->audioCodecStr); 941 stinfo->audioCodecStr = NULL; 942 } 943 } 944 945 946 static char *FLVVideoCodecs[] = { 947 NULL, 948 NULL, 949 "Sorenson Spark", 950 "ScreenVideo", 951 "On2 TrueMotion VP6", 952 "On2 TrueMotion VP6 Alpha", 953 "ScreenVideo 2", 954 "H.264" /* XXX not found in docs */ 955 }; 956 957 static int sorenson_predefined_res[][2] = { 958 { -1, -1 }, 959 { -1, -1 }, 960 { 352, 288 }, 961 { 176, 144 }, 962 { 128, 96 }, 963 { 320, 240 }, 964 { 160, 120 }, 965 { -1, -1 } 966 }; 967 968 static void 969 handleVideoBody (const unsigned char *data, size_t len, 970 FLVStreamInfo *stinfo) 971 { 972 int codecId, frameType; 973 974 codecId = *data & 0x0F; 975 frameType = (*data & 0xF0) >> 4; 976 data++; 977 978 /* try to get video dimensions */ 979 switch (codecId) 980 { 981 case 0x02: /* Sorenson */ 982 if (len < 9) 983 break; 984 if (frameType == 1) 985 { 986 int start_code = (data[0] << 9) | (data[1] << 1) | ((data[2] >> 7) & 0x1); 987 int version = (data[2] & 0x7C) >> 2; 988 int frame_size = ((data[3] & 0x03) << 1) | (data[4] >> 7); 989 if (start_code != 0x00000001) 990 break; 991 if (! ((version == 0) || (version == 1) )) 992 break; 993 if (frame_size == 0) 994 { 995 stinfo->videoWidth = ((data[4] & 0x7F) >> 1) | (data[5] >> 7); 996 stinfo->videoHeight = ((data[5] & 0x7F) >> 1) | (data[6] >> 7); 997 } 998 else if (frame_size == 1) 999 { 1000 stinfo->videoWidth = ((data[4] & 0x7F) << 9) | (data[5] << 1) 1001 | (data[6] >> 7); 1002 stinfo->videoHeight = ((data[6] & 0x7F) << 9) | (data[7] << 1) 1003 | (data[8] >> 7); 1004 } 1005 else 1006 { 1007 stinfo->videoWidth = sorenson_predefined_res[frame_size][0]; 1008 stinfo->videoHeight = sorenson_predefined_res[frame_size][1]; 1009 } 1010 } 1011 break; 1012 case 0x03: /* ScreenVideo */ 1013 if (len < 5) 1014 break; 1015 stinfo->videoWidth = readInt16 (&data) & 0x0FFF; 1016 stinfo->videoHeight = readInt16 (&data) & 0x0FFF; 1017 break; 1018 case 0x04: /* On2 VP6 */ 1019 case 0x05: 1020 { 1021 unsigned char dim_adj; 1022 if (len < 10) 1023 break; 1024 dim_adj = *data++; 1025 if ((frameType == 1) && ((data[0] & 0x80) == 0)) 1026 { 1027 /* see ffmpeg vp6 decoder */ 1028 int separated_coeff = data[0] & 0x01; 1029 int filter_header = data[1] & 0x06; 1030 /*int interlaced = data[1] & 0x01; TODO: used in flv ever? */ 1031 if (separated_coeff || ! filter_header) 1032 { 1033 data += 2; 1034 } 1035 /* XXX encoded/displayed dimensions might vary, but which are the 1036 * right ones? */ 1037 stinfo->videoWidth = (data[3] * 16) - (dim_adj >> 4); 1038 stinfo->videoHeight = (data[2] * 16) - (dim_adj & 0x0F); 1039 } 1040 break; 1041 } 1042 default: 1043 break; 1044 } 1045 1046 stinfo->videoCodec = codecId; 1047 if (stinfo->videoCodecStr != NULL) 1048 { 1049 free (stinfo->videoCodecStr); 1050 stinfo->videoCodecStr = NULL; 1051 } 1052 } 1053 1054 1055 static int 1056 readFLVTag (const unsigned char **data, 1057 const unsigned char *end, 1058 FLVStreamInfo *stinfo, 1059 EXTRACTOR_MetaDataProcessor proc, 1060 void *proc_cls) 1061 { 1062 const unsigned char *ptr = *data; 1063 FLVTagHeader header; 1064 int ret = 0; 1065 1066 if (readFLVTagHeader (&ptr, end, &header) == -1) 1067 return -1; 1068 1069 if ((ptr + header.bodyLength) > end) 1070 return -1; 1071 1072 switch (header.type) 1073 { 1074 case FLV_TAG_TYPE_AUDIO: 1075 handleAudioBody (ptr, header.bodyLength, stinfo); 1076 break; 1077 case FLV_TAG_TYPE_VIDEO: 1078 handleVideoBody (ptr, header.bodyLength, stinfo); 1079 break; 1080 case FLV_TAG_TYPE_META: 1081 ret = handleMetaBody (ptr, header.bodyLength, stinfo, proc, proc_cls); 1082 break; 1083 default: 1084 break; 1085 } 1086 1087 ptr += header.bodyLength; 1088 *data = ptr; 1089 return ret; 1090 } 1091 1092 1093 #define MAX_FLV_FORMAT_LINE 80 1094 static char * 1095 printVideoFormat (FLVStreamInfo *stinfo) 1096 { 1097 char s[MAX_FLV_FORMAT_LINE + 1]; 1098 int n; 1099 size_t len = MAX_FLV_FORMAT_LINE; 1100 1101 n = 0; 1102 /* some files seem to specify only the width or the height, print '?' for 1103 * the unknown dimension */ 1104 if ((stinfo->videoWidth != -1) || (stinfo->videoHeight != -1)) 1105 { 1106 if (n < len) 1107 { 1108 if (stinfo->videoWidth != -1) 1109 n += snprintf (s + n, len - n, "%d", stinfo->videoWidth); 1110 else 1111 n += snprintf (s + n, len - n, "?"); 1112 } 1113 1114 if (n < len) 1115 { 1116 if (stinfo->videoHeight != -1) 1117 n += snprintf (s + n, len - n, "x%d", stinfo->videoHeight); 1118 else 1119 n += snprintf (s + n, len - n, "x?"); 1120 } 1121 } 1122 1123 if ((stinfo->videoFrameRate != 0.0) && (n < len)) 1124 { 1125 if (n > 0) 1126 n += snprintf (s + n, len - n, ", "); 1127 if (n < len) 1128 n += snprintf (s + n, len - n, "%0.2f fps", stinfo->videoFrameRate); 1129 } 1130 1131 if ((stinfo->videoCodec > -1) && (stinfo->videoCodec < 8) && 1132 (FLVVideoCodecs[stinfo->videoCodec] != NULL) && (n < len) ) 1133 { 1134 if (n > 0) 1135 n += snprintf (s + n, len - n, ", "); 1136 if (n < len) 1137 n += snprintf (s + n, len - n, "%s", FLVVideoCodecs[stinfo->videoCodec]); 1138 } 1139 else if ((stinfo->videoCodecStr != NULL) && (n < len)) 1140 { 1141 if (n > 0) 1142 n += snprintf (s + n, len - n, ", "); 1143 if (n < len) 1144 n += snprintf (s + n, len - n, "%s", stinfo->videoCodecStr); 1145 } 1146 1147 if ((stinfo->videoDataRate != 0.0) && (n < len)) 1148 { 1149 if (n > 0) 1150 n += snprintf (s + n, len - n, ", "); 1151 if (n < len) 1152 n += snprintf (s + n, len - n, "%.4f kbps", stinfo->videoDataRate); 1153 } 1154 1155 if (n == 0) 1156 return NULL; 1157 return strdup (s); 1158 } 1159 1160 1161 static char * 1162 printAudioFormat (FLVStreamInfo *stinfo) 1163 { 1164 char s[MAX_FLV_FORMAT_LINE + 1]; 1165 int n; 1166 size_t len = MAX_FLV_FORMAT_LINE; 1167 1168 n = 0; 1169 if ( (stinfo->audioRate != -1) && (n < len)) 1170 { 1171 n += snprintf (s + n, len - n, "%s Hz", 1172 FLVAudioSampleRates[stinfo->audioRate]); 1173 } 1174 1175 if ((stinfo->audioSampleBits != -1) && (n < len)) 1176 { 1177 if (n > 0) 1178 n += snprintf (s + n, len - n, ", "); 1179 if (n < len) 1180 n += snprintf (s + n, len - n, "%s", 1181 FLVAudioSampleSizes[stinfo->audioSampleBits]); 1182 } 1183 1184 if ((stinfo->audioChannels != -1) && (n < len)) 1185 { 1186 if (n > 0) 1187 n += snprintf (s + n, len - n, ", "); 1188 if (n < len) 1189 { 1190 if ((stinfo->audioChannels >= 1) && (stinfo->audioChannels <= 2)) 1191 n += snprintf (s + n, len - n, "%s", 1192 FLVAudioChannels[stinfo->audioChannels - 1]); 1193 else 1194 n += snprintf (s + n, len - n, "%d", 1195 stinfo->audioChannels); 1196 } 1197 } 1198 1199 if ((stinfo->audioCodec > -1) && (stinfo->audioCodec < 12) && 1200 (FLVAudioCodecs[stinfo->audioCodec] != NULL) && (n < len)) 1201 { 1202 if (n > 0) 1203 n += snprintf (s + n, len - n, ", "); 1204 if (n < len) 1205 n += snprintf (s + n, len - n, "%s", FLVAudioCodecs[stinfo->audioCodec]); 1206 } 1207 else if ((stinfo->audioCodecStr != NULL) && (n < len)) 1208 { 1209 if (n > 0) 1210 n += snprintf (s + n, len - n, ", "); 1211 if (n < len) 1212 n += snprintf (s + n, len - n, "%s", stinfo->audioCodecStr); 1213 } 1214 1215 if ((stinfo->audioDataRate != 0.0) && (n < len)) 1216 { 1217 if (n > 0) 1218 n += snprintf (s + n, len - n, ", "); 1219 if (n < len) 1220 n += snprintf (s + n, len - n, "%.4f kbps", stinfo->audioDataRate); 1221 } 1222 1223 if (n == 0) 1224 return NULL; 1225 return strdup (s); 1226 } 1227 1228 1229 int 1230 EXTRACTOR_flv_extract (const unsigned char *data, 1231 size_t size, 1232 EXTRACTOR_MetaDataProcessor proc, 1233 void *proc_cls, 1234 const char *options) 1235 { 1236 const unsigned char *ptr; 1237 const unsigned char *end; 1238 FLVStreamInfo stinfo; 1239 FLVHeader header; 1240 unsigned long prev_tag_size; 1241 char *s; 1242 int ret; 1243 1244 ptr = data; 1245 end = ptr + size; 1246 1247 if (readFLVHeader (&ptr, end, &header) == -1) 1248 return 0; 1249 1250 if (memcmp (header.signature, FLV_SIGNATURE, 3) != 0) 1251 return 0; 1252 1253 if (0 != proc (proc_cls, 1254 "flv", 1255 EXTRACTOR_METATYPE_MIMETYPE, 1256 EXTRACTOR_METAFORMAT_UTF8, 1257 "text/plain", 1258 "video/x-flv", 1259 strlen ("video/x-flv") + 1)) 1260 return 0; 1261 if (header.version != 1) 1262 return 0; 1263 if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1) 1264 return 0; 1265 1266 stinfo.videoCodec = -1; 1267 stinfo.videoCodecStr = NULL; 1268 stinfo.videoWidth = -1; 1269 stinfo.videoHeight = -1; 1270 stinfo.videoFrameRate = 0.0; 1271 stinfo.videoDataRate = 0.0; 1272 stinfo.audioCodec = -1; 1273 stinfo.audioCodecStr = NULL; 1274 stinfo.audioRate = -1; 1275 stinfo.audioSampleBits = -1; 1276 stinfo.audioChannels = -1; 1277 stinfo.audioDataRate = 0.0; 1278 ret = 0; 1279 while (ptr < end) 1280 { 1281 if (-1 == (ret = readFLVTag (&ptr, end, &stinfo, proc, proc_cls))) 1282 break; 1283 if (readPreviousTagSize (&ptr, end, &prev_tag_size) == -1) 1284 break; 1285 } 1286 if (1 == ret) 1287 return 1; 1288 s = printVideoFormat (&stinfo); 1289 if (s != NULL) 1290 { 1291 if (0 != proc (proc_cls, 1292 "flv", 1293 EXTRACTOR_METATYPE_RESOURCE_TYPE, 1294 EXTRACTOR_METAFORMAT_UTF8, 1295 "text/plain", 1296 s, 1297 strlen (s) + 1)) 1298 { 1299 free (s); 1300 return 1; 1301 } 1302 free (s); 1303 } 1304 s = printAudioFormat (&stinfo); 1305 if (s != NULL) 1306 { 1307 if (0 != proc (proc_cls, 1308 "flv", 1309 EXTRACTOR_METATYPE_RESOURCE_TYPE, 1310 EXTRACTOR_METAFORMAT_UTF8, 1311 "text/plain", 1312 s, 1313 strlen (s) + 1)) 1314 { 1315 free (s); 1316 return 1; 1317 } 1318 free (s); 1319 } 1320 return 0; 1321 }