From 32f7a53a68ea894f86735ee9193f8cf498d459d7 Mon Sep 17 00:00:00 2001 From: Karl Blomster Date: Sun, 13 Jul 2008 23:45:42 +0000 Subject: [PATCH] vastly improved keyframe reading with ffmpeg, should be much faster and more reliable. Originally committed to SVN as r2248. --- aegisub/lavc_keyframes.cpp | 53 ++++++++++++-------------------------- aegisub/lavc_keyframes.h | 3 --- aegisub/video_context.cpp | 33 +++++++++++++++--------- 3 files changed, 38 insertions(+), 51 deletions(-) diff --git a/aegisub/lavc_keyframes.cpp b/aegisub/lavc_keyframes.cpp index 38b85e302..13061310a 100644 --- a/aegisub/lavc_keyframes.cpp +++ b/aegisub/lavc_keyframes.cpp @@ -38,49 +38,36 @@ // Headers #include "config.h" #ifdef WITH_FFMPEG + +#ifdef WIN32 +#define __STDC_CONSTANT_MACROS 1 +#include +#endif /* WIN32 */ + #include "dialog_progress.h" #include "lavc_keyframes.h" /////////////// // Constructor LAVCKeyFrames::LAVCKeyFrames(const Aegisub::String filename) - : file(0), codecContext(0), codec(0), stream(0), frame(0), - streamN(-1) { + : file(0), stream(0), streamN(-1) { // Open LAVCFile file = LAVCFile::Create(filename); // Find video stream for (unsigned int i = 0; i < file->fctx->nb_streams; ++i) { - codecContext = file->fctx->streams[i]->codec; - if (!codecContext) continue; - codecContext->skip_frame = AVDISCARD_NONKEY; - codecContext->workaround_bugs = FF_BUG_AUTODETECT; - if (codecContext->codec_type == CODEC_TYPE_VIDEO) { + if (file->fctx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { stream = file->fctx->streams[i]; - stream->discard = AVDISCARD_NONKEY; streamN = i; break; } } if (streamN == -1) throw _T("Could not find a video stream"); - - // Find codec - codec = avcodec_find_decoder(codecContext->codec_id); - if (!codec) throw _T("Could not find suitable video decoder"); - - // Open codec - int result = avcodec_open(codecContext, codec); - if (result < 0) throw _T("Failed to open video decoder"); - - // Allocate frame - frame = avcodec_alloc_frame(); } ////////////// // Destructor LAVCKeyFrames::~LAVCKeyFrames() { - if (frame) av_free((void*) frame); - if (codec && codecContext) avcodec_close(codecContext); if (file) file->Release(); } @@ -90,7 +77,10 @@ wxArrayInt LAVCKeyFrames::GetKeyFrames() { wxArrayInt keyframes; AVPacket packet; - int total_frames = stream->duration; + // sanity check stream duration + if (stream->duration == AV_NOPTS_VALUE) + throw _T("ffmpeg keyframes reader: demuxer returned invalid stream length"); + int total_frames = stream->duration; // FIXME: this will most likely NOT WORK for VFR files! register unsigned int frameN = 0; // Number of parsed frames volatile bool canceled = false; @@ -110,21 +100,12 @@ wxArrayInt LAVCKeyFrames::GetKeyFrames() { if ((frameN & (1024 - 1)) == 0) progress->SetProgress(frameN,total_frames); - // Decode frame - int frameFinished; - avcodec_decode_video(codecContext, frame, &frameFinished, packet.data, packet.size); - - // Success? - if(frameFinished) { - if (frame->key_frame) - // Aegisub starts counting at frame 0, so the result must be - // parsed frames - 1 - keyframes.Add(frameN - 1); - - // Free packet - av_free_packet(&packet); - } + // Aegisub starts counting at frame 0, so the result must be + // parsed frames - 1 + if (packet.flags == PKT_FLAG_KEY) + keyframes.Add(frameN - 1); } + av_free_packet(&packet); } // Clean up progress diff --git a/aegisub/lavc_keyframes.h b/aegisub/lavc_keyframes.h index 2844b7f25..6aa36e10b 100644 --- a/aegisub/lavc_keyframes.h +++ b/aegisub/lavc_keyframes.h @@ -41,10 +41,7 @@ class LAVCKeyFrames { private: LAVCFile* file; // Video file - AVCodecContext* codecContext; // Codec context - AVCodec* codec; // Used codec AVStream* stream; // Used stream - AVFrame* frame; // Frame buffer int streamN; // Stream index public: diff --git a/aegisub/video_context.cpp b/aegisub/video_context.cpp index 0a34de4ee..523bc439a 100644 --- a/aegisub/video_context.cpp +++ b/aegisub/video_context.cpp @@ -63,11 +63,14 @@ #include "subs_grid.h" #include "vfw_wrap.h" -#if !defined(__WINDOWS__) #ifdef WITH_FFMPEG +#ifdef WIN32 +#define __STDC_CONSTANT_MACROS 1 +#include +#endif /* WIN32 */ #include "lavc_keyframes.h" #endif -#endif + #include "mkv_wrap.h" #include "options.h" #include "subs_edit_box.h" @@ -288,22 +291,28 @@ void VideoContext::SetVideo(const wxString &filename) { // Close mkv MatroskaWrapper::wrapper.Close(); } - - else if (ext == _T(".avi")) { +// do we have ffmpeg? if so try to load keyframes with it +#ifdef WITH_FFMPEG + else { keyFramesLoaded = false; KeyFrames.Clear(); -#ifdef __WINDOWS__ - KeyFrames = VFWWrapper::GetKeyFrames(filename); - keyFramesLoaded = true; -#else -#ifdef WITH_FFMPEG LAVCKeyFrames k(filename.c_str()); KeyFrames = k.GetKeyFrames(); keyFramesLoaded = true; -#endif -#endif } - +#else +// no ffmpeg, check if we have windows, if so we can load keyframes +// from AVI files using VFW +#ifdef __WINDOWS__ + else if (ext == _T(".avi")) { + keyFramesLoaded = false; + KeyFrames.Clear(); + KeyFrames = VFWWrapper::GetKeyFrames(filename); + keyFramesLoaded = true; + } +#endif +#endif + // Check if the file is all keyframes bool isAllKeyFrames = true; for (unsigned int i=1; i