1 /* 2 * Copyright 2009, Stephan Aßmus <superstippi@gmx.de> 3 * All rights reserved. Distributed under the terms of the GNU L-GPL license. 4 */ 5 6 #include "AVFormatReader.h" 7 8 #include <stdio.h> 9 #include <string.h> 10 #include <stdlib.h> 11 12 #include <new> 13 14 #include <AutoDeleter.h> 15 #include <Autolock.h> 16 #include <ByteOrder.h> 17 #include <DataIO.h> 18 #include <MediaDefs.h> 19 #include <MediaFormats.h> 20 21 extern "C" { 22 #include "avcodec.h" 23 #include "avformat.h" 24 } 25 26 #include "DemuxerTable.h" 27 #include "gfx_util.h" 28 29 30 #define TRACE_AVFORMAT_READER 31 #ifdef TRACE_AVFORMAT_READER 32 # define TRACE printf 33 # define TRACE_IO(a...) 34 # define TRACE_SEEK(a...) 35 # define TRACE_PACKET(a...) 36 #else 37 # define TRACE(a...) 38 # define TRACE_IO(a...) 39 # define TRACE_SEEK(a...) 40 # define TRACE_PACKET(a...) 41 #endif 42 43 #define ERROR(a...) fprintf(stderr, a) 44 45 46 static const size_t kIOBufferSize = 64 * 1024; 47 // TODO: This could depend on the BMediaFile creation flags, IIRC, 48 // they allow to specify a buffering mode. 49 50 static const int64 kNoPTSValue = 0x8000000000000000LL; 51 // NOTE: For some reasons, I have trouble with the avcodec.h define: 52 // #define AV_NOPTS_VALUE INT64_C(0x8000000000000000) 53 // INT64_C is not defined here. 54 55 56 uint32 57 avformat_to_beos_format(SampleFormat format) 58 { 59 switch (format) { 60 case SAMPLE_FMT_U8: return media_raw_audio_format::B_AUDIO_UCHAR; 61 case SAMPLE_FMT_S16: return media_raw_audio_format::B_AUDIO_SHORT; 62 case SAMPLE_FMT_S32: return media_raw_audio_format::B_AUDIO_INT; 63 case SAMPLE_FMT_FLT: return media_raw_audio_format::B_AUDIO_FLOAT; 64 case SAMPLE_FMT_DBL: return media_raw_audio_format::B_AUDIO_DOUBLE; 65 default: 66 break; 67 } 68 return 0; 69 } 70 71 72 uint32 73 avformat_to_beos_byte_order(SampleFormat format) 74 { 75 return B_MEDIA_HOST_ENDIAN; 76 } 77 78 79 // #pragma mark - AVFormatReader::StreamCookie 80 81 82 class AVFormatReader::StreamCookie { 83 public: 84 StreamCookie(BPositionIO* source, 85 BLocker* streamLock); 86 virtual ~StreamCookie(); 87 88 // Init an indivual AVFormatContext 89 status_t Open(); 90 91 // Setup this stream to point to the AVStream at the given streamIndex. 92 // This will also initialize the media_format. 93 status_t Init(int32 streamIndex); 94 95 inline const AVFormatContext* Context() const 96 { return fContext; } 97 int32 Index() const; 98 int32 CountStreams() const; 99 int32 StreamIndexFor(int32 virtualIndex) const; 100 inline int32 VirtualIndex() const 101 { return fVirtualIndex; } 102 103 inline const media_format& Format() const 104 { return fFormat; } 105 106 double FrameRate() const; 107 108 // Support for AVFormatReader 109 status_t GetStreamInfo(int64* frameCount, 110 bigtime_t* duration, media_format* format, 111 const void** infoBuffer, 112 size_t* infoSize) const; 113 114 status_t Seek(uint32 flags, int64* frame, 115 bigtime_t* time); 116 status_t FindKeyFrame(uint32 flags, int64* frame, 117 bigtime_t* time) const; 118 119 status_t GetNextChunk(const void** chunkBuffer, 120 size_t* chunkSize, 121 media_header* mediaHeader); 122 123 private: 124 // I/O hooks for libavformat, cookie will be a StreamCookie instance. 125 // Since multiple StreamCookies use the same BPositionIO source, they 126 // maintain the position individually, and may need to seek the source 127 // if it does not match anymore in _Read(). 128 // TODO: This concept prevents the use of a plain BDataIO that is not 129 // seekable. There is a version of AVFormatReader in the SVN history 130 // which implements packet buffering for other streams when reading 131 // packets. To support non-seekable network streams for example, this 132 // code should be resurrected. It will make handling seekable streams, 133 // especially from different threads that read from totally independent 134 // positions in the stream (aggressive pre-buffering perhaps), a lot 135 // more difficult with potentially large memory overhead. 136 static int _Read(void* cookie, uint8* buffer, 137 int bufferSize); 138 static off_t _Seek(void* cookie, off_t offset, int whence); 139 140 status_t _NextPacket(bool reuse); 141 142 private: 143 BPositionIO* fSource; 144 off_t fPosition; 145 // Since different threads may read from the source, 146 // we need to protect the file position and I/O by a lock. 147 BLocker* fStreamLock; 148 149 AVFormatContext* fContext; 150 AVStream* fStream; 151 int32 fVirtualIndex; 152 153 ByteIOContext fIOContext; 154 uint8 fIOBuffer[kIOBufferSize]; 155 156 AVPacket fPacket; 157 bool fReusePacket; 158 159 media_format fFormat; 160 }; 161 162 163 164 AVFormatReader::StreamCookie::StreamCookie(BPositionIO* source, 165 BLocker* streamLock) 166 : 167 fSource(source), 168 fPosition(0), 169 fStreamLock(streamLock), 170 171 fContext(NULL), 172 fStream(NULL), 173 fVirtualIndex(-1), 174 175 fReusePacket(false) 176 { 177 memset(&fIOBuffer, 0, sizeof(fIOBuffer)); 178 memset(&fFormat, 0, sizeof(media_format)); 179 av_new_packet(&fPacket, 0); 180 } 181 182 183 AVFormatReader::StreamCookie::~StreamCookie() 184 { 185 av_free_packet(&fPacket); 186 av_free(fContext); 187 } 188 189 190 status_t 191 AVFormatReader::StreamCookie::Open() 192 { 193 // Init probing data 194 size_t probeSize = 2048; 195 AVProbeData probeData; 196 probeData.filename = ""; 197 probeData.buf = fIOBuffer; 198 probeData.buf_size = probeSize; 199 200 // Read a bit of the input... 201 // NOTE: Even if other streams have already read from the source, 202 // it is ok to not seek first, since our fPosition is 0, so the necessary 203 // seek will happen automatically in _Read(). 204 if (_Read(this, fIOBuffer, probeSize) != (ssize_t)probeSize) 205 return B_IO_ERROR; 206 // ...and seek back to the beginning of the file. This is important 207 // since libavformat will assume the stream to be at offset 0, the 208 // probe data is not reused. 209 _Seek(this, 0, SEEK_SET); 210 211 // Probe the input format 212 AVInputFormat* inputFormat = av_probe_input_format(&probeData, 1); 213 214 if (inputFormat == NULL) { 215 TRACE("AVFormatReader::StreamCookie::Open() - " 216 "av_probe_input_format() failed!\n"); 217 return B_NOT_SUPPORTED; 218 } 219 220 TRACE("AVFormatReader::StreamCookie::Open() - " 221 "av_probe_input_format(): %s\n", inputFormat->name); 222 223 const DemuxerFormat* demuxerFormat = demuxer_format_for(inputFormat); 224 if (demuxerFormat == NULL) { 225 // We could support this format, but we don't want to. Bail out. 226 ERROR("AVFormatReader::StreamCookie::Open() - " 227 "support for demuxer '%s' is not enabled. " 228 "See DemuxerTable.cpp\n", inputFormat->name); 229 return B_NOT_SUPPORTED; 230 } 231 232 // Init I/O context with buffer and hook functions, pass ourself as 233 // cookie. 234 if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, this, 235 _Read, 0, _Seek) != 0) { 236 TRACE("AVFormatReader::StreamCookie::Open() - " 237 "init_put_byte() failed!\n"); 238 return B_ERROR; 239 } 240 241 // Initialize our context. 242 if (av_open_input_stream(&fContext, &fIOContext, "", inputFormat, 243 NULL) < 0) { 244 TRACE("AVFormatReader::StreamCookie::Open() - " 245 "av_open_input_stream() failed!\n"); 246 return B_NOT_SUPPORTED; 247 } 248 249 // Retrieve stream information 250 if (av_find_stream_info(fContext) < 0) { 251 TRACE("AVFormatReader::StreamCookie::Open() - " 252 "av_find_stream_info() failed!\n"); 253 return B_NOT_SUPPORTED; 254 } 255 256 TRACE("AVFormatReader::StreamCookie::Open() - " 257 "av_find_stream_info() success!\n"); 258 259 return B_OK; 260 } 261 262 263 status_t 264 AVFormatReader::StreamCookie::Init(int32 virtualIndex) 265 { 266 TRACE("AVFormatReader::StreamCookie::Init(%ld)\n", virtualIndex); 267 268 if (fContext == NULL) 269 return B_NO_INIT; 270 271 int32 streamIndex = StreamIndexFor(virtualIndex); 272 if (streamIndex < 0) { 273 TRACE(" Bad stream index!\n"); 274 return B_BAD_INDEX; 275 } 276 277 TRACE(" context stream index: %ld\n", streamIndex); 278 279 const DemuxerFormat* demuxerFormat = demuxer_format_for(fContext->iformat); 280 if (demuxerFormat == NULL) { 281 TRACE(" unknown AVInputFormat!\n"); 282 return B_NOT_SUPPORTED; 283 } 284 285 // We need to remember the virtual index so that 286 // AVFormatReader::FreeCookie() can clear the correct stream entry. 287 fVirtualIndex = virtualIndex; 288 289 // Make us point to the AVStream at streamIndex 290 fStream = fContext->streams[streamIndex]; 291 292 // Discard all other streams 293 for (unsigned i = 0; i < fContext->nb_streams; i++) { 294 if (i != (unsigned)streamIndex) 295 fContext->streams[i]->discard = AVDISCARD_ALL; 296 } 297 298 // Get a pointer to the AVCodecContext for the stream at streamIndex. 299 AVCodecContext* codecContext = fStream->codec; 300 AVStream* stream = fStream; 301 302 #if 0 303 // stippi: Here I was experimenting with the question if some fields of the 304 // AVCodecContext change (or get filled out at all), if the AVCodec is opened. 305 class CodecOpener { 306 public: 307 CodecOpener(AVCodecContext* context) 308 { 309 fCodecContext = context; 310 AVCodec* codec = avcodec_find_decoder(context->codec_id); 311 fCodecOpen = avcodec_open(context, codec) >= 0; 312 if (!fCodecOpen) 313 TRACE(" failed to open the codec!\n"); 314 } 315 ~CodecOpener() 316 { 317 if (fCodecOpen) 318 avcodec_close(fCodecContext); 319 } 320 private: 321 AVCodecContext* fCodecContext; 322 bool fCodecOpen; 323 } codecOpener(codecContext); 324 #endif 325 326 // initialize the media_format for this stream 327 media_format* format = &fFormat; 328 memset(format, 0, sizeof(media_format)); 329 330 media_format_description description; 331 332 // Set format family and type depending on codec_type of the stream. 333 switch (codecContext->codec_type) { 334 case CODEC_TYPE_AUDIO: 335 if ((codecContext->codec_id >= CODEC_ID_PCM_S16LE) 336 && (codecContext->codec_id <= CODEC_ID_PCM_U8)) { 337 TRACE(" raw audio\n"); 338 format->type = B_MEDIA_RAW_AUDIO; 339 description.family = B_ANY_FORMAT_FAMILY; 340 } else { 341 TRACE(" encoded audio\n"); 342 format->type = B_MEDIA_ENCODED_AUDIO; 343 description.family = demuxerFormat->audio_family; 344 } 345 break; 346 case CODEC_TYPE_VIDEO: 347 TRACE(" encoded video\n"); 348 format->type = B_MEDIA_ENCODED_VIDEO; 349 description.family = demuxerFormat->video_family; 350 break; 351 default: 352 TRACE(" unknown type\n"); 353 format->type = B_MEDIA_UNKNOWN_TYPE; 354 break; 355 } 356 357 if (format->type == B_MEDIA_RAW_AUDIO) { 358 switch (codecContext->codec_id) { 359 case CODEC_ID_PCM_S16LE: 360 format->u.raw_audio.format 361 = media_raw_audio_format::B_AUDIO_SHORT; 362 format->u.raw_audio.byte_order 363 = B_MEDIA_LITTLE_ENDIAN; 364 break; 365 case CODEC_ID_PCM_S16BE: 366 format->u.raw_audio.format 367 = media_raw_audio_format::B_AUDIO_SHORT; 368 format->u.raw_audio.byte_order 369 = B_MEDIA_BIG_ENDIAN; 370 break; 371 case CODEC_ID_PCM_U16LE: 372 // format->u.raw_audio.format 373 // = media_raw_audio_format::B_AUDIO_USHORT; 374 // format->u.raw_audio.byte_order 375 // = B_MEDIA_LITTLE_ENDIAN; 376 return B_NOT_SUPPORTED; 377 break; 378 case CODEC_ID_PCM_U16BE: 379 // format->u.raw_audio.format 380 // = media_raw_audio_format::B_AUDIO_USHORT; 381 // format->u.raw_audio.byte_order 382 // = B_MEDIA_BIG_ENDIAN; 383 return B_NOT_SUPPORTED; 384 break; 385 case CODEC_ID_PCM_S8: 386 format->u.raw_audio.format 387 = media_raw_audio_format::B_AUDIO_CHAR; 388 break; 389 case CODEC_ID_PCM_U8: 390 format->u.raw_audio.format 391 = media_raw_audio_format::B_AUDIO_UCHAR; 392 break; 393 default: 394 return B_NOT_SUPPORTED; 395 break; 396 } 397 } else { 398 uint32 codecTag = codecContext->codec_tag; 399 if (codecTag == 0) { 400 // Ugh, no codec_tag. Let's try to fake some known codecs. 401 // Such a situation seems to occur for the "mpegts" demuxer for 402 // example. These are some tags I could test with. 403 switch (codecContext->codec_id) { 404 case CODEC_ID_H264: 405 codecTag = 'h264'; 406 break; 407 case CODEC_ID_DVVIDEO: 408 codecTag = 'pcvd'; 409 break; 410 case CODEC_ID_AC3: 411 description.family = B_WAV_FORMAT_FAMILY; 412 codecTag = 0x2000; 413 break; 414 case CODEC_ID_FLAC: 415 description.family = B_WAV_FORMAT_FAMILY; 416 codecTag = 'flac'; 417 break; 418 case CODEC_ID_VP6F: 419 description.family = B_QUICKTIME_FORMAT_FAMILY; 420 codecTag = B_BENDIAN_TO_HOST_INT32('VP6F'); 421 break; 422 case CODEC_ID_MP3: 423 description.family = B_QUICKTIME_FORMAT_FAMILY; 424 codecTag = B_BENDIAN_TO_HOST_INT32('.mp3'); 425 break; 426 default: 427 fprintf(stderr, "ffmpeg codecTag is null, codec_id " 428 "unknown 0x%x\n", codecContext->codec_id); 429 // TODO: Add more... 430 break; 431 } 432 } 433 switch (description.family) { 434 case B_AIFF_FORMAT_FAMILY: 435 TRACE(" B_AIFF_FORMAT_FAMILY\n"); 436 description.u.aiff.codec = codecTag; 437 break; 438 case B_ASF_FORMAT_FAMILY: 439 TRACE(" B_ASF_FORMAT_FAMILY\n"); 440 // description.u.asf.guid = GUID(codecTag); 441 return B_NOT_SUPPORTED; 442 break; 443 case B_AVI_FORMAT_FAMILY: 444 TRACE(" B_AVI_FORMAT_FAMILY\n"); 445 description.u.avi.codec = codecTag; 446 break; 447 case B_AVR_FORMAT_FAMILY: 448 TRACE(" B_AVR_FORMAT_FAMILY\n"); 449 description.u.avr.id = codecTag; 450 break; 451 case B_MPEG_FORMAT_FAMILY: 452 TRACE(" B_MPEG_FORMAT_FAMILY\n"); 453 if (codecContext->codec_id == CODEC_ID_MPEG1VIDEO) 454 description.u.mpeg.id = B_MPEG_1_VIDEO; 455 else if (codecContext->codec_id == CODEC_ID_MPEG2VIDEO) 456 description.u.mpeg.id = B_MPEG_2_VIDEO; 457 else if (codecContext->codec_id == CODEC_ID_MP2) 458 description.u.mpeg.id = B_MPEG_2_AUDIO_LAYER_2; 459 else if (codecContext->codec_id == CODEC_ID_MP3) 460 description.u.mpeg.id = B_MPEG_1_AUDIO_LAYER_3; 461 // TODO: Add some more... 462 else 463 description.u.mpeg.id = B_MPEG_ANY; 464 break; 465 case B_QUICKTIME_FORMAT_FAMILY: 466 TRACE(" B_QUICKTIME_FORMAT_FAMILY\n"); 467 description.u.quicktime.codec 468 = B_HOST_TO_BENDIAN_INT32(codecTag); 469 break; 470 case B_WAV_FORMAT_FAMILY: 471 TRACE(" B_WAV_FORMAT_FAMILY\n"); 472 description.u.wav.codec = codecTag; 473 break; 474 case B_MISC_FORMAT_FAMILY: 475 TRACE(" B_MISC_FORMAT_FAMILY\n"); 476 description.u.misc.codec = codecTag; 477 break; 478 479 default: 480 break; 481 } 482 TRACE(" codecTag '%.4s' or %ld\n", (char*)&codecTag, codecTag); 483 TRACE(" fourcc '%.4s' or %d\n", (char*)&codecContext->codec_id, 484 codecContext->codec_id); 485 486 BMediaFormats formats; 487 status_t status = formats.GetFormatFor(description, format); 488 if (status < B_OK) 489 TRACE(" formats.GetFormatFor() error: %s\n", strerror(status)); 490 491 format->user_data_type = B_CODEC_TYPE_INFO; 492 *(uint32*)format->user_data = codecTag; 493 format->user_data[4] = 0; 494 } 495 496 // format->require_flags = 0; 497 format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 498 499 switch (format->type) { 500 case B_MEDIA_RAW_AUDIO: 501 format->u.raw_audio.frame_rate = (float)codecContext->sample_rate; 502 format->u.raw_audio.channel_count = codecContext->channels; 503 format->u.raw_audio.byte_order 504 = avformat_to_beos_byte_order(codecContext->sample_fmt); 505 format->u.raw_audio.format 506 = avformat_to_beos_format(codecContext->sample_fmt); 507 format->u.raw_audio.buffer_size = 0; 508 509 // Read one packet and mark it for later re-use. (So our first 510 // GetNextChunk() call does not read another packet.) 511 if (_NextPacket(true) == B_OK) { 512 TRACE(" successfully determined audio buffer size: %d\n", 513 fPacket.size); 514 format->u.raw_audio.buffer_size = fPacket.size; 515 } 516 break; 517 518 case B_MEDIA_ENCODED_AUDIO: 519 format->u.encoded_audio.bit_rate = codecContext->bit_rate; 520 format->u.encoded_audio.frame_size = codecContext->frame_size; 521 // Fill in some info about possible output format 522 format->u.encoded_audio.output 523 = media_multi_audio_format::wildcard; 524 format->u.encoded_audio.output.frame_rate 525 = (float)codecContext->sample_rate; 526 format->u.encoded_audio.output.channel_count 527 = codecContext->channels; 528 format->u.encoded_audio.output.byte_order 529 = avformat_to_beos_byte_order(codecContext->sample_fmt); 530 format->u.encoded_audio.output.format 531 = avformat_to_beos_format(codecContext->sample_fmt); 532 if (codecContext->block_align > 0) { 533 format->u.encoded_audio.output.buffer_size 534 = codecContext->block_align; 535 } else { 536 format->u.encoded_audio.output.buffer_size 537 = codecContext->frame_size * codecContext->channels 538 * (format->u.encoded_audio.output.format 539 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 540 } 541 break; 542 543 case B_MEDIA_ENCODED_VIDEO: 544 // TODO: Specifying any of these seems to throw off the format matching 545 // later on. 546 // format->u.encoded_video.avg_bit_rate = codecContext->bit_rate; 547 // format->u.encoded_video.max_bit_rate = codecContext->bit_rate 548 // + codecContext->bit_rate_tolerance; 549 550 // format->u.encoded_video.encoding 551 // = media_encoded_video_format::B_ANY; 552 553 // format->u.encoded_video.frame_size = 1; 554 // format->u.encoded_video.forward_history = 0; 555 // format->u.encoded_video.backward_history = 0; 556 557 // TODO: Fix up for interlaced video 558 format->u.encoded_video.output.field_rate 559 = av_q2d(stream->r_frame_rate); 560 if (format->u.encoded_video.output.field_rate == 50.0f) 561 format->u.encoded_video.output.field_rate = 25.0f; 562 format->u.encoded_video.output.interlace = 1; 563 564 format->u.encoded_video.output.first_active = 0; 565 format->u.encoded_video.output.last_active 566 = codecContext->height - 1; 567 // TODO: Maybe libavformat actually provides that info 568 // somewhere... 569 format->u.encoded_video.output.orientation 570 = B_VIDEO_TOP_LEFT_RIGHT; 571 572 // Calculate the display aspect ratio 573 AVRational displayAspectRatio; 574 if (codecContext->sample_aspect_ratio.num != 0) { 575 av_reduce(&displayAspectRatio.num, &displayAspectRatio.den, 576 codecContext->width 577 * codecContext->sample_aspect_ratio.num, 578 codecContext->height 579 * codecContext->sample_aspect_ratio.den, 580 1024 * 1024); 581 TRACE(" pixel aspect ratio: %d/%d, " 582 "display aspect ratio: %d/%d\n", 583 codecContext->sample_aspect_ratio.num, 584 codecContext->sample_aspect_ratio.den, 585 displayAspectRatio.num, displayAspectRatio.den); 586 } else { 587 av_reduce(&displayAspectRatio.num, &displayAspectRatio.den, 588 codecContext->width, codecContext->height, 1024 * 1024); 589 TRACE(" no display aspect ratio (%d/%d)\n", 590 displayAspectRatio.num, displayAspectRatio.den); 591 } 592 format->u.encoded_video.output.pixel_width_aspect 593 = displayAspectRatio.num; 594 format->u.encoded_video.output.pixel_height_aspect 595 = displayAspectRatio.den; 596 597 format->u.encoded_video.output.display.format 598 = pixfmt_to_colorspace(codecContext->pix_fmt); 599 format->u.encoded_video.output.display.line_width 600 = codecContext->width; 601 format->u.encoded_video.output.display.line_count 602 = codecContext->height; 603 format->u.encoded_video.output.display.bytes_per_row = 0; 604 format->u.encoded_video.output.display.pixel_offset = 0; 605 format->u.encoded_video.output.display.line_offset = 0; 606 format->u.encoded_video.output.display.flags = 0; // TODO 607 608 break; 609 610 default: 611 // This is an unknown format to us. 612 break; 613 } 614 615 // Add the meta data, if any 616 if (codecContext->extradata_size > 0) { 617 format->SetMetaData(codecContext->extradata, 618 codecContext->extradata_size); 619 TRACE(" extradata: %p\n", format->MetaData()); 620 } 621 622 TRACE(" extradata_size: %d\n", codecContext->extradata_size); 623 TRACE(" intra_matrix: %p\n", codecContext->intra_matrix); 624 TRACE(" inter_matrix: %p\n", codecContext->inter_matrix); 625 TRACE(" get_buffer(): %p\n", codecContext->get_buffer); 626 TRACE(" release_buffer(): %p\n", codecContext->release_buffer); 627 628 #ifdef TRACE_AVFORMAT_READER 629 char formatString[512]; 630 if (string_for_format(*format, formatString, sizeof(formatString))) 631 TRACE(" format: %s\n", formatString); 632 633 uint32 encoding = format->Encoding(); 634 TRACE(" encoding '%.4s'\n", (char*)&encoding); 635 #endif 636 637 return B_OK; 638 } 639 640 641 int32 642 AVFormatReader::StreamCookie::Index() const 643 { 644 if (fStream != NULL) 645 return fStream->index; 646 return -1; 647 } 648 649 650 int32 651 AVFormatReader::StreamCookie::CountStreams() const 652 { 653 // Figure out the stream count. If the context has "AVPrograms", use 654 // the first program (for now). 655 // TODO: To support "programs" properly, the BMediaFile/Track API should 656 // be extended accordingly. I guess programs are like TV channels in the 657 // same satilite transport stream. Maybe call them "TrackGroups". 658 if (fContext->nb_programs > 0) { 659 // See libavformat/utils.c:dump_format() 660 return fContext->programs[0]->nb_stream_indexes; 661 } 662 return fContext->nb_streams; 663 } 664 665 666 int32 667 AVFormatReader::StreamCookie::StreamIndexFor(int32 virtualIndex) const 668 { 669 // NOTE: See CountStreams() 670 if (fContext->nb_programs > 0) { 671 const AVProgram* program = fContext->programs[0]; 672 if (virtualIndex >= 0 673 && virtualIndex < (int32)program->nb_stream_indexes) { 674 return program->stream_index[virtualIndex]; 675 } 676 } else { 677 if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams) 678 return virtualIndex; 679 } 680 return -1; 681 } 682 683 684 double 685 AVFormatReader::StreamCookie::FrameRate() const 686 { 687 // TODO: Find a way to always calculate a correct frame rate... 688 double frameRate; 689 switch (fStream->codec->codec_type) { 690 case CODEC_TYPE_AUDIO: 691 frameRate = (double)fStream->codec->sample_rate; 692 break; 693 case CODEC_TYPE_VIDEO: 694 frameRate = av_q2d(fStream->r_frame_rate); 695 break; 696 default: 697 frameRate = 1.0; 698 break; 699 } 700 if (frameRate <= 0.0) 701 frameRate = 1.0; 702 return frameRate; 703 } 704 705 706 status_t 707 AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount, 708 bigtime_t* duration, media_format* format, const void** infoBuffer, 709 size_t* infoSize) const 710 { 711 TRACE("AVFormatReader::StreamCookie::GetStreamInfo(%ld)\n", 712 VirtualIndex()); 713 714 double frameRate = FrameRate(); 715 TRACE(" frameRate: %.4f\n", frameRate); 716 717 // TODO: This is obviously not working correctly for all stream types... 718 // It seems that the calculations here are correct, because they work 719 // for a couple of streams and are in line with the documentation, but 720 // unfortunately, libavformat itself seems to set the time_base and 721 // duration wrongly sometimes. :-( 722 if ((int64)fStream->duration != kNoPTSValue) { 723 *duration = (bigtime_t)(1000000LL * fStream->duration 724 * fStream->time_base.num / fStream->time_base.den); 725 TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n", 726 fStream->duration, av_q2d(fStream->time_base), 727 fStream->time_base.num, fStream->time_base.den); 728 } else if ((int64)fContext->duration != kNoPTSValue) { 729 *duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE); 730 TRACE(" stream duration: %lld (from AVFormatContext)\n", 731 *duration); 732 } else { 733 *duration = 0; 734 TRACE(" stream duration: N/A\n"); 735 } 736 737 TRACE(" duration: %lld or %.2fs\n", *duration, *duration / 1000000.0); 738 739 *frameCount = fStream->nb_frames; 740 if (*frameCount == 0) { 741 // Calculate from duration and frame rate 742 *frameCount = (int64)(*duration * frameRate / 1000000LL); 743 TRACE(" frameCount (calculated): %lld\n", *frameCount); 744 } else 745 TRACE(" frameCount: %lld\n", *frameCount); 746 747 *format = fFormat; 748 749 *infoBuffer = fStream->codec->extradata; 750 *infoSize = fStream->codec->extradata_size; 751 752 return B_OK; 753 } 754 755 756 status_t 757 AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame, 758 bigtime_t* time) 759 { 760 if (fContext == NULL || fStream == NULL) 761 return B_NO_INIT; 762 763 if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) { 764 TRACE_SEEK("AVFormatReader::StreamCookie::Seek() - " 765 "B_MEDIA_SEEK_CLOSEST_FORWARD not supported.\n"); 766 return B_NOT_SUPPORTED; 767 } 768 769 TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, " 770 "%lld)\n", VirtualIndex(), 771 (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "", 772 (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "", 773 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 774 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 775 *frame, *time); 776 777 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) 778 *time = (bigtime_t)(*frame * 1000000LL / FrameRate()); 779 780 #if 0 781 // This happens in ffplay.c: 782 783 int64_t pos = get_master_clock(cur_stream); 784 // The master clock seems to be the current system time 785 // with an offset for the current PTS value of the respective 786 // stream. 787 pos += incr; 788 // depends on the seek direction... 789 790 pos = (int64_t)(pos * AV_TIME_BASE); 791 uint32_t seekFlags = incr < 0 ? AVSEEK_FLAG_BACKWARD : 0; 792 793 pos = av_rescale_q(pos, AV_TIME_BASE_Q, fStream->time_base); 794 795 ret = av_seek_frame(fContext, Index(), pos, seekFlags); 796 #endif 797 798 799 int64_t timeStamp; 800 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 801 // Can use frame, because stream timeStamp is actually in frame 802 // units. 803 timeStamp = *frame; 804 } else { 805 timeStamp = *time * fStream->time_base.num 806 / ((int64_t)fStream->time_base.den * 1000000); 807 } 808 809 TRACE_SEEK(" time: %.5fs -> %lld, current DTS: %lld (time_base: %d/%d)\n", 810 *time / 1000000.0, timeStamp, fStream->cur_dts, fStream->time_base.num, 811 fStream->time_base.den); 812 813 if (av_seek_frame(fContext, Index(), timeStamp, 0) < 0) { 814 TRACE_SEEK(" av_seek_frame() failed.\n"); 815 return B_ERROR; 816 } 817 818 // Our last packet is toast in any case. 819 av_free_packet(&fPacket); 820 fReusePacket = false; 821 822 return B_OK; 823 } 824 825 826 status_t 827 AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame, 828 bigtime_t* time) const 829 { 830 if (fContext == NULL || fStream == NULL) 831 return B_NO_INIT; 832 833 TRACE_SEEK("AVFormatReader::StreamCookie::FindKeyFrame(%ld, %s %s %s %s, " 834 "%lld, %lld)\n", VirtualIndex(), 835 (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "", 836 (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "", 837 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 838 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 839 *frame, *time); 840 841 double frameRate = FrameRate(); 842 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) 843 *time = (bigtime_t)(*frame * 1000000LL / frameRate); 844 845 int64_t timeStamp; 846 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 847 // Can use frame, because stream timeStamp is actually in frame 848 // units. 849 timeStamp = *frame; 850 } else { 851 timeStamp = *time * fStream->time_base.num 852 / ((int64_t)fStream->time_base.den * 1000000); 853 } 854 855 TRACE_SEEK(" time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 1000000.0, 856 timeStamp, fStream->time_base.num, fStream->time_base.den); 857 858 int searchFlags = AVSEEK_FLAG_BACKWARD; 859 if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) 860 searchFlags = 0; 861 862 int index = av_index_search_timestamp(fStream, timeStamp, searchFlags); 863 if (index < 0) { 864 TRACE_SEEK(" av_index_search_timestamp() failed.\n"); 865 // Just seek to the beginning of the stream and assume it is a 866 // keyframe... 867 *frame = 0; 868 *time = 0; 869 return B_OK; 870 } 871 872 const AVIndexEntry& entry = fStream->index_entries[index]; 873 timeStamp = entry.timestamp; 874 *time = (bigtime_t)(timeStamp * 1000000 * fStream->time_base.num 875 / fStream->time_base.den); 876 877 TRACE_SEEK(" seeked time: %.2fs (%lld)\n", *time / 1000000.0, timeStamp); 878 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 879 *frame = timeStamp;//*time * frameRate / 1000000LL; 880 TRACE_SEEK(" seeked frame: %lld\n", *frame); 881 } 882 883 return B_OK; 884 } 885 886 887 status_t 888 AVFormatReader::StreamCookie::GetNextChunk(const void** chunkBuffer, 889 size_t* chunkSize, media_header* mediaHeader) 890 { 891 TRACE_PACKET("AVFormatReader::StreamCookie::GetNextChunk()\n"); 892 893 // Get the last stream DTS before reading the next packet, since 894 // then it points to that one. 895 int64 lastStreamDTS = fStream->cur_dts; 896 897 status_t ret = _NextPacket(false); 898 if (ret != B_OK) { 899 *chunkBuffer = NULL; 900 *chunkSize = 0; 901 return ret; 902 } 903 904 // NOTE: AVPacket has a field called "convergence_duration", for which 905 // the documentation is quite interesting. It sounds like it could be 906 // used to know the time until the next I-Frame in streams that don't 907 // let you know the position of keyframes in another way (like through 908 // the index). 909 910 // According to libavformat documentation, fPacket is valid until the 911 // next call to av_read_frame(). This is what we want and we can share 912 // the memory with the least overhead. 913 *chunkBuffer = fPacket.data; 914 *chunkSize = fPacket.size; 915 916 if (mediaHeader != NULL) { 917 mediaHeader->type = fFormat.type; 918 mediaHeader->buffer = 0; 919 mediaHeader->destination = -1; 920 mediaHeader->time_source = -1; 921 mediaHeader->size_used = fPacket.size; 922 if (fPacket.pts != kNoPTSValue) { 923 //TRACE(" PTS: %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n", 924 //fPacket.pts, fStream->time_base.num, fStream->time_base.den, 925 //fStream->cur_dts); 926 mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts 927 * fStream->time_base.num / fStream->time_base.den); 928 } else { 929 //TRACE(" PTS (stream): %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n", 930 //lastStreamDTS, fStream->time_base.num, fStream->time_base.den, 931 //fStream->cur_dts); 932 mediaHeader->start_time = (bigtime_t)(1000000.0 * lastStreamDTS 933 * fStream->time_base.num / fStream->time_base.den); 934 } 935 mediaHeader->file_pos = fPacket.pos; 936 mediaHeader->data_offset = 0; 937 switch (mediaHeader->type) { 938 case B_MEDIA_RAW_AUDIO: 939 break; 940 case B_MEDIA_ENCODED_AUDIO: 941 mediaHeader->u.encoded_audio.buffer_flags 942 = (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 943 break; 944 case B_MEDIA_RAW_VIDEO: 945 mediaHeader->u.raw_video.line_count 946 = fFormat.u.raw_video.display.line_count; 947 break; 948 case B_MEDIA_ENCODED_VIDEO: 949 mediaHeader->u.encoded_video.field_flags 950 = (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 951 mediaHeader->u.encoded_video.line_count 952 = fFormat.u.encoded_video.output.display.line_count; 953 break; 954 default: 955 break; 956 } 957 } 958 959 return B_OK; 960 } 961 962 963 // #pragma mark - 964 965 966 /*static*/ int 967 AVFormatReader::StreamCookie::_Read(void* cookie, uint8* buffer, 968 int bufferSize) 969 { 970 TRACE_IO("AVFormatReader::StreamCookie::_Read(%p, %p, %d)\n", 971 cookie, buffer, bufferSize); 972 973 StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie); 974 975 BAutolock _(stream->fStreamLock); 976 977 if (stream->fPosition != stream->fSource->Position()) { 978 off_t position 979 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 980 if (position != stream->fPosition) 981 return -1; 982 } 983 984 ssize_t read = stream->fSource->Read(buffer, bufferSize); 985 if (read > 0) 986 stream->fPosition += read; 987 988 TRACE_IO(" read: %ld\n", read); 989 return (int)read; 990 991 } 992 993 994 /*static*/ off_t 995 AVFormatReader::StreamCookie::_Seek(void* cookie, off_t offset, int whence) 996 { 997 TRACE_IO("AVFormatReader::StreamCookie::_Seek(%p, %lld, %d)\n", 998 cookie, offset, whence); 999 1000 StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie); 1001 1002 BAutolock _(stream->fStreamLock); 1003 1004 // Support for special file size retrieval API without seeking 1005 // anywhere: 1006 if (whence == AVSEEK_SIZE) { 1007 off_t size; 1008 if (stream->fSource->GetSize(&size) == B_OK) 1009 return size; 1010 return -1; 1011 } 1012 1013 // If not requested to seek to an absolute position, we need to 1014 // confirm that the stream is currently at the position that we 1015 // think it is. 1016 if (whence != SEEK_SET 1017 && stream->fPosition != stream->fSource->Position()) { 1018 off_t position 1019 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 1020 if (position != stream->fPosition) 1021 return -1; 1022 } 1023 1024 off_t position = stream->fSource->Seek(offset, whence); 1025 TRACE_IO(" position: %lld\n", position); 1026 if (position < 0) 1027 return -1; 1028 1029 stream->fPosition = position; 1030 1031 return position; 1032 } 1033 1034 1035 status_t 1036 AVFormatReader::StreamCookie::_NextPacket(bool reuse) 1037 { 1038 TRACE_PACKET("AVFormatReader::StreamCookie::_NextPacket(%d)\n", reuse); 1039 1040 if (fReusePacket) { 1041 // The last packet was marked for reuse, so we keep using it. 1042 TRACE_PACKET(" re-using last packet\n"); 1043 fReusePacket = reuse; 1044 return B_OK; 1045 } 1046 1047 av_free_packet(&fPacket); 1048 1049 while (true) { 1050 if (av_read_frame(fContext, &fPacket) < 0) { 1051 // NOTE: Even though we may get the error for a different stream, 1052 // av_read_frame() is not going to be successful from here on, so 1053 // it doesn't matter 1054 fReusePacket = false; 1055 return B_LAST_BUFFER_ERROR; 1056 } 1057 1058 if (fPacket.stream_index == Index()) 1059 break; 1060 1061 // This is a packet from another stream, ignore it. 1062 av_free_packet(&fPacket); 1063 } 1064 1065 // Mark this packet with the new reuse flag. 1066 fReusePacket = reuse; 1067 return B_OK; 1068 } 1069 1070 1071 // #pragma mark - AVFormatReader 1072 1073 1074 AVFormatReader::AVFormatReader() 1075 : 1076 fStreams(NULL), 1077 fStreamLock("stream lock") 1078 { 1079 TRACE("AVFormatReader::AVFormatReader\n"); 1080 } 1081 1082 1083 AVFormatReader::~AVFormatReader() 1084 { 1085 TRACE("AVFormatReader::~AVFormatReader\n"); 1086 if (fStreams != NULL) { 1087 delete fStreams[0]; 1088 delete[] fStreams; 1089 } 1090 } 1091 1092 1093 // #pragma mark - 1094 1095 1096 const char* 1097 AVFormatReader::Copyright() 1098 { 1099 // TODO: Could not find the equivalent in libavformat >= version 53. 1100 // if (fStreams != NULL && fStreams[0] != NULL) 1101 // return fStreams[0]->Context()->copyright; 1102 // TODO: Return copyright of the file instead! 1103 return "Copyright 2009, Stephan Aßmus"; 1104 } 1105 1106 1107 status_t 1108 AVFormatReader::Sniff(int32* _streamCount) 1109 { 1110 TRACE("AVFormatReader::Sniff\n"); 1111 1112 BPositionIO* source = dynamic_cast<BPositionIO*>(Source()); 1113 if (source == NULL) { 1114 TRACE(" not a BPositionIO, but we need it to be one.\n"); 1115 return B_NOT_SUPPORTED; 1116 } 1117 1118 StreamCookie* stream = new(std::nothrow) StreamCookie(source, 1119 &fStreamLock); 1120 if (stream == NULL) { 1121 ERROR("AVFormatReader::Sniff() - failed to allocate StreamCookie\n"); 1122 return B_NO_MEMORY; 1123 } 1124 1125 ObjectDeleter<StreamCookie> streamDeleter(stream); 1126 1127 status_t ret = stream->Open(); 1128 if (ret != B_OK) { 1129 TRACE(" failed to detect stream: %s\n", strerror(ret)); 1130 return ret; 1131 } 1132 1133 delete[] fStreams; 1134 fStreams = NULL; 1135 1136 int32 streamCount = stream->CountStreams(); 1137 if (streamCount == 0) { 1138 TRACE(" failed to detect any streams: %s\n", strerror(ret)); 1139 return B_ERROR; 1140 } 1141 1142 fStreams = new(std::nothrow) StreamCookie*[streamCount]; 1143 if (fStreams == NULL) { 1144 ERROR("AVFormatReader::Sniff() - failed to allocate streams\n"); 1145 return B_NO_MEMORY; 1146 } 1147 1148 memset(fStreams, 0, sizeof(StreamCookie*) * streamCount); 1149 fStreams[0] = stream; 1150 streamDeleter.Detach(); 1151 1152 #ifdef TRACE_AVFORMAT_READER 1153 dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0); 1154 #endif 1155 1156 if (_streamCount != NULL) 1157 *_streamCount = streamCount; 1158 1159 return B_OK; 1160 } 1161 1162 1163 void 1164 AVFormatReader::GetFileFormatInfo(media_file_format* mff) 1165 { 1166 TRACE("AVFormatReader::GetFileFormatInfo\n"); 1167 1168 if (fStreams == NULL) 1169 return; 1170 1171 // The first cookie is always there! 1172 const AVFormatContext* context = fStreams[0]->Context(); 1173 1174 if (context == NULL || context->iformat == NULL) { 1175 TRACE(" no AVFormatContext or AVInputFormat!\n"); 1176 return; 1177 } 1178 1179 const DemuxerFormat* format = demuxer_format_for(context->iformat); 1180 1181 mff->capabilities = media_file_format::B_READABLE 1182 | media_file_format::B_KNOWS_ENCODED_VIDEO 1183 | media_file_format::B_KNOWS_ENCODED_AUDIO 1184 | media_file_format::B_IMPERFECTLY_SEEKABLE; 1185 1186 if (format != NULL) { 1187 // TODO: Check if AVInputFormat has audio only and then use 1188 // format->audio_family! 1189 mff->family = format->video_family; 1190 } else { 1191 TRACE(" no DemuxerFormat for AVInputFormat!\n"); 1192 mff->family = B_MISC_FORMAT_FAMILY; 1193 } 1194 1195 mff->version = 100; 1196 1197 if (format != NULL) { 1198 strcpy(mff->mime_type, format->mime_type); 1199 } else { 1200 // TODO: Would be nice to be able to provide this from AVInputFormat, 1201 // maybe by extending the FFmpeg code itself (all demuxers). 1202 strcpy(mff->mime_type, ""); 1203 } 1204 1205 if (context->iformat->extensions != NULL) 1206 strcpy(mff->file_extension, context->iformat->extensions); 1207 else { 1208 TRACE(" no file extensions for AVInputFormat.\n"); 1209 strcpy(mff->file_extension, ""); 1210 } 1211 1212 if (context->iformat->name != NULL) 1213 strcpy(mff->short_name, context->iformat->name); 1214 else { 1215 TRACE(" no short name for AVInputFormat.\n"); 1216 strcpy(mff->short_name, ""); 1217 } 1218 1219 if (context->iformat->long_name != NULL) 1220 strcpy(mff->pretty_name, context->iformat->long_name); 1221 else { 1222 if (format != NULL) 1223 strcpy(mff->pretty_name, format->pretty_name); 1224 else 1225 strcpy(mff->pretty_name, ""); 1226 } 1227 } 1228 1229 1230 // #pragma mark - 1231 1232 1233 status_t 1234 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie) 1235 { 1236 TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex); 1237 1238 BAutolock _(fStreamLock); 1239 1240 if (fStreams == NULL) 1241 return B_NO_INIT; 1242 1243 if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams()) 1244 return B_BAD_INDEX; 1245 1246 if (_cookie == NULL) 1247 return B_BAD_VALUE; 1248 1249 StreamCookie* cookie = fStreams[streamIndex]; 1250 if (cookie == NULL) { 1251 // Allocate the cookie 1252 BPositionIO* source = dynamic_cast<BPositionIO*>(Source()); 1253 if (source == NULL) { 1254 TRACE(" not a BPositionIO, but we need it to be one.\n"); 1255 return B_NOT_SUPPORTED; 1256 } 1257 1258 cookie = new(std::nothrow) StreamCookie(source, &fStreamLock); 1259 if (cookie == NULL) { 1260 ERROR("AVFormatReader::Sniff() - failed to allocate " 1261 "StreamCookie\n"); 1262 return B_NO_MEMORY; 1263 } 1264 1265 status_t ret = cookie->Open(); 1266 if (ret != B_OK) { 1267 TRACE(" stream failed to open: %s\n", strerror(ret)); 1268 delete cookie; 1269 return ret; 1270 } 1271 } 1272 1273 status_t ret = cookie->Init(streamIndex); 1274 if (ret != B_OK) { 1275 TRACE(" stream failed to initialize: %s\n", strerror(ret)); 1276 // NOTE: Never delete the first stream! 1277 if (streamIndex != 0) 1278 delete cookie; 1279 return ret; 1280 } 1281 1282 fStreams[streamIndex] = cookie; 1283 *_cookie = cookie; 1284 1285 return B_OK; 1286 } 1287 1288 1289 status_t 1290 AVFormatReader::FreeCookie(void *_cookie) 1291 { 1292 BAutolock _(fStreamLock); 1293 1294 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1295 1296 // NOTE: Never delete the first cookie! 1297 if (cookie != NULL && cookie->VirtualIndex() != 0) { 1298 if (fStreams != NULL) 1299 fStreams[cookie->VirtualIndex()] = NULL; 1300 delete cookie; 1301 } 1302 1303 return B_OK; 1304 } 1305 1306 1307 // #pragma mark - 1308 1309 1310 status_t 1311 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount, 1312 bigtime_t* duration, media_format* format, const void** infoBuffer, 1313 size_t* infoSize) 1314 { 1315 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1316 return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer, 1317 infoSize); 1318 } 1319 1320 1321 status_t 1322 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame, 1323 bigtime_t* time) 1324 { 1325 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1326 return cookie->Seek(seekTo, frame, time); 1327 } 1328 1329 1330 status_t 1331 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame, 1332 bigtime_t* time) 1333 { 1334 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1335 return cookie->FindKeyFrame(flags, frame, time); 1336 } 1337 1338 1339 status_t 1340 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer, 1341 size_t* chunkSize, media_header* mediaHeader) 1342 { 1343 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1344 return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader); 1345 } 1346 1347 1348