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