FFmpegSource 1.12
Originally committed to SVN as r1563.
This commit is contained in:
parent
a68fb2671a
commit
86fad7d3b2
7 changed files with 77 additions and 32 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -9,6 +9,14 @@ FFmpegSource Documentation
|
|||
|
||||
<h2>Changes</h2>
|
||||
<ul>
|
||||
<li>1.12<ul>
|
||||
<li>Now caches the last fully decoded frame to increase the reliability of seekmode=-1 and possibly reduce seeking in other modes</li>
|
||||
<li>Video that needs to be converted to a suitable output format should now always have correct colors (was reversed in 1.11 and inconsistent in earlier versions)</li>
|
||||
<li>Added seekmode=-1 which is mostly useful for opening image files very carefully</li>
|
||||
<li>Now throws an error if the container is unseekable and seekmode=-1 isn't set</li>
|
||||
<li>Updated FFmpeg to rev 10492 + camtasia swapped colors fix</li>
|
||||
</ul></li>
|
||||
|
||||
<li>1.11<ul>
|
||||
<li>Now officially uses the MIT license</li>
|
||||
<li>Much cleaner source</li>
|
||||
|
@ -104,6 +112,7 @@ FFmpegSource Documentation
|
|||
<li>VOB: No rff flags applied, frame accurate?</li>
|
||||
<li>MPG: Seeking seems to be off by one or two frames now and then</li>
|
||||
<li>TS: don't bother</li>
|
||||
<li>Image files: most formats can be opened if seekmode=-1 is set</li>
|
||||
</ul>
|
||||
|
||||
<h2>Compatibility - Audio</h2>
|
||||
|
@ -117,7 +126,7 @@ FFmpegSource Documentation
|
|||
</p>
|
||||
|
||||
<p>
|
||||
Note that the audio cache will always be created when opening files with audio and that it will be huge since it stores all audio as raw signed 16 bit pcm.
|
||||
Note that the audio cache will always be created when opening files with audio and that it will be huge since it stores all audio as raw signed 16/24/32 bit pcm, unsigned 8 bit pcm or as float, using flac to compress it is also possible to reduce the size by half.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -152,7 +161,7 @@ Separate postprocessing which also seems to include a few simple deinterlacers
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<b>accompression</b>
|
||||
<b>accompression:</b>
|
||||
Audio cache compression, -1 means raw audio and 0-8 uses FLAC with that compression level.
|
||||
</p>
|
||||
|
||||
|
@ -169,6 +178,7 @@ Separate postprocessing which also seems to include a few simple deinterlacers
|
|||
<p>
|
||||
<b>seekmode:</b>
|
||||
Force how seeking is handled, has no effect on matroska files which always use the equivalent of seekmode=1<br />
|
||||
<b>-1:</b> linear access without rewind, will throw an error if each successive requested frame number isn't bigger than the last one, only intended for opening images but might work on well with some obscure video format<br />
|
||||
<b>0:</b> linear access, the definition of slow but should make some formats "usable"<br />
|
||||
<b>1:</b> safe normal, bases seeking decisions on the reported keyframe positions<br />
|
||||
<b>2:</b> unsafe normal, same as 1 but no error will be thrown if the exact destination has to be guessed<br />
|
||||
|
@ -234,4 +244,4 @@ tn:64:128:256
|
|||
--disable-encoders --disable-muxers --enable-small</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -72,6 +72,9 @@ AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnviro
|
|||
if (VTrack <= -2 && ATrack <= -2)
|
||||
Env->ThrowError("FFmpegSource: No tracks selected");
|
||||
|
||||
if (SeekMode < -1 || SeekMode > 3)
|
||||
Env->ThrowError("FFmpegSource: Invalid seekmode selected");
|
||||
|
||||
#ifdef FLAC_CACHE
|
||||
if (ACCompression < -1 || ACCompression > 8)
|
||||
#else
|
||||
|
@ -87,10 +90,14 @@ AVSValue __cdecl CreateFFmpegSource(AVSValue Args, void* UserData, IScriptEnviro
|
|||
bool IsMatroska = !strcmp(FormatContext->iformat->name, "matroska");
|
||||
av_close_input_file(FormatContext);
|
||||
|
||||
if (IsMatroska)
|
||||
if (IsMatroska) {
|
||||
return new FFMatroskaSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, Env);
|
||||
else
|
||||
} else {
|
||||
// Do a separate indexing pass, enjoy the constructor sideeffects
|
||||
if (SeekMode == -1)
|
||||
delete new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, -2, Env);
|
||||
return new FFmpegSource(Source, VTrack, ATrack, Timecodes, VCache, VCacheFile, ACacheFile, ACCompression, PPString, PPQuality, SeekMode, Env);
|
||||
}
|
||||
}
|
||||
|
||||
AVSValue __cdecl CreateFFPP(AVSValue Args, void* UserData, IScriptEnvironment* Env) {
|
||||
|
|
|
@ -241,7 +241,7 @@ CodecID MatroskaToFFCodecID(TrackInfo *TI) {
|
|||
case 16: return CODEC_ID_PCM_S16LE;
|
||||
case 24: return CODEC_ID_PCM_S24LE;
|
||||
case 32: return CODEC_ID_PCM_S32LE;
|
||||
default: CODEC_ID_NONE;
|
||||
default: return CODEC_ID_NONE;
|
||||
}
|
||||
} else if (!strcmp(Codec, "A_PCM/FLOAT/IEEE"))
|
||||
return CODEC_ID_NONE; // no float codec id?
|
||||
|
|
Loading…
Reference in a new issue