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
This commit is contained in:
Stephan Aßmus 2010-08-24 13:57:40 +00:00
parent f242acd5a0
commit 303ecf89ec

View File

@ -1,5 +1,5 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
* Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de>
* 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)");
}
}