From b0137363f60ed9c298a21122dd899f882b1d6fad Mon Sep 17 00:00:00 2001 From: Fredrik Mellbin Date: Wed, 1 Oct 2008 18:13:12 +0000 Subject: [PATCH] FFmpegSource2: semi vfr fix Originally committed to SVN as r2403. --- FFmpegSource2/ffavisynth.cpp | 27 ++++++++++++++++++++------- FFmpegSource2/ffavisynth.h | 4 +++- FFmpegSource2/ffavsfilters.cpp | 14 ++++++++------ FFmpegSource2/ffms.cpp | 18 +++++++++--------- FFmpegSource2/ffms.h | 20 +++++++++++--------- FFmpegSource2/ffvideosource.cpp | 12 +++++++++--- FFmpegSource2/ffvideosource.h | 2 +- 7 files changed, 61 insertions(+), 36 deletions(-) diff --git a/FFmpegSource2/ffavisynth.cpp b/FFmpegSource2/ffavisynth.cpp index 3c8eee115..ecf285a3b 100644 --- a/FFmpegSource2/ffavisynth.cpp +++ b/FFmpegSource2/ffavisynth.cpp @@ -21,10 +21,12 @@ #include "ffavisynth.h" #include "utils.h" -AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) { +AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, int FPSNum, int FPSDen, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) { memset(&VI, 0, sizeof(VI)); SWS = NULL; ConvertToFormat = PIX_FMT_NONE; + this->FPSNum = FPSNum; + this->FPSDen = FPSDen; VS = FFMS_CreateVideoSource(SourceFile, Track, TrackIndices, PP, Threads, SeekMode, ErrorMsg, MsgSize); if (!VS) @@ -35,9 +37,16 @@ AvisynthVideoSource::AvisynthVideoSource(const char *SourceFile, int Track, Fram VI.image_type = VideoInfo::IT_TFF; VI.width = VP.Width; VI.height = VP.Height; - VI.fps_denominator = VP.FPSDenominator; - VI.fps_numerator = VP.FPSNumerator; - VI.num_frames = VP.NumFrames; + + if (FPSNum > 0 && FPSDen > 0) { + VI.fps_denominator = FPSDen; + VI.fps_numerator = FPSNum; + VI.num_frames = ceil(((VP.LastTime - VP.FirstTime) * FPSNum) / FPSDen); + } else { + VI.fps_denominator = VP.FPSDenominator; + VI.fps_numerator = VP.FPSNumerator; + VI.num_frames = VP.NumFrames; + } try { InitOutputFormat(VP.PixelFormat, Env); @@ -129,7 +138,13 @@ PVideoFrame AvisynthVideoSource::OutputFrame(const AVFrameLite *Frame, IScriptEn PVideoFrame AvisynthVideoSource::GetFrame(int n, IScriptEnvironment *Env) { char ErrorMsg[1024]; unsigned MsgSize = sizeof(ErrorMsg); - const AVFrameLite *Frame = FFMS_GetFrame(VS, n, ErrorMsg, MsgSize); + const AVFrameLite *Frame; + + if (FPSNum > 0 && FPSDen > 0) + Frame = FFMS_GetFrameByTime(VS, FFMS_GetVideoProperties(VS)->FirstTime + (double)(n * (int64_t)FPSDen) / FPSNum, ErrorMsg, MsgSize); + else + Frame = FFMS_GetFrame(VS, n, ErrorMsg, MsgSize); + if (Frame == NULL) Env->ThrowError("FFVideoSource: %s", ErrorMsg); @@ -137,7 +152,6 @@ PVideoFrame AvisynthVideoSource::GetFrame(int n, IScriptEnvironment *Env) { return OutputFrame(Frame, Env); } - AvisynthAudioSource::AvisynthAudioSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize) { memset(&VI, 0, sizeof(VI)); @@ -147,7 +161,6 @@ AvisynthAudioSource::AvisynthAudioSource(const char *SourceFile, int Track, Fram const AudioProperties AP = *FFMS_GetAudioProperties(AS); - VI.nchannels = AP.Channels; VI.num_audio_samples = AP.NumSamples; VI.audio_samples_per_second = AP.SampleRate; diff --git a/FFmpegSource2/ffavisynth.h b/FFmpegSource2/ffavisynth.h index 28d4afc7d..1c3a94ad5 100644 --- a/FFmpegSource2/ffavisynth.h +++ b/FFmpegSource2/ffavisynth.h @@ -38,11 +38,13 @@ private: VideoBase *VS; SwsContext *SWS; int ConvertToFormat; + int FPSNum; + int FPSDen; void InitOutputFormat(int CurrentFormat, IScriptEnvironment *Env); PVideoFrame OutputFrame(const AVFrameLite *SrcPicture, IScriptEnvironment *Env); public: - AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize); + AvisynthVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, int FPSNum, int FPSDen, const char *PP, int Threads, int SeekMode, IScriptEnvironment* Env, char *ErrorMsg, unsigned MsgSize); ~AvisynthVideoSource(); bool __stdcall GetParity(int n) { return false; } void __stdcall SetCacheHints(int cachehints, int frame_range) { } diff --git a/FFmpegSource2/ffavsfilters.cpp b/FFmpegSource2/ffavsfilters.cpp index 1161a1dd5..99b843c1d 100644 --- a/FFmpegSource2/ffavsfilters.cpp +++ b/FFmpegSource2/ffavsfilters.cpp @@ -92,10 +92,12 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir int Track = Args[1].AsInt(-1); bool Cache = Args[2].AsBool(true); const char *CacheFile = Args[3].AsString(""); - const char *PP = Args[4].AsString(""); - int Threads = Args[5].AsInt(-1); - const char *Timecodes = Args[6].AsString(""); - int SeekMode = Args[7].AsInt(1); + int FPSNum = Args[4].AsInt(-1); + int FPSDen = Args[5].AsInt(1); + const char *PP = Args[6].AsString(""); + int Threads = Args[7].AsInt(-1); + const char *Timecodes = Args[8].AsString(""); + int SeekMode = Args[9].AsInt(1); if (Track <= -2) Env->ThrowError("FFVideoSource: No video track selected"); @@ -145,7 +147,7 @@ AVSValue __cdecl CreateFFVideoSource(AVSValue Args, void* UserData, IScriptEnvir AvisynthVideoSource *Filter; try { - Filter = new AvisynthVideoSource(Source, Track, Index, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize); + Filter = new AvisynthVideoSource(Source, Track, Index, FPSNum, FPSDen, PP, Threads, SeekMode, Env, ErrorMsg, MsgSize); } catch (...) { FFMS_DestroyFrameIndex(Index); throw; @@ -219,7 +221,7 @@ AVSValue __cdecl CreateSWScale(AVSValue Args, void* UserData, IScriptEnvironment extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* Env) { Env->AddFunction("FFIndex", "[source]s[cachefile]s[indexmask]i[dumpmask]i[audiofile]s[overwrite]b", CreateFFIndex, 0); - Env->AddFunction("FFVideoSource", "[source]s[track]i[cache]b[cachefile]s[pp]s[threads]i[timecodes]s[seekmode]i", CreateFFVideoSource, 0); + Env->AddFunction("FFVideoSource", "[source]s[track]i[cache]b[cachefile]s[fpsnum]i[fpsden]i[pp]s[threads]i[timecodes]s[seekmode]i", CreateFFVideoSource, 0); Env->AddFunction("FFAudioSource", "[source]s[track]i[cache]b[cachefile]s", CreateFFAudioSource, 0); Env->AddFunction("FFPP", "c[pp]s", CreateFFPP, 0); Env->AddFunction("SWScale", "c[width]i[height]i[resizer]s[colorspace]s", CreateSWScale, 0); diff --git a/FFmpegSource2/ffms.cpp b/FFmpegSource2/ffms.cpp index ff6fd2770..c60634e39 100644 --- a/FFmpegSource2/ffms.cpp +++ b/FFmpegSource2/ffms.cpp @@ -110,8 +110,8 @@ FFMS_API(int) FFMS_GetAudio(AudioBase *AB, void *Buf, int64_t Start, int64_t Cou return AB->GetAudio(Buf, Start, Count, ErrorMsg, MsgSize); } -FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height) { - return VB->SetOutputFormat(TargetFormat, Width, Height); +FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize) { + return VB->SetOutputFormat(TargetFormat, Width, Height, ErrorMsg, MsgSize); } FFMS_API(void) FFMS_ResetOutputFormat(VideoBase *VB) { @@ -130,15 +130,15 @@ FFMS_API(int) FFMS_GetFirstTrackOfType(FrameIndex *TrackIndices, int TrackType, return -1; } -FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices) { return TrackIndices->size(); } -FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV) { return FIV->TT; } -FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV) { return FIV->size(); } @@ -160,7 +160,7 @@ FFMS_API(FrameInfoVector *) FFMS_GetTITrackIndex(FrameIndex *TrackIndices, int T } } -FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB) { return VB->GetFrameInfoVector(); } @@ -173,15 +173,15 @@ FFMS_API(int) FFMS_FindClosestKeyFrame(FrameInfoVector *FIV, int Frame, char *Er } } -FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS) { return FIV->FrameFromDTS(DTS); } -FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS) { return FIV->ClosestFrameFromDTS(DTS); } -FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize) { +FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV) { return &FIV->TB; } diff --git a/FFmpegSource2/ffms.h b/FFmpegSource2/ffms.h index 7c017c569..44b64c30d 100644 --- a/FFmpegSource2/ffms.h +++ b/FFmpegSource2/ffms.h @@ -157,6 +157,8 @@ struct AudioProperties { int64_t NumSamples; }; +// Most functions return 0 on success +// Functions without error message output can be assumed to never fail FFMS_API(void) FFMS_Init(); FFMS_API(VideoBase *) FFMS_CreateVideoSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, const char *PP, int Threads, int SeekMode, char *ErrorMsg, unsigned MsgSize); FFMS_API(AudioBase *) FFMS_CreateAudioSource(const char *SourceFile, int Track, FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize); @@ -167,21 +169,21 @@ FFMS_API(const AudioProperties *) FFMS_GetAudioProperties(AudioBase *AB); FFMS_API(const AVFrameLite *) FFMS_GetFrame(VideoBase *VB, int n, char *ErrorMsg, unsigned MsgSize); FFMS_API(const AVFrameLite *) FFMS_GetFrameByTime(VideoBase *VB, double Time, char *ErrorMsg, unsigned MsgSize); FFMS_API(int) FFMS_GetAudio(AudioBase *AB, void *Buf, int64_t Start, int64_t Count, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height); +FFMS_API(int) FFMS_SetOutputFormat(VideoBase *VB, int TargetFormat, int Width, int Height, char *ErrorMsg, unsigned MsgSize); FFMS_API(void) FFMS_ResetOutputFormat(VideoBase *VB); FFMS_API(void) FFMS_DestroyFrameIndex(FrameIndex *FI); FFMS_API(int) FFMS_GetFirstTrackOfType(FrameIndex *TrackIndices, int TrackType, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize); +FFMS_API(int) FFMS_GetNumTracks(FrameIndex *TrackIndices); +FFMS_API(int) FFMS_GetTrackType(FrameInfoVector *FIV); +FFMS_API(int) FFMS_GetNumFrames(FrameInfoVector *FIV); FFMS_API(const FrameInfo *) FFMS_GetFrameInfo(FrameInfoVector *FIV, int Frame, char *ErrorMsg, unsigned MsgSize); FFMS_API(FrameInfoVector *) FFMS_GetTITrackIndex(FrameIndex *TrackIndices, int Track, char *ErrorMsg, unsigned MsgSize); -FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB, char *ErrorMsg, unsigned MsgSize); -FFMS_API(FrameInfoVector *) FFMS_GetASTrackIndex(AudioBase *AB, char *ErrorMsg, unsigned MsgSize); +FFMS_API(FrameInfoVector *) FFMS_GetVSTrackIndex(VideoBase *VB); +FFMS_API(FrameInfoVector *) FFMS_GetASTrackIndex(AudioBase *AB); FFMS_API(int) FFMS_FindClosestKeyFrame(FrameInfoVector *FIV, int Frame, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize); -FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS, char *ErrorMsg, unsigned MsgSize); -FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV, char *ErrorMsg, unsigned MsgSize); +FFMS_API(int) FFMS_FrameFromDTS(FrameInfoVector *FIV, int64_t DTS); +FFMS_API(int) FFMS_ClosestFrameFromDTS(FrameInfoVector *FIV, int64_t DTS); +FFMS_API(const TrackTimeBase *) FFMS_GetTimeBase(FrameInfoVector *FIV); FFMS_API(int) FFMS_WriteTimecodes(FrameInfoVector *FIV, const char *TimecodeFile, char *ErrorMsg, unsigned MsgSize); FFMS_API(FrameIndex *) FFMS_MakeIndex(const char *SourceFile, int IndexMask, int DumpMask, const char *AudioFile, bool IgnoreDecodeErrors, IndexCallback IP, void *Private, char *ErrorMsg, unsigned MsgSize); FFMS_API(FrameIndex *) FFMS_ReadIndex(const char *IndexFile, char *ErrorMsg, unsigned MsgSize); diff --git a/FFmpegSource2/ffvideosource.cpp b/FFmpegSource2/ffvideosource.cpp index 77f21bbb7..f0ed36654 100644 --- a/FFmpegSource2/ffvideosource.cpp +++ b/FFmpegSource2/ffvideosource.cpp @@ -110,11 +110,11 @@ VideoBase::~VideoBase() { } AVFrameLite *VideoBase::GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize) { - int Frame = Frames.ClosestFrameFromDTS(Time * Frames.TB.Den / Frames.TB.Num); + int Frame = Frames.ClosestFrameFromDTS((Time * Frames.TB.Num) / Frames.TB.Den); return GetFrame(Frame, ErrorMsg, MsgSize); } -int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height) { +int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height, char *ErrorMsg, unsigned MsgSize) { // FIXME: investigate the possible bug in avcodec_find_best_pix_fmt // int Loss; // int OutputFormat = avcodec_find_best_pix_fmt(TargetFormats, @@ -128,8 +128,10 @@ int VideoBase::SetOutputFormat(int TargetFormats, int Width, int Height) { if (CodecContext->pix_fmt != OutputFormat || Width != CodecContext->width || Height != CodecContext->height) { NewSWS = sws_getContext(CodecContext->width, CodecContext->height, CodecContext->pix_fmt, Width, Height, OutputFormat, GetCPUFlags() | SWS_BICUBIC, NULL, NULL, NULL); - if (NewSWS == NULL) + if (NewSWS == NULL) { + _snprintf(ErrorMsg, MsgSize, "Failed to allocate SWScale context"); return 1; + } } if (SWS) @@ -234,6 +236,8 @@ FFVideoSource::FFVideoSource(const char *SourceFile, int Track, FrameIndex *Trac VP.FPSNumerator = FormatContext->streams[VideoTrack]->time_base.den; VP.NumFrames = Frames.size(); VP.PixelFormat = CodecContext->pix_fmt; + VP.FirstTime = (Frames.front().DTS * Frames.TB.Den) / (double)Frames.TB.Num; + VP.LastTime = (Frames.back().DTS * Frames.TB.Den) / (double)Frames.TB.Num; if (VP.Width <= 0 || VP.Height <= 0) { Free(true); @@ -451,6 +455,8 @@ MatroskaVideoSource::MatroskaVideoSource(const char *SourceFile, int Track, VP.FPSNumerator = 30; VP.NumFrames = Frames.size(); VP.PixelFormat = CodecContext->pix_fmt; + VP.FirstTime = (Frames.front().DTS * Frames.TB.Den) / (double)Frames.TB.Num; + VP.LastTime = (Frames.back().DTS * Frames.TB.Den) / (double)Frames.TB.Num; if (VP.Width <= 0 || VP.Height <= 0) { Free(true); diff --git a/FFmpegSource2/ffvideosource.h b/FFmpegSource2/ffvideosource.h index dd97489ec..cbe870c15 100644 --- a/FFmpegSource2/ffvideosource.h +++ b/FFmpegSource2/ffvideosource.h @@ -58,7 +58,7 @@ public: FrameInfoVector *GetFrameInfoVector() { return &Frames; } virtual AVFrameLite *GetFrame(int n, char *ErrorMsg, unsigned MsgSize) = 0; AVFrameLite *GetFrameByTime(double Time, char *ErrorMsg, unsigned MsgSize); - int SetOutputFormat(int TargetFormats, int Width, int Height); + int SetOutputFormat(int TargetFormats, int Width, int Height, char *ErrorMsg, unsigned MsgSize); void ResetOutputFormat(); };