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'\n", (char*)&codecContext->codec_id); 484 485 BMediaFormats formats; 486 status_t status = formats.GetFormatFor(description, format); 487 if (status < B_OK) 488 TRACE(" formats.GetFormatFor() error: %s\n", strerror(status)); 489 490 format->user_data_type = B_CODEC_TYPE_INFO; 491 *(uint32*)format->user_data = codecTag; 492 format->user_data[4] = 0; 493 } 494 495 // format->require_flags = 0; 496 format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 497 498 switch (format->type) { 499 case B_MEDIA_RAW_AUDIO: 500 format->u.raw_audio.frame_rate = (float)codecContext->sample_rate; 501 format->u.raw_audio.channel_count = codecContext->channels; 502 format->u.raw_audio.byte_order 503 = avformat_to_beos_byte_order(codecContext->sample_fmt); 504 format->u.raw_audio.format 505 = avformat_to_beos_format(codecContext->sample_fmt); 506 format->u.raw_audio.buffer_size = 0; 507 508 // Read one packet and mark it for later re-use. (So our first 509 // GetNextChunk() call does not read another packet.) 510 if (_NextPacket(true) == B_OK) { 511 TRACE(" successfully determined audio buffer size: %d\n", 512 fPacket.size); 513 format->u.raw_audio.buffer_size = fPacket.size; 514 } 515 break; 516 517 case B_MEDIA_ENCODED_AUDIO: 518 format->u.encoded_audio.bit_rate = codecContext->bit_rate; 519 format->u.encoded_audio.frame_size = codecContext->frame_size; 520 // Fill in some info about possible output format 521 format->u.encoded_audio.output 522 = media_multi_audio_format::wildcard; 523 format->u.encoded_audio.output.frame_rate 524 = (float)codecContext->sample_rate; 525 format->u.encoded_audio.output.channel_count 526 = codecContext->channels; 527 format->u.encoded_audio.output.byte_order 528 = avformat_to_beos_byte_order(codecContext->sample_fmt); 529 format->u.encoded_audio.output.format 530 = avformat_to_beos_format(codecContext->sample_fmt); 531 if (codecContext->block_align > 0) { 532 format->u.encoded_audio.output.buffer_size 533 = codecContext->block_align; 534 } else { 535 format->u.encoded_audio.output.buffer_size 536 = codecContext->frame_size * codecContext->channels 537 * (format->u.encoded_audio.output.format 538 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 539 } 540 break; 541 542 case B_MEDIA_ENCODED_VIDEO: 543 // TODO: Specifying any of these seems to throw off the format matching 544 // later on. 545 // format->u.encoded_video.avg_bit_rate = codecContext->bit_rate; 546 // format->u.encoded_video.max_bit_rate = codecContext->bit_rate 547 // + codecContext->bit_rate_tolerance; 548 549 // format->u.encoded_video.encoding 550 // = media_encoded_video_format::B_ANY; 551 552 // format->u.encoded_video.frame_size = 1; 553 // format->u.encoded_video.forward_history = 0; 554 // format->u.encoded_video.backward_history = 0; 555 556 // TODO: Fix up for interlaced video 557 format->u.encoded_video.output.field_rate 558 = av_q2d(stream->r_frame_rate); 559 if (format->u.encoded_video.output.field_rate == 50.0f) 560 format->u.encoded_video.output.field_rate = 25.0f; 561 format->u.encoded_video.output.interlace = 1; 562 563 format->u.encoded_video.output.first_active = 0; 564 format->u.encoded_video.output.last_active 565 = codecContext->height - 1; 566 // TODO: Maybe libavformat actually provides that info 567 // somewhere... 568 format->u.encoded_video.output.orientation 569 = B_VIDEO_TOP_LEFT_RIGHT; 570 571 // Calculate the display aspect ratio 572 AVRational displayAspectRatio; 573 if (codecContext->sample_aspect_ratio.num != 0) { 574 av_reduce(&displayAspectRatio.num, &displayAspectRatio.den, 575 codecContext->width 576 * codecContext->sample_aspect_ratio.num, 577 codecContext->height 578 * codecContext->sample_aspect_ratio.den, 579 1024 * 1024); 580 TRACE(" pixel aspect ratio: %d/%d, " 581 "display aspect ratio: %d/%d\n", 582 codecContext->sample_aspect_ratio.num, 583 codecContext->sample_aspect_ratio.den, 584 displayAspectRatio.num, displayAspectRatio.den); 585 } else { 586 av_reduce(&displayAspectRatio.num, &displayAspectRatio.den, 587 codecContext->width, codecContext->height, 1024 * 1024); 588 TRACE(" no display aspect ratio (%d/%d)\n", 589 displayAspectRatio.num, displayAspectRatio.den); 590 } 591 format->u.encoded_video.output.pixel_width_aspect 592 = displayAspectRatio.num; 593 format->u.encoded_video.output.pixel_height_aspect 594 = displayAspectRatio.den; 595 596 format->u.encoded_video.output.display.format 597 = pixfmt_to_colorspace(codecContext->pix_fmt); 598 format->u.encoded_video.output.display.line_width 599 = codecContext->width; 600 format->u.encoded_video.output.display.line_count 601 = codecContext->height; 602 format->u.encoded_video.output.display.bytes_per_row = 0; 603 format->u.encoded_video.output.display.pixel_offset = 0; 604 format->u.encoded_video.output.display.line_offset = 0; 605 format->u.encoded_video.output.display.flags = 0; // TODO 606 607 break; 608 609 default: 610 // This is an unknown format to us. 611 break; 612 } 613 614 // Add the meta data, if any 615 if (codecContext->extradata_size > 0) { 616 format->SetMetaData(codecContext->extradata, 617 codecContext->extradata_size); 618 TRACE(" extradata: %p\n", format->MetaData()); 619 } 620 621 TRACE(" extradata_size: %d\n", codecContext->extradata_size); 622 TRACE(" intra_matrix: %p\n", codecContext->intra_matrix); 623 TRACE(" inter_matrix: %p\n", codecContext->inter_matrix); 624 TRACE(" get_buffer(): %p\n", codecContext->get_buffer); 625 TRACE(" release_buffer(): %p\n", codecContext->release_buffer); 626 627 #ifdef TRACE_AVFORMAT_READER 628 char formatString[512]; 629 if (string_for_format(*format, formatString, sizeof(formatString))) 630 TRACE(" format: %s\n", formatString); 631 632 uint32 encoding = format->Encoding(); 633 TRACE(" encoding '%.4s'\n", (char*)&encoding); 634 #endif 635 636 return B_OK; 637 } 638 639 640 int32 641 AVFormatReader::StreamCookie::Index() const 642 { 643 if (fStream != NULL) 644 return fStream->index; 645 return -1; 646 } 647 648 649 int32 650 AVFormatReader::StreamCookie::CountStreams() const 651 { 652 // Figure out the stream count. If the context has "AVPrograms", use 653 // the first program (for now). 654 // TODO: To support "programs" properly, the BMediaFile/Track API should 655 // be extended accordingly. I guess programs are like TV channels in the 656 // same satilite transport stream. Maybe call them "TrackGroups". 657 if (fContext->nb_programs > 0) { 658 // See libavformat/utils.c:dump_format() 659 return fContext->programs[0]->nb_stream_indexes; 660 } 661 return fContext->nb_streams; 662 } 663 664 665 int32 666 AVFormatReader::StreamCookie::StreamIndexFor(int32 virtualIndex) const 667 { 668 // NOTE: See CountStreams() 669 if (fContext->nb_programs > 0) { 670 const AVProgram* program = fContext->programs[0]; 671 if (virtualIndex >= 0 672 && virtualIndex < (int32)program->nb_stream_indexes) { 673 return program->stream_index[virtualIndex]; 674 } 675 } else { 676 if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams) 677 return virtualIndex; 678 } 679 return -1; 680 } 681 682 683 double 684 AVFormatReader::StreamCookie::FrameRate() const 685 { 686 // TODO: Find a way to always calculate a correct frame rate... 687 double frameRate; 688 switch (fStream->codec->codec_type) { 689 case CODEC_TYPE_AUDIO: 690 frameRate = (double)fStream->codec->sample_rate; 691 break; 692 case CODEC_TYPE_VIDEO: 693 frameRate = av_q2d(fStream->r_frame_rate); 694 break; 695 default: 696 frameRate = 1.0; 697 break; 698 } 699 if (frameRate <= 0.0) 700 frameRate = 1.0; 701 return frameRate; 702 } 703 704 705 status_t 706 AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount, 707 bigtime_t* duration, media_format* format, const void** infoBuffer, 708 size_t* infoSize) const 709 { 710 TRACE("AVFormatReader::StreamCookie::GetStreamInfo(%ld)\n", 711 VirtualIndex()); 712 713 double frameRate = FrameRate(); 714 TRACE(" frameRate: %.4f\n", frameRate); 715 716 // TODO: This is obviously not working correctly for all stream types... 717 // It seems that the calculations here are correct, because they work 718 // for a couple of streams and are in line with the documentation, but 719 // unfortunately, libavformat itself seems to set the time_base and 720 // duration wrongly sometimes. :-( 721 if ((int64)fStream->duration != kNoPTSValue) { 722 *duration = (bigtime_t)(1000000LL * fStream->duration 723 * fStream->time_base.num / fStream->time_base.den); 724 TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n", 725 fStream->duration, av_q2d(fStream->time_base), 726 fStream->time_base.num, fStream->time_base.den); 727 } else if ((int64)fContext->duration != kNoPTSValue) { 728 *duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE); 729 TRACE(" stream duration: %lld (from AVFormatContext)\n", 730 *duration); 731 } else { 732 *duration = 0; 733 TRACE(" stream duration: N/A\n"); 734 } 735 736 TRACE(" duration: %lld or %.2fs\n", *duration, *duration / 1000000.0); 737 738 *frameCount = fStream->nb_frames; 739 if (*frameCount == 0) { 740 // Calculate from duration and frame rate 741 *frameCount = (int64)(*duration * frameRate / 1000000LL); 742 TRACE(" frameCount (calculated): %lld\n", *frameCount); 743 } else 744 TRACE(" frameCount: %lld\n", *frameCount); 745 746 *format = fFormat; 747 748 *infoBuffer = fStream->codec->extradata; 749 *infoSize = fStream->codec->extradata_size; 750 751 return B_OK; 752 } 753 754 755 status_t 756 AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame, 757 bigtime_t* time) 758 { 759 if (fContext == NULL || fStream == NULL) 760 return B_NO_INIT; 761 762 if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) { 763 TRACE_SEEK("AVFormatReader::StreamCookie::Seek() - " 764 "B_MEDIA_SEEK_CLOSEST_FORWARD not supported.\n"); 765 return B_NOT_SUPPORTED; 766 } 767 768 TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, " 769 "%lld)\n", VirtualIndex(), 770 (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "", 771 (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "", 772 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 773 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 774 *frame, *time); 775 776 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) 777 *time = (bigtime_t)(*frame * 1000000LL / FrameRate()); 778 779 #if 0 780 // This happens in ffplay.c: 781 782 int64_t pos = get_master_clock(cur_stream); 783 // The master clock seems to be the current system time 784 // with an offset for the current PTS value of the respective 785 // stream. 786 pos += incr; 787 // depends on the seek direction... 788 789 pos = (int64_t)(pos * AV_TIME_BASE); 790 uint32_t seekFlags = incr < 0 ? AVSEEK_FLAG_BACKWARD : 0; 791 792 pos = av_rescale_q(pos, AV_TIME_BASE_Q, fStream->time_base); 793 794 ret = av_seek_frame(fContext, Index(), pos, seekFlags); 795 #endif 796 797 798 int64_t timeStamp; 799 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 800 // Can use frame, because stream timeStamp is actually in frame 801 // units. 802 timeStamp = *frame; 803 } else { 804 timeStamp = *time * fStream->time_base.num 805 / ((int64_t)fStream->time_base.den * 1000000); 806 } 807 808 TRACE_SEEK(" time: %.5fs -> %lld, current DTS: %lld (time_base: %d/%d)\n", 809 *time / 1000000.0, timeStamp, fStream->cur_dts, fStream->time_base.num, 810 fStream->time_base.den); 811 812 if (av_seek_frame(fContext, Index(), timeStamp, 0) < 0) { 813 TRACE_SEEK(" av_seek_frame() failed.\n"); 814 return B_ERROR; 815 } 816 817 // Our last packet is toast in any case. 818 av_free_packet(&fPacket); 819 fReusePacket = false; 820 821 return B_OK; 822 } 823 824 825 status_t 826 AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame, 827 bigtime_t* time) const 828 { 829 if (fContext == NULL || fStream == NULL) 830 return B_NO_INIT; 831 832 TRACE_SEEK("AVFormatReader::StreamCookie::FindKeyFrame(%ld, %s %s %s %s, " 833 "%lld, %lld)\n", VirtualIndex(), 834 (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "", 835 (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "", 836 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? "B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 837 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 838 *frame, *time); 839 840 double frameRate = FrameRate(); 841 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) 842 *time = (bigtime_t)(*frame * 1000000LL / frameRate); 843 844 int64_t timeStamp; 845 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 846 // Can use frame, because stream timeStamp is actually in frame 847 // units. 848 timeStamp = *frame; 849 } else { 850 timeStamp = *time * fStream->time_base.num 851 / ((int64_t)fStream->time_base.den * 1000000); 852 } 853 854 TRACE_SEEK(" time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 1000000.0, 855 timeStamp, fStream->time_base.num, fStream->time_base.den); 856 857 int searchFlags = AVSEEK_FLAG_BACKWARD; 858 if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) 859 searchFlags = 0; 860 861 int index = av_index_search_timestamp(fStream, timeStamp, searchFlags); 862 if (index < 0) { 863 TRACE_SEEK(" av_index_search_timestamp() failed.\n"); 864 // Just seek to the beginning of the stream and assume it is a 865 // keyframe... 866 *frame = 0; 867 *time = 0; 868 return B_OK; 869 } 870 871 const AVIndexEntry& entry = fStream->index_entries[index]; 872 timeStamp = entry.timestamp; 873 *time = (bigtime_t)(timeStamp * 1000000 * fStream->time_base.num 874 / fStream->time_base.den); 875 876 TRACE_SEEK(" seeked time: %.2fs (%lld)\n", *time / 1000000.0, timeStamp); 877 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 878 *frame = timeStamp;//*time * frameRate / 1000000LL; 879 TRACE_SEEK(" seeked frame: %lld\n", *frame); 880 } 881 882 return B_OK; 883 } 884 885 886 status_t 887 AVFormatReader::StreamCookie::GetNextChunk(const void** chunkBuffer, 888 size_t* chunkSize, media_header* mediaHeader) 889 { 890 TRACE_PACKET("AVFormatReader::StreamCookie::GetNextChunk()\n"); 891 892 // Get the last stream DTS before reading the next packet, since 893 // then it points to that one. 894 int64 lastStreamDTS = fStream->cur_dts; 895 896 status_t ret = _NextPacket(false); 897 if (ret != B_OK) { 898 *chunkBuffer = NULL; 899 *chunkSize = 0; 900 return ret; 901 } 902 903 // NOTE: AVPacket has a field called "convergence_duration", for which 904 // the documentation is quite interesting. It sounds like it could be 905 // used to know the time until the next I-Frame in streams that don't 906 // let you know the position of keyframes in another way (like through 907 // the index). 908 909 // According to libavformat documentation, fPacket is valid until the 910 // next call to av_read_frame(). This is what we want and we can share 911 // the memory with the least overhead. 912 *chunkBuffer = fPacket.data; 913 *chunkSize = fPacket.size; 914 915 if (mediaHeader != NULL) { 916 mediaHeader->type = fFormat.type; 917 mediaHeader->buffer = 0; 918 mediaHeader->destination = -1; 919 mediaHeader->time_source = -1; 920 mediaHeader->size_used = fPacket.size; 921 if (fPacket.pts != kNoPTSValue) { 922 //TRACE(" PTS: %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n", 923 //fPacket.pts, fStream->time_base.num, fStream->time_base.den, 924 //fStream->cur_dts); 925 mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts 926 * fStream->time_base.num / fStream->time_base.den); 927 } else { 928 //TRACE(" PTS (stream): %lld (time_base.num: %d, .den: %d), stream DTS: %lld\n", 929 //lastStreamDTS, fStream->time_base.num, fStream->time_base.den, 930 //fStream->cur_dts); 931 mediaHeader->start_time = (bigtime_t)(1000000.0 * lastStreamDTS 932 * fStream->time_base.num / fStream->time_base.den); 933 } 934 mediaHeader->file_pos = fPacket.pos; 935 mediaHeader->data_offset = 0; 936 switch (mediaHeader->type) { 937 case B_MEDIA_RAW_AUDIO: 938 break; 939 case B_MEDIA_ENCODED_AUDIO: 940 mediaHeader->u.encoded_audio.buffer_flags 941 = (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 942 break; 943 case B_MEDIA_RAW_VIDEO: 944 mediaHeader->u.raw_video.line_count 945 = fFormat.u.raw_video.display.line_count; 946 break; 947 case B_MEDIA_ENCODED_VIDEO: 948 mediaHeader->u.encoded_video.field_flags 949 = (fPacket.flags & PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 950 mediaHeader->u.encoded_video.line_count 951 = fFormat.u.encoded_video.output.display.line_count; 952 break; 953 default: 954 break; 955 } 956 } 957 958 return B_OK; 959 } 960 961 962 // #pragma mark - 963 964 965 /*static*/ int 966 AVFormatReader::StreamCookie::_Read(void* cookie, uint8* buffer, 967 int bufferSize) 968 { 969 TRACE_IO("AVFormatReader::StreamCookie::_Read(%p, %p, %d)\n", 970 cookie, buffer, bufferSize); 971 972 StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie); 973 974 BAutolock _(stream->fStreamLock); 975 976 if (stream->fPosition != stream->fSource->Position()) { 977 off_t position 978 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 979 if (position != stream->fPosition) 980 return -1; 981 } 982 983 ssize_t read = stream->fSource->Read(buffer, bufferSize); 984 if (read > 0) 985 stream->fPosition += read; 986 987 TRACE_IO(" read: %ld\n", read); 988 return (int)read; 989 990 } 991 992 993 /*static*/ off_t 994 AVFormatReader::StreamCookie::_Seek(void* cookie, off_t offset, int whence) 995 { 996 TRACE_IO("AVFormatReader::StreamCookie::_Seek(%p, %lld, %d)\n", 997 cookie, offset, whence); 998 999 StreamCookie* stream = reinterpret_cast<StreamCookie*>(cookie); 1000 1001 BAutolock _(stream->fStreamLock); 1002 1003 // Support for special file size retrieval API without seeking 1004 // anywhere: 1005 if (whence == AVSEEK_SIZE) { 1006 off_t size; 1007 if (stream->fSource->GetSize(&size) == B_OK) 1008 return size; 1009 return -1; 1010 } 1011 1012 // If not requested to seek to an absolute position, we need to 1013 // confirm that the stream is currently at the position that we 1014 // think it is. 1015 if (whence != SEEK_SET 1016 && stream->fPosition != stream->fSource->Position()) { 1017 off_t position 1018 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 1019 if (position != stream->fPosition) 1020 return -1; 1021 } 1022 1023 off_t position = stream->fSource->Seek(offset, whence); 1024 TRACE_IO(" position: %lld\n", position); 1025 if (position < 0) 1026 return -1; 1027 1028 stream->fPosition = position; 1029 1030 return position; 1031 } 1032 1033 1034 status_t 1035 AVFormatReader::StreamCookie::_NextPacket(bool reuse) 1036 { 1037 TRACE_PACKET("AVFormatReader::StreamCookie::_NextPacket(%d)\n", reuse); 1038 1039 if (fReusePacket) { 1040 // The last packet was marked for reuse, so we keep using it. 1041 TRACE_PACKET(" re-using last packet\n"); 1042 fReusePacket = reuse; 1043 return B_OK; 1044 } 1045 1046 av_free_packet(&fPacket); 1047 1048 while (true) { 1049 if (av_read_frame(fContext, &fPacket) < 0) { 1050 // NOTE: Even though we may get the error for a different stream, 1051 // av_read_frame() is not going to be successful from here on, so 1052 // it doesn't matter 1053 fReusePacket = false; 1054 return B_LAST_BUFFER_ERROR; 1055 } 1056 1057 if (fPacket.stream_index == Index()) 1058 break; 1059 1060 // This is a packet from another stream, ignore it. 1061 av_free_packet(&fPacket); 1062 } 1063 1064 // Mark this packet with the new reuse flag. 1065 fReusePacket = reuse; 1066 return B_OK; 1067 } 1068 1069 1070 // #pragma mark - AVFormatReader 1071 1072 1073 AVFormatReader::AVFormatReader() 1074 : 1075 fStreams(NULL), 1076 fStreamLock("stream lock") 1077 { 1078 TRACE("AVFormatReader::AVFormatReader\n"); 1079 } 1080 1081 1082 AVFormatReader::~AVFormatReader() 1083 { 1084 TRACE("AVFormatReader::~AVFormatReader\n"); 1085 if (fStreams != NULL) { 1086 delete fStreams[0]; 1087 delete[] fStreams; 1088 } 1089 } 1090 1091 1092 // #pragma mark - 1093 1094 1095 const char* 1096 AVFormatReader::Copyright() 1097 { 1098 // TODO: Could not find the equivalent in libavformat >= version 53. 1099 // if (fStreams != NULL && fStreams[0] != NULL) 1100 // return fStreams[0]->Context()->copyright; 1101 // TODO: Return copyright of the file instead! 1102 return "Copyright 2009, Stephan Aßmus"; 1103 } 1104 1105 1106 status_t 1107 AVFormatReader::Sniff(int32* _streamCount) 1108 { 1109 TRACE("AVFormatReader::Sniff\n"); 1110 1111 BPositionIO* source = dynamic_cast<BPositionIO*>(Source()); 1112 if (source == NULL) { 1113 TRACE(" not a BPositionIO, but we need it to be one.\n"); 1114 return B_NOT_SUPPORTED; 1115 } 1116 1117 StreamCookie* stream = new(std::nothrow) StreamCookie(source, 1118 &fStreamLock); 1119 if (stream == NULL) { 1120 ERROR("AVFormatReader::Sniff() - failed to allocate StreamCookie\n"); 1121 return B_NO_MEMORY; 1122 } 1123 1124 ObjectDeleter<StreamCookie> streamDeleter(stream); 1125 1126 status_t ret = stream->Open(); 1127 if (ret != B_OK) { 1128 TRACE(" failed to detect stream: %s\n", strerror(ret)); 1129 return ret; 1130 } 1131 1132 delete[] fStreams; 1133 fStreams = NULL; 1134 1135 int32 streamCount = stream->CountStreams(); 1136 if (streamCount == 0) { 1137 TRACE(" failed to detect any streams: %s\n", strerror(ret)); 1138 return B_ERROR; 1139 } 1140 1141 fStreams = new(std::nothrow) StreamCookie*[streamCount]; 1142 if (fStreams == NULL) { 1143 ERROR("AVFormatReader::Sniff() - failed to allocate streams\n"); 1144 return B_NO_MEMORY; 1145 } 1146 1147 memset(fStreams, 0, sizeof(StreamCookie*) * streamCount); 1148 fStreams[0] = stream; 1149 streamDeleter.Detach(); 1150 1151 #ifdef TRACE_AVFORMAT_READER 1152 dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0); 1153 #endif 1154 1155 if (_streamCount != NULL) 1156 *_streamCount = streamCount; 1157 1158 return B_OK; 1159 } 1160 1161 1162 void 1163 AVFormatReader::GetFileFormatInfo(media_file_format* mff) 1164 { 1165 TRACE("AVFormatReader::GetFileFormatInfo\n"); 1166 1167 if (fStreams == NULL) 1168 return; 1169 1170 // The first cookie is always there! 1171 const AVFormatContext* context = fStreams[0]->Context(); 1172 1173 if (context == NULL || context->iformat == NULL) { 1174 TRACE(" no AVFormatContext or AVInputFormat!\n"); 1175 return; 1176 } 1177 1178 const DemuxerFormat* format = demuxer_format_for(context->iformat); 1179 1180 mff->capabilities = media_file_format::B_READABLE 1181 | media_file_format::B_KNOWS_ENCODED_VIDEO 1182 | media_file_format::B_KNOWS_ENCODED_AUDIO 1183 | media_file_format::B_IMPERFECTLY_SEEKABLE; 1184 1185 if (format != NULL) { 1186 // TODO: Check if AVInputFormat has audio only and then use 1187 // format->audio_family! 1188 mff->family = format->video_family; 1189 } else { 1190 TRACE(" no DemuxerFormat for AVInputFormat!\n"); 1191 mff->family = B_MISC_FORMAT_FAMILY; 1192 } 1193 1194 mff->version = 100; 1195 1196 if (format != NULL) { 1197 strcpy(mff->mime_type, format->mime_type); 1198 } else { 1199 // TODO: Would be nice to be able to provide this from AVInputFormat, 1200 // maybe by extending the FFmpeg code itself (all demuxers). 1201 strcpy(mff->mime_type, ""); 1202 } 1203 1204 if (context->iformat->extensions != NULL) 1205 strcpy(mff->file_extension, context->iformat->extensions); 1206 else { 1207 TRACE(" no file extensions for AVInputFormat.\n"); 1208 strcpy(mff->file_extension, ""); 1209 } 1210 1211 if (context->iformat->name != NULL) 1212 strcpy(mff->short_name, context->iformat->name); 1213 else { 1214 TRACE(" no short name for AVInputFormat.\n"); 1215 strcpy(mff->short_name, ""); 1216 } 1217 1218 if (context->iformat->long_name != NULL) 1219 strcpy(mff->pretty_name, context->iformat->long_name); 1220 else { 1221 if (format != NULL) 1222 strcpy(mff->pretty_name, format->pretty_name); 1223 else 1224 strcpy(mff->pretty_name, ""); 1225 } 1226 } 1227 1228 1229 // #pragma mark - 1230 1231 1232 status_t 1233 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie) 1234 { 1235 TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex); 1236 1237 BAutolock _(fStreamLock); 1238 1239 if (fStreams == NULL) 1240 return B_NO_INIT; 1241 1242 if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams()) 1243 return B_BAD_INDEX; 1244 1245 if (_cookie == NULL) 1246 return B_BAD_VALUE; 1247 1248 StreamCookie* cookie = fStreams[streamIndex]; 1249 if (cookie == NULL) { 1250 // Allocate the cookie 1251 BPositionIO* source = dynamic_cast<BPositionIO*>(Source()); 1252 if (source == NULL) { 1253 TRACE(" not a BPositionIO, but we need it to be one.\n"); 1254 return B_NOT_SUPPORTED; 1255 } 1256 1257 cookie = new(std::nothrow) StreamCookie(source, &fStreamLock); 1258 if (cookie == NULL) { 1259 ERROR("AVFormatReader::Sniff() - failed to allocate " 1260 "StreamCookie\n"); 1261 return B_NO_MEMORY; 1262 } 1263 1264 status_t ret = cookie->Open(); 1265 if (ret != B_OK) { 1266 TRACE(" stream failed to open: %s\n", strerror(ret)); 1267 delete cookie; 1268 return ret; 1269 } 1270 } 1271 1272 status_t ret = cookie->Init(streamIndex); 1273 if (ret != B_OK) { 1274 TRACE(" stream failed to initialize: %s\n", strerror(ret)); 1275 // NOTE: Never delete the first stream! 1276 if (streamIndex != 0) 1277 delete cookie; 1278 return ret; 1279 } 1280 1281 fStreams[streamIndex] = cookie; 1282 *_cookie = cookie; 1283 1284 return B_OK; 1285 } 1286 1287 1288 status_t 1289 AVFormatReader::FreeCookie(void *_cookie) 1290 { 1291 BAutolock _(fStreamLock); 1292 1293 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1294 1295 // NOTE: Never delete the first cookie! 1296 if (cookie != NULL && cookie->VirtualIndex() != 0) { 1297 if (fStreams != NULL) 1298 fStreams[cookie->VirtualIndex()] = NULL; 1299 delete cookie; 1300 } 1301 1302 return B_OK; 1303 } 1304 1305 1306 // #pragma mark - 1307 1308 1309 status_t 1310 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount, 1311 bigtime_t* duration, media_format* format, const void** infoBuffer, 1312 size_t* infoSize) 1313 { 1314 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1315 return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer, 1316 infoSize); 1317 } 1318 1319 1320 status_t 1321 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame, 1322 bigtime_t* time) 1323 { 1324 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1325 return cookie->Seek(seekTo, frame, time); 1326 } 1327 1328 1329 status_t 1330 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame, 1331 bigtime_t* time) 1332 { 1333 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1334 return cookie->FindKeyFrame(flags, frame, time); 1335 } 1336 1337 1338 status_t 1339 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer, 1340 size_t* chunkSize, media_header* mediaHeader) 1341 { 1342 StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie); 1343 return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader); 1344 } 1345 1346 1347