Added support for copying attachments selectively

Attachments are now included in the output of --identify. They
can be selected just like the other track types. The option used
for them is -m / --attachments and disabled with -M / --no-attachments.
This commit is contained in:
Moritz Bunkus 2009-01-14 23:44:01 +01:00
parent a2b7d6b28c
commit 988ea9cc58
14 changed files with 195 additions and 78 deletions

View File

@ -43,6 +43,8 @@ using namespace std;
static void
handle_attachments(KaxAttachments *atts,
vector<track_spec_t> &tracks) {
static int64_t attachment_ui_id = 0;
int i;
for (i = 0; atts->ListSize() > i; ++i) {
KaxAttached *att = dynamic_cast<KaxAttached *>((*atts)[i]);
@ -74,10 +76,12 @@ handle_attachments(KaxAttachments *atts,
}
if ((-1 != id) && (-1 != size) && !type.empty()) {
++attachment_ui_id;
bool found = false;
for (k = 0; k < tracks.size(); k++)
if (tracks[k].tid == id) {
if (tracks[k].tid == attachment_ui_id) {
found = true;
break;
}
@ -89,7 +93,7 @@ handle_attachments(KaxAttachments *atts,
tracks[k].out_name = safestrdup(name.c_str());
}
mxinfo(boost::format(Y("The attachment #%1%, MIME type %2%, size %3%, is written to '%4%'.\n")) % id % type % size % tracks[k].out_name);
mxinfo(boost::format(Y("The attachment #%1%, ID %2%, MIME type %3%, size %4%, is written to '%5%'.\n")) % attachment_ui_id % id % type % size % tracks[k].out_name);
mm_io_c *out = NULL;
try {
out = new mm_file_io_c(tracks[k].out_name, MODE_CREATE);

View File

@ -136,7 +136,6 @@ avi_reader_c::~avi_reader_c() {
void
avi_reader_c::parse_subtitle_chunks() {
int i;
for (i = 0; AVI_text_tracks(avi) > i; ++i) {
AVI_set_text_track(avi, i);
@ -159,10 +158,8 @@ avi_reader_c::parse_subtitle_chunks() {
mm_mem_io_c io(chunk->get(), chunk_size);
uint32_t tag = io.read_uint32_be();
if (GAB2_TAG != tag) {
mxinfo("muuuuh :(( 1\n");
if (GAB2_TAG != tag)
continue;
}
io.skip(1);
@ -310,7 +307,7 @@ avi_reader_c::create_ssa_packetizer(int idx) {
avi_subs_demuxer_t &demuxer = sdemuxers[idx];
int id = idx + 1 + AVI_audio_tracks(avi);
ssa_parser_c *parser = new ssa_parser_c(demuxer.text_io.get(), ti.fname, id);
ssa_parser_c *parser = new ssa_parser_c(this, demuxer.text_io.get(), ti.fname, id);
demuxer.subs = subtitles_cptr(parser);
int cc_utf8 = map_has_key(ti.sub_charsets, id) ? utf8_init(ti.sub_charsets[id])
@ -319,7 +316,7 @@ avi_reader_c::create_ssa_packetizer(int idx) {
: cc_local_utf8;
parser->set_iconv_handle(cc_utf8);
parser->set_ignore_attachments(ti.no_attachments);
parser->set_attachment_id_base(g_attachments.size());
parser->parse();
std::string global = parser->get_global();
@ -799,6 +796,7 @@ avi_reader_c::identify() {
identify_video();
identify_audio();
identify_subtitles();
identify_attachments();
}
void
@ -850,6 +848,27 @@ avi_reader_c::identify_subtitles() {
: "unknown");
}
void
avi_reader_c::identify_attachments() {
int i;
for (i = 0; sdemuxers.size() > i; ++i) {
try {
avi_subs_demuxer_t &demuxer = sdemuxers[i];
mm_text_io_c text_io(new mm_mem_io_c(demuxer.subtitles->get(), demuxer.subtitles->get_size()));
ssa_parser_c parser(this, &text_io, ti.fname, i + 1 + AVI_audio_tracks(avi));
parser.set_attachment_id_base(g_attachments.size());
parser.parse();
} catch (...) {
}
}
for (i = 0; i < g_attachments.size(); i++)
id_result_attachment(g_attachments[i].ui_id, g_attachments[i].mime_type, g_attachments[i].data->get_size(), g_attachments[i].name, g_attachments[i].description);
}
void
avi_reader_c::add_available_track_ids() {
int i;

View File

@ -104,6 +104,7 @@ protected:
virtual void identify_video();
virtual void identify_audio();
virtual void identify_subtitles();
virtual void identify_attachments();
};
#endif // __R_AVI_H

View File

@ -134,12 +134,13 @@ kax_reader_c::probe_file(mm_io_c *io,
// {{{ C'TOR
kax_reader_c::kax_reader_c(track_info_c &_ti)
throw (error_c):
generic_reader_c(_ti),
segment_duration(0),
first_timecode(-1),
writing_app_ver(-1) {
throw (error_c)
: generic_reader_c(_ti)
, segment_duration(0)
, first_timecode(-1)
, writing_app_ver(-1)
, m_attachment_id(0)
{
if (!read_headers())
throw error_c(Y("matroska_reader: Failed to read the headers."));
if (verbose)
@ -543,17 +544,18 @@ kax_reader_c::handle_attachments(mm_io_c *io,
}
}
if ((-1 != id) && (-1 != size) && !mime_type.empty() && (0 < name.length())) {
attachment_t matt;
attach_mode_e attach_mode;
if ((-1 != id) && (-1 != size) && !mime_type.empty() && (0 != name.length()) && ((attach_mode = attachment_requested(m_attachment_id + 1)) != ATTACH_MODE_SKIP)) {
++m_attachment_id;
attachment_t matt;
matt.name = UTFstring_to_cstrutf8(name);
matt.mime_type = mime_type;
matt.description = UTFstring_to_cstrutf8(description);
matt.id = id;
matt.to_all_files = true;
matt.data = counted_ptr<buffer_t>(new buffer_t);
matt.data->m_size = size;
matt.data->m_buffer = (unsigned char *)safememdup(data, size);
matt.ui_id = m_attachment_id;
matt.to_all_files = ATTACH_MODE_TO_ALL_FILES == attach_mode;
matt.data = clone_memory(data, size);
add_attachment(matt);
}
@ -570,9 +572,6 @@ void
kax_reader_c::handle_chapters(mm_io_c *io,
EbmlElement *l0,
int64_t pos) {
if (ti.no_chapters)
return;
bool found = false;
int i;
for (i = 0; i < handled_chapters.size(); i++)
@ -615,9 +614,6 @@ void
kax_reader_c::handle_tags(mm_io_c *io,
EbmlElement *l0,
int64_t pos) {
if (ti.no_tags)
return;
bool found = false;
int i;
for (i = 0; i < handled_tags.size(); i++)
@ -1201,10 +1197,14 @@ kax_reader_c::read_headers() {
if (!ti.no_attachments)
for (i = 0; i < deferred_attachments.size(); i++)
handle_attachments(in, l0, deferred_attachments[i]);
for (i = 0; i < deferred_chapters.size(); i++)
handle_chapters(in, l0, deferred_chapters[i]);
for (i = 0; i < deferred_tags.size(); i++)
handle_tags(in, l0, deferred_tags[i]);
if (!ti.no_chapters)
for (i = 0; i < deferred_chapters.size(); i++)
handle_chapters(in, l0, deferred_chapters[i]);
if (!ti.no_tags)
for (i = 0; i < deferred_tags.size(); i++)
handle_tags(in, l0, deferred_tags[i]);
} catch (...) {
mxerror(Y("matroska_reader: caught exception\n"));
@ -2149,7 +2149,7 @@ kax_reader_c::identify() {
}
for (i = 0; i < g_attachments.size(); i++)
id_result_attachment(g_attachments[i].id, g_attachments[i].mime_type, g_attachments[i].data->m_size, g_attachments[i].name, g_attachments[i].description);
id_result_attachment(g_attachments[i].ui_id, g_attachments[i].mime_type, g_attachments[i].data->get_size(), g_attachments[i].name, g_attachments[i].description);
}
// }}}

View File

@ -169,6 +169,8 @@ private:
string writing_app, muxing_app;
int64_t writing_app_ver;
int64_t m_attachment_id;
public:
kax_reader_c(track_info_c &_ti) throw (error_c);
virtual ~kax_reader_c();

View File

@ -51,10 +51,9 @@ ssa_reader_c::ssa_reader_c(track_info_c &_ti)
: cc_local_utf8;
ti.id = 0;
m_subs = ssa_parser_cptr(new ssa_parser_c(io.get(), ti.fname, 0));
m_subs = ssa_parser_cptr(new ssa_parser_c(this, io.get(), ti.fname, 0));
m_subs->set_iconv_handle(cc_utf8);
m_subs->set_ignore_attachments(ti.no_attachments);
m_subs->parse();
if (verbose)
@ -101,4 +100,8 @@ void
ssa_reader_c::identify() {
id_result_container("SSA/ASS");
id_result_track(0, ID_RESULT_TRACK_SUBTITLES, "SSA/ASS");
int i;
for (i = 0; i < g_attachments.size(); i++)
id_result_attachment(g_attachments[i].ui_id, g_attachments[i].mime_type, g_attachments[i].data->get_size(), g_attachments[i].name, g_attachments[i].description);
}

View File

@ -234,15 +234,17 @@ ssa_parser_c::probe(mm_text_io_c *io) {
return false;
}
ssa_parser_c::ssa_parser_c(mm_text_io_c *io,
ssa_parser_c::ssa_parser_c(generic_reader_c *reader,
mm_text_io_c *io,
const std::string &file_name,
int64_t tid)
: m_io(io)
: m_reader(reader)
, m_io(io)
, m_file_name(file_name)
, m_tid(tid)
, m_cc_utf8(-1)
, m_is_ass(false)
, m_ignore_attachments(true)
, m_attachment_id(0)
{
}
@ -454,7 +456,15 @@ void
ssa_parser_c::add_attachment_maybe(std::string &name,
std::string &data_uu,
ssa_section_e section) {
if (m_ignore_attachments || name.empty() || data_uu.empty() || ((SSA_SECTION_FONTS != section) && (SSA_SECTION_GRAPHICS != section))) {
if (name.empty() || data_uu.empty() || ((SSA_SECTION_FONTS != section) && (SSA_SECTION_GRAPHICS != section))) {
name = "";
data_uu = "";
return;
}
++m_attachment_id;
if (!m_reader->attachment_requested(m_attachment_id)) {
name = "";
data_uu = "";
return;
@ -471,27 +481,28 @@ ssa_parser_c::add_attachment_maybe(std::string &name,
if (0 < pos)
short_name.erase(0, pos + 1);
attachment.ui_id = m_attachment_id;
attachment.name = to_utf8(m_cc_utf8, name);
attachment.description = (boost::format(SSA_SECTION_FONTS == section ? Y("Imported font from %1%") : Y("Imported picture from %1%")) % short_name).str();
attachment.to_all_files = true;
int allocated = 1024;
buffer_t *buffer = new buffer_t((unsigned char *)safemalloc(allocated), 0);
attachment.data = memory_c::alloc(allocated);
attachment.data->set_size(0);
const unsigned char *p = (const unsigned char *)data_uu.c_str();
for (pos = 0; data_uu.length() > (pos + 4); pos += 4)
decode_chars(p[pos], p[pos + 1], p[pos + 2], p[pos + 3], *buffer, 3, allocated);
decode_chars(p[pos], p[pos + 1], p[pos + 2], p[pos + 3], attachment.data, 3, allocated);
switch (data_uu.length() % 4) {
case 2:
decode_chars(p[pos], p[pos + 1], 0, 0, *buffer, 1, allocated);
decode_chars(p[pos], p[pos + 1], 0, 0, attachment.data, 1, allocated);
break;
case 3:
decode_chars(p[pos], p[pos + 1], p[pos + 2], 0, *buffer, 2, allocated);
decode_chars(p[pos], p[pos + 1], p[pos + 2], 0, attachment.data, 2, allocated);
break;
}
attachment.data = counted_ptr<buffer_t>(buffer);
attachment.mime_type = guess_mime_type(name, false);
if (attachment.mime_type == "")
@ -508,7 +519,7 @@ ssa_parser_c::decode_chars(unsigned char c1,
unsigned char c2,
unsigned char c3,
unsigned char c4,
buffer_t &buffer,
memory_cptr &buffer,
int bytes_to_add,
int &allocated) {
unsigned char bytes[3];
@ -518,15 +529,15 @@ ssa_parser_c::decode_chars(unsigned char c1,
bytes[1] = (value & 0x00ff00) >> 8;
bytes[0] = (value & 0xff0000) >> 16;
if ((buffer.m_size + bytes_to_add) > allocated) {
allocated += 1024;
buffer.m_buffer = (unsigned char *)realloc(buffer.m_buffer, allocated);
if ((buffer->get_size() + bytes_to_add) > allocated) {
int old_size = buffer->get_size();
allocated += 1024;
buffer->resize(allocated);
buffer->set_size(old_size);
}
int i;
for (i = 0; i < bytes_to_add; ++i)
buffer.m_buffer[buffer.m_size + i] = bytes[i];
buffer.m_size += bytes_to_add;
memcpy(buffer->get() + buffer->get_size(), bytes, bytes_to_add);
buffer->set_size(buffer->get_size() + bytes_to_add);
}
// ------------------------------------------------------------

View File

@ -19,6 +19,7 @@
#include <string>
#include <vector>
#include "output_control.h"
#include "p_textsubs.h"
typedef struct sub_t {
@ -102,6 +103,7 @@ public:
};
protected:
generic_reader_c *m_reader;
mm_text_io_c *m_io;
const std::string &m_file_name;
int64_t m_tid;
@ -109,10 +111,13 @@ protected:
std::vector<std::string> m_format;
bool m_is_ass;
std::string m_global;
bool m_ignore_attachments;
int64_t m_attachment_id;
public:
ssa_parser_c(mm_text_io_c *io, const std::string &file_name, int64_t tid);
vector<attachment_t> m_attachments;
public:
ssa_parser_c(generic_reader_c *reader, mm_text_io_c *io, const std::string &file_name, int64_t tid);
void parse();
bool is_ass() {
@ -123,14 +128,14 @@ public:
m_cc_utf8 = cc_utf8;
}
void set_ignore_attachments(bool ignore_attachments) {
m_ignore_attachments = ignore_attachments;
}
std::string get_global() {
return m_global;
}
void set_attachment_id_base(int64_t id) {
m_attachment_id = id;
}
public:
static bool probe(mm_text_io_c *io);
@ -139,7 +144,7 @@ protected:
string get_element(const char *index, std::vector<std::string> &fields);
string recode_text(std::vector<std::string> &fields);
void add_attachment_maybe(std::string &name, std::string &data_uu, ssa_section_e section);
void decode_chars(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, buffer_t &buffer, int bytes_to_add, int &allocated);
void decode_chars(unsigned char c1, unsigned char c2, unsigned char c3, unsigned char c4, memory_cptr &buffer, int bytes_to_add, int &allocated);
};
typedef counted_ptr<ssa_parser_c> ssa_parser_cptr;

View File

@ -196,7 +196,11 @@ set_usage() {
usage_text += Y(" -b, --btracks <n,m,...> Copy buttons tracks n,m etc. Default: copy\n"
" all buttons tracks.\n");
usage_text += Y(" -B, --nobuttons Don't copy any buttons track from this file.\n");
usage_text += Y(" --no-attachments Don't keep attachments from a Matroska file.\n");
usage_text += Y(" -m, --attachments <n[:all|first],m[:all|first],...>\n"
" Copy the attachments with the IDs n, m etc to\n"
" all or only the first output file. Default: copy\n"
" all attachments to all output files.\n");
usage_text += Y(" -M, --no-attachments Don't copy attachments from a Matroska file.\n");
usage_text += Y(" --no-chapters Don't keep chapters from a Matroska file.\n");
usage_text += Y(" --no-tags Don't keep tags from a Matroska file.\n");
usage_text += Y(" -y, --sync, --delay <TID:d[,o[/p]]>\n"
@ -1407,14 +1411,13 @@ parse_arg_attach_file(attachment_t &attachment,
attachment.mime_type = guess_mime_type_and_report(arg);
try {
attachment.data = counted_ptr<buffer_t>(new buffer_t);
mm_io_cptr io = mm_io_cptr(new mm_file_io_c(attachment.name));
attachment.data->m_size = io->get_size();
mm_io_cptr io = mm_io_cptr(new mm_file_io_c(attachment.name));
if (0 == attachment.data->m_size)
if (0 == io->get_size())
mxerror(boost::format(Y("The size of attachment '%1%' is 0.\n")) % attachment.name);
attachment.data->m_buffer = (unsigned char *)safemalloc(attachment.data->m_size); io->read(attachment.data->m_buffer, attachment.data->m_size);
attachment.data = memory_c::alloc(io->get_size());
io->read(attachment.data->get(), attachment.data->get_size());
} catch (...) {
mxerror(boost::format(Y("The attachment '%1%' could not be read.\n")) % attachment.name);
@ -1507,6 +1510,37 @@ parse_arg_default_language(const string &arg) {
g_default_language = iso639_languages[i].iso639_2_code;
}
static void
parse_arg_attachments(const string &param,
const string &arg,
track_info_c &ti) {
vector<string> elements = split(arg, ",");
int i;
for (i = 0; elements.size() > i; ++i) {
vector<string> pair = split(elements[i], ":");
if (1 == pair.size())
pair.push_back("all");
else if (2 != pair.size())
mxerror(boost::format(Y("The argument '%1%' to '%2%' is invalid: too many colons in element '%3%'.\n")) % arg % param % elements[i]);
int64_t id;
if (!parse_int(pair[0], id))
mxerror(boost::format(Y("The argument '%1%' to '%2%' is invalid: '%3%' is not a valid track ID.\n")) % arg % param % pair[0]);
if (pair[1] == "all")
ti.attach_mode_list[id] = ATTACH_MODE_TO_ALL_FILES;
else if (pair[1] == "first")
ti.attach_mode_list[id] = ATTACH_MODE_TO_FIRST_FILE;
else
mxerror(boost::format(Y("The argument '%1%' to '%2%' is invalid: '%3%' must be either 'all' or 'first'.\n")) % arg % param % pair[1]);
}
}
/** \brief Parses and handles command line arguments
Also probes input files for their type and creates the appropriate
@ -1792,9 +1826,16 @@ parse_args(vector<string> args) {
} else if (this_arg == "--no-chapters") {
ti->no_chapters = true;
} else if (this_arg == "--no-attachments") {
} else if ((this_arg == "-M") || (this_arg == "--no-attachments")) {
ti->no_attachments = true;
} else if ((this_arg == "-m") || (this_arg == "--attachments")) {
if (no_next_arg)
mxerror(boost::format(Y("'%1%' lacks its argument.")) % this_arg);
parse_arg_attachments(this_arg, next_arg, *ti);
sit++;
} else if (this_arg == "--no-tags") {
ti->no_tags = true;

View File

@ -466,9 +466,9 @@ add_attachment(attachment_t attachment) {
if (( (i->id == attachment.id)
&& !hack_engaged(ENGAGE_NO_VARIABLE_DATA))
||
( (i->name == attachment.name)
&& (i->description == attachment.description)
&& (i->data->m_size == attachment.data->m_size)))
( (i->name == attachment.name)
&& (i->description == attachment.description)
&& (i->data->get_size() == attachment.data->get_size())))
return attachment.id;
add_unique_uint32(attachment.id, UNIQUE_ATTACHMENT_IDS);
@ -764,7 +764,7 @@ render_attachments(IOCallback *out) {
GetChildAs<KaxFileName, EbmlUnicodeString>(kax_a) = cstr_to_UTFstring(name);
GetChildAs<KaxFileUID, EbmlUInteger>(kax_a) = attch->id;
GetChild<KaxFileData>(*kax_a).CopyBuffer(attch->data->m_buffer, attch->data->m_size);
GetChild<KaxFileData>(*kax_a).CopyBuffer(attch->data->get(), attch->data->get_size());
}
}
@ -1143,9 +1143,9 @@ create_readers() {
// Calculate the size of all attachments for split control.
mxforeach(att, g_attachments) {
g_attachment_sizes_first += att->data->m_size;
g_attachment_sizes_first += att->data->get_size();
if (att->to_all_files)
g_attachment_sizes_others += att->data->m_size;
g_attachment_sizes_others += att->data->get_size();
}
calc_max_chapter_size();

View File

@ -96,19 +96,21 @@ struct attachment_t {
string name, stored_name, mime_type, description;
int64_t id;
bool to_all_files;
counted_ptr<buffer_t> data;
memory_cptr data;
int64_t ui_id;
attachment_t() {
clear();
}
void clear() {
name = "";
stored_name = "";
mime_type = "";
description = "";
id = 0;
name = "";
stored_name = "";
mime_type = "";
description = "";
id = 0;
ui_id = 0;
to_all_files = false;
data = counted_ptr<buffer_t>(NULL);
data = memory_cptr(NULL);
}
};

View File

@ -1124,6 +1124,23 @@ generic_reader_c::demuxing_requested(char type,
return false;
}
attach_mode_e
generic_reader_c::attachment_requested(int64_t id) {
if (ti.no_attachments)
return ATTACH_MODE_SKIP;
if (ti.attach_mode_list.empty())
return ATTACH_MODE_TO_ALL_FILES;
if (map_has_key(ti.attach_mode_list, id))
return ti.attach_mode_list[id];
if (map_has_key(ti.attach_mode_list, -1))
return ti.attach_mode_list[-1];
return ATTACH_MODE_SKIP;
}
int
generic_reader_c::add_packetizer(generic_packetizer_c *ptzr) {
reader_packetizers.push_back(ptzr);
@ -1454,6 +1471,8 @@ track_info_c::operator =(const track_info_c &src) {
nalu_size_lengths = src.nalu_size_lengths;
nalu_size_length = src.nalu_size_length;
attach_mode_list = src.attach_mode_list;
no_chapters = src.no_chapters;
no_attachments = src.no_attachments;
no_tags = src.no_tags;

View File

@ -165,6 +165,12 @@ enum stereo_mode_e {
STEREO_MODE_BOTH = 3,
};
enum attach_mode_e {
ATTACH_MODE_SKIP,
ATTACH_MODE_TO_FIRST_FILE,
ATTACH_MODE_TO_ALL_FILES,
};
class track_info_c {
protected:
bool initialized;
@ -234,6 +240,8 @@ public:
map<int64_t, int> nalu_size_lengths;
int nalu_size_length;
map<int64_t, attach_mode_e> attach_mode_list; // As given on the command line
bool no_chapters, no_attachments, no_tags;
// Some file formats can contain chapters, but for some the charset
@ -315,6 +323,8 @@ public:
virtual void flush_packetizers();
virtual attach_mode_e attachment_requested(int64_t id);
virtual void display_identification_results();
protected:

View File

@ -64,7 +64,7 @@ T_213mp4_broken_pixel_dimensions:dc4f6c0c82b1d1aabaadac51d70b77c0:passed:2005091
T_214one_frame_avi:bea975277e91ded1a4085043e89608ce:passed:20051004-192755
T_215X_codec_extradata_avi:78d669fc6511b6b931cd0981e2e1cca9-3fabc505fdd377c05ce4557b1bc13545:passed:20051004-194707
T_216mp4_editlists:16705ae21c46e6d1b64ca55b5d54ed9d:passed:20051118-191453
T_217file_identification:ef3c502529537c1d3699d0e0487751c3-39c82d78b1ea6ffc1ccd20f07f2cfcc6-9e935f2c47c31e35d5267859601f4bf6-fdcd19f0b817e3db32c3d891f283462e-57f72aff43b852c96e8929495d91bebf-9c926be4a5c0dbf460ebc0c0ecf9a756-d7678dc91cba91a946c22e5b96f3b3b6-3f60e3a03129d1e4610ae668459457cc-c170654ad0688c40fc9e2ceeb9ef0b9f-6b44c4e351ac48b7fdb63355c65783eb-d701319c3f77c58adfee92b1186a3993-12aa395d3bc0431c5acb81bc4407b70f-3e7956db47487933b47241fc7bc76359-52dfc8091ce64db9f8ad44aee34748ec-6b7149a5774a37d214b8085c6409aab3-15beba0108723bff77bf8d88876f8f31-72fabb6ff0194c82321db1c317b11c63-2b03944260062946d1ceabde9c71e007-87cb6b0e3933210309228a79d3a3f823-34b0b13ac1b1b3ced17cbb31df973d62-e592a5d28c92ebb23fe6d7ea901ec0a9-f997737ca7eff867d33ee58af611e741:passed:20051209-180815
T_217file_identification:ef3c502529537c1d3699d0e0487751c3-39c82d78b1ea6ffc1ccd20f07f2cfcc6-9055d420c47bb3d615271d6af02bb9ce-fdcd19f0b817e3db32c3d891f283462e-57f72aff43b852c96e8929495d91bebf-9c926be4a5c0dbf460ebc0c0ecf9a756-d7678dc91cba91a946c22e5b96f3b3b6-3f60e3a03129d1e4610ae668459457cc-c170654ad0688c40fc9e2ceeb9ef0b9f-6b44c4e351ac48b7fdb63355c65783eb-d701319c3f77c58adfee92b1186a3993-12aa395d3bc0431c5acb81bc4407b70f-3e7956db47487933b47241fc7bc76359-52dfc8091ce64db9f8ad44aee34748ec-6b7149a5774a37d214b8085c6409aab3-15beba0108723bff77bf8d88876f8f31-72fabb6ff0194c82321db1c317b11c63-2b03944260062946d1ceabde9c71e007-87cb6b0e3933210309228a79d3a3f823-34b0b13ac1b1b3ced17cbb31df973d62-e592a5d28c92ebb23fe6d7ea901ec0a9-f997737ca7eff867d33ee58af611e741:passed:20051209-180815
T_218theora:b09cfce53d36b68422e315bf5ff12341-fac4b041366588e3c8215b9fbb696db2:passed:20060428-105054
T_219srt_short_timecodes:a7db07ee64751fcc24993dd4af73ccf1:passed:20060926-112658
T_220ass_with_comments_at_start:51ccd0cbe4e60b21817d7547310250bb:passed:20060926-120101