Moved the external timecode stuff into their own classes. Enabled proper durations for tracks with external timecodes.

This commit is contained in:
Moritz Bunkus 2004-10-09 14:28:58 +00:00
parent 263dfa4409
commit d5ca84ac0d
10 changed files with 461 additions and 280 deletions

View File

@ -1,3 +1,9 @@
2004-10-09 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: Rewrote the code for the external timecode files. This
also fixes bug 99: The durations for the individual tracks were
not correct for those tracks for which --timecodes was used.
2004-10-08 Moritz Bunkus <moritz@bunkus.org>
* mmg: bug fix: Crash when saving chapters from the chapter

View File

@ -288,7 +288,8 @@ src/output/libmtxoutput.a: $(libmtxoutput_OBJECTS)
mkvmerge_SOURCES = src/mkvmerge.cpp \
src/cluster_helper.cpp \
src/pr_generic.cpp
src/pr_generic.cpp \
src/timecode_factory.cpp
mkvmerge_OBJECTS := $(patsubst %.cpp,%.o,$(mkvmerge_SOURCES))
mkvmerge_DEPENDENCIES += $(DEP_COMMON) \
$(DEP_COMP) $(DEP_INPUT) $(DEP_OUTPUT) $(DEP_AVI) $(DEP_RMFF)

View File

@ -341,10 +341,13 @@ cluster_helper_c::set_duration(render_groups_t *rg) {
if (rg->duration_mandatory) {
if ((block_duration == 0) ||
((block_duration > 0) && (block_duration != def_duration)))
((block_duration > 0) &&
(block_duration != (rg->durations.size() * def_duration))))
group->SetBlockDuration(RND_TIMECODE_SCALE(block_duration));
} else if (use_durations && (block_duration > 0) &&
(block_duration != def_duration))
} else if ((use_durations || (def_duration > 0)) &&
(block_duration > 0) &&
(RND_TIMECODE_SCALE(block_duration) !=
RND_TIMECODE_SCALE(rg->durations.size() * def_duration)))
group->SetBlockDuration(RND_TIMECODE_SCALE(block_duration));
}

View File

@ -1,3 +1,4 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
@ -1496,6 +1497,31 @@ mxsprintf(const char *fmt,
return dst;
}
/** \brief Platform independant version of sscanf
*
* This is a platform independant version of sscanf. It first fixes the format
* string (\see fix_format) and then calls sscanf.
*
* \param str The string to parse
* \param fmt The format string
* \returns The number of elements assigned
*/
int
mxsscanf(const string &str,
const char *fmt,
...) {
va_list ap;
string new_fmt;
int result;
fix_format(fmt, new_fmt);
va_start(ap, fmt);
result = vsscanf(str.c_str(), new_fmt.c_str(), ap);
va_end(ap);
return result;
}
void
mxhexdump(int level,
const unsigned char *buffer,

View File

@ -143,6 +143,8 @@ void MTX_DLL_API mxverb(int level, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
void MTX_DLL_API mxdebug(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
int MTX_DLL_API mxsscanf(const string &str, const char *fmt, ...)
__attribute__ ((format (scanf, 2, 3)));
#else
void MTX_DLL_API die(const char *fmt, ...);
void MTX_DLL_API mxprint(void *stream, const char *fmt, ...);
@ -153,6 +155,7 @@ void MTX_DLL_API mxerror(const char *fmt, ...);
void MTX_DLL_API mxinfo(const char *fmt, ...);
void MTX_DLL_API mxverb(int level, const char *fmt, ...);
void MTX_DLL_API mxdebug(const char *fmt, ...);
int MTX_DLL_API mxsscanf(const string &str, const char *fmt, ...);
#endif
void MTX_DLL_API mxexit(int code = -1);
@ -238,7 +241,7 @@ int MTX_DLL_API get_varg_len(const char *fmt, va_list ap);
extern int MTX_DLL_API verbose;
#define foreach(it, vec) for (it = (vec).begin(); it < (vec).end(); it++)
#define foreach(it, vec) for (it = (vec).begin(); it != (vec).end(); it++)
class MTX_DLL_API bit_cursor_c {
private:

View File

@ -244,14 +244,8 @@ generic_packetizer_c::generic_packetizer_c(generic_reader_c *nreader,
dumped_packet_number = 0;
frameno = 0;
ext_timecodes_version = -1;
timecode_ranges = NULL;
ext_timecodes = NULL;
ext_timecodes_warning_printed = false;
current_tc_range = 0;
if (ti->ext_timecodes != NULL)
parse_ext_timecode_file(ti->ext_timecodes);
timecode_factory = timecode_factory_c::create(ti->ext_timecodes,
ti->fname, ti->id);
}
generic_packetizer_c::~generic_packetizer_c() {
@ -261,10 +255,7 @@ generic_packetizer_c::~generic_packetizer_c() {
safefree(hcodec_private);
if (compressor != NULL)
delete compressor;
if (timecode_ranges != NULL)
delete timecode_ranges;
if (ext_timecodes != NULL)
delete ext_timecodes;
delete timecode_factory;
}
void
@ -595,6 +586,8 @@ generic_packetizer_c::set_headers() {
*(static_cast<EbmlUInteger *>
(&GetChild<KaxTrackMaxCache>(*track_entry))) = htrack_max_cache;
htrack_default_duration =
(int64_t)timecode_factory->get_default_duration(htrack_default_duration);
if (htrack_default_duration != -1.0)
*(static_cast<EbmlUInteger *>
(&GetChild<KaxTrackDefaultDuration>(*track_entry))) =
@ -860,7 +853,8 @@ generic_packetizer_c::add_packet(memory_c &mem,
pack->duration = duration;
pack->duration_mandatory = duration_mandatory;
pack->source = this;
pack->assigned_timecode = get_next_timecode(timecode) + ti->packet_delay;
timecode_factory->get_next(timecode, pack->duration);
pack->assigned_timecode = timecode + ti->packet_delay;
if (reader->max_timecode_seen < (pack->assigned_timecode + pack->duration))
reader->max_timecode_seen = pack->assigned_timecode + pack->duration;
@ -907,236 +901,6 @@ generic_packetizer_c::dump_packet(const void *buffer,
safefree(path);
}
void
generic_packetizer_c::parse_ext_timecode_file(const char *name) {
mm_io_c *in;
string line;
in = NULL;
try {
in = new mm_text_io_c(name);
} catch(...) {
mxerror(_("The timecode file '%s' could not be opened for reading.\n"),
name);
}
if (!in->getline2(line) || !starts_with_case(line, "# timecode format v") ||
!parse_int(&line.c_str()[strlen("# timecode format v")],
ext_timecodes_version))
mxerror(_("The timecode file '%s' contains an unsupported/unrecognized "
"format line. The very first line must look like "
"'# timecode format v1'.\n"), name);
if (ext_timecodes_version == 1)
parse_ext_timecode_file_v1(in, name);
else if (ext_timecodes_version == 2)
parse_ext_timecode_file_v2(in, name);
else
mxerror(_("The timecode file '%s' contains an unsupported/unrecognized "
"format (version %d).\n"), name, ext_timecodes_version);
delete in;
}
void
generic_packetizer_c::parse_ext_timecode_file_v1(mm_io_c *in,
const char *name) {
string line;
timecode_range_c t;
vector<string> fields;
vector<timecode_range_c>::iterator iit, pit;
uint32_t i, line_no;
bool done;
double default_fps;
line_no = 1;
do {
if (!in->getline2(line))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line"
" with the default number of frames per second.\n"), name);
line_no++;
strip(line);
if ((line.length() != 0) && (line[0] != '#'))
break;
} while (true);
if (!starts_with_case(line, "assume "))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line "
"with the default number of frames per second.\n"), name);
line.erase(0, 6);
strip(line);
if (!parse_double(line.c_str(), default_fps))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line "
"with the default number of frames per second.\n"), name);
if (timecode_ranges != NULL)
delete timecode_ranges;
timecode_ranges = new vector<timecode_range_c>;
while (in->getline2(line)) {
line_no++;
strip(line, true);
if ((line.length() == 0) || (line[0] == '#'))
continue;
fields = split(line.c_str());
strip(fields, true);
if (fields.size() != 3) {
mxwarn(_("Line %d of the timecode file '%s' could not be parsed: It "
"does not contain exactly three fields.\n"), line_no, name);
continue;
}
if (!parse_int(fields[0].c_str(), t.start_frame)) {
mxwarn(_("Line %d of the timecode file '%s' could not be parsed: The "
"start frame number is not a valid number.\n"), line_no, name);
continue;
}
if (!parse_int(fields[1].c_str(), t.end_frame)) {
mxwarn(_("Line %d of the timecode file '%s' could not be parsed: The "
"end frame number is not a valid number.\n"), line_no, name);
continue;
}
if (!parse_double(fields[2].c_str(), t.fps)) {
mxwarn(_("Line %d of the timecode file '%s' could not be parsed: The "
"number of frames per second is not a valid floating point "
"number.\n"), line_no, name);
continue;
}
if ((t.fps <= 0) || (t.start_frame < 0) || (t.end_frame < 0) ||
(t.end_frame < t.start_frame)) {
mxwarn(_("Line %d of the timecode file '%s' contains inconsistent data "
"(e.g. the start frame number is bigger than the end frame "
"number, or some values are smaller than zero).\n"),
line_no, name);
continue;
}
timecode_ranges->push_back(t);
}
mxverb(3, "ext_timecodes: Version %d, default fps %f, %u entries.\n",
ext_timecodes_version, default_fps, timecode_ranges->size());
if (timecode_ranges->size() == 0)
mxwarn(_("The timecode file '%s' does not contain any valid entry.\n"),
name);
sort(timecode_ranges->begin(), timecode_ranges->end());
if (timecode_ranges->size() > 0) {
do {
done = true;
iit = timecode_ranges->begin();
for (i = 0; i < (timecode_ranges->size() - 1); i++) {
iit++;
if ((*timecode_ranges)[i].end_frame <
((*timecode_ranges)[i + 1].start_frame - 1)) {
t.start_frame = (*timecode_ranges)[i].end_frame + 1;
t.end_frame = (*timecode_ranges)[i + 1].start_frame - 1;
t.fps = default_fps;
timecode_ranges->insert(iit, t);
done = false;
break;
}
}
} while (!done);
if ((*timecode_ranges)[0].start_frame != 0) {
t.start_frame = 0;
t.end_frame = (*timecode_ranges)[0].start_frame - 1;
t.fps = default_fps;
timecode_ranges->insert(timecode_ranges->begin(), t);
}
t.start_frame = (*timecode_ranges)
[timecode_ranges->size() - 1].end_frame + 1;
} else
t.start_frame = 0;
t.end_frame = 0xfffffffffffffffll;
t.fps = default_fps;
timecode_ranges->push_back(t);
(*timecode_ranges)[0].base_timecode = 0.0;
pit = timecode_ranges->begin();
for (iit = pit + 1; iit < timecode_ranges->end(); iit++, pit++)
iit->base_timecode = pit->base_timecode +
((double)pit->end_frame - (double)pit->start_frame + 1) * 1000000000.0 /
pit->fps;
for (iit = timecode_ranges->begin(); iit < timecode_ranges->end(); iit++)
mxverb(3, "timecode_ranges: entry %lld -> %lld at %f with %f\n",
iit->start_frame, iit->end_frame, iit->fps, iit->base_timecode);
}
void
generic_packetizer_c::parse_ext_timecode_file_v2(mm_io_c *in,
const char *name) {
int line_no;
string line;
double timecode;
if (ext_timecodes != NULL)
delete ext_timecodes;
ext_timecodes = new vector<int64_t>;
line_no = 0;
while (in->getline2(line)) {
line_no++;
strip(line);
if ((line.length() == 0) || (line[0] == '#'))
continue;
if (!parse_double(line.c_str(), timecode))
mxerror(_("The line %d of the timecode file '%s' does not contain a "
"valid floating point number.\n"), line_no, name);
ext_timecodes->push_back((int64_t)timecode * 1000000);
}
}
int64_t
generic_packetizer_c::get_next_timecode(int64_t timecode) {
int64_t new_timecode;
timecode_range_c *t;
if (ext_timecodes_version == 1) {
if (timecode_ranges == NULL)
die("generic_packetizer: ext_timecodes_version == 1 && "
"timecodes_range == NULL. %s\n", BUGMSG);
t = &(*timecode_ranges)[current_tc_range];
new_timecode = (int64_t)(t->base_timecode + 1000000000.0 *
(frameno - t->start_frame) / t->fps);
frameno++;
if ((frameno > t->end_frame) &&
(current_tc_range < (timecode_ranges->size() - 1)))
current_tc_range++;
mxverb(4, "ext_timecodes v1: %lld for %lld\n", new_timecode, frameno - 1);
return new_timecode;
} else if (ext_timecodes_version == 2) {
if (ext_timecodes == NULL)
die("generic_packetizer: ext_timecodes_version == 2 && "
"ext_timecodes == NULL. %s\n", BUGMSG);
if ((frameno >= ext_timecodes->size()) && !ext_timecodes_warning_printed) {
mxwarn(_("generic_packetizer: The number of external timecodes %u is "
"smaller than the number of frames in track %lld of '%s'. "
"The remaining frames of this track might not be timestamped "
"the way you intended them to be. mkvmerge might even crash."
"\n"),
ext_timecodes->size(), ti->id, ti->fname);
ext_timecodes_warning_printed = true;
return timecode;
}
new_timecode = (*ext_timecodes)[frameno];
frameno++;
mxverb(4, "ext_timecodes v2: %lld for %lld\n", new_timecode, frameno - 1);
return new_timecode;
}
return timecode;
}
void
generic_packetizer_c::displace(float by_ns) {
ti->async.displacement += (int64_t)by_ns;

View File

@ -30,6 +30,7 @@
#include "compression.h"
#include "error.h"
#include "mm_io.h"
#include "timecode_factory.h"
using namespace libmatroska;
using namespace std;
@ -238,16 +239,6 @@ public:
virtual void free_contents();
};
class timecode_range_c {
public:
int64_t start_frame, end_frame;
double fps, base_timecode;
bool operator <(const timecode_range_c &cmp) const {
return start_frame < cmp.start_frame;
}
};
typedef struct packetizer_container_t {
generic_packetizer_c *orig;
generic_packetizer_c *current;
@ -333,12 +324,7 @@ protected:
int hcompression;
compression_c *compressor;
vector<timecode_range_c> *timecode_ranges;
vector<int64_t> *ext_timecodes;
uint32_t current_tc_range;
int64_t frameno;
int ext_timecodes_version;
bool ext_timecodes_warning_printed;
timecode_factory_c *timecode_factory;
int64_t last_cue_timecode;
@ -460,11 +446,6 @@ public:
hcompression = method;
}
virtual int64_t get_next_timecode(int64_t timecode);
virtual void parse_ext_timecode_file(const char *name);
virtual void parse_ext_timecode_file_v1(mm_io_c *in, const char *name);
virtual void parse_ext_timecode_file_v2(mm_io_c *in, const char *name);
inline bool needs_negative_displacement(float) {
return ((initial_displacement < 0) &&
(ti->async.displacement > initial_displacement));

274
src/timecode_factory.cpp Normal file
View File

@ -0,0 +1,274 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* the timecode factory
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include <map>
#include "common.h"
#include "mm_io.h"
#include "pr_generic.h"
#include "timecode_factory.h"
using namespace std;
struct lt_int64_t {
bool operator()(int64_t i1, int64_t i2) {
return i1 < i2;
}
};
timecode_factory_c *
timecode_factory_c::create(const char *_file_name,
const char *_source_name,
int64_t _tid) {
mm_io_c *in;
string line;
int version;
timecode_factory_c *factory;
if (_file_name == NULL)
return new timecode_factory_c("", _source_name, _tid);
in = NULL; // avoid gcc warning
try {
in = new mm_text_io_c(_file_name);
} catch(...) {
mxerror(_("The timecode file '%s' could not be opened for reading.\n"),
_file_name);
}
if (!in->getline2(line) || !starts_with_case(line, "# timecode format v") ||
!parse_int(&line.c_str()[strlen("# timecode format v")], version))
mxerror(_("The timecode file '%s' contains an unsupported/unrecognized "
"format line. The very first line must look like "
"'# timecode format v1'.\n"), _file_name);
factory = NULL; // avoid gcc warning
if (version == 1)
factory = new timecode_factory_v1_c(_file_name, _source_name, _tid);
else if (version == 2)
factory = new timecode_factory_v2_c(_file_name, _source_name, _tid);
else
mxerror(_("The timecode file '%s' contains an unsupported/unrecognized "
"format (version %d).\n"), _file_name, version);
factory->parse(*in);
delete in;
return factory;
}
void
timecode_factory_v1_c::parse(mm_io_c &in) {
string line;
timecode_range_c t;
vector<string> fields;
vector<timecode_range_c>::iterator iit, pit;
uint32_t i, line_no;
bool done;
const char *name;
line_no = 1;
do {
if (!in.getline2(line))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line"
" with the default number of frames per second.\n"),
file_name.c_str());
line_no++;
strip(line);
if ((line.length() != 0) && (line[0] != '#'))
break;
} while (true);
if (!starts_with_case(line, "assume "))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line "
"with the default number of frames per second.\n"),
file_name.c_str());
line.erase(0, 6);
strip(line);
if (!parse_double(line.c_str(), default_fps))
mxerror(_("The timecode file '%s' does not contain a valid 'Assume' line "
"with the default number of frames per second.\n"),
file_name.c_str());
while (in.getline2(line)) {
line_no++;
strip(line, true);
if ((line.length() == 0) || (line[0] == '#'))
continue;
if (mxsscanf(line, "%lld,%lld,%lf", &t.start_frame, &t.end_frame, &t.fps)
!= 3) {
mxwarn(_("Line %d of the timecode file '%s' could not be parsed.\n"),
line_no, file_name.c_str());
continue;
}
if ((t.fps <= 0) || (t.start_frame < 0) || (t.end_frame < 0) ||
(t.end_frame < t.start_frame)) {
mxwarn(_("Line %d of the timecode file '%s' contains inconsistent data "
"(e.g. the start frame number is bigger than the end frame "
"number, or some values are smaller than zero).\n"),
line_no, file_name.c_str());
continue;
}
ranges.push_back(t);
}
mxverb(3, "ext_timecodes: Version 1, default fps %f, %u entries.\n",
default_fps, ranges.size());
if (ranges.size() == 0) {
mxwarn(_("The timecode file '%s' does not contain any valid entry.\n"),
name);
t.start_frame = 0;
} else {
sort(ranges.begin(), ranges.end());
do {
done = true;
iit = ranges.begin();
for (i = 0; i < (ranges.size() - 1); i++) {
iit++;
if (ranges[i].end_frame <
(ranges[i + 1].start_frame - 1)) {
t.start_frame = ranges[i].end_frame + 1;
t.end_frame = ranges[i + 1].start_frame - 1;
t.fps = default_fps;
ranges.insert(iit, t);
done = false;
break;
}
}
} while (!done);
if (ranges[0].start_frame != 0) {
t.start_frame = 0;
t.end_frame = ranges[0].start_frame - 1;
t.fps = default_fps;
ranges.insert(ranges.begin(), t);
}
t.start_frame = ranges
[ranges.size() - 1].end_frame + 1;
}
t.end_frame = 0xfffffffffffffffll;
t.fps = default_fps;
ranges.push_back(t);
ranges[0].base_timecode = 0.0;
pit = ranges.begin();
for (iit = pit + 1; iit < ranges.end(); iit++, pit++)
iit->base_timecode = pit->base_timecode +
((double)pit->end_frame - (double)pit->start_frame + 1) * 1000000000.0 /
pit->fps;
for (iit = ranges.begin(); iit < ranges.end(); iit++)
mxverb(3, "ranges: entry %lld -> %lld at %f with %f\n",
iit->start_frame, iit->end_frame, iit->fps, iit->base_timecode);
}
void
timecode_factory_v1_c::get_next(int64_t &timecode,
int64_t &duration,
bool peek_only) {
timecode = get_at(frameno);
duration = get_at(frameno + 1) - timecode;
if (!peek_only) {
frameno++;
if ((frameno > ranges[current_range].end_frame) &&
(current_range < (ranges.size() - 1)))
current_range++;
}
mxverb(4, "ext_timecodes v1: tc %lld dur %lld for %lld\n", timecode,
duration, frameno - 1);
}
int64_t
timecode_factory_v1_c::get_at(int64_t frame) {
timecode_range_c *t;
t = &ranges[current_range];
if ((frame > t->end_frame) && (current_range < (ranges.size() - 1)))
t = &ranges[current_range + 1];
return (int64_t)(t->base_timecode + 1000000000.0 *
(frame - t->start_frame) / t->fps);
}
void
timecode_factory_v2_c::parse(mm_io_c &in) {
int line_no;
string line;
double timecode;
map<int64_t, int64_t, lt_int64_t> dur_map;
map<int64_t, int64_t, lt_int64_t>::const_iterator it;
int64_t duration, dur_sum;
dur_sum = 0;
line_no = 0;
while (in.getline2(line)) {
line_no++;
strip(line);
if ((line.length() == 0) || (line[0] == '#'))
continue;
if (!parse_double(line.c_str(), timecode))
mxerror(_("The line %d of the timecode file '%s' does not contain a "
"valid floating point number.\n"), line_no, file_name.c_str());
timecodes.push_back((int64_t)(timecode * 1000000));
if (timecodes.size() > 1) {
duration = timecodes[timecodes.size() - 1] -
timecodes[timecodes.size() - 2];
if (dur_map.find(duration) == dur_map.end())
dur_map[duration] = 1;
else
dur_map[duration] = dur_map[duration] + 1;
dur_sum += duration;
durations.push_back(duration);
}
}
if (timecodes.size() == 0)
mxerror(_("The timecode file '%s' does not contain any valid entry.\n"),
file_name.c_str());
dur_sum = -1;
foreach(it, dur_map) {
if ((dur_sum < 0) || (dur_map[dur_sum] < (*it).second))
dur_sum = (*it).first;
mxverb(4, "ext_timecodes v2 dur_map %lld = %lld\n", (*it).first,
(*it).second);
}
mxverb(4, "ext_timecodes v2 max is %lld = %lld\n", dur_sum,
dur_map[dur_sum]);
if (dur_sum > 0)
default_fps = (double)1.0 / dur_sum;
durations.push_back(dur_sum);
}
void
timecode_factory_v2_c::get_next(int64_t &timecode,
int64_t &duration,
bool peek_only) {
if ((frameno >= timecodes.size()) && !warning_printed) {
mxwarn(FMT_TID "The number of external timecodes %u is "
"smaller than the number of frames in this track. "
"The remaining frames of this track might not be timestamped "
"the way you intended them to be. mkvmerge might even crash.\n",
source_name.c_str(), tid, timecodes.size());
warning_printed = true;
return;
}
timecode = timecodes[frameno];
duration = durations[frameno];
if (!peek_only)
frameno++;
}

