mirror of https://github.com/odrling/Aegisub
Originally committed to SVN as r175.
This commit is contained in:
parent
202c0a2222
commit
817f13bbc7
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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("");
|
videoName = _T("");
|
||||||
|
loaded = false;
|
||||||
frame_n = 0;
|
frame_n = 0;
|
||||||
|
|
||||||
Reset();
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////
|
//////////
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,19 +295,34 @@ 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
|
||||||
|
@ -305,6 +332,12 @@ wxBitmap LAVCVideoProvider::GetFrame(int n) {
|
||||||
} while (lastDecodeTime <= n && ok);
|
} while (lastDecodeTime <= n && ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Failed seeking
|
||||||
|
else {
|
||||||
|
GetNextFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bitmap
|
// Bitmap
|
||||||
wxBitmap bmp;
|
wxBitmap bmp;
|
||||||
if (frame) bmp = AVFrameToWX(frame);
|
if (frame) bmp = AVFrameToWX(frame);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue