forked from mia/Aegisub
Delete all the unused things in MatroskaWrapper (i.e. most of it), fix some derpy things, and make it throw typed exceptions.
Originally committed to SVN as r5632.
This commit is contained in:
parent
2ca9392942
commit
f341a63f14
3 changed files with 137 additions and 501 deletions
|
@ -38,6 +38,8 @@
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
@ -47,249 +49,79 @@
|
||||||
#include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
|
#include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ass_file.h"
|
|
||||||
#include "ass_time.h"
|
|
||||||
#include "dialog_progress.h"
|
|
||||||
#include <libaegisub/vfr.h>
|
|
||||||
#include "mkv_wrap.h"
|
#include "mkv_wrap.h"
|
||||||
|
|
||||||
/// DOCME
|
#include "ass_file.h"
|
||||||
MatroskaWrapper MatroskaWrapper::wrapper;
|
#include "ass_time.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "dialog_progress.h"
|
||||||
|
#include "MatroskaParser.h"
|
||||||
|
|
||||||
/// DOCME
|
class MkvStdIO : public InputStream {
|
||||||
#define CACHESIZE 65536
|
public:
|
||||||
|
MkvStdIO(wxString filename);
|
||||||
|
~MkvStdIO() { if (fp) fclose(fp); }
|
||||||
|
|
||||||
/// @brief Constructor
|
FILE *fp;
|
||||||
///
|
int error;
|
||||||
MatroskaWrapper::MatroskaWrapper() {
|
};
|
||||||
file = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Destructor
|
#define CACHESIZE 65536
|
||||||
///
|
|
||||||
MatroskaWrapper::~MatroskaWrapper() {
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Open file
|
void MatroskaWrapper::GetSubtitles(wxString const& filename, AssFile *target) {
|
||||||
/// @param filename
|
MkvStdIO input(filename);
|
||||||
/// @param parse
|
|
||||||
///
|
|
||||||
void MatroskaWrapper::Open(wxString filename,bool parse) {
|
|
||||||
// Make sure it's closed first
|
|
||||||
Close();
|
|
||||||
|
|
||||||
// Open
|
|
||||||
char err[2048];
|
char err[2048];
|
||||||
input = new MkvStdIO(filename);
|
MatroskaFile *file = mkv_Open(&input, err, sizeof(err));
|
||||||
if (input->fp) {
|
if (!file) throw MatroskaException(err);
|
||||||
file = mkv_Open(input,err,sizeof(err));
|
|
||||||
|
|
||||||
// Failed parsing
|
try {
|
||||||
if (!file) {
|
// Get info
|
||||||
delete input;
|
unsigned tracks = mkv_GetNumTracks(file);
|
||||||
throw wxString("MatroskaParser error: " + wxString(err,wxConvUTF8));
|
TrackInfo *trackInfo;
|
||||||
}
|
std::vector<unsigned> tracksFound;
|
||||||
|
wxArrayString tracksNames;
|
||||||
|
unsigned trackToRead;
|
||||||
|
|
||||||
// Parse
|
// Haali's library variables
|
||||||
if (parse) Parse();
|
ulonglong startTime, endTime, filePos;
|
||||||
}
|
unsigned int rt, frameSize, frameFlags;
|
||||||
|
|
||||||
// Failed opening
|
// Find tracks
|
||||||
else {
|
for (unsigned track = 0; track < tracks; track++) {
|
||||||
delete input;
|
trackInfo = mkv_GetTrackInfo(file,track);
|
||||||
throw "Unable to open Matroska file for parsing.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Close file
|
// Subtitle track
|
||||||
/// @return
|
if (trackInfo->Type == 0x11) {
|
||||||
///
|
wxString CodecID = wxString(trackInfo->CodecID,*wxConvCurrent);
|
||||||
void MatroskaWrapper::Close() {
|
wxString TrackName = wxString(trackInfo->Name,*wxConvCurrent);
|
||||||
if (file) {
|
wxString TrackLanguage = wxString(trackInfo->Language,*wxConvCurrent);
|
||||||
mkv_Close(file);
|
|
||||||
file = NULL;
|
// Known subtitle format
|
||||||
delete input;
|
if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") {
|
||||||
}
|
tracksFound.push_back(track);
|
||||||
keyFrames.clear();
|
tracksNames.Add(wxString::Format("%d (%s %s): %s", track, CodecID, TrackLanguage, TrackName));
|
||||||
timecodes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Return keyframes
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
std::vector<int> MatroskaWrapper::GetKeyFrames() {
|
|
||||||
return keyFrames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Comparison operator
|
|
||||||
/// @param t1
|
|
||||||
/// @param t2
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool operator < (MkvFrame &t1, MkvFrame &t2) {
|
|
||||||
return t1.time < t2.time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Actually parse
|
|
||||||
///
|
|
||||||
void MatroskaWrapper::Parse() {
|
|
||||||
// Clear keyframes and timecodes
|
|
||||||
keyFrames.clear();
|
|
||||||
bytePos.Clear();
|
|
||||||
timecodes.clear();
|
|
||||||
frames.clear();
|
|
||||||
rawFrames.clear();
|
|
||||||
bytePos.Clear();
|
|
||||||
|
|
||||||
// Get info
|
|
||||||
int tracks = mkv_GetNumTracks(file);
|
|
||||||
TrackInfo *trackInfo;
|
|
||||||
SegmentInfo *segInfo = mkv_GetFileInfo(file);
|
|
||||||
|
|
||||||
// Parse tracks
|
|
||||||
for (int track=0;track<tracks;track++) {
|
|
||||||
trackInfo = mkv_GetTrackInfo(file,track);
|
|
||||||
|
|
||||||
// Video track
|
|
||||||
if (trackInfo->Type == 1) {
|
|
||||||
// Variables
|
|
||||||
ulonglong startTime, endTime, filePos;
|
|
||||||
unsigned int rt, frameSize, frameFlags;
|
|
||||||
//CompressedStream *cs = NULL;
|
|
||||||
|
|
||||||
// Timecode scale
|
|
||||||
longlong timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;
|
|
||||||
|
|
||||||
// Mask other tracks away
|
|
||||||
mkv_SetTrackMask(file, ~(1 << track));
|
|
||||||
|
|
||||||
// Progress bar
|
|
||||||
int totalTime = int(double(segInfo->Duration) / timecodeScale);
|
|
||||||
volatile bool canceled = false;
|
|
||||||
DialogProgress *progress = new DialogProgress(NULL,_("Parsing Matroska"),&canceled,_("Reading keyframe and timecode data from Matroska file."),0,totalTime);
|
|
||||||
progress->Show();
|
|
||||||
progress->SetProgress(0,1);
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
register int frameN = 0;
|
|
||||||
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,filePos));
|
|
||||||
frameN++;
|
|
||||||
|
|
||||||
// Cancelled?
|
|
||||||
if (canceled) {
|
|
||||||
Close();
|
|
||||||
throw agi::UserCancelException("Canceled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identical to (frameN % 2048) == 0,
|
|
||||||
// but much faster.
|
|
||||||
if ((frameN & (2048 - 1)) == 0)
|
|
||||||
// Update progress
|
|
||||||
progress->SetProgress(int(curTime),totalTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up progress
|
|
||||||
if (!canceled) progress->Destroy();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rawFrames.reserve(frames.size());
|
|
||||||
std::copy(frames.begin(), frames.end(), std::back_inserter(rawFrames));
|
|
||||||
|
|
||||||
// Process timecodes and keyframes
|
|
||||||
frames.sort();
|
|
||||||
int i = 0;
|
|
||||||
for (std::list<MkvFrame>::iterator cur=frames.begin();cur!=frames.end();cur++) {
|
|
||||||
if (cur->isKey) keyFrames.push_back(i);
|
|
||||||
bytePos.Add(cur->filePos);
|
|
||||||
timecodes.push_back(cur->time);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mkv_round(double num) {
|
|
||||||
return (int)(num + .5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Set target to timecodes
|
|
||||||
/// @param target
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void MatroskaWrapper::SetToTimecodes(agi::vfr::Framerate &target) {
|
|
||||||
if (timecodes.size() <= 1) return;
|
|
||||||
|
|
||||||
std::vector<int> times;
|
|
||||||
times.reserve(timecodes.size());
|
|
||||||
std::transform(timecodes.begin(), timecodes.end(), std::back_inserter(times), &mkv_round);
|
|
||||||
target = agi::vfr::Framerate(times);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Get subtitles
|
|
||||||
/// @param target
|
|
||||||
///
|
|
||||||
void MatroskaWrapper::GetSubtitles(AssFile *target) {
|
|
||||||
// Get info
|
|
||||||
int tracks = mkv_GetNumTracks(file);
|
|
||||||
TrackInfo *trackInfo;
|
|
||||||
//SegmentInfo *segInfo = mkv_GetFileInfo(file);
|
|
||||||
wxArrayInt tracksFound;
|
|
||||||
wxArrayString tracksNames;
|
|
||||||
int trackToRead = -1;
|
|
||||||
|
|
||||||
// Haali's library variables
|
|
||||||
ulonglong startTime, endTime, filePos;
|
|
||||||
unsigned int rt, frameSize, frameFlags;
|
|
||||||
//CompressedStream *cs = NULL;
|
|
||||||
|
|
||||||
// Find tracks
|
|
||||||
for (int track=0;track<tracks;track++) {
|
|
||||||
trackInfo = mkv_GetTrackInfo(file,track);
|
|
||||||
|
|
||||||
// Subtitle track
|
|
||||||
if (trackInfo->Type == 0x11) {
|
|
||||||
wxString CodecID = wxString(trackInfo->CodecID,*wxConvCurrent);
|
|
||||||
wxString TrackName = wxString(trackInfo->Name,*wxConvCurrent);
|
|
||||||
wxString TrackLanguage = wxString(trackInfo->Language,*wxConvCurrent);
|
|
||||||
|
|
||||||
// Known subtitle format
|
|
||||||
if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") {
|
|
||||||
tracksFound.Add(track);
|
|
||||||
tracksNames.Add(wxString::Format("%i (",track) + CodecID + " " + TrackLanguage + "): " + TrackName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// No tracks found
|
// No tracks found
|
||||||
if (tracksFound.Count() == 0) {
|
if (tracksFound.empty())
|
||||||
target->LoadDefault(true);
|
throw MatroskaException("File has no recognised subtitle tracks.");
|
||||||
Close();
|
|
||||||
throw "File has no recognised subtitle tracks.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only one track found
|
// Only one track found
|
||||||
else if (tracksFound.Count() == 1) {
|
if (tracksFound.size() == 1) {
|
||||||
trackToRead = tracksFound[0];
|
trackToRead = tracksFound[0];
|
||||||
}
|
|
||||||
|
|
||||||
// Pick a track
|
|
||||||
else {
|
|
||||||
int choice = wxGetSingleChoiceIndex("Choose which track to read:","Multiple subtitle tracks found",tracksNames);
|
|
||||||
if (choice == -1) {
|
|
||||||
target->LoadDefault(true);
|
|
||||||
Close();
|
|
||||||
throw agi::UserCancelException("cancelled");
|
|
||||||
}
|
}
|
||||||
trackToRead = tracksFound[choice];
|
// Pick a track
|
||||||
}
|
else {
|
||||||
|
int choice = wxGetSingleChoiceIndex(_("Choose which track to read:"), _("Multiple subtitle tracks found"), tracksNames);
|
||||||
|
if (choice == -1)
|
||||||
|
throw agi::UserCancelException("cancelled");
|
||||||
|
|
||||||
// Picked track
|
trackToRead = tracksFound[choice];
|
||||||
if (trackToRead != -1) {
|
}
|
||||||
|
|
||||||
|
// Picked track
|
||||||
// Get codec type (0 = ASS/SSA, 1 = SRT)
|
// Get codec type (0 = ASS/SSA, 1 = SRT)
|
||||||
trackInfo = mkv_GetTrackInfo(file,trackToRead);
|
trackInfo = mkv_GetTrackInfo(file,trackToRead);
|
||||||
wxString CodecID = wxString(trackInfo->CodecID,*wxConvCurrent);
|
wxString CodecID = wxString(trackInfo->CodecID,*wxConvCurrent);
|
||||||
|
@ -300,12 +132,7 @@ void MatroskaWrapper::GetSubtitles(AssFile *target) {
|
||||||
if (codecType == 0) {
|
if (codecType == 0) {
|
||||||
// Read raw data
|
// Read raw data
|
||||||
trackInfo = mkv_GetTrackInfo(file,trackToRead);
|
trackInfo = mkv_GetTrackInfo(file,trackToRead);
|
||||||
unsigned int privSize = trackInfo->CodecPrivateSize;
|
wxString privString((const char *)trackInfo->CodecPrivate, wxConvUTF8, trackInfo->CodecPrivateSize);
|
||||||
char *privData = new char[privSize+1];
|
|
||||||
memcpy(privData,trackInfo->CodecPrivate,privSize);
|
|
||||||
privData[privSize] = 0;
|
|
||||||
wxString privString(privData,wxConvUTF8);
|
|
||||||
delete[] privData;
|
|
||||||
|
|
||||||
// Load into file
|
// Load into file
|
||||||
wxString group = "[Script Info]";
|
wxString group = "[Script Info]";
|
||||||
|
@ -317,13 +144,7 @@ void MatroskaWrapper::GetSubtitles(AssFile *target) {
|
||||||
if (next[0] == '[') group = next;
|
if (next[0] == '[') group = next;
|
||||||
target->AddLine(next,group,version,&group);
|
target->AddLine(next,group,version,&group);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert "[Events]"
|
|
||||||
//target->AddLine("",group,lasttime,version,&group);
|
|
||||||
//target->AddLine("[Events]",group,lasttime,version,&group);
|
|
||||||
//target->AddLine("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text",group,lasttime,version,&group);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load default if it's SRT
|
// Load default if it's SRT
|
||||||
else {
|
else {
|
||||||
target->LoadDefault(false);
|
target->LoadDefault(false);
|
||||||
|
@ -333,10 +154,6 @@ void MatroskaWrapper::GetSubtitles(AssFile *target) {
|
||||||
SegmentInfo *segInfo = mkv_GetFileInfo(file);
|
SegmentInfo *segInfo = mkv_GetFileInfo(file);
|
||||||
longlong timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;
|
longlong timecodeScale = mkv_TruncFloat(trackInfo->TimecodeScale) * segInfo->TimecodeScale;
|
||||||
|
|
||||||
// Prepare STD vector to get lines inserted
|
|
||||||
std::vector<wxString> subList;
|
|
||||||
long int order = -1;
|
|
||||||
|
|
||||||
// Progress bar
|
// Progress bar
|
||||||
int totalTime = int(double(segInfo->Duration) / timecodeScale);
|
int totalTime = int(double(segInfo->Duration) / timecodeScale);
|
||||||
volatile bool canceled = false;
|
volatile bool canceled = false;
|
||||||
|
@ -344,155 +161,120 @@ void MatroskaWrapper::GetSubtitles(AssFile *target) {
|
||||||
progress->Show();
|
progress->Show();
|
||||||
progress->SetProgress(0,1);
|
progress->SetProgress(0,1);
|
||||||
|
|
||||||
|
std::map<int, wxString> subList;
|
||||||
|
char *readBuf = 0;
|
||||||
|
size_t readBufSize = 0;
|
||||||
|
|
||||||
// Load blocks
|
// Load blocks
|
||||||
mkv_SetTrackMask(file, ~(1 << trackToRead));
|
mkv_SetTrackMask(file, ~(1 << trackToRead));
|
||||||
while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) {
|
while (mkv_ReadFrame(file,0,&rt,&startTime,&endTime,&filePos,&frameSize,&frameFlags) == 0) {
|
||||||
// Canceled
|
|
||||||
if (canceled) {
|
if (canceled) {
|
||||||
target->LoadDefault(true);
|
delete readBuf;
|
||||||
Close();
|
|
||||||
throw agi::UserCancelException("cancelled");
|
throw agi::UserCancelException("cancelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read to temp
|
// Read to temp
|
||||||
char *tmp = new char[frameSize+1];
|
if (frameSize > readBufSize) {
|
||||||
fseek(input->fp, filePos, SEEK_SET);
|
delete readBuf;
|
||||||
fread(tmp,1,frameSize,input->fp);
|
readBufSize = frameSize * 2;
|
||||||
tmp[frameSize] = 0;
|
readBuf = new char[readBufSize];
|
||||||
wxString blockString(tmp,wxConvUTF8);
|
}
|
||||||
delete[] tmp;
|
|
||||||
|
fseek(input.fp, filePos, SEEK_SET);
|
||||||
|
fread(readBuf, 1, frameSize, input.fp);
|
||||||
|
wxString blockString(readBuf, wxConvUTF8, frameSize);
|
||||||
|
|
||||||
// Get start and end times
|
// Get start and end times
|
||||||
//longlong timecodeScaleLow = timecodeScale / 100;
|
|
||||||
longlong timecodeScaleLow = 1000000;
|
longlong timecodeScaleLow = 1000000;
|
||||||
AssTime subStart,subEnd;
|
AssTime subStart,subEnd;
|
||||||
subStart.SetMS(startTime / timecodeScaleLow);
|
subStart.SetMS(startTime / timecodeScaleLow);
|
||||||
subEnd.SetMS(endTime / timecodeScaleLow);
|
subEnd.SetMS(endTime / timecodeScaleLow);
|
||||||
//wxLogMessage(subStart.GetASSFormated() + "-" + subEnd.GetASSFormated() + ": " + blockString);
|
|
||||||
|
|
||||||
// Process SSA/ASS
|
// Process SSA/ASS
|
||||||
if (codecType == 0) {
|
if (codecType == 0) {
|
||||||
// Get order number
|
long order = 0, layer = 0;
|
||||||
int pos = blockString.Find(",");
|
blockString.BeforeFirst(',', &blockString).ToLong(&order);
|
||||||
wxString orderString = blockString.Left(pos);
|
blockString.BeforeFirst(',', &blockString).ToLong(&layer);
|
||||||
orderString.ToLong(&order);
|
|
||||||
blockString = blockString.Mid(pos+1);
|
|
||||||
|
|
||||||
// Get layer number
|
subList[order] = wxString::Format("Dialogue: %d,%s,%s,%s", layer, subStart.GetASSFormated(), subEnd.GetASSFormated(), blockString);
|
||||||
pos = blockString.Find(",");
|
|
||||||
long int layer = 0;
|
|
||||||
if (pos) {
|
|
||||||
wxString layerString = blockString.Left(pos);
|
|
||||||
layerString.ToLong(&layer);
|
|
||||||
blockString = blockString.Mid(pos+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble final
|
|
||||||
blockString = wxString::Format("Dialogue: %i,",layer) + subStart.GetASSFormated() + "," + subEnd.GetASSFormated() + "," + blockString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process SRT
|
// Process SRT
|
||||||
else {
|
else {
|
||||||
blockString = wxString("Dialogue: 0,") + subStart.GetASSFormated() + "," + subEnd.GetASSFormated() + ",Default,,0000,0000,0000,," + blockString;
|
blockString = wxString::Format("Dialogue: 0,%s,%s,%s", subStart.GetASSFormated(), subEnd.GetASSFormated(), blockString);
|
||||||
blockString.Replace("\r\n","\\N");
|
blockString.Replace("\r\n","\\N");
|
||||||
blockString.Replace("\r","\\N");
|
blockString.Replace("\r","\\N");
|
||||||
blockString.Replace("\n","\\N");
|
blockString.Replace("\n","\\N");
|
||||||
order++;
|
|
||||||
|
subList[subList.size()] = blockString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert into vector
|
|
||||||
if (subList.size() == (unsigned int)order) subList.push_back(blockString);
|
|
||||||
else {
|
|
||||||
if ((signed)(subList.size()) < order+1) subList.resize(order+1);
|
|
||||||
subList[order] = blockString;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update progress bar
|
|
||||||
progress->SetProgress(int(double(startTime) / 1000000.0),totalTime);
|
progress->SetProgress(int(double(startTime) / 1000000.0),totalTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete readBuf;
|
||||||
|
|
||||||
// Insert into file
|
// Insert into file
|
||||||
wxString group = "[Events]";
|
wxString group = "[Events]";
|
||||||
int version = (CodecID == "S_TEXT/SSA");
|
int version = (CodecID == "S_TEXT/SSA");
|
||||||
for (unsigned int i=0;i<subList.size();i++) {
|
for (std::map<int, wxString>::iterator it = subList.begin(); it != subList.end(); ++it) {
|
||||||
target->AddLine(subList[i],group,version,&group);
|
target->AddLine(it->second,group,version,&group);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close progress bar
|
// Close progress bar
|
||||||
if (!canceled) progress->Destroy();
|
if (!canceled) progress->Destroy();
|
||||||
}
|
}
|
||||||
|
catch (...) {
|
||||||
// No track to load
|
mkv_Close(file);
|
||||||
else {
|
throw;
|
||||||
target->LoadDefault(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MatroskaWrapper::HasSubtitles(wxString const& filename) {
|
bool MatroskaWrapper::HasSubtitles(wxString const& filename) {
|
||||||
char err[2048];
|
char err[2048];
|
||||||
MkvStdIO input(filename);
|
try {
|
||||||
if (!input.fp) return false;
|
MkvStdIO input(filename);
|
||||||
|
MatroskaFile* file = mkv_Open(&input, err, sizeof(err));
|
||||||
|
if (!file) return false;
|
||||||
|
|
||||||
MatroskaFile* file = mkv_Open(&input, err, sizeof(err));
|
// Find tracks
|
||||||
if (!file) return false;
|
int tracks = mkv_GetNumTracks(file);
|
||||||
|
for (int track = 0; track < tracks; track++) {
|
||||||
|
TrackInfo *trackInfo = mkv_GetTrackInfo(file, track);
|
||||||
|
|
||||||
// Find tracks
|
if (trackInfo->Type == 0x11) {
|
||||||
int tracks = mkv_GetNumTracks(file);
|
wxString CodecID = wxString(trackInfo->CodecID, *wxConvCurrent);
|
||||||
for (int track = 0; track < tracks; track++) {
|
if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") {
|
||||||
TrackInfo *trackInfo = mkv_GetTrackInfo(file, track);
|
mkv_Close(file);
|
||||||
|
return true;
|
||||||
if (trackInfo->Type == 0x11) {
|
}
|
||||||
wxString CodecID = wxString(trackInfo->CodecID, *wxConvCurrent);
|
|
||||||
if (CodecID == "S_TEXT/SSA" || CodecID == "S_TEXT/ASS" || CodecID == "S_TEXT/UTF8") {
|
|
||||||
mkv_Close(file);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mkv_Close(file);
|
mkv_Close(file);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// We don't care about why we couldn't read subtitles here
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////// LOTS OF HAALI C CODE DOWN HERE ///////////////////////////////////////
|
|
||||||
|
|
||||||
#ifdef __VISUALC__
|
#ifdef __VISUALC__
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_fread fread
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_fseek _fseeki64
|
#define std_fseek _fseeki64
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_ftell _ftelli64
|
#define std_ftell _ftelli64
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_fread fread
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_fseek fseeko
|
#define std_fseek fseeko
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
#define std_ftell ftello
|
#define std_ftell ftello
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// @brief STDIO class
|
|
||||||
/// @param _st
|
|
||||||
/// @param pos
|
|
||||||
/// @param buffer
|
|
||||||
/// @param count
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int StdIoRead(InputStream *_st, ulonglong pos, void *buffer, int count) {
|
int StdIoRead(InputStream *_st, ulonglong pos, void *buffer, int count) {
|
||||||
MkvStdIO *st = (MkvStdIO *) _st;
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
size_t rd;
|
size_t rd;
|
||||||
if (std_fseek(st->fp, pos, SEEK_SET)) {
|
if (fseek(st->fp, pos, SEEK_SET)) {
|
||||||
st->error = errno;
|
st->error = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
rd = std_fread(buffer, 1, count, st->fp);
|
rd = fread(buffer, 1, count, st->fp);
|
||||||
if (rd == 0) {
|
if (rd == 0) {
|
||||||
if (feof(st->fp))
|
if (feof(st->fp))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -502,15 +284,8 @@ int StdIoRead(InputStream *_st, ulonglong pos, void *buffer, int count) {
|
||||||
return rd;
|
return rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan for a signature sig(big-endian) starting at file position pos
|
/// @brief scan for a signature sig(big-endian) starting at file position pos
|
||||||
* return position of the first byte of signature or -1 if error/not found
|
/// @return position of the first byte of signature or -1 if error/not found
|
||||||
|
|
||||||
/// @brief */
|
|
||||||
/// @param _st
|
|
||||||
/// @param start
|
|
||||||
/// @param signature
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
longlong StdIoScan(InputStream *_st, ulonglong start, unsigned signature) {
|
longlong StdIoScan(InputStream *_st, ulonglong start, unsigned signature) {
|
||||||
MkvStdIO *st = (MkvStdIO *) _st;
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
int c;
|
int c;
|
||||||
|
@ -530,63 +305,32 @@ longlong StdIoScan(InputStream *_st, ulonglong start, unsigned signature) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief This is used to limit readahead.
|
/// @brief This is used to limit readahead.
|
||||||
/// @param _st
|
unsigned StdIoGetCacheSize(InputStream *st) {
|
||||||
/// @return Cache size
|
|
||||||
///
|
|
||||||
unsigned StdIoGetCacheSize(InputStream *_st) {
|
|
||||||
return CACHESIZE;
|
return CACHESIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Get last error message
|
/// @brief Get last error message
|
||||||
/// @param _st
|
const char *StdIoGetLastError(InputStream *st) {
|
||||||
/// @return Last error message
|
return strerror(((MkvStdIO *)st)->error);
|
||||||
///
|
|
||||||
const char *StdIoGetLastError(InputStream *_st) {
|
|
||||||
MkvStdIO *st = (MkvStdIO *) _st;
|
|
||||||
return strerror(st->error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Memory allocation, this is done via stdlib
|
/// @brief Memory allocation, this is done via stdlib
|
||||||
/// @param _st
|
void *StdIoMalloc(InputStream *, size_t size) {
|
||||||
/// @param size
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void *StdIoMalloc(InputStream *_st, size_t size) {
|
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
void *StdIoRealloc(InputStream *, void *mem, size_t size) {
|
||||||
/// @param _st
|
return realloc(mem, size);
|
||||||
/// @param mem
|
|
||||||
/// @param size
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
void *StdIoRealloc(InputStream *_st, void *mem, size_t size) {
|
|
||||||
return realloc(mem,size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
void StdIoFree(InputStream *, void *mem) {
|
||||||
/// @param _st
|
|
||||||
/// @param mem
|
|
||||||
///
|
|
||||||
void StdIoFree(InputStream *_st, void *mem) {
|
|
||||||
free(mem);
|
free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
int StdIoProgress(InputStream *, ulonglong cur, ulonglong max) {
|
||||||
/// @param _st
|
|
||||||
/// @param cur
|
|
||||||
/// @param max
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
int StdIoProgress(InputStream *_st, ulonglong cur, ulonglong max) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param _st
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
longlong StdIoGetFileSize(InputStream *_st) {
|
longlong StdIoGetFileSize(InputStream *_st) {
|
||||||
MkvStdIO *st = (MkvStdIO *) _st;
|
MkvStdIO *st = (MkvStdIO *) _st;
|
||||||
longlong epos = 0;
|
longlong epos = 0;
|
||||||
|
@ -597,9 +341,6 @@ longlong StdIoGetFileSize(InputStream *_st) {
|
||||||
return epos;
|
return epos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param filename
|
|
||||||
///
|
|
||||||
MkvStdIO::MkvStdIO(wxString filename) {
|
MkvStdIO::MkvStdIO(wxString filename) {
|
||||||
read = StdIoRead;
|
read = StdIoRead;
|
||||||
scan = StdIoScan;
|
scan = StdIoScan;
|
||||||
|
@ -610,10 +351,17 @@ MkvStdIO::MkvStdIO(wxString filename) {
|
||||||
memfree = StdIoFree;
|
memfree = StdIoFree;
|
||||||
progress = StdIoProgress;
|
progress = StdIoProgress;
|
||||||
getfilesize = StdIoGetFileSize;
|
getfilesize = StdIoGetFileSize;
|
||||||
|
|
||||||
wxFileName fname(filename);
|
wxFileName fname(filename);
|
||||||
fp = fopen(fname.GetShortPath().mb_str(wxConvUTF8),"rb");
|
#ifdef __VISUALC__
|
||||||
|
fp = _wfopen(fname.GetFullPath().wc_str(), L"rb");
|
||||||
|
#else
|
||||||
|
fp = fopen(fname.GetFullPath().utf8_str(), "rb");
|
||||||
|
#endif
|
||||||
if (fp) {
|
if (fp) {
|
||||||
setvbuf(fp, NULL, _IOFBF, CACHESIZE);
|
setvbuf(fp, NULL, _IOFBF, CACHESIZE);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
throw agi::FileNotFoundError(STD_STR(filename));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,76 +35,14 @@
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
#include <stdint.h>
|
#include <wx/string.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <wx/dynarray.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "MatroskaParser.h"
|
#include <libaegisub/exception.h>
|
||||||
|
|
||||||
|
DEFINE_SIMPLE_EXCEPTION_NOINNER(MatroskaException, agi::Exception, "matroksa_wrapper/generic")
|
||||||
|
|
||||||
class AssFile;
|
class AssFile;
|
||||||
namespace agi { namespace vfr { class Framerate; } }
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class MkvStdIO
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class MkvStdIO : public InputStream {
|
|
||||||
public:
|
|
||||||
MkvStdIO(wxString filename);
|
|
||||||
~MkvStdIO() { if (fp) fclose(fp); }
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
/// @class MkvFrame
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
/// DOCME
|
|
||||||
class MkvFrame {
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
double time;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
bool isKey;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
int64_t filePos;
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
///
|
|
||||||
MkvFrame() {
|
|
||||||
time = 0;
|
|
||||||
isKey = false;
|
|
||||||
filePos = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @param keyframe
|
|
||||||
/// @param timecode
|
|
||||||
/// @param _filePos
|
|
||||||
///
|
|
||||||
MkvFrame(bool keyframe,double timecode,int64_t _filePos) {
|
|
||||||
isKey = keyframe;
|
|
||||||
time = timecode;
|
|
||||||
filePos = _filePos;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator < (MkvFrame &t1, MkvFrame &t2);
|
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
/// @class MatroskaWrapper
|
/// @class MatroskaWrapper
|
||||||
|
@ -112,57 +50,9 @@ bool operator < (MkvFrame &t1, MkvFrame &t2);
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class MatroskaWrapper {
|
class MatroskaWrapper {
|
||||||
private:
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
std::vector<int> keyFrames;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
std::vector<double> timecodes;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
wxArrayInt bytePos;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// Check if the file is a matroska file with at least one subtitle track
|
||||||
/// DOCME
|
|
||||||
MkvStdIO *input;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
MatroskaFile *file;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
std::list<MkvFrame> frames;
|
|
||||||
|
|
||||||
/// DOCME
|
|
||||||
std::vector<MkvFrame> rawFrames;
|
|
||||||
|
|
||||||
MatroskaWrapper();
|
|
||||||
~MatroskaWrapper();
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
bool IsOpen() { return file != NULL; }
|
|
||||||
void Open(wxString filename,bool parse=true);
|
|
||||||
void Close();
|
|
||||||
void Parse();
|
|
||||||
|
|
||||||
void SetToTimecodes(agi::vfr::Framerate &target);
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
wxArrayInt GetBytePositions() { return bytePos; }
|
|
||||||
|
|
||||||
/// @brief DOCME
|
|
||||||
/// @return
|
|
||||||
///
|
|
||||||
unsigned int GetFrameCount() { return timecodes.size(); }
|
|
||||||
std::vector<int> GetKeyFrames();
|
|
||||||
void GetSubtitles(AssFile *target);
|
|
||||||
static bool HasSubtitles(wxString const& filename);
|
static bool HasSubtitles(wxString const& filename);
|
||||||
|
/// Load subtitles from a matroska file
|
||||||
/// DOCME
|
static void GetSubtitles(wxString const& filename, AssFile *target);
|
||||||
static MatroskaWrapper wrapper;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,8 +53,6 @@ wxArrayString MKVSubtitleFormat::GetReadWildcards() const {
|
||||||
return formats;
|
return formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MKVSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) {
|
void MKVSubtitleFormat::ReadFile(wxString const& filename, wxString const&) {
|
||||||
MatroskaWrapper wrap;
|
MatroskaWrapper::GetSubtitles(filename, GetAssFile());
|
||||||
wrap.Open(filename, false);
|
|
||||||
wrap.GetSubtitles(GetAssFile());
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue