1 /* 2 * Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de> 3 * Copyright 2014, Colin Günther <coling@gmx.de> 4 * Copyright 2018, Dario Casalinuovo 5 * All rights reserved. Distributed under the terms of the GNU L-GPL license. 6 */ 7 8 #include "AVFormatReader.h" 9 10 #include <stdio.h> 11 #include <string.h> 12 #include <stdlib.h> 13 14 #include <new> 15 16 #include <AutoDeleter.h> 17 #include <Autolock.h> 18 #include <ByteOrder.h> 19 #include <MediaIO.h> 20 #include <MediaDefs.h> 21 #include <MediaFormats.h> 22 #include <MimeType.h> 23 24 extern "C" { 25 #include "avcodec.h" 26 #include "avformat.h" 27 } 28 29 #include "DemuxerTable.h" 30 #include "gfx_util.h" 31 #include "Utilities.h" 32 33 34 //#define TRACE_AVFORMAT_READER 35 #ifdef TRACE_AVFORMAT_READER 36 # define TRACE printf 37 # define TRACE_IO(a...) 38 # define TRACE_SEEK(a...) printf(a) 39 # define TRACE_FIND(a...) 40 # define TRACE_PACKET(a...) 41 #else 42 # define TRACE(a...) 43 # define TRACE_IO(a...) 44 # define TRACE_SEEK(a...) 45 # define TRACE_FIND(a...) 46 # define TRACE_PACKET(a...) 47 #endif 48 49 #define ERROR(a...) fprintf(stderr, a) 50 51 52 static uint32 53 avformat_to_beos_byte_order(AVSampleFormat format) 54 { 55 // TODO: Huh? 56 return B_MEDIA_HOST_ENDIAN; 57 } 58 59 60 static void 61 avdictionary_to_message(AVDictionary* dictionary, BMessage* message) 62 { 63 if (dictionary == NULL) 64 return; 65 66 AVDictionaryEntry* entry = NULL; 67 while ((entry = av_dict_get(dictionary, "", entry, 68 AV_DICT_IGNORE_SUFFIX))) { 69 // convert entry keys into something more meaningful using the names from 70 // id3v2.c 71 if (strcmp(entry->key, "TALB") == 0 || strcmp(entry->key, "TAL") == 0) 72 message->AddString("album", entry->value); 73 else if (strcmp(entry->key, "TCOM") == 0) 74 message->AddString("composer", entry->value); 75 else if (strcmp(entry->key, "TCON") == 0 || strcmp(entry->key, "TCO") == 0) 76 message->AddString("genre", entry->value); 77 else if (strcmp(entry->key, "TCOP") == 0) 78 message->AddString("copyright", entry->value); 79 else if (strcmp(entry->key, "TDRL") == 0 || strcmp(entry->key, "TDRC") == 0) 80 message->AddString("date", entry->value); 81 else if (strcmp(entry->key, "TENC") == 0 || strcmp(entry->key, "TEN") == 0) 82 message->AddString("encoded_by", entry->value); 83 else if (strcmp(entry->key, "TIT2") == 0 || strcmp(entry->key, "TT2") == 0) 84 message->AddString("title", entry->value); 85 else if (strcmp(entry->key, "TLAN") == 0) 86 message->AddString("language", entry->value); 87 else if (strcmp(entry->key, "TPE1") == 0 || strcmp(entry->key, "TP1") == 0) 88 message->AddString("artist", entry->value); 89 else if (strcmp(entry->key, "TPE2") == 0 || strcmp(entry->key, "TP2") == 0) 90 message->AddString("album_artist", entry->value); 91 else if (strcmp(entry->key, "TPE3") == 0 || strcmp(entry->key, "TP3") == 0) 92 message->AddString("performer", entry->value); 93 else if (strcmp(entry->key, "TPOS") == 0) 94 message->AddString("disc", entry->value); 95 else if (strcmp(entry->key, "TPUB") == 0) 96 message->AddString("publisher", entry->value); 97 else if (strcmp(entry->key, "TRCK") == 0 || strcmp(entry->key, "TRK") == 0) 98 message->AddString("track", entry->value); 99 else if (strcmp(entry->key, "TSOA") == 0) 100 message->AddString("album-sort", entry->value); 101 else if (strcmp(entry->key, "TSOP") == 0) 102 message->AddString("artist-sort", entry->value); 103 else if (strcmp(entry->key, "TSOT") == 0) 104 message->AddString("title-sort", entry->value); 105 else if (strcmp(entry->key, "TSSE") == 0) 106 message->AddString("encoder", entry->value); 107 else if (strcmp(entry->key, "TYER") == 0) 108 message->AddString("year", entry->value); 109 else 110 message->AddString(entry->key, entry->value); 111 } 112 } 113 114 115 // #pragma mark - StreamBase 116 117 118 class StreamBase { 119 public: 120 StreamBase(BMediaIO* source, 121 BLocker* sourceLock, BLocker* streamLock); 122 virtual ~StreamBase(); 123 124 // Init an indivual AVFormatContext 125 status_t Open(); 126 127 // Setup this stream to point to the AVStream at the given streamIndex. 128 virtual status_t Init(int32 streamIndex); 129 130 inline const AVFormatContext* Context() const 131 { return fContext; } 132 int32 Index() const; 133 int32 CountStreams() const; 134 int32 StreamIndexFor(int32 virtualIndex) const; 135 inline int32 VirtualIndex() const 136 { return fVirtualIndex; } 137 138 double FrameRate() const; 139 bigtime_t Duration() const; 140 141 virtual status_t Seek(uint32 flags, int64* frame, 142 bigtime_t* time); 143 144 status_t GetNextChunk(const void** chunkBuffer, 145 size_t* chunkSize, 146 media_header* mediaHeader); 147 148 protected: 149 // I/O hooks for libavformat, cookie will be a Stream instance. 150 // Since multiple StreamCookies use the same BMediaIO source, they 151 // maintain the position individually, and may need to seek the source 152 // if it does not match anymore in _Read(). 153 static int _Read(void* cookie, uint8* buffer, 154 int bufferSize); 155 static off_t _Seek(void* cookie, off_t offset, int whence); 156 157 status_t _NextPacket(bool reuse); 158 159 int64_t _ConvertToStreamTimeBase(bigtime_t time) const; 160 bigtime_t _ConvertFromStreamTimeBase(int64_t time) const; 161 162 protected: 163 BMediaIO* fSource; 164 off_t fPosition; 165 // Since different threads may read from the source, 166 // we need to protect the file position and I/O by a lock. 167 BLocker* fSourceLock; 168 169 BLocker* fStreamLock; 170 171 AVFormatContext* fContext; 172 AVStream* fStream; 173 int32 fVirtualIndex; 174 175 media_format fFormat; 176 177 AVIOContext* fIOContext; 178 179 AVPacket fPacket; 180 bool fReusePacket; 181 182 bool fSeekByBytes; 183 bool fStreamBuildsIndexWhileReading; 184 }; 185 186 187 StreamBase::StreamBase(BMediaIO* source, BLocker* sourceLock, 188 BLocker* streamLock) 189 : 190 fSource(source), 191 fPosition(0), 192 fSourceLock(sourceLock), 193 194 fStreamLock(streamLock), 195 196 fContext(NULL), 197 fStream(NULL), 198 fVirtualIndex(-1), 199 fIOContext(NULL), 200 201 fReusePacket(false), 202 203 fSeekByBytes(false), 204 fStreamBuildsIndexWhileReading(false) 205 { 206 // NOTE: Don't use streamLock here, it may not yet be initialized! 207 208 av_new_packet(&fPacket, 0); 209 memset(&fFormat, 0, sizeof(media_format)); 210 } 211 212 213 StreamBase::~StreamBase() 214 { 215 avformat_close_input(&fContext); 216 av_free_packet(&fPacket); 217 if (fIOContext != NULL) 218 av_free(fIOContext->buffer); 219 av_free(fIOContext); 220 } 221 222 223 status_t 224 StreamBase::Open() 225 { 226 BAutolock _(fStreamLock); 227 228 // Init probing data 229 size_t bufferSize = 32768; 230 uint8* buffer = static_cast<uint8*>(av_malloc(bufferSize)); 231 if (buffer == NULL) 232 return B_NO_MEMORY; 233 234 // First try to identify the file using the MIME database, as ffmpeg 235 // (especially old versions) is not very good at this and relies on us 236 // to give it the file extension as an hint. 237 // For this we need some valid data in the buffer, the first 512 bytes 238 // should do because our MIME sniffing never uses more. 239 const char* extension = NULL; 240 BMessage message; 241 if (fSource->Read(buffer, 512) == 512) { 242 BMimeType type; 243 if (BMimeType::GuessMimeType(buffer, 512, &type) == B_OK) { 244 if (type.GetFileExtensions(&message) == B_OK) { 245 extension = message.FindString("extensions"); 246 } 247 } 248 } 249 250 // If the format is not identified, try Amiga MOD-files, because these do 251 // not currently have a sniffing rule. 252 if (extension == NULL) 253 extension = ".mod"; 254 255 // Allocate I/O context with buffer and hook functions, pass ourself as 256 // cookie. 257 memset(buffer, 0, bufferSize); 258 fIOContext = avio_alloc_context(buffer, bufferSize, 0, this, _Read, 0, 259 _Seek); 260 if (fIOContext == NULL) { 261 TRACE("StreamBase::Open() - avio_alloc_context() failed!\n"); 262 av_free(buffer); 263 return B_ERROR; 264 } 265 266 fContext = avformat_alloc_context(); 267 fContext->pb = fIOContext; 268 269 // Allocate our context and probe the input format 270 if (avformat_open_input(&fContext, extension, NULL, NULL) < 0) { 271 TRACE("StreamBase::Open() - avformat_open_input() failed!\n"); 272 // avformat_open_input() frees the context in case of failure 273 fContext = NULL; 274 av_free(fIOContext); 275 fIOContext = NULL; 276 return B_NOT_SUPPORTED; 277 } 278 279 TRACE("StreamBase::Open() - " 280 "avformat_open_input(): %s\n", fContext->iformat->name); 281 TRACE(" flags:%s%s%s%s%s\n", 282 (fContext->iformat->flags & AVFMT_GLOBALHEADER) ? " AVFMT_GLOBALHEADER" : "", 283 (fContext->iformat->flags & AVFMT_NOTIMESTAMPS) ? " AVFMT_NOTIMESTAMPS" : "", 284 (fContext->iformat->flags & AVFMT_GENERIC_INDEX) ? " AVFMT_GENERIC_INDEX" : "", 285 (fContext->iformat->flags & AVFMT_TS_DISCONT) ? " AVFMT_TS_DISCONT" : "", 286 (fContext->iformat->flags & AVFMT_VARIABLE_FPS) ? " AVFMT_VARIABLE_FPS" : "" 287 ); 288 289 290 // Retrieve stream information 291 if (avformat_find_stream_info(fContext, NULL) < 0) { 292 TRACE("StreamBase::Open() - avformat_find_stream_info() failed!\n"); 293 return B_NOT_SUPPORTED; 294 } 295 296 fSeekByBytes = (fContext->iformat->flags & AVFMT_TS_DISCONT) != 0; 297 fStreamBuildsIndexWhileReading 298 = (fContext->iformat->flags & AVFMT_GENERIC_INDEX) != 0 299 || fSeekByBytes; 300 301 TRACE("StreamBase::Open() - " 302 "av_find_stream_info() success! Seeking by bytes: %d\n", 303 fSeekByBytes); 304 305 return B_OK; 306 } 307 308 309 status_t 310 StreamBase::Init(int32 virtualIndex) 311 { 312 BAutolock _(fStreamLock); 313 314 TRACE("StreamBase::Init(%ld)\n", virtualIndex); 315 316 if (fContext == NULL) 317 return B_NO_INIT; 318 319 int32 streamIndex = StreamIndexFor(virtualIndex); 320 if (streamIndex < 0) { 321 TRACE(" bad stream index!\n"); 322 return B_BAD_INDEX; 323 } 324 325 TRACE(" context stream index: %ld\n", streamIndex); 326 327 // We need to remember the virtual index so that 328 // AVFormatReader::FreeCookie() can clear the correct stream entry. 329 fVirtualIndex = virtualIndex; 330 331 // Make us point to the AVStream at streamIndex 332 fStream = fContext->streams[streamIndex]; 333 334 // NOTE: Discarding other streams works for most, but not all containers, 335 // for example it does not work for the ASF demuxer. Since I don't know what 336 // other demuxer it breaks, let's just keep reading packets for unwanted 337 // streams, it just makes the _GetNextPacket() function slightly less 338 // efficient. 339 // // Discard all other streams 340 // for (unsigned i = 0; i < fContext->nb_streams; i++) { 341 // if (i != (unsigned)streamIndex) 342 // fContext->streams[i]->discard = AVDISCARD_ALL; 343 // } 344 345 return B_OK; 346 } 347 348 349 int32 350 StreamBase::Index() const 351 { 352 if (fStream != NULL) 353 return fStream->index; 354 return -1; 355 } 356 357 358 int32 359 StreamBase::CountStreams() const 360 { 361 // Figure out the stream count. If the context has "AVPrograms", use 362 // the first program (for now). 363 // TODO: To support "programs" properly, the BMediaFile/Track API should 364 // be extended accordingly. I guess programs are like TV channels in the 365 // same satilite transport stream. Maybe call them "TrackGroups". 366 if (fContext->nb_programs > 0) { 367 // See libavformat/utils.c:dump_format() 368 return fContext->programs[0]->nb_stream_indexes; 369 } 370 return fContext->nb_streams; 371 } 372 373 374 int32 375 StreamBase::StreamIndexFor(int32 virtualIndex) const 376 { 377 // NOTE: See CountStreams() 378 if (fContext->nb_programs > 0) { 379 const AVProgram* program = fContext->programs[0]; 380 if (virtualIndex >= 0 381 && virtualIndex < (int32)program->nb_stream_indexes) { 382 return program->stream_index[virtualIndex]; 383 } 384 } else { 385 if (virtualIndex >= 0 && virtualIndex < (int32)fContext->nb_streams) 386 return virtualIndex; 387 } 388 return -1; 389 } 390 391 392 double 393 StreamBase::FrameRate() const 394 { 395 // TODO: Find a way to always calculate a correct frame rate... 396 double frameRate = 1.0; 397 switch (fStream->codecpar->codec_type) { 398 case AVMEDIA_TYPE_AUDIO: 399 frameRate = (double)fStream->codecpar->sample_rate; 400 break; 401 case AVMEDIA_TYPE_VIDEO: 402 if (fStream->avg_frame_rate.den && fStream->avg_frame_rate.num) 403 frameRate = av_q2d(fStream->avg_frame_rate); 404 else if (fStream->r_frame_rate.den && fStream->r_frame_rate.num) 405 frameRate = av_q2d(fStream->r_frame_rate); 406 else if (fStream->time_base.den && fStream->time_base.num) 407 frameRate = 1 / av_q2d(fStream->time_base); 408 409 // TODO: Fix up interlaced video for real 410 if (frameRate == 50.0f) 411 frameRate = 25.0f; 412 break; 413 default: 414 break; 415 } 416 if (frameRate <= 0.0) 417 frameRate = 1.0; 418 return frameRate; 419 } 420 421 422 bigtime_t 423 StreamBase::Duration() const 424 { 425 // TODO: This is not working correctly for all stream types... 426 // It seems that the calculations here are correct, because they work 427 // for a couple of streams and are in line with the documentation, but 428 // unfortunately, libavformat itself seems to set the time_base and 429 // duration wrongly sometimes. :-( 430 431 int32 flags; 432 fSource->GetFlags(&flags); 433 434 // "Mutable Size" (ie http streams) means we can't realistically compute 435 // a duration. So don't let ffmpeg giva (wrong) estimate in this case. 436 if ((flags & B_MEDIA_MUTABLE_SIZE) != 0) 437 return 0; 438 439 if ((int64)fStream->duration != AV_NOPTS_VALUE) 440 return _ConvertFromStreamTimeBase(fStream->duration); 441 else if ((int64)fContext->duration != AV_NOPTS_VALUE) 442 return (bigtime_t)fContext->duration; 443 444 return 0; 445 } 446 447 448 status_t 449 StreamBase::Seek(uint32 flags, int64* frame, bigtime_t* time) 450 { 451 BAutolock _(fStreamLock); 452 453 if (fContext == NULL || fStream == NULL) 454 return B_NO_INIT; 455 456 TRACE_SEEK("StreamBase::Seek(%ld,%s%s%s%s, %lld, " 457 "%lld)\n", VirtualIndex(), 458 (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "", 459 (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "", 460 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) 461 ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 462 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) 463 ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 464 *frame, *time); 465 466 double frameRate = FrameRate(); 467 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 468 // Seeking is always based on time, initialize it when client seeks 469 // based on frame. 470 *time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5); 471 } 472 473 int64_t timeStamp = *time; 474 475 int searchFlags = AVSEEK_FLAG_BACKWARD; 476 if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) 477 searchFlags = 0; 478 479 if (fSeekByBytes) { 480 searchFlags |= AVSEEK_FLAG_BYTE; 481 482 BAutolock _(fSourceLock); 483 int64_t fileSize; 484 485 if (fSource->GetSize(&fileSize) != B_OK) 486 return B_NOT_SUPPORTED; 487 488 int64_t duration = Duration(); 489 if (duration == 0) 490 return B_NOT_SUPPORTED; 491 492 timeStamp = int64_t(fileSize * ((double)timeStamp / duration)); 493 if ((flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) != 0) { 494 timeStamp -= 65536; 495 if (timeStamp < 0) 496 timeStamp = 0; 497 } 498 499 bool seekAgain = true; 500 bool seekForward = true; 501 bigtime_t lastFoundTime = -1; 502 int64_t closestTimeStampBackwards = -1; 503 while (seekAgain) { 504 if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp, 505 INT64_MAX, searchFlags) < 0) { 506 TRACE(" avformat_seek_file() (by bytes) failed.\n"); 507 return B_ERROR; 508 } 509 seekAgain = false; 510 511 // Our last packet is toast in any case. Read the next one so we 512 // know where we really seeked. 513 fReusePacket = false; 514 if (_NextPacket(true) == B_OK) { 515 while (fPacket.pts == AV_NOPTS_VALUE) { 516 fReusePacket = false; 517 if (_NextPacket(true) != B_OK) 518 return B_ERROR; 519 } 520 if (fPacket.pos >= 0) 521 timeStamp = fPacket.pos; 522 bigtime_t foundTime 523 = _ConvertFromStreamTimeBase(fPacket.pts); 524 if (foundTime != lastFoundTime) { 525 lastFoundTime = foundTime; 526 if (foundTime > *time) { 527 if (closestTimeStampBackwards >= 0) { 528 timeStamp = closestTimeStampBackwards; 529 seekAgain = true; 530 seekForward = false; 531 continue; 532 } 533 int64_t diff = int64_t(fileSize 534 * ((double)(foundTime - *time) / (2 * duration))); 535 if (diff < 8192) 536 break; 537 timeStamp -= diff; 538 TRACE_SEEK(" need to seek back (%lld) (time: %.2f " 539 "-> %.2f)\n", timeStamp, *time / 1000000.0, 540 foundTime / 1000000.0); 541 if (timeStamp < 0) 542 foundTime = 0; 543 else { 544 seekAgain = true; 545 continue; 546 } 547 } else if (seekForward && foundTime < *time - 100000) { 548 closestTimeStampBackwards = timeStamp; 549 int64_t diff = int64_t(fileSize 550 * ((double)(*time - foundTime) / (2 * duration))); 551 if (diff < 8192) 552 break; 553 timeStamp += diff; 554 TRACE_SEEK(" need to seek forward (%lld) (time: " 555 "%.2f -> %.2f)\n", timeStamp, *time / 1000000.0, 556 foundTime / 1000000.0); 557 if (timeStamp > duration) 558 foundTime = duration; 559 else { 560 seekAgain = true; 561 continue; 562 } 563 } 564 } 565 TRACE_SEEK(" found time: %lld -> %lld (%.2f)\n", *time, 566 foundTime, foundTime / 1000000.0); 567 *time = foundTime; 568 *frame = (uint64)(*time * frameRate / 1000000LL + 0.5); 569 TRACE_SEEK(" seeked frame: %lld\n", *frame); 570 } else { 571 TRACE_SEEK(" _NextPacket() failed!\n"); 572 return B_ERROR; 573 } 574 } 575 } else { 576 // We may not get a PTS from the next packet after seeking, so 577 // we try to get an expected time from the index. 578 int64_t streamTimeStamp = _ConvertToStreamTimeBase(*time); 579 int index = av_index_search_timestamp(fStream, streamTimeStamp, 580 searchFlags); 581 if (index < 0) { 582 TRACE(" av_index_search_timestamp() failed\n"); 583 } else { 584 if (index > 0) { 585 const AVIndexEntry& entry = fStream->index_entries[index]; 586 streamTimeStamp = entry.timestamp; 587 } else { 588 // Some demuxers use the first index entry to store some 589 // other information, like the total playing time for example. 590 // Assume the timeStamp of the first entry is alays 0. 591 // TODO: Handle start-time offset? 592 streamTimeStamp = 0; 593 } 594 bigtime_t foundTime = _ConvertFromStreamTimeBase(streamTimeStamp); 595 bigtime_t timeDiff = foundTime > *time 596 ? foundTime - *time : *time - foundTime; 597 598 if (timeDiff > 1000000 599 && (fStreamBuildsIndexWhileReading 600 || index == fStream->nb_index_entries - 1)) { 601 // If the stream is building the index on the fly while parsing 602 // it, we only have entries in the index for positions already 603 // decoded, i.e. we cannot seek into the future. In that case, 604 // just assume that we can seek where we want and leave 605 // time/frame unmodified. Since successfully seeking one time 606 // will generate index entries for the seeked to position, we 607 // need to remember this in fStreamBuildsIndexWhileReading, 608 // since when seeking back there will be later index entries, 609 // but we still want to ignore the found entry. 610 fStreamBuildsIndexWhileReading = true; 611 TRACE_SEEK(" Not trusting generic index entry. " 612 "(Current count: %d)\n", fStream->nb_index_entries); 613 } else { 614 // If we found a reasonably time, write it into *time. 615 // After seeking, we will try to read the sought time from 616 // the next packet. If the packet has no PTS value, we may 617 // still have a more accurate time from the index lookup. 618 *time = foundTime; 619 } 620 } 621 622 if (avformat_seek_file(fContext, -1, INT64_MIN, timeStamp, INT64_MAX, 623 searchFlags) < 0) { 624 TRACE(" avformat_seek_file() failed.\n"); 625 // Try to fall back to av_seek_frame() 626 timeStamp = _ConvertToStreamTimeBase(timeStamp); 627 if (av_seek_frame(fContext, fStream->index, timeStamp, 628 searchFlags) < 0) { 629 TRACE(" avformat_seek_frame() failed as well.\n"); 630 // Fall back to seeking to the beginning by bytes 631 timeStamp = 0; 632 if (av_seek_frame(fContext, fStream->index, timeStamp, 633 AVSEEK_FLAG_BYTE) < 0) { 634 TRACE(" avformat_seek_frame() by bytes failed as " 635 "well.\n"); 636 // Do not propagate error in any case. We fail if we can't 637 // read another packet. 638 } else 639 *time = 0; 640 } 641 } 642 643 // Our last packet is toast in any case. Read the next one so 644 // we know where we really sought. 645 bigtime_t foundTime = *time; 646 647 fReusePacket = false; 648 if (_NextPacket(true) == B_OK) { 649 if (fPacket.pts != AV_NOPTS_VALUE) 650 foundTime = _ConvertFromStreamTimeBase(fPacket.pts); 651 else 652 TRACE_SEEK(" no PTS in packet after seeking\n"); 653 } else 654 TRACE_SEEK(" _NextPacket() failed!\n"); 655 656 *time = foundTime; 657 TRACE_SEEK(" sought time: %.2fs\n", *time / 1000000.0); 658 *frame = (uint64)(*time * frameRate / 1000000.0 + 0.5); 659 TRACE_SEEK(" sought frame: %lld\n", *frame); 660 } 661 662 return B_OK; 663 } 664 665 666 status_t 667 StreamBase::GetNextChunk(const void** chunkBuffer, 668 size_t* chunkSize, media_header* mediaHeader) 669 { 670 BAutolock _(fStreamLock); 671 672 TRACE_PACKET("StreamBase::GetNextChunk()\n"); 673 674 // Get the last stream DTS before reading the next packet, since 675 // then it points to that one. 676 int64 lastStreamDTS = fStream->cur_dts; 677 678 status_t ret = _NextPacket(false); 679 if (ret != B_OK) { 680 *chunkBuffer = NULL; 681 *chunkSize = 0; 682 return ret; 683 } 684 685 // NOTE: AVPacket has a field called "convergence_duration", for which 686 // the documentation is quite interesting. It sounds like it could be 687 // used to know the time until the next I-Frame in streams that don't 688 // let you know the position of keyframes in another way (like through 689 // the index). 690 691 // According to libavformat documentation, fPacket is valid until the 692 // next call to av_read_frame(). This is what we want and we can share 693 // the memory with the least overhead. 694 *chunkBuffer = fPacket.data; 695 *chunkSize = fPacket.size; 696 697 if (mediaHeader != NULL) { 698 mediaHeader->type = fFormat.type; 699 mediaHeader->buffer = 0; 700 mediaHeader->destination = -1; 701 mediaHeader->time_source = -1; 702 mediaHeader->size_used = fPacket.size; 703 704 // FFmpeg recommends to use the decoding time stamps as primary source 705 // for presentation time stamps, especially for video formats that are 706 // using frame reordering. More over this way it is ensured that the 707 // returned start times are ordered in a monotonically increasing time 708 // series (even for videos that contain B-frames). 709 // \see http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/avformat.h;h=1e8a6294890d580cd9ebc684eaf4ce57c8413bd8;hb=9153b33a742c4e2a85ff6230aea0e75f5a8b26c2#l1623 710 bigtime_t presentationTimeStamp; 711 if (fPacket.dts != AV_NOPTS_VALUE) 712 presentationTimeStamp = fPacket.dts; 713 else if (fPacket.pts != AV_NOPTS_VALUE) 714 presentationTimeStamp = fPacket.pts; 715 else 716 presentationTimeStamp = lastStreamDTS; 717 718 mediaHeader->start_time = _ConvertFromStreamTimeBase(presentationTimeStamp); 719 mediaHeader->file_pos = fPacket.pos; 720 mediaHeader->data_offset = 0; 721 switch (mediaHeader->type) { 722 case B_MEDIA_RAW_AUDIO: 723 break; 724 case B_MEDIA_ENCODED_AUDIO: 725 mediaHeader->u.encoded_audio.buffer_flags 726 = (fPacket.flags & AV_PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 727 break; 728 case B_MEDIA_RAW_VIDEO: 729 mediaHeader->u.raw_video.line_count 730 = fFormat.u.raw_video.display.line_count; 731 break; 732 case B_MEDIA_ENCODED_VIDEO: 733 mediaHeader->u.encoded_video.field_flags 734 = (fPacket.flags & AV_PKT_FLAG_KEY) ? B_MEDIA_KEY_FRAME : 0; 735 mediaHeader->u.encoded_video.line_count 736 = fFormat.u.encoded_video.output.display.line_count; 737 break; 738 default: 739 break; 740 } 741 } 742 743 // static bigtime_t pts[2]; 744 // static bigtime_t lastPrintTime = system_time(); 745 // static BLocker printLock; 746 // if (fStream->index < 2) { 747 // if (fPacket.pts != AV_NOPTS_VALUE) 748 // pts[fStream->index] = _ConvertFromStreamTimeBase(fPacket.pts); 749 // printLock.Lock(); 750 // bigtime_t now = system_time(); 751 // if (now - lastPrintTime > 1000000) { 752 // printf("PTS: %.4f/%.4f, diff: %.4f\r", pts[0] / 1000000.0, 753 // pts[1] / 1000000.0, (pts[0] - pts[1]) / 1000000.0); 754 // fflush(stdout); 755 // lastPrintTime = now; 756 // } 757 // printLock.Unlock(); 758 // } 759 760 return B_OK; 761 } 762 763 764 // #pragma mark - 765 766 767 /*static*/ int 768 StreamBase::_Read(void* cookie, uint8* buffer, int bufferSize) 769 { 770 StreamBase* stream = reinterpret_cast<StreamBase*>(cookie); 771 772 BAutolock _(stream->fSourceLock); 773 774 TRACE_IO("StreamBase::_Read(%p, %p, %d) position: %lld\n", 775 cookie, buffer, bufferSize, stream->fPosition); 776 777 if (stream->fPosition != stream->fSource->Position()) { 778 TRACE_IO("StreamBase::_Read fSource position: %lld\n", 779 stream->fSource->Position()); 780 781 off_t position 782 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 783 if (position != stream->fPosition) 784 return -1; 785 } 786 787 ssize_t read = stream->fSource->Read(buffer, bufferSize); 788 if (read > 0) 789 stream->fPosition += read; 790 791 TRACE_IO(" read: %ld\n", read); 792 return (int)read; 793 794 } 795 796 797 /*static*/ off_t 798 StreamBase::_Seek(void* cookie, off_t offset, int whence) 799 { 800 TRACE_IO("StreamBase::_Seek(%p, %lld, %d)\n", 801 cookie, offset, whence); 802 803 StreamBase* stream = reinterpret_cast<StreamBase*>(cookie); 804 805 BAutolock _(stream->fSourceLock); 806 807 // Support for special file size retrieval API without seeking 808 // anywhere: 809 if (whence == AVSEEK_SIZE) { 810 off_t size; 811 if (stream->fSource->GetSize(&size) == B_OK) 812 return size; 813 return -1; 814 } 815 816 // If not requested to seek to an absolute position, we need to 817 // confirm that the stream is currently at the position that we 818 // think it is. 819 if (whence != SEEK_SET 820 && stream->fPosition != stream->fSource->Position()) { 821 off_t position 822 = stream->fSource->Seek(stream->fPosition, SEEK_SET); 823 if (position != stream->fPosition) 824 return -1; 825 } 826 827 off_t position = stream->fSource->Seek(offset, whence); 828 TRACE_IO(" position: %lld\n", position); 829 if (position < 0) 830 return -1; 831 832 stream->fPosition = position; 833 834 return position; 835 } 836 837 838 status_t 839 StreamBase::_NextPacket(bool reuse) 840 { 841 TRACE_PACKET("StreamBase::_NextPacket(%d)\n", reuse); 842 843 if (fReusePacket) { 844 // The last packet was marked for reuse, so we keep using it. 845 TRACE_PACKET(" re-using last packet\n"); 846 fReusePacket = reuse; 847 return B_OK; 848 } 849 850 av_free_packet(&fPacket); 851 852 while (true) { 853 if (av_read_frame(fContext, &fPacket) < 0) { 854 // NOTE: Even though we may get the error for a different stream, 855 // av_read_frame() is not going to be successful from here on, so 856 // it doesn't matter 857 fReusePacket = false; 858 return B_LAST_BUFFER_ERROR; 859 } 860 861 if (fPacket.stream_index == Index()) 862 break; 863 864 // This is a packet from another stream, ignore it. 865 av_free_packet(&fPacket); 866 } 867 868 // Mark this packet with the new reuse flag. 869 fReusePacket = reuse; 870 return B_OK; 871 } 872 873 874 int64_t 875 StreamBase::_ConvertToStreamTimeBase(bigtime_t time) const 876 { 877 int64 timeStamp = int64_t((double)time * fStream->time_base.den 878 / (1000000.0 * fStream->time_base.num) + 0.5); 879 if (fStream->start_time != AV_NOPTS_VALUE) 880 timeStamp += fStream->start_time; 881 return timeStamp; 882 } 883 884 885 bigtime_t 886 StreamBase::_ConvertFromStreamTimeBase(int64_t time) const 887 { 888 if (fStream->start_time != AV_NOPTS_VALUE) 889 time -= fStream->start_time; 890 891 return bigtime_t(1000000.0 * time * fStream->time_base.num 892 / fStream->time_base.den + 0.5); 893 } 894 895 896 // #pragma mark - AVFormatReader::Stream 897 898 899 class AVFormatReader::Stream : public StreamBase { 900 public: 901 Stream(BMediaIO* source, 902 BLocker* streamLock); 903 virtual ~Stream(); 904 905 // Setup this stream to point to the AVStream at the given streamIndex. 906 // This will also initialize the media_format. 907 virtual status_t Init(int32 streamIndex); 908 909 status_t GetMetaData(BMessage* data); 910 911 // Support for AVFormatReader 912 status_t GetStreamInfo(int64* frameCount, 913 bigtime_t* duration, media_format* format, 914 const void** infoBuffer, 915 size_t* infoSize) const; 916 917 status_t FindKeyFrame(uint32 flags, int64* frame, 918 bigtime_t* time) const; 919 virtual status_t Seek(uint32 flags, int64* frame, 920 bigtime_t* time); 921 922 private: 923 mutable BLocker fLock; 924 925 struct KeyframeInfo { 926 bigtime_t requestedTime; 927 int64 requestedFrame; 928 bigtime_t reportedTime; 929 int64 reportedFrame; 930 uint32 seekFlags; 931 }; 932 mutable KeyframeInfo fLastReportedKeyframe; 933 mutable StreamBase* fGhostStream; 934 }; 935 936 937 938 AVFormatReader::Stream::Stream(BMediaIO* source, BLocker* streamLock) 939 : 940 StreamBase(source, streamLock, &fLock), 941 fLock("stream lock"), 942 fGhostStream(NULL) 943 { 944 fLastReportedKeyframe.requestedTime = 0; 945 fLastReportedKeyframe.requestedFrame = 0; 946 fLastReportedKeyframe.reportedTime = 0; 947 fLastReportedKeyframe.reportedFrame = 0; 948 } 949 950 951 AVFormatReader::Stream::~Stream() 952 { 953 delete fGhostStream; 954 } 955 956 957 status_t 958 AVFormatReader::Stream::Init(int32 virtualIndex) 959 { 960 TRACE("AVFormatReader::Stream::Init(%ld)\n", virtualIndex); 961 962 status_t ret = StreamBase::Init(virtualIndex); 963 if (ret != B_OK) 964 return ret; 965 966 // Get a pointer to the AVCodecPaarameters for the stream at streamIndex. 967 AVCodecParameters* codecParams = fStream->codecpar; 968 969 // initialize the media_format for this stream 970 media_format* format = &fFormat; 971 memset(format, 0, sizeof(media_format)); 972 973 media_format_description description; 974 975 // Set format family and type depending on codec_type of the stream. 976 switch (codecParams->codec_type) { 977 case AVMEDIA_TYPE_AUDIO: 978 if ((codecParams->codec_id >= AV_CODEC_ID_PCM_S16LE) 979 && (codecParams->codec_id <= AV_CODEC_ID_PCM_U8)) { 980 TRACE(" raw audio\n"); 981 format->type = B_MEDIA_RAW_AUDIO; 982 description.family = B_ANY_FORMAT_FAMILY; 983 // This will then apparently be handled by the (built into 984 // BMediaTrack) RawDecoder. 985 } else { 986 TRACE(" encoded audio\n"); 987 format->type = B_MEDIA_ENCODED_AUDIO; 988 description.family = B_MISC_FORMAT_FAMILY; 989 description.u.misc.file_format = 'ffmp'; 990 } 991 break; 992 case AVMEDIA_TYPE_VIDEO: 993 TRACE(" encoded video\n"); 994 format->type = B_MEDIA_ENCODED_VIDEO; 995 description.family = B_MISC_FORMAT_FAMILY; 996 description.u.misc.file_format = 'ffmp'; 997 break; 998 default: 999 TRACE(" unknown type\n"); 1000 format->type = B_MEDIA_UNKNOWN_TYPE; 1001 return B_ERROR; 1002 break; 1003 } 1004 1005 if (format->type == B_MEDIA_RAW_AUDIO) { 1006 // We cannot describe all raw-audio formats, some are unsupported. 1007 switch (codecParams->codec_id) { 1008 case AV_CODEC_ID_PCM_S16LE: 1009 format->u.raw_audio.format 1010 = media_raw_audio_format::B_AUDIO_SHORT; 1011 format->u.raw_audio.byte_order 1012 = B_MEDIA_LITTLE_ENDIAN; 1013 break; 1014 case AV_CODEC_ID_PCM_S16BE: 1015 format->u.raw_audio.format 1016 = media_raw_audio_format::B_AUDIO_SHORT; 1017 format->u.raw_audio.byte_order 1018 = B_MEDIA_BIG_ENDIAN; 1019 break; 1020 case AV_CODEC_ID_PCM_U16LE: 1021 // format->u.raw_audio.format 1022 // = media_raw_audio_format::B_AUDIO_USHORT; 1023 // format->u.raw_audio.byte_order 1024 // = B_MEDIA_LITTLE_ENDIAN; 1025 return B_NOT_SUPPORTED; 1026 break; 1027 case AV_CODEC_ID_PCM_U16BE: 1028 // format->u.raw_audio.format 1029 // = media_raw_audio_format::B_AUDIO_USHORT; 1030 // format->u.raw_audio.byte_order 1031 // = B_MEDIA_BIG_ENDIAN; 1032 return B_NOT_SUPPORTED; 1033 break; 1034 case AV_CODEC_ID_PCM_S8: 1035 format->u.raw_audio.format 1036 = media_raw_audio_format::B_AUDIO_CHAR; 1037 break; 1038 case AV_CODEC_ID_PCM_U8: 1039 format->u.raw_audio.format 1040 = media_raw_audio_format::B_AUDIO_UCHAR; 1041 break; 1042 default: 1043 return B_NOT_SUPPORTED; 1044 break; 1045 } 1046 } else { 1047 if (description.family == B_MISC_FORMAT_FAMILY) 1048 description.u.misc.codec = codecParams->codec_id; 1049 1050 BMediaFormats formats; 1051 status_t status = formats.GetFormatFor(description, format); 1052 if (status < B_OK) 1053 TRACE(" formats.GetFormatFor() error: %s\n", strerror(status)); 1054 1055 format->user_data_type = B_CODEC_TYPE_INFO; 1056 *(uint32*)format->user_data = codecParams->codec_tag; 1057 format->user_data[4] = 0; 1058 } 1059 1060 format->require_flags = 0; 1061 format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 1062 1063 switch (format->type) { 1064 case B_MEDIA_RAW_AUDIO: 1065 format->u.raw_audio.frame_rate = (float)codecParams->sample_rate; 1066 format->u.raw_audio.channel_count = codecParams->channels; 1067 format->u.raw_audio.channel_mask = codecParams->channel_layout; 1068 ConvertAVSampleFormatToRawAudioFormat( 1069 (AVSampleFormat)codecParams->format, 1070 format->u.raw_audio.format); 1071 format->u.raw_audio.buffer_size = 0; 1072 1073 // Read one packet and mark it for later re-use. (So our first 1074 // GetNextChunk() call does not read another packet.) 1075 if (_NextPacket(true) == B_OK) { 1076 TRACE(" successfully determined audio buffer size: %d\n", 1077 fPacket.size); 1078 format->u.raw_audio.buffer_size = fPacket.size; 1079 } 1080 break; 1081 1082 case B_MEDIA_ENCODED_AUDIO: 1083 format->u.encoded_audio.bit_rate = codecParams->bit_rate; 1084 format->u.encoded_audio.frame_size = codecParams->frame_size; 1085 // Fill in some info about possible output format 1086 format->u.encoded_audio.output 1087 = media_multi_audio_format::wildcard; 1088 format->u.encoded_audio.output.frame_rate 1089 = (float)codecParams->sample_rate; 1090 // Channel layout bits match in Be API and FFmpeg. 1091 format->u.encoded_audio.output.channel_count 1092 = codecParams->channels; 1093 format->u.encoded_audio.multi_info.channel_mask 1094 = codecParams->channel_layout; 1095 format->u.encoded_audio.output.byte_order 1096 = avformat_to_beos_byte_order( 1097 (AVSampleFormat)codecParams->format); 1098 1099 ConvertAVSampleFormatToRawAudioFormat( 1100 (AVSampleFormat)codecParams->format, 1101 format->u.encoded_audio.output.format); 1102 1103 if (codecParams->block_align > 0) { 1104 format->u.encoded_audio.output.buffer_size 1105 = codecParams->block_align; 1106 } else { 1107 format->u.encoded_audio.output.buffer_size 1108 = codecParams->frame_size * codecParams->channels 1109 * (format->u.encoded_audio.output.format 1110 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 1111 } 1112 break; 1113 1114 case B_MEDIA_ENCODED_VIDEO: 1115 // TODO: Specifying any of these seems to throw off the format matching 1116 // later on. 1117 // format->u.encoded_video.avg_bit_rate = codecParams->bit_rate; 1118 // format->u.encoded_video.max_bit_rate = codecParams->bit_rate 1119 // + codecParams->bit_rate_tolerance; 1120 1121 // format->u.encoded_video.encoding 1122 // = media_encoded_video_format::B_ANY; 1123 1124 // format->u.encoded_video.frame_size = 1; 1125 // format->u.encoded_video.forward_history = 0; 1126 // format->u.encoded_video.backward_history = 0; 1127 1128 format->u.encoded_video.output.field_rate = FrameRate(); 1129 format->u.encoded_video.output.interlace = 1; 1130 1131 format->u.encoded_video.output.first_active = 0; 1132 format->u.encoded_video.output.last_active 1133 = codecParams->height - 1; 1134 // TODO: Maybe libavformat actually provides that info 1135 // somewhere... 1136 format->u.encoded_video.output.orientation 1137 = B_VIDEO_TOP_LEFT_RIGHT; 1138 1139 ConvertAVCodecParametersToVideoAspectWidthAndHeight(*codecParams, 1140 format->u.encoded_video.output.pixel_width_aspect, 1141 format->u.encoded_video.output.pixel_height_aspect); 1142 1143 format->u.encoded_video.output.display.format 1144 = pixfmt_to_colorspace(codecParams->format); 1145 format->u.encoded_video.output.display.line_width 1146 = codecParams->width; 1147 format->u.encoded_video.output.display.line_count 1148 = codecParams->height; 1149 TRACE(" width/height: %d/%d\n", codecParams->width, 1150 codecParams->height); 1151 format->u.encoded_video.output.display.bytes_per_row = 0; 1152 format->u.encoded_video.output.display.pixel_offset = 0; 1153 format->u.encoded_video.output.display.line_offset = 0; 1154 format->u.encoded_video.output.display.flags = 0; // TODO 1155 1156 break; 1157 1158 default: 1159 // This is an unknown format to us. 1160 break; 1161 } 1162 1163 // Add the meta data, if any 1164 if (codecParams->extradata_size > 0) { 1165 format->SetMetaData(codecParams->extradata, 1166 codecParams->extradata_size); 1167 TRACE(" extradata: %p\n", format->MetaData()); 1168 } 1169 1170 TRACE(" extradata_size: %d\n", codecParams->extradata_size); 1171 // TRACE(" intra_matrix: %p\n", codecParams->intra_matrix); 1172 // TRACE(" inter_matrix: %p\n", codecParams->inter_matrix); 1173 // TRACE(" get_buffer(): %p\n", codecParams->get_buffer); 1174 // TRACE(" release_buffer(): %p\n", codecParams->release_buffer); 1175 1176 #ifdef TRACE_AVFORMAT_READER 1177 char formatString[512]; 1178 if (string_for_format(*format, formatString, sizeof(formatString))) 1179 TRACE(" format: %s\n", formatString); 1180 1181 uint32 encoding = format->Encoding(); 1182 TRACE(" encoding '%.4s'\n", (char*)&encoding); 1183 #endif 1184 1185 return B_OK; 1186 } 1187 1188 1189 status_t 1190 AVFormatReader::Stream::GetMetaData(BMessage* data) 1191 { 1192 BAutolock _(&fLock); 1193 1194 avdictionary_to_message(fStream->metadata, data); 1195 1196 return B_OK; 1197 } 1198 1199 1200 status_t 1201 AVFormatReader::Stream::GetStreamInfo(int64* frameCount, 1202 bigtime_t* duration, media_format* format, const void** infoBuffer, 1203 size_t* infoSize) const 1204 { 1205 BAutolock _(&fLock); 1206 1207 TRACE("AVFormatReader::Stream::GetStreamInfo(%ld)\n", 1208 VirtualIndex()); 1209 1210 double frameRate = FrameRate(); 1211 TRACE(" frameRate: %.4f\n", frameRate); 1212 1213 #ifdef TRACE_AVFORMAT_READER 1214 if (fStream->start_time != AV_NOPTS_VALUE) { 1215 bigtime_t startTime = _ConvertFromStreamTimeBase(fStream->start_time); 1216 TRACE(" start_time: %lld or %.5fs\n", startTime, 1217 startTime / 1000000.0); 1218 // TODO: Handle start time in FindKeyFrame() and Seek()?! 1219 } 1220 #endif // TRACE_AVFORMAT_READER 1221 1222 *duration = Duration(); 1223 1224 TRACE(" duration: %lld or %.5fs\n", *duration, *duration / 1000000.0); 1225 1226 #if 0 1227 if (fStream->nb_index_entries > 0) { 1228 TRACE(" dump of index entries:\n"); 1229 int count = 5; 1230 int firstEntriesCount = min_c(fStream->nb_index_entries, count); 1231 int i = 0; 1232 for (; i < firstEntriesCount; i++) { 1233 AVIndexEntry& entry = fStream->index_entries[i]; 1234 bigtime_t timeGlobal = entry.timestamp; 1235 bigtime_t timeNative = _ConvertFromStreamTimeBase(timeGlobal); 1236 TRACE(" [%d] native: %.5fs global: %.5fs\n", i, 1237 timeNative / 1000000.0f, timeGlobal / 1000000.0f); 1238 } 1239 if (fStream->nb_index_entries - count > i) { 1240 i = fStream->nb_index_entries - count; 1241 TRACE(" ...\n"); 1242 for (; i < fStream->nb_index_entries; i++) { 1243 AVIndexEntry& entry = fStream->index_entries[i]; 1244 bigtime_t timeGlobal = entry.timestamp; 1245 bigtime_t timeNative = _ConvertFromStreamTimeBase(timeGlobal); 1246 TRACE(" [%d] native: %.5fs global: %.5fs\n", i, 1247 timeNative / 1000000.0f, timeGlobal / 1000000.0f); 1248 } 1249 } 1250 } 1251 #endif 1252 1253 *frameCount = fStream->nb_frames * fStream->codecpar->frame_size; 1254 if (*frameCount == 0) { 1255 // Calculate from duration and frame rate 1256 *frameCount = (int64)(*duration * frameRate / 1000000LL); 1257 TRACE(" frameCount calculated: %lld, from context: %lld\n", 1258 *frameCount, fStream->nb_frames); 1259 } else 1260 TRACE(" frameCount: %lld\n", *frameCount); 1261 1262 *format = fFormat; 1263 1264 *infoBuffer = fStream->codecpar->extradata; 1265 *infoSize = fStream->codecpar->extradata_size; 1266 1267 return B_OK; 1268 } 1269 1270 1271 status_t 1272 AVFormatReader::Stream::FindKeyFrame(uint32 flags, int64* frame, 1273 bigtime_t* time) const 1274 { 1275 BAutolock _(&fLock); 1276 1277 if (fContext == NULL || fStream == NULL) 1278 return B_NO_INIT; 1279 1280 TRACE_FIND("AVFormatReader::Stream::FindKeyFrame(%ld,%s%s%s%s, " 1281 "%lld, %lld)\n", VirtualIndex(), 1282 (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "", 1283 (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "", 1284 (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) 1285 ? " B_MEDIA_SEEK_CLOSEST_BACKWARD" : "", 1286 (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) 1287 ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "", 1288 *frame, *time); 1289 1290 bool inLastRequestedRange = false; 1291 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 1292 if (fLastReportedKeyframe.reportedFrame 1293 <= fLastReportedKeyframe.requestedFrame) { 1294 inLastRequestedRange 1295 = *frame >= fLastReportedKeyframe.reportedFrame 1296 && *frame <= fLastReportedKeyframe.requestedFrame; 1297 } else { 1298 inLastRequestedRange 1299 = *frame >= fLastReportedKeyframe.requestedFrame 1300 && *frame <= fLastReportedKeyframe.reportedFrame; 1301 } 1302 } else if ((flags & B_MEDIA_SEEK_TO_FRAME) == 0) { 1303 if (fLastReportedKeyframe.reportedTime 1304 <= fLastReportedKeyframe.requestedTime) { 1305 inLastRequestedRange 1306 = *time >= fLastReportedKeyframe.reportedTime 1307 && *time <= fLastReportedKeyframe.requestedTime; 1308 } else { 1309 inLastRequestedRange 1310 = *time >= fLastReportedKeyframe.requestedTime 1311 && *time <= fLastReportedKeyframe.reportedTime; 1312 } 1313 } 1314 1315 if (inLastRequestedRange) { 1316 *frame = fLastReportedKeyframe.reportedFrame; 1317 *time = fLastReportedKeyframe.reportedTime; 1318 TRACE_FIND(" same as last reported keyframe\n"); 1319 return B_OK; 1320 } 1321 1322 double frameRate = FrameRate(); 1323 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) 1324 *time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5); 1325 1326 status_t ret; 1327 if (fGhostStream == NULL) { 1328 BAutolock _(fSourceLock); 1329 1330 fGhostStream = new(std::nothrow) StreamBase(fSource, fSourceLock, 1331 &fLock); 1332 if (fGhostStream == NULL) { 1333 TRACE(" failed to allocate ghost stream\n"); 1334 return B_NO_MEMORY; 1335 } 1336 1337 ret = fGhostStream->Open(); 1338 if (ret != B_OK) { 1339 TRACE(" ghost stream failed to open: %s\n", strerror(ret)); 1340 return B_ERROR; 1341 } 1342 1343 ret = fGhostStream->Init(fVirtualIndex); 1344 if (ret != B_OK) { 1345 TRACE(" ghost stream failed to init: %s\n", strerror(ret)); 1346 return B_ERROR; 1347 } 1348 } 1349 fLastReportedKeyframe.requestedFrame = *frame; 1350 fLastReportedKeyframe.requestedTime = *time; 1351 fLastReportedKeyframe.seekFlags = flags; 1352 1353 ret = fGhostStream->Seek(flags, frame, time); 1354 if (ret != B_OK) { 1355 TRACE(" ghost stream failed to seek: %s\n", strerror(ret)); 1356 return B_ERROR; 1357 } 1358 1359 fLastReportedKeyframe.reportedFrame = *frame; 1360 fLastReportedKeyframe.reportedTime = *time; 1361 1362 TRACE_FIND(" found time: %.2fs\n", *time / 1000000.0); 1363 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 1364 *frame = int64_t(*time * FrameRate() / 1000000.0 + 0.5); 1365 TRACE_FIND(" found frame: %lld\n", *frame); 1366 } 1367 1368 return B_OK; 1369 } 1370 1371 1372 status_t 1373 AVFormatReader::Stream::Seek(uint32 flags, int64* frame, bigtime_t* time) 1374 { 1375 BAutolock _(&fLock); 1376 1377 if (fContext == NULL || fStream == NULL) 1378 return B_NO_INIT; 1379 1380 // Put the old requested values into frame/time, since we already know 1381 // that the sought frame/time will then match the reported values. 1382 // TODO: Will not work if client changes seek flags (from backwards to 1383 // forward or vice versa)!! 1384 bool inLastRequestedRange = false; 1385 if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { 1386 if (fLastReportedKeyframe.reportedFrame 1387 <= fLastReportedKeyframe.requestedFrame) { 1388 inLastRequestedRange 1389 = *frame >= fLastReportedKeyframe.reportedFrame 1390 && *frame <= fLastReportedKeyframe.requestedFrame; 1391 } else { 1392 inLastRequestedRange 1393 = *frame >= fLastReportedKeyframe.requestedFrame 1394 && *frame <= fLastReportedKeyframe.reportedFrame; 1395 } 1396 } else if ((flags & B_MEDIA_SEEK_TO_FRAME) == 0) { 1397 if (fLastReportedKeyframe.reportedTime 1398 <= fLastReportedKeyframe.requestedTime) { 1399 inLastRequestedRange 1400 = *time >= fLastReportedKeyframe.reportedTime 1401 && *time <= fLastReportedKeyframe.requestedTime; 1402 } else { 1403 inLastRequestedRange 1404 = *time >= fLastReportedKeyframe.requestedTime 1405 && *time <= fLastReportedKeyframe.reportedTime; 1406 } 1407 } 1408 1409 if (inLastRequestedRange) { 1410 *frame = fLastReportedKeyframe.requestedFrame; 1411 *time = fLastReportedKeyframe.requestedTime; 1412 flags = fLastReportedKeyframe.seekFlags; 1413 } 1414 1415 return StreamBase::Seek(flags, frame, time); 1416 } 1417 1418 1419 // #pragma mark - AVFormatReader 1420 1421 1422 AVFormatReader::AVFormatReader() 1423 : 1424 fCopyright(""), 1425 fStreams(NULL), 1426 fSourceLock("source I/O lock") 1427 { 1428 TRACE("AVFormatReader::AVFormatReader\n"); 1429 } 1430 1431 1432 AVFormatReader::~AVFormatReader() 1433 { 1434 TRACE("AVFormatReader::~AVFormatReader\n"); 1435 if (fStreams != NULL) { 1436 // The client was supposed to call FreeCookie() on all 1437 // allocated streams. Deleting the first stream is always 1438 // prevented, we delete the other ones just in case. 1439 int32 count = fStreams[0]->CountStreams(); 1440 for (int32 i = 0; i < count; i++) 1441 delete fStreams[i]; 1442 delete[] fStreams; 1443 } 1444 } 1445 1446 1447 // #pragma mark - 1448 1449 1450 const char* 1451 AVFormatReader::Copyright() 1452 { 1453 if (fCopyright.Length() <= 0) { 1454 BMessage message; 1455 if (GetMetaData(&message) == B_OK) 1456 message.FindString("copyright", &fCopyright); 1457 } 1458 return fCopyright.String(); 1459 } 1460 1461 1462 status_t 1463 AVFormatReader::Sniff(int32* _streamCount) 1464 { 1465 TRACE("AVFormatReader::Sniff\n"); 1466 1467 BMediaIO* source = dynamic_cast<BMediaIO*>(Source()); 1468 if (source == NULL) { 1469 TRACE(" not a BMediaIO, but we need it to be one.\n"); 1470 return B_NOT_SUPPORTED; 1471 } 1472 1473 Stream* stream = new(std::nothrow) Stream(source, 1474 &fSourceLock); 1475 if (stream == NULL) { 1476 ERROR("AVFormatReader::Sniff() - failed to allocate Stream\n"); 1477 return B_NO_MEMORY; 1478 } 1479 1480 ObjectDeleter<Stream> streamDeleter(stream); 1481 1482 status_t ret = stream->Open(); 1483 if (ret != B_OK) { 1484 TRACE(" failed to detect stream: %s\n", strerror(ret)); 1485 return ret; 1486 } 1487 1488 delete[] fStreams; 1489 fStreams = NULL; 1490 1491 int32 streamCount = stream->CountStreams(); 1492 if (streamCount == 0) { 1493 TRACE(" failed to detect any streams: %s\n", strerror(ret)); 1494 return B_ERROR; 1495 } 1496 1497 fStreams = new(std::nothrow) Stream*[streamCount]; 1498 if (fStreams == NULL) { 1499 ERROR("AVFormatReader::Sniff() - failed to allocate streams\n"); 1500 return B_NO_MEMORY; 1501 } 1502 1503 memset(fStreams, 0, sizeof(Stream*) * streamCount); 1504 fStreams[0] = stream; 1505 streamDeleter.Detach(); 1506 1507 #ifdef TRACE_AVFORMAT_READER 1508 av_dump_format(const_cast<AVFormatContext*>(stream->Context()), 0, "", 0); 1509 #endif 1510 1511 if (_streamCount != NULL) 1512 *_streamCount = streamCount; 1513 1514 return B_OK; 1515 } 1516 1517 1518 void 1519 AVFormatReader::GetFileFormatInfo(media_file_format* mff) 1520 { 1521 TRACE("AVFormatReader::GetFileFormatInfo\n"); 1522 1523 if (fStreams == NULL) 1524 return; 1525 1526 // The first cookie is always there! 1527 const AVFormatContext* context = fStreams[0]->Context(); 1528 1529 if (context == NULL || context->iformat == NULL) { 1530 TRACE(" no AVFormatContext or AVInputFormat!\n"); 1531 return; 1532 } 1533 1534 const media_file_format* format = demuxer_format_for(context->iformat); 1535 1536 mff->capabilities = media_file_format::B_READABLE 1537 | media_file_format::B_KNOWS_ENCODED_VIDEO 1538 | media_file_format::B_KNOWS_ENCODED_AUDIO 1539 | media_file_format::B_IMPERFECTLY_SEEKABLE; 1540 1541 if (format != NULL) { 1542 mff->family = format->family; 1543 } else { 1544 TRACE(" no DemuxerFormat for AVInputFormat!\n"); 1545 mff->family = B_MISC_FORMAT_FAMILY; 1546 } 1547 1548 mff->version = 100; 1549 1550 if (format != NULL) { 1551 strcpy(mff->mime_type, format->mime_type); 1552 } else { 1553 // TODO: Would be nice to be able to provide this from AVInputFormat, 1554 // maybe by extending the FFmpeg code itself (all demuxers). 1555 strcpy(mff->mime_type, ""); 1556 } 1557 1558 if (context->iformat->extensions != NULL) 1559 strcpy(mff->file_extension, context->iformat->extensions); 1560 else { 1561 TRACE(" no file extensions for AVInputFormat.\n"); 1562 strcpy(mff->file_extension, ""); 1563 } 1564 1565 if (context->iformat->name != NULL) 1566 strcpy(mff->short_name, context->iformat->name); 1567 else { 1568 TRACE(" no short name for AVInputFormat.\n"); 1569 strcpy(mff->short_name, ""); 1570 } 1571 1572 if (context->iformat->long_name != NULL) 1573 sprintf(mff->pretty_name, "%s (FFmpeg)", context->iformat->long_name); 1574 else { 1575 if (format != NULL) 1576 sprintf(mff->pretty_name, "%s (FFmpeg)", format->pretty_name); 1577 else 1578 strcpy(mff->pretty_name, "Unknown (FFmpeg)"); 1579 } 1580 } 1581 1582 1583 status_t 1584 AVFormatReader::GetMetaData(BMessage* _data) 1585 { 1586 // The first cookie is always there! 1587 const AVFormatContext* context = fStreams[0]->Context(); 1588 1589 if (context == NULL) 1590 return B_NO_INIT; 1591 1592 avdictionary_to_message(context->metadata, _data); 1593 1594 // Add chapter info 1595 for (unsigned i = 0; i < context->nb_chapters; i++) { 1596 AVChapter* chapter = context->chapters[i]; 1597 BMessage chapterData; 1598 chapterData.AddInt64("start", bigtime_t(1000000.0 1599 * chapter->start * chapter->time_base.num 1600 / chapter->time_base.den + 0.5)); 1601 chapterData.AddInt64("end", bigtime_t(1000000.0 1602 * chapter->end * chapter->time_base.num 1603 / chapter->time_base.den + 0.5)); 1604 1605 avdictionary_to_message(chapter->metadata, &chapterData); 1606 _data->AddMessage("be:chapter", &chapterData); 1607 } 1608 1609 // Add program info 1610 for (unsigned i = 0; i < context->nb_programs; i++) { 1611 BMessage programData; 1612 avdictionary_to_message(context->programs[i]->metadata, &programData); 1613 _data->AddMessage("be:program", &programData); 1614 } 1615 1616 return B_OK; 1617 } 1618 1619 1620 // #pragma mark - 1621 1622 1623 status_t 1624 AVFormatReader::AllocateCookie(int32 streamIndex, void** _cookie) 1625 { 1626 TRACE("AVFormatReader::AllocateCookie(%ld)\n", streamIndex); 1627 1628 BAutolock _(fSourceLock); 1629 1630 if (fStreams == NULL) 1631 return B_NO_INIT; 1632 1633 if (streamIndex < 0 || streamIndex >= fStreams[0]->CountStreams()) 1634 return B_BAD_INDEX; 1635 1636 if (_cookie == NULL) 1637 return B_BAD_VALUE; 1638 1639 Stream* cookie = fStreams[streamIndex]; 1640 if (cookie == NULL) { 1641 // Allocate the cookie 1642 BMediaIO* source = dynamic_cast<BMediaIO*>(Source()); 1643 if (source == NULL) { 1644 TRACE(" not a BMediaIO, but we need it to be one.\n"); 1645 return B_NOT_SUPPORTED; 1646 } 1647 1648 cookie = new(std::nothrow) Stream(source, &fSourceLock); 1649 if (cookie == NULL) { 1650 ERROR("AVFormatReader::Sniff() - failed to allocate " 1651 "Stream\n"); 1652 return B_NO_MEMORY; 1653 } 1654 1655 status_t ret = cookie->Open(); 1656 if (ret != B_OK) { 1657 TRACE(" stream failed to open: %s\n", strerror(ret)); 1658 delete cookie; 1659 return ret; 1660 } 1661 } 1662 1663 status_t ret = cookie->Init(streamIndex); 1664 if (ret != B_OK) { 1665 TRACE(" stream failed to initialize: %s\n", strerror(ret)); 1666 // NOTE: Never delete the first stream! 1667 if (streamIndex != 0) 1668 delete cookie; 1669 return ret; 1670 } 1671 1672 fStreams[streamIndex] = cookie; 1673 *_cookie = cookie; 1674 1675 return B_OK; 1676 } 1677 1678 1679 status_t 1680 AVFormatReader::FreeCookie(void *_cookie) 1681 { 1682 BAutolock _(fSourceLock); 1683 1684 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1685 1686 // NOTE: Never delete the first cookie! 1687 if (cookie != NULL && cookie->VirtualIndex() != 0) { 1688 if (fStreams != NULL) 1689 fStreams[cookie->VirtualIndex()] = NULL; 1690 delete cookie; 1691 } 1692 1693 return B_OK; 1694 } 1695 1696 1697 // #pragma mark - 1698 1699 1700 status_t 1701 AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount, 1702 bigtime_t* duration, media_format* format, const void** infoBuffer, 1703 size_t* infoSize) 1704 { 1705 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1706 return cookie->GetStreamInfo(frameCount, duration, format, infoBuffer, 1707 infoSize); 1708 } 1709 1710 1711 status_t 1712 AVFormatReader::GetStreamMetaData(void* _cookie, BMessage* _data) 1713 { 1714 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1715 return cookie->GetMetaData(_data); 1716 } 1717 1718 1719 status_t 1720 AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame, 1721 bigtime_t* time) 1722 { 1723 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1724 return cookie->Seek(seekTo, frame, time); 1725 } 1726 1727 1728 status_t 1729 AVFormatReader::FindKeyFrame(void* _cookie, uint32 flags, int64* frame, 1730 bigtime_t* time) 1731 { 1732 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1733 return cookie->FindKeyFrame(flags, frame, time); 1734 } 1735 1736 1737 status_t 1738 AVFormatReader::GetNextChunk(void* _cookie, const void** chunkBuffer, 1739 size_t* chunkSize, media_header* mediaHeader) 1740 { 1741 Stream* cookie = reinterpret_cast<Stream*>(_cookie); 1742 return cookie->GetNextChunk(chunkBuffer, chunkSize, mediaHeader); 1743 } 1744