123
src/timecode_factory.h Normal file
View File

@ -0,0 +1,123 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* class definition for the timecode factory
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#ifndef __TIMECODE_FACTORY_H
#define __TIMECODE_FACTORY_H
#include <string>
#include <vector>
using namespace std;
class mm_io_c;
class timecode_range_c {
public:
int64_t start_frame, end_frame;
double fps, base_timecode;
bool operator <(const timecode_range_c &cmp) const {
return start_frame < cmp.start_frame;
}
};
class timecode_factory_c {
protected:
string file_name, source_name;
int64_t tid;
public:
timecode_factory_c(const string &_file_name, const string &_source_name,
int64_t _tid):
file_name(_file_name),
source_name(_source_name),
tid(_tid) {
}
virtual ~timecode_factory_c() {
}
virtual void parse(mm_io_c &) {
}
virtual void get_next(int64_t &timecode, int64_t &duration,
bool peek_only = false) {
}
virtual void peek_next(int64_t &timecode, int64_t &duration) {
get_next(timecode, duration, true);
}
virtual double get_default_duration(double proposal) {
return proposal;
}
static timecode_factory_c *create(const char *_file_name,
const char *_source_name,
int64_t _tid);
};
class timecode_factory_v1_c: public timecode_factory_c {
protected:
vector<timecode_range_c> ranges;
uint32_t current_range;
int64_t frameno;
double default_fps;
public:
timecode_factory_v1_c(const string &_file_name, const string &_source_name,
int64_t _tid):
timecode_factory_c(_file_name, _source_name, _tid),
current_range(0),
frameno(0),
default_fps(0.0) {
}
virtual ~timecode_factory_v1_c() {
}
virtual void parse(mm_io_c &in);
virtual void get_next(int64_t &timecode, int64_t &duration,
bool peek_only = false);
virtual double get_default_duration(double proposal) {
return default_fps != 0.0 ? 1 / default_fps : proposal;
}
protected:
virtual int64_t get_at(int64_t frame);
};
class timecode_factory_v2_c: public timecode_factory_c {
protected:
vector<int64_t> timecodes, durations;
bool warning_printed;
int64_t frameno;
double default_fps;
public:
timecode_factory_v2_c(const string &_file_name, const string &_source_name,
int64_t _tid):
timecode_factory_c(_file_name, _source_name, _tid),
warning_printed(false),
frameno(0),
default_fps(0.0) {
}
virtual ~timecode_factory_v2_c() {
}
virtual void parse(mm_io_c &in);
virtual void get_next(int64_t &timecode, int64_t &duration,
bool peek_only = false);
virtual double get_default_duration(double proposal) {
return default_fps != 0.0 ? 1 / default_fps : proposal;
}
};
#endif // __TIMECODE_FACTORY_H

