From 303ecf89ec6b9d4a1cef8cf4aa27c90f2fdb2f16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Tue, 24 Aug 2010 13:57:40 +0000 Subject: [PATCH] There was some bogus code in the Seek and FindKeyframe methods: First B_MEDIA_SEEK_TO_FRAME was handled to compute a time, then it was ignored and frame was used as time stamp. Also the conversion from frame to time had the num and den members of the time base swapped in the computation, so it computed bogus time stamps. Refactored the conversion methods, always seek based on the time. Needs more testing (perhaps there are rounding issues), but overriding a lot of native reader implementations with AVFormatReader holds up very well now with a lot of files I tested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38332 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/plugins/ffmpeg/AVFormatReader.cpp | 63 +++++++++---------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp b/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp index 3a34798003..c559ebd625 100644 --- a/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp +++ b/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Stephan Aßmus + * Copyright 2009-2010, Stephan Aßmus * All rights reserved. Distributed under the terms of the GNU L-GPL license. */ @@ -139,6 +139,9 @@ private: status_t _NextPacket(bool reuse); + int64_t _ConvertToStreamTimeBase(bigtime_t time) const; + bigtime_t _ConvertFromStreamTimeBase(int64_t time) const; + private: BPositionIO* fSource; off_t fPosition; @@ -720,8 +723,7 @@ AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount, // unfortunately, libavformat itself seems to set the time_base and // duration wrongly sometimes. :-( if ((int64)fStream->duration != kNoPTSValue) { - *duration = (bigtime_t)(1000000LL * fStream->duration - * fStream->time_base.num / fStream->time_base.den); + *duration = _ConvertFromStreamTimeBase(fStream->duration); TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n", fStream->duration, av_q2d(fStream->time_base), fStream->time_base.num, fStream->time_base.den); @@ -760,12 +762,6 @@ AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame, if (fContext == NULL || fStream == NULL) return B_NO_INIT; - if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0) { - TRACE_SEEK("AVFormatReader::StreamCookie::Seek() - " - "B_MEDIA_SEEK_CLOSEST_FORWARD not supported.\n"); - return B_NOT_SUPPORTED; - } - TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, " "%lld)\n", VirtualIndex(), (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "", @@ -774,6 +770,8 @@ AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame, (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? "B_MEDIA_SEEK_CLOSEST_FORWARD" : "", *frame, *time); + // Seeking is always based on time, initialize it when client seeks + // based on frame. if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) *time = (bigtime_t)(*frame * 1000000LL / FrameRate()); @@ -795,16 +793,7 @@ AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame, ret = av_seek_frame(fContext, Index(), pos, seekFlags); #endif - - int64_t timeStamp; - if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { - // Can use frame, because stream timeStamp is actually in frame - // units. - timeStamp = *frame; - } else { - timeStamp = *time * fStream->time_base.num - / ((int64_t)fStream->time_base.den * 1000000); - } + int64_t timeStamp = _ConvertToStreamTimeBase(*time); TRACE_SEEK(" time: %.5fs -> %lld, current DTS: %lld (time_base: %d/%d)\n", *time / 1000000.0, timeStamp, fStream->cur_dts, fStream->time_base.num, @@ -842,15 +831,7 @@ AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame, if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) *time = (bigtime_t)(*frame * 1000000LL / frameRate); - int64_t timeStamp; - if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { - // Can use frame, because stream timeStamp is actually in frame - // units. - timeStamp = *frame; - } else { - timeStamp = *time * fStream->time_base.num - / ((int64_t)fStream->time_base.den * 1000000); - } + int64_t timeStamp = _ConvertToStreamTimeBase(*time); TRACE_SEEK(" time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 1000000.0, timeStamp, fStream->time_base.num, fStream->time_base.den); @@ -871,12 +852,11 @@ AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame, const AVIndexEntry& entry = fStream->index_entries[index]; timeStamp = entry.timestamp; - *time = (bigtime_t)(timeStamp * 1000000 * fStream->time_base.num - / fStream->time_base.den); + *time = _ConvertFromStreamTimeBase(timeStamp); TRACE_SEEK(" seeked time: %.2fs (%lld)\n", *time / 1000000.0, timeStamp); if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) { - *frame = timeStamp;//*time * frameRate / 1000000LL; + *frame = *time * frameRate / 1000000LL; TRACE_SEEK(" seeked frame: %lld\n", *frame); } @@ -1068,6 +1048,21 @@ AVFormatReader::StreamCookie::_NextPacket(bool reuse) } +int64_t +AVFormatReader::StreamCookie::_ConvertToStreamTimeBase(bigtime_t time) const +{ + return time * fStream->time_base.den + / (1000000LL * fStream->time_base.num); +} + + +bigtime_t +AVFormatReader::StreamCookie::_ConvertFromStreamTimeBase(int64_t time) const +{ + return 1000000LL * time * fStream->time_base.num / fStream->time_base.den; +} + + // #pragma mark - AVFormatReader @@ -1217,12 +1212,12 @@ AVFormatReader::GetFileFormatInfo(media_file_format* mff) } if (context->iformat->long_name != NULL) - strcpy(mff->pretty_name, context->iformat->long_name); + sprintf(mff->pretty_name, "%s (FFmpeg)", context->iformat->long_name); else { if (format != NULL) - strcpy(mff->pretty_name, format->pretty_name); + sprintf(mff->pretty_name, "%s (FFmpeg)", format->pretty_name); else - strcpy(mff->pretty_name, ""); + strcpy(mff->pretty_name, "Unknown (FFmpeg)"); } }