Originally committed to SVN as r175.

This commit is contained in:
Rodrigo Braz Monteiro 2006-02-25 20:48:32 +00:00
parent 202c0a2222
commit 817f13bbc7
8 changed files with 116 additions and 55 deletions

View File

@ -41,6 +41,11 @@
#include "dialog_progress.h" #include "dialog_progress.h"
////////////
// Instance
MatroskaWrapper MatroskaWrapper::wrapper;
/////////// ///////////
// Defines // Defines
#define CACHESIZE 65536 #define CACHESIZE 65536
@ -120,6 +125,7 @@ bool operator < (MkvFrame &t1, MkvFrame &t2) {
void MatroskaWrapper::Parse() { void MatroskaWrapper::Parse() {
// Clear keyframes and timecodes // Clear keyframes and timecodes
keyFrames.Clear(); keyFrames.Clear();
bytePos.Clear();
timecodes.clear(); timecodes.clear();
std::list<MkvFrame> frames; std::list<MkvFrame> frames;
@ -157,7 +163,7 @@ void MatroskaWrapper::Parse() {
while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) { while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) {
// Read value // Read value
double curTime = double(startTime) / 1000000.0; double curTime = double(startTime) / 1000000.0;
frames.push_back(MkvFrame((frameFlags & FRAME_KF) != 0,curTime)); frames.push_back(MkvFrame((frameFlags & FRAME_KF) != 0,curTime,filePos));
frameN++; frameN++;
// Cancelled? // Cancelled?
@ -179,11 +185,12 @@ void MatroskaWrapper::Parse() {
// Process timecodes and keyframes // Process timecodes and keyframes
frames.sort(); frames.sort();
MkvFrame curFrame(false,0); MkvFrame curFrame(false,0,0);
int i = 0; int i = 0;
for (std::list<MkvFrame>::iterator cur=frames.begin();cur!=frames.end();cur++) { for (std::list<MkvFrame>::iterator cur=frames.begin();cur!=frames.end();cur++) {
curFrame = *cur; curFrame = *cur;
if (curFrame.isKey) keyFrames.Add(i); if (curFrame.isKey) keyFrames.Add(i);
bytePos.Add(curFrame.filePos);
timecodes.push_back(curFrame.time); timecodes.push_back(curFrame.time);
i++; i++;
} }

View File

@ -62,10 +62,12 @@ class MkvFrame {
public: public:
double time; double time;
bool isKey; bool isKey;
__int64 filePos;
MkvFrame(bool keyframe,double timecode) { MkvFrame(bool keyframe,double timecode,__int64 _filePos) {
isKey = keyframe; isKey = keyframe;
time = timecode; time = timecode;
filePos = _filePos;
} }
}; };
@ -80,6 +82,7 @@ private:
MkvStdIO *input; MkvStdIO *input;
wxArrayInt keyFrames; wxArrayInt keyFrames;
std::vector<double> timecodes; std::vector<double> timecodes;
wxArrayInt bytePos;
void Parse(); void Parse();
@ -87,8 +90,14 @@ public:
MatroskaWrapper(); MatroskaWrapper();
~MatroskaWrapper(); ~MatroskaWrapper();
bool IsOpen() { return file != NULL; }
void Open(wxString filename); void Open(wxString filename);
void Close(); void Close();
void SetToTimecodes(FrameRate &target); void SetToTimecodes(FrameRate &target);
wxArrayInt GetBytePositions() { return bytePos; }
unsigned int GetFrameCount() { return timecodes.size(); }
wxArrayInt GetKeyFrames(); wxArrayInt GetKeyFrames();
static MatroskaWrapper wrapper;
}; };

View File

@ -140,53 +140,47 @@ void VideoDisplay::UpdateSize() {
// Sets video filename // Sets video filename
void VideoDisplay::SetVideo(const wxString &filename) { void VideoDisplay::SetVideo(const wxString &filename) {
// Unload video // Unload video
if (filename.IsEmpty()) { delete provider;
delete provider; provider = NULL;
provider = NULL; if (VFR_Output.GetFrameRateType() == VFR) VFR_Output.Unload();
if (VFR_Output.GetFrameRateType() == VFR) VFR_Output.Unload(); VFR_Input.Unload();
VFR_Input.Unload(); videoName = _T("");
loaded = false;
videoName = _T(""); frame_n = 0;
Reset();
frame_n = 0;
Reset();
}
// Load video // Load video
else { if (!filename.IsEmpty()) {
SetVideo(_T(""));
try { try {
grid->CommitChanges(true); grid->CommitChanges(true);
// Choose a provider // Choose a provider
bool usedDirectshow = false;
provider = VideoProvider::GetProvider(filename,GetTempWorkFile()); provider = VideoProvider::GetProvider(filename,GetTempWorkFile());
provider->SetZoom(zoomValue); provider->SetZoom(zoomValue);
provider->SetDAR(GetARFromType(arType)); provider->SetDAR(GetARFromType(arType));
// Set keyframes // Read extra data from file
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
wxString ext = filename.Right(4).Lower(); wxString ext = filename.Right(4).Lower();
if (ext == _T(".avi")) KeyFrames = VFWWrapper::GetKeyFrames(filename); KeyFrames.Clear();
else if (ext == _T(".mkv")) { if (ext == _T(".mkv") || mkvOpen) {
// Parse mkv // Parse mkv
MatroskaWrapper mkvwrap; if (!mkvOpen) MatroskaWrapper::wrapper.Open(filename);
mkvwrap.Open(filename);
// Get keyframes // Get keyframes
KeyFrames = mkvwrap.GetKeyFrames(); KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
// Ask to override timecodes // Ask to override timecodes
int override = wxYES; int override = wxYES;
if (VFR_Output.GetFrameRateType() == VFR) override = wxMessageBox(_T("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_T("Replace timecodes?"),wxYES_NO | wxICON_QUESTION); if (VFR_Output.GetFrameRateType() == VFR) override = wxMessageBox(_T("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_T("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
if (override == wxYES) mkvwrap.SetToTimecodes(VFR_Output); if (override == wxYES) MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
// Close mkv // Close mkv
mkvwrap.Close(); MatroskaWrapper::wrapper.Close();
} }
else KeyFrames.Clear(); else if (ext == _T(".avi")) KeyFrames = VFWWrapper::GetKeyFrames(filename);
// Update size
UpdateSize(); UpdateSize();
//Gather video parameters //Gather video parameters
@ -214,7 +208,6 @@ void VideoDisplay::SetVideo(const wxString &filename) {
} }
loaded = provider != NULL; loaded = provider != NULL;
} }
////////// //////////

View File

@ -64,31 +64,43 @@ VideoProvider *VideoProvider::GetProvider(wxString video,wxString subtitles) {
// See if it's OK to use LAVC // See if it's OK to use LAVC
#ifdef USE_LAVC #ifdef USE_LAVC
if (preffered == _T("ffmpeg")) { if (preffered == _T("ffmpeg")) {
// Load
bool success = false;
wxString error;
try { try {
provider = new LAVCVideoProvider(video,subtitles); provider = new LAVCVideoProvider(video,subtitles);
success = true;
}
// Catch error
catch (wchar_t *err) {
error = err;
} }
catch (...) { catch (...) {
error = _T("Unhandled exception.");
}
if (!success) {
// Delete old provider // Delete old provider
delete provider; delete provider;
// Try to fallback to avisynth // Try to fallback to avisynth
if (avisynthAvailable) { if (avisynthAvailable) {
wxMessageBox(_T("Failed loading FFmpeg decoder for video, falling back to Avisynth."),_T("FFmpeg error.")); wxMessageBox(_T("Failed loading FFmpeg decoder for video, falling back to Avisynth.\nError message: ") + error,_T("FFmpeg error."));
provider = NULL; provider = NULL;
} }
// Out of options, rethrow // Out of options, rethrow
else throw; else throw error.c_str();
} }
} }
#endif #endif
// Use avisynth provider // Use avisynth provider
#ifdef __WINDOWS__ #ifdef __WINDOWS__
bool usedDirectshow = false;
if (!provider) { if (!provider) {
try { try {
provider = new AvisynthVideoProvider(video,subtitles,usedDirectshow); provider = new AvisynthVideoProvider(video,subtitles);
} }
catch (...) { catch (...) {
delete provider; delete provider;

View File

@ -43,7 +43,7 @@
#ifdef __WINDOWS__ #ifdef __WINDOWS__
AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfilename, bool &usedDirectshow) { AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfilename) {
bool mpeg2dec3_priority = true; bool mpeg2dec3_priority = true;
RGB32Video = NULL; RGB32Video = NULL;
SubtitledVideo = NULL; SubtitledVideo = NULL;
@ -57,7 +57,7 @@ AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfi
LoadVSFilter(); LoadVSFilter();
RGB32Video = OpenVideo(_filename,usedDirectshow,mpeg2dec3_priority); RGB32Video = OpenVideo(_filename,mpeg2dec3_priority);
dar = GetSourceWidth()/(double)GetSourceHeight(); dar = GetSourceWidth()/(double)GetSourceHeight();
@ -110,11 +110,11 @@ void AvisynthVideoProvider::SetZoom(double _zoom) {
GetFrame(last_fnum,true); GetFrame(last_fnum,true);
} }
PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool &usedDirectshow, bool mpeg2dec3_priority) { PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool mpeg2dec3_priority) {
wxMutexLocker lock(AviSynthMutex); wxMutexLocker lock(AviSynthMutex);
AVSValue script; AVSValue script;
usedDirectshow = false; bool usedDirectshow = false;
wxString extension = _filename.Right(4); wxString extension = _filename.Right(4);
extension.LowerCase(); extension.LowerCase();
@ -161,6 +161,9 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool &usedDirectshow,
// Convert to RGB32 // Convert to RGB32
script = env->Invoke("ConvertToRGB32", script); script = env->Invoke("ConvertToRGB32", script);
// Directshow
if (usedDirectshow) wxMessageBox(_T("Warning! The file is being opened using Avisynth's DirectShowSource, which has unreliable seeking. Frame numbers might not match the real number. PROCEED AT YOUR OWN RISK!"),_T("DirectShowSource warning"),wxICON_EXCLAMATION);
// Cache // Cache
return (env->Invoke("Cache", script)).AsClip(); return (env->Invoke("Cache", script)).AsClip();
} }

View File

@ -76,14 +76,14 @@ private:
PClip SubtitledVideo; PClip SubtitledVideo;
PClip ResizedVideo; PClip ResizedVideo;
PClip OpenVideo(wxString _filename, bool &usedDirectshow, bool mpeg2dec3_priority = true); PClip OpenVideo(wxString _filename, bool mpeg2dec3_priority = true);
PClip ApplySubtitles(wxString _filename, PClip videosource); PClip ApplySubtitles(wxString _filename, PClip videosource);
PClip ApplyDARZoom(double _zoom, double _dar, PClip videosource); PClip ApplyDARZoom(double _zoom, double _dar, PClip videosource);
wxBitmap GetFrame(int n, bool force); wxBitmap GetFrame(int n, bool force);
void LoadVSFilter(); void LoadVSFilter();
public: public:
AvisynthVideoProvider(wxString _filename, wxString _subfilename, bool &usedDirectshow); AvisynthVideoProvider(wxString _filename, wxString _subfilename);
~AvisynthVideoProvider(); ~AvisynthVideoProvider();
void RefreshSubtitles(); void RefreshSubtitles();

View File

@ -41,6 +41,7 @@
#include "video_provider_lavc.h" #include "video_provider_lavc.h"
#include "utils.h" #include "utils.h"
#include "vfr.h" #include "vfr.h"
#include "mkv_wrap.h"
/////////////// ///////////////
@ -121,7 +122,18 @@ void LAVCVideoProvider::LoadVideo(wxString filename) {
if (result < 0) throw _T("Failed to open video decoder"); if (result < 0) throw _T("Failed to open video decoder");
// Check length // Check length
if (stream->duration <= 0) throw _T("Returned invalid stream length"); isVFR = false;
length = stream->duration;
if (length <= 0) {
if (strcmp(formatContext->iformat->name,"matroska") == 0) {
throw _T("FFmpeg fails at seeking Matroska. If you have any idea on how to fix it, Aegisub is open source.");
MatroskaWrapper::wrapper.Open(filename);
length = MatroskaWrapper::wrapper.GetFrameCount();
bytePos = MatroskaWrapper::wrapper.GetBytePositions();
isVFR = true;
}
if (length <= 0) throw _T("Returned invalid stream length");
}
// Set size // Set size
dar = double(GetSourceWidth()) / GetSourceHeight(); dar = double(GetSourceWidth()) / GetSourceHeight();
@ -283,26 +295,47 @@ wxBitmap LAVCVideoProvider::GetFrame(int n) {
// Following frame, just get it // Following frame, just get it
if (n == frameNumber+1) { if (n == frameNumber+1) {
GetNextFrame(); GetNextFrame();
//wxLogMessage(wxString::Format(_T("%i"),lastDecodeTime));
} }
// Needs to seek // Needs to seek
else { else {
// Get seek position // Prepare seek
//__int64 half = __int64(AV_TIME_BASE) * stream->r_frame_rate.den / stream->r_frame_rate.num / 2; __int64 seekTo;
//__int64 seekTo = __int64(n) * AV_TIME_BASE * stream->r_frame_rate.den / stream->r_frame_rate.num + stream->start_time; int result;
//if (seekTo > half) seekTo -= half;
//else seekTo = 0; // Get time to seek to
//__int64 finalPos = av_rescale(seekTo,stream->time_base.den,AV_TIME_BASE * __int64(stream->time_base.num)); if (isVFR) {
//__int64 base = AV_TIME_BASE;
//__int64 time = VFR_Output.GetTimeAtFrame(n,true) * base / 1000000;
//seekTo = av_rescale(time,stream->time_base.den,AV_TIME_BASE * __int64(stream->time_base.num));
//seekTo = __int64(n) * 1000 * stream->r_frame_rate.den / stream->r_frame_rate.num;
seekTo = bytePos[n];
result = av_seek_frame(formatContext,vidStream,seekTo,AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_BYTE);
}
// Constant frame rate
else {
seekTo = n;
result = av_seek_frame(formatContext,vidStream,seekTo,AVSEEK_FLAG_BACKWARD);
}
// Seek to keyframe // Seek to keyframe
int result = av_seek_frame(formatContext,vidStream,n,AVSEEK_FLAG_BACKWARD); if (result == 0) {
avcodec_flush_buffers(codecContext); avcodec_flush_buffers(codecContext);
// Seek until final frame // Seek until final frame
bool ok = true; bool ok = true;
do { do {
ok = GetNextFrame(); ok = GetNextFrame();
} while (lastDecodeTime <= n && ok); } while (lastDecodeTime <= n && ok);
}
// Failed seeking
else {
GetNextFrame();
}
} }
// Bitmap // Bitmap
@ -336,7 +369,7 @@ int LAVCVideoProvider::GetPosition() {
//////////////////////// ////////////////////////
// Get number of frames // Get number of frames
int LAVCVideoProvider::GetFrameCount() { int LAVCVideoProvider::GetFrameCount() {
return stream->duration; return length;
} }

View File

@ -70,8 +70,12 @@ private:
int display_w; int display_w;
int display_h; int display_h;
wxArrayInt bytePos;
bool isVFR;
__int64 lastDecodeTime; __int64 lastDecodeTime;
int frameNumber; int frameNumber;
int length;
wxBitmap curFrame; wxBitmap curFrame;
bool validFrame; bool validFrame;