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

View file

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

View file

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

View file

@ -64,31 +64,43 @@ VideoProvider *VideoProvider::GetProvider(wxString video,wxString subtitles) {
// See if it's OK to use LAVC
#ifdef USE_LAVC
if (preffered == _T("ffmpeg")) {
// Load
bool success = false;
wxString error;
try {
provider = new LAVCVideoProvider(video,subtitles);
success = true;
}
// Catch error
catch (wchar_t *err) {
error = err;
}
catch (...) {
error = _T("Unhandled exception.");
}
if (!success) {
// Delete old provider
delete provider;
// Try to fallback to avisynth
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;
}
// Out of options, rethrow
else throw;
else throw error.c_str();
}
}
#endif
// Use avisynth provider
#ifdef __WINDOWS__
bool usedDirectshow = false;
if (!provider) {
try {
provider = new AvisynthVideoProvider(video,subtitles,usedDirectshow);
provider = new AvisynthVideoProvider(video,subtitles);
}
catch (...) {
delete provider;

View file

@ -43,7 +43,7 @@
#ifdef __WINDOWS__
AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfilename, bool &usedDirectshow) {
AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfilename) {
bool mpeg2dec3_priority = true;
RGB32Video = NULL;
SubtitledVideo = NULL;
@ -57,7 +57,7 @@ AvisynthVideoProvider::AvisynthVideoProvider(wxString _filename, wxString _subfi
LoadVSFilter();
RGB32Video = OpenVideo(_filename,usedDirectshow,mpeg2dec3_priority);
RGB32Video = OpenVideo(_filename,mpeg2dec3_priority);
dar = GetSourceWidth()/(double)GetSourceHeight();
@ -110,11 +110,11 @@ void AvisynthVideoProvider::SetZoom(double _zoom) {
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);
AVSValue script;
usedDirectshow = false;
bool usedDirectshow = false;
wxString extension = _filename.Right(4);
extension.LowerCase();
@ -161,6 +161,9 @@ PClip AvisynthVideoProvider::OpenVideo(wxString _filename, bool &usedDirectshow,
// Convert to RGB32
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
return (env->Invoke("Cache", script)).AsClip();
}

View file

@ -76,14 +76,14 @@ private:
PClip SubtitledVideo;
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 ApplyDARZoom(double _zoom, double _dar, PClip videosource);
wxBitmap GetFrame(int n, bool force);
void LoadVSFilter();
public:
AvisynthVideoProvider(wxString _filename, wxString _subfilename, bool &usedDirectshow);
AvisynthVideoProvider(wxString _filename, wxString _subfilename);
~AvisynthVideoProvider();
void RefreshSubtitles();

View file

@ -41,6 +41,7 @@
#include "video_provider_lavc.h"
#include "utils.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");
// 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
dar = double(GetSourceWidth()) / GetSourceHeight();
@ -283,26 +295,47 @@ wxBitmap LAVCVideoProvider::GetFrame(int n) {
// Following frame, just get it
if (n == frameNumber+1) {
GetNextFrame();
//wxLogMessage(wxString::Format(_T("%i"),lastDecodeTime));
}
// Needs to seek
else {
// Get seek position
//__int64 half = __int64(AV_TIME_BASE) * stream->r_frame_rate.den / stream->r_frame_rate.num / 2;
//__int64 seekTo = __int64(n) * AV_TIME_BASE * stream->r_frame_rate.den / stream->r_frame_rate.num + stream->start_time;
//if (seekTo > half) seekTo -= half;
//else seekTo = 0;
//__int64 finalPos = av_rescale(seekTo,stream->time_base.den,AV_TIME_BASE * __int64(stream->time_base.num));
// Prepare seek
__int64 seekTo;
int result;
// Get time to seek to
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
int result = av_seek_frame(formatContext,vidStream,n,AVSEEK_FLAG_BACKWARD);
avcodec_flush_buffers(codecContext);
if (result == 0) {
avcodec_flush_buffers(codecContext);
// Seek until final frame
bool ok = true;
do {
ok = GetNextFrame();
} while (lastDecodeTime <= n && ok);
// Seek until final frame
bool ok = true;
do {
ok = GetNextFrame();
} while (lastDecodeTime <= n && ok);
}
// Failed seeking
else {
GetNextFrame();
}
}
// Bitmap
@ -336,7 +369,7 @@ int LAVCVideoProvider::GetPosition() {
////////////////////////
// Get number of frames
int LAVCVideoProvider::GetFrameCount() {
return stream->duration;
return length;
}

View file

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