Originally committed to SVN as r175.
This commit is contained in:
parent
202c0a2222
commit
817f13bbc7
8 changed files with 116 additions and 55 deletions
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
//////////
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue