diff --git a/src/extract/attachments.cpp b/src/extract/attachments.cpp index 978aab99a..b97b18f4e 100644 --- a/src/extract/attachments.cpp +++ b/src/extract/attachments.cpp @@ -43,6 +43,8 @@ using namespace std; static void handle_attachments(KaxAttachments *atts, vector &tracks) { + static int64_t attachment_ui_id = 0; + int i; for (i = 0; atts->ListSize() > i; ++i) { KaxAttached *att = dynamic_cast((*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); diff --git a/src/input/r_avi.cpp b/src/input/r_avi.cpp index cd150ba19..432587278 100644 --- a/src/input/r_avi.cpp +++ b/src/input/r_avi.cpp @@ -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; diff --git a/src/input/r_avi.h b/src/input/r_avi.h index c966ddd0a..2adc6b177 100644 --- a/src/input/r_avi.h +++ b/src/input/r_avi.h @@ -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 diff --git a/src/input/r_matroska.cpp b/src/input/r_matroska.cpp index 27d840a26..835a86fc3 100644 --- a/src/input/r_matroska.cpp +++ b/src/input/r_matroska.cpp @@ -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(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); } // }}} diff --git a/src/input/r_matroska.h b/src/input/r_matroska.h index 2dc8a0e31..7cca66c9f 100644 --- a/src/input/r_matroska.h +++ b/src/input/r_matroska.h @@ -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(); diff --git a/src/input/r_ssa.cpp b/src/input/r_ssa.cpp index a9ae45032..1d4cfafc8 100644 --- a/src/input/r_ssa.cpp +++ b/src/input/r_ssa.cpp @@ -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); } diff --git a/src/input/subtitles.cpp b/src/input/subtitles.cpp index f2a1151e2..2c301ac8d 100644 --- a/src/input/subtitles.cpp +++ b/src/input/subtitles.cpp @@ -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); 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); } // ------------------------------------------------------------ diff --git a/src/input/subtitles.h b/src/input/subtitles.h index b45e2b4ac..9b1a97d67 100644 --- a/src/input/subtitles.h +++ b/src/input/subtitles.h @@ -19,6 +19,7 @@ #include #include +#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 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 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 &fields); string recode_text(std::vector &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_cptr; diff --git a/src/merge/mkvmerge.cpp b/src/merge/mkvmerge.cpp index 074e02cc7..8e54a6202 100644 --- a/src/merge/mkvmerge.cpp +++ b/src/merge/mkvmerge.cpp @@ -196,7 +196,11 @@ set_usage() { usage_text += Y(" -b, --btracks 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" + " 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 \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(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 ¶m, + const string &arg, + track_info_c &ti) { + vector elements = split(arg, ","); + + int i; + for (i = 0; elements.size() > i; ++i) { + vector 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 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; diff --git a/src/merge/output_control.cpp b/src/merge/output_control.cpp index 376128655..27fac1b0d 100644 --- a/src/merge/output_control.cpp +++ b/src/merge/output_control.cpp @@ -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(kax_a) = cstr_to_UTFstring(name); GetChildAs(kax_a) = attch->id; - GetChild(*kax_a).CopyBuffer(attch->data->m_buffer, attch->data->m_size); + GetChild(*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(); diff --git a/src/merge/output_control.h b/src/merge/output_control.h index 7fde471bb..f83200c32 100644 --- a/src/merge/output_control.h +++ b/src/merge/output_control.h @@ -96,19 +96,21 @@ struct attachment_t { string name, stored_name, mime_type, description; int64_t id; bool to_all_files; - counted_ptr 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(NULL); + data = memory_cptr(NULL); } }; diff --git a/src/merge/pr_generic.cpp b/src/merge/pr_generic.cpp index c76ea71a2..61fb8f83d 100644 --- a/src/merge/pr_generic.cpp +++ b/src/merge/pr_generic.cpp @@ -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; diff --git a/src/merge/pr_generic.h b/src/merge/pr_generic.h index d15158f51..25b014427 100644 --- a/src/merge/pr_generic.h +++ b/src/merge/pr_generic.h @@ -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 nalu_size_lengths; int nalu_size_length; + map 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: diff --git a/tests/results.txt b/tests/results.txt index 9bf0e9352..44378efb8 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -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