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