diff --git a/FFmpegSource/ffbase.cpp b/FFmpegSource/ffbase.cpp index 24445a2fc..2e18a66b2 100644 --- a/FFmpegSource/ffbase.cpp +++ b/FFmpegSource/ffbase.cpp @@ -318,6 +318,7 @@ void FFBase::InitPP(int AWidth, int AHeight, const char *APPString, int AQuality if (AQuality < 0 || AQuality > PP_QUALITY_MAX) Env->ThrowError("FFmpegSource: Quality is out of range"); + // Unsafe? PPMode = pp_get_mode_by_name_and_quality((char *)APPString, AQuality); if (!PPMode) Env->ThrowError("FFmpegSource: Invalid postprocesing settings"); @@ -341,14 +342,14 @@ void FFBase::InitPP(int AWidth, int AHeight, const char *APPString, int AQuality void FFBase::SetOutputFormat(int ACurrentFormat, IScriptEnvironment *Env) { int Loss; - int BestFormat = avcodec_find_best_pix_fmt((1 << PIX_FMT_YUVJ420P) | (1 << PIX_FMT_YUV420P) | (1 << PIX_FMT_YUYV422) | (1 << PIX_FMT_RGB32) | (1 << PIX_FMT_RGB24), ACurrentFormat, 1 /* Required to prevent pointless RGB32 => RGB24 conversion */, &Loss); + int BestFormat = avcodec_find_best_pix_fmt((1 << PIX_FMT_YUVJ420P) | (1 << PIX_FMT_YUV420P) | (1 << PIX_FMT_YUYV422) | (1 << PIX_FMT_RGB32) | (1 << PIX_FMT_BGR24), ACurrentFormat, 1 /* Required to prevent pointless RGB32 => RGB24 conversion */, &Loss); switch (BestFormat) { case PIX_FMT_YUVJ420P: // stupid yv12 distinctions, also inexplicably completely undeniably incompatible with all other supported output formats case PIX_FMT_YUV420P: VI.pixel_type = VideoInfo::CS_I420; break; case PIX_FMT_YUYV422: VI.pixel_type = VideoInfo::CS_YUY2; break; case PIX_FMT_RGB32: VI.pixel_type = VideoInfo::CS_BGR32; break; - case PIX_FMT_RGB24: VI.pixel_type = VideoInfo::CS_BGR24; break; + case PIX_FMT_BGR24: VI.pixel_type = VideoInfo::CS_BGR24; break; default: Env->ThrowError("FFmpegSource: No suitable output format found"); } @@ -422,6 +423,7 @@ FFBase::FFBase() { PPContext = NULL; PPMode = NULL; SWS = NULL; + LastFrameNum = -1; DecodingBuffer = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE]; #ifdef FLAC_CACHE FLACAudioCache = NULL; diff --git a/FFmpegSource/ffmatroskasource.cpp b/FFmpegSource/ffmatroskasource.cpp index 83a9a6d36..a1d5d40ca 100644 --- a/FFmpegSource/ffmatroskasource.cpp +++ b/FFmpegSource/ffmatroskasource.cpp @@ -44,7 +44,10 @@ int FFMatroskaSource::GetTrackIndex(int Index, unsigned char ATrackType, IScript return Index; } -FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, int AQuality, IScriptEnvironment* Env) { +FFMatroskaSource::FFMatroskaSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, + bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, + int AQuality, IScriptEnvironment* Env) { + CurrentFrame = 0; int VideoTrack; int AudioTrack; @@ -386,6 +389,9 @@ Done: } PVideoFrame FFMatroskaSource::GetFrame(int n, IScriptEnvironment* Env) { + if (LastFrameNum == n) + return LastFrame; + bool HasSeeked = false; if (n < CurrentFrame || FindClosestKeyFrame(n) > CurrentFrame) { @@ -408,5 +414,7 @@ PVideoFrame FFMatroskaSource::GetFrame(int n, IScriptEnvironment* Env) { CurrentFrame++; } while (CurrentFrame <= n); - return OutputFrame(DecodeFrame, Env); + LastFrame = OutputFrame(DecodeFrame, Env); + LastFrameNum = n; + return LastFrame; } diff --git a/FFmpegSource/ffmpegsource.cpp b/FFmpegSource/ffmpegsource.cpp index a545bb2c1..76e06ecbb 100644 --- a/FFmpegSource/ffmpegsource.cpp +++ b/FFmpegSource/ffmpegsource.cpp @@ -20,10 +20,6 @@ #include "ffmpegsource.h" -static DWORD WINAPI AVFindStreamInfoExecute(AVFormatContext *FormatContext) { - return av_find_stream_info(FormatContext); -} - int FFmpegSource::GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironment *Env) { if (Index == -1) for (unsigned int i = 0; i < FormatContext->nb_streams; i++) @@ -46,7 +42,10 @@ int FFmpegSource::GetTrackIndex(int Index, CodecType ATrackType, IScriptEnvironm return Index; } -FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, int AQuality, int ASeekMode, IScriptEnvironment* Env) { +FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack, const char *ATimecodes, + bool AVCache, const char *AVideoCache, const char *AAudioCache, int AACCompression, const char *APPString, + int AQuality, int ASeekMode, IScriptEnvironment* Env) { + CurrentFrame = 0; SeekMode = ASeekMode; @@ -71,7 +70,10 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack bool ACacheIsValid = true; if (VideoTrack >= 0) { - VCacheIsValid = LoadFrameInfoFromFile(AVideoCache, ASource, VideoTrack); + if (SeekMode >= 0 && av_seek_frame(FormatContext, VideoTrack, 0, AVSEEK_FLAG_BACKWARD) < 0) + Env->ThrowError("FFmpegSource: Video track is unseekable"); + + VCacheIsValid = LoadFrameInfoFromFile(AVideoCache, ASource, VideoTrack); VideoCodecContext = FormatContext->streams[VideoTrack]->codec; @@ -124,6 +126,9 @@ FFmpegSource::FFmpegSource(const char *ASource, int AVideoTrack, int AAudioTrack ACacheIsValid = OpenAudioCache(AAudioCache, ASource, AudioTrack, Env); } + if ((!ACacheIsValid || !VCacheIsValid) && SeekMode == -1) + Env->ThrowError("FFmpegSource: Unusual indexing error, report on doom9"); + // Needs to be indexed? if (!ACacheIsValid || !VCacheIsValid) { #ifdef FLAC_CACHE @@ -257,22 +262,30 @@ Done: } PVideoFrame FFmpegSource::GetFrame(int n, IScriptEnvironment* Env) { - bool HasSeeked = false; - int ClosestKF = FindClosestKeyFrame(n); + if (LastFrameNum == n) + return LastFrame; - if (SeekMode == 0) { - if (n < CurrentFrame) { - av_seek_frame(FormatContext, VideoTrack, FrameToDTS.front().DTS, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(VideoCodecContext); - CurrentFrame = 0; - } - } else { - // 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat - if (n < CurrentFrame || ClosestKF > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) { - av_seek_frame(FormatContext, VideoTrack, (SeekMode == 3) ? FrameToDTS[n].DTS : FrameToDTS[ClosestKF].DTS, AVSEEK_FLAG_BACKWARD); - avcodec_flush_buffers(VideoCodecContext); - HasSeeked = true; + bool HasSeeked = false; + + if (SeekMode >= 0) { + int ClosestKF = FindClosestKeyFrame(n); + + if (SeekMode == 0) { + if (n < CurrentFrame) { + av_seek_frame(FormatContext, VideoTrack, 0, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(VideoCodecContext); + CurrentFrame = 0; + } + } else { + // 10 frames is used as a margin to prevent excessive seeking since the predicted best keyframe isn't always selected by avformat + if (n < CurrentFrame || ClosestKF > CurrentFrame + 10 || (SeekMode == 3 && n > CurrentFrame + 10)) { + av_seek_frame(FormatContext, VideoTrack, (SeekMode == 3) ? FrameToDTS[n].DTS : FrameToDTS[ClosestKF].DTS, AVSEEK_FLAG_BACKWARD); + avcodec_flush_buffers(VideoCodecContext); + HasSeeked = true; + } } + } else if (n < CurrentFrame) { + Env->ThrowError("FFmpegSource: Non-linear access attempted"); } do { @@ -300,5 +313,7 @@ PVideoFrame FFmpegSource::GetFrame(int n, IScriptEnvironment* Env) { CurrentFrame++; } while (CurrentFrame <= n); - return OutputFrame(DecodeFrame, Env); + LastFrame = OutputFrame(DecodeFrame, Env); + LastFrameNum = n; + return LastFrame; } diff --git a/FFmpegSource/ffmpegsource.h b/FFmpegSource/ffmpegsource.h index 561ac0114..c1b0be41d 100644 --- a/FFmpegSource/ffmpegsource.h +++ b/FFmpegSource/ffmpegsource.h @@ -81,13 +81,16 @@ protected: AVFrame *DecodeFrame; AudioCacheFormat AudioCacheType; FILE *RawAudioCache; + PVideoFrame LastFrame; + int LastFrameNum; + uint8_t *DecodingBuffer; #ifdef FLAC_CACHE FLAC__StreamDecoder *FLACAudioCache; FLAC__int32 *FLACBuffer; #endif // FLAC_CACHE - uint8_t *DecodingBuffer; + struct FrameInfo { int64_t DTS; diff --git a/FFmpegSource/ffmpegsource.html b/FFmpegSource/ffmpegsource.html index c7d7a2ce9..20971c0a0 100644 --- a/FFmpegSource/ffmpegsource.html +++ b/FFmpegSource/ffmpegsource.html @@ -9,6 +9,14 @@ FFmpegSource Documentation

Changes