View File

@ -1,34 +1,34 @@
T_001mp3:790f9415ba41cb29ba4836a035a0411e:passed:20040825-175700
T_002aac:73164d9430db643128a2a160f3d4aa14:passed:20040825-175700
T_003ac3:7ade2a219d4c5f89c6e39010a585903f:passed:20040825-175700
T_004aacmp4:7b3a23c96c8df4c71d3dc59175680bb1:passed:20040825-175700
T_004aacmp4:49c4bc364e62d59f19207bb091b69ad6:passed:20040825-175700
T_005flac:62571b0e2b971b181992062252987190:passed:20040825-175700
T_006oggflac:68cfdf432f987f04f454a9c222ece7d2:passed:20040825-175700
T_007oggvorbis:bec4fb34f6bf5f7542dac36c21c856ab:passed:20040825-175700
T_008avi_divx3_mp3:767b7cad0fc95a67ecd63ae60d6771c3:passed:20040825-175700
T_008avi_divx3_mp3:822d32b9405fcf1c0eea0988c901ca85:passed:20040825-175700
T_009realvideo_3:a0d70a589067fdd9ae67992c41fa595d:passed:20040825-175700
T_010realvideo_4:0d25e4137c50066f43fd12da6a4871af:passed:20040825-175700
T_011srt:d7ac4923916c695a9b47425a90e39a0b:passed:20040825-175700
T_012ssa:9ecbc6bdfa5dec6495f99c7a97342844:passed:20040825-175700
T_013vobsubs:8983288ea21b811fbb85d2ea272ccfe5:passed:20040825-175700
T_014splitting_by_size:feeb1aba481b5a51d7142599359f2eac-eacf20880a6dff6fc1128c1ffd47d23b:passed:20040825-175700
T_015splitting_by_time:d0e769a906ec4eacc9c9af929add6474-6f8dd1e514ea2a76941fb841d25a06dc:passed:20040825-175700
T_014splitting_by_size:feeb1aba481b5a51d7142599359f2eac-5c639e8a08cf526d051fdf64f856c0d2:passed:20040825-175700
T_015splitting_by_time:d0e769a906ec4eacc9c9af929add6474-c32e2d8c31e21e71f68875f2d9735565:passed:20040825-175700
T_016cuesheet:e2e88f91b6bf6ff411f4984ce7d89e35:passed:20040825-175700
T_017chapters:990b4b6b0931b7d52e589f715c919e10-4fff45a76f54708f881312aca04fd887:passed:20040825-175700
T_018attachments:bac27359516bab4984df3021aa295213-7e8e1f17615f157db0e98fba9ad88bad:passed:20040825-175700
T_019attachments2:8d9ba46c4edbf3daf50175f9de2f87b4-689f99b17a166efe5457f16bff240b93-8d9ba46c4edbf3daf50175f9de2f87b4-eacf20880a6dff6fc1128c1ffd47d23b:passed:20040825-175700
T_020languages:5e5c257edc758c326d17f11224fa8441:passed:20040825-234208
T_019attachments2:8d9ba46c4edbf3daf50175f9de2f87b4-94349d68c9b7d493ec0d5a49f7291e40-8d9ba46c4edbf3daf50175f9de2f87b4-5c639e8a08cf526d051fdf64f856c0d2:passed:20040825-175700
T_020languages:dc8b8792f86ac4e92e70154faef990a7:passed:20040825-234208
T_021aspect_ratio:f6e8aa4cfd776d99ff824f21d4e3c640-990a5f94678b5c8886dc8c3a5c6a22dd:passed:20040825-234244
T_022display_dimensions:108880396ffe5244465a3d25e8a57f93:passed:20040825-234339
T_023no_x:0b7f257f1c801da7b2ef1976291e5d44-c8ff96f9dc08f98dfbebe19275aeb125-66105284756c6867756143920a242960:passed:20040825-234343
T_023no_x:0b7f257f1c801da7b2ef1976291e5d44-39f690e6a11bc2e32b54334e67374feb-2662148f7a3d60c152c92ad9a9d5e672:passed:20040825-234343
T_024sync_mp3:a6c35d309947a52196d2a5428f87224a-6a638028d795bd48db95446f3521c302:passed:20040825-234344
T_025sync_vorbis:e9d13a6b769cf6c2e4987bf6bd160698-51fcfab150642a66484d3c6bedff697a:passed:20040825-234344
T_026sync_pcm:f337f057c059d771128206c0da3d4807-9b559191edb65655e49186c302c4b815:passed:20040825-234346
T_027default_track:db15cd5861cdc5e43dc82bb0924ad3d9:passed:20040825-234348
T_027default_track:e3177712483af5b129bbeb9cf0e6a820:passed:20040825-234348
T_028compression:f6c15855e42e5a0e80d22a2060ae13e8:passed:20040825-234348
T_029link:49e174d0a7700ea2e288e20ddb85cc2a:passed:20040825-235039
T_032cues:73c0452451a00010299e191a39c783f9:passed:20040825-235040
T_033timecode_scale:ba6bc8dff27d7d9fd433670067fa716d-d54414d993caad6cea47ef7913cb13db:passed:20040825-235040
T_029link:d92e5f123b799212f65bb7b394dd4f6e:passed:20040825-235039
T_032cues:f84c58a6380b3104434b6943e0eb87e3:passed:20040825-235040
T_033timecode_scale:ba6bc8dff27d7d9fd433670067fa716d-bbc4e4faad71330e8c6d7ec0b725898c:passed:20040825-235040
T_034ac3misdetected_as_mp2:f6765afb6d86ae09e0859f32ba65ced4:passed:20040920-100447
T_035X_vfw_video:5bcb3426b2635ae5c89a5e5fe46aa416:passed:20040920-185358
T_036X_mp3:b3bb67d316e20da12926d5c1d628f6e5:passed:20040920-190109