mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-25 12:27:21 +00:00
239 lines
6.0 KiB
C++
239 lines
6.0 KiB
C++
/*
|
|
mkvmerge -- utility for splicing together matroska files
|
|
from component media subtypes
|
|
|
|
r_ssa.cpp
|
|
|
|
Written by Moritz Bunkus <moritz@bunkus.org>
|
|
|
|
Distributed under the GPL
|
|
see the file COPYING for details
|
|
or visit http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
/*!
|
|
\file
|
|
\version $Id$
|
|
\brief SSA/ASS subtitle parser
|
|
\author Moritz Bunkus <moritz@bunkus.org>
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "mkvmerge.h"
|
|
#include "pr_generic.h"
|
|
#include "r_ssa.h"
|
|
#include "subtitles.h"
|
|
#include "matroska.h"
|
|
|
|
using namespace std;
|
|
|
|
int ssa_reader_c::probe_file(mm_io_c *mm_io, int64_t size) {
|
|
string line;
|
|
|
|
try {
|
|
mm_io->setFilePointer(0, seek_beginning);
|
|
line = mm_io->getline();
|
|
if (strcasecmp(line.c_str(), "[script info]"))
|
|
return 0;
|
|
mm_io->setFilePointer(0, seek_beginning);
|
|
} catch (exception &ex) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ssa_reader_c::ssa_reader_c(track_info_t *nti) throw (error_c):
|
|
generic_reader_c(nti) {
|
|
string line, global;
|
|
int64_t old_pos;
|
|
bool is_ass;
|
|
|
|
is_ass = false;
|
|
|
|
try {
|
|
mm_io = new mm_io_c(ti->fname, MODE_READ);
|
|
if (!ssa_reader_c::probe_file(mm_io, 0))
|
|
throw error_c("ssa_reader: Source is not a valid SSA/ASS file.");
|
|
ti->id = 0; // ID for this track.
|
|
global = mm_io->getline(); // [Script Info]
|
|
while (!mm_io->eof()) {
|
|
old_pos = mm_io->getFilePointer();
|
|
line = mm_io->getline();
|
|
if (line.length() == 0) // Ignore empty lines.
|
|
continue;
|
|
if (line.c_str()[0] == ';') { // Just a comment.
|
|
global += "\r\n"; // DOS style newlines
|
|
global += line;
|
|
continue;
|
|
}
|
|
|
|
if (!strncasecmp(line.c_str(), "Dialogue: ", strlen("Dialogue: "))) {
|
|
// End of global data - restore file position to just before this
|
|
// line end bail out.
|
|
mm_io->setFilePointer(old_pos);
|
|
break;
|
|
}
|
|
|
|
// A normal line. Let's see if this file is ASS and not SSA.
|
|
if (!strcasecmp(line.c_str(), "ScriptType: v4.00+") ||
|
|
!strcasecmp(line.c_str(), "[V4+ Styles]"))
|
|
is_ass = true;
|
|
|
|
// Now just append the current line and some DOS style newlines.
|
|
global += "\r\n";
|
|
global += line;
|
|
}
|
|
|
|
textsubs_packetizer = new textsubs_packetizer_c(this, is_ass ?
|
|
MKV_S_TEXTASS :
|
|
MKV_S_TEXTSSA,
|
|
global.c_str(),
|
|
global.length(), ti);
|
|
} catch (exception &ex) {
|
|
throw error_c("ssa_reader: Could not open the source file.");
|
|
}
|
|
if (verbose)
|
|
fprintf(stdout, "Using SSA/ASS subtitle reader for %s.\n+-> Using "
|
|
"text subtitle output module for subtitles.\n", ti->fname);
|
|
}
|
|
|
|
ssa_reader_c::~ssa_reader_c() {
|
|
if (textsubs_packetizer != NULL)
|
|
delete textsubs_packetizer;
|
|
}
|
|
|
|
int64_t ssa_reader_c::parse_time(string &stime) {
|
|
int64_t th, tm, ts, tds;
|
|
int pos;
|
|
string s;
|
|
|
|
pos = stime.find(':');
|
|
if (pos < 0)
|
|
return -1;
|
|
|
|
s = stime.substr(0, pos);
|
|
if (!parse_int(s.c_str(), th))
|
|
return -1;
|
|
stime.erase(0, pos + 1);
|
|
|
|
pos = stime.find(':');
|
|
if (pos < 0)
|
|
return -1;
|
|
|
|
s = stime.substr(0, pos);
|
|
if (!parse_int(s.c_str(), tm))
|
|
return -1;
|
|
stime.erase(0, pos + 1);
|
|
|
|
pos = stime.find('.');
|
|
if (pos < 0)
|
|
return -1;
|
|
|
|
s = stime.substr(0, pos);
|
|
if (!parse_int(s.c_str(), ts))
|
|
return -1;
|
|
stime.erase(0, pos + 1);
|
|
|
|
if (!parse_int(stime.c_str(), tds))
|
|
return -1;
|
|
|
|
return tds * 10 + ts * 1000 + tm * 60 * 1000 + th * 60 * 60 * 1000;
|
|
}
|
|
|
|
int ssa_reader_c::read() {
|
|
string line, stime, orig_line;
|
|
int pos1, pos2;
|
|
int64_t start, end;
|
|
|
|
do {
|
|
line = mm_io->getline();
|
|
orig_line = line;
|
|
if (strncasecmp(line.c_str(), "Dialogue: ", strlen("Dialogue: ")))
|
|
continue;
|
|
|
|
line.erase(0, strlen("Dialogue: ")); // Trim the start.
|
|
|
|
pos1 = line.find(','); // Find and parse the start time.
|
|
if (pos1 < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
pos2 = line.find(',', pos1 + 1);
|
|
if (pos2 < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
|
|
stime = line.substr(pos1 + 1, pos2 - pos1 - 1);
|
|
start = parse_time(stime);
|
|
if (start < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
line.erase(pos1, pos2 - pos1);
|
|
|
|
pos1 = line.find(','); // Find and parse the end time.
|
|
if (pos1 < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
pos2 = line.find(',', pos1 + 1);
|
|
if (pos2 < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
|
|
stime = line.substr(pos1 + 1, pos2 - pos1 - 1);
|
|
end = parse_time(stime);
|
|
if (end < 0) {
|
|
fprintf(stderr, "ssa_reader: Warning: Malformed line? (%s)\n",
|
|
orig_line.c_str());
|
|
continue;
|
|
}
|
|
line.erase(pos1, pos2 - pos1);
|
|
|
|
// Let the packetizer handle this line.
|
|
textsubs_packetizer->process((unsigned char *)line.c_str(), 0, start,
|
|
end - start);
|
|
} while (!mm_io->eof());
|
|
|
|
return 0;
|
|
}
|
|
|
|
packet_t *ssa_reader_c::get_packet() {
|
|
return textsubs_packetizer->get_packet();
|
|
}
|
|
|
|
int ssa_reader_c::display_priority() {
|
|
return DISPLAYPRIORITY_LOW;
|
|
}
|
|
|
|
static char wchar[] = "-\\|/-\\|/-";
|
|
|
|
void ssa_reader_c::display_progress() {
|
|
fprintf(stdout, "working... %c\r", wchar[act_wchar]);
|
|
act_wchar++;
|
|
if (act_wchar == strlen(wchar))
|
|
act_wchar = 0;
|
|
fflush(stdout);
|
|
}
|
|
|
|
void ssa_reader_c::set_headers() {
|
|
textsubs_packetizer->set_headers();
|
|
}
|
|
|
|
void ssa_reader_c::identify() {
|
|
fprintf(stdout, "File '%s': container: SSA/ASS\nTrack ID 0: subtitles "
|
|
"(SSA/ASS)\n", ti->fname);
|
|
}
|