diff --git a/ChangeLog b/ChangeLog index 9dbe2573a..8a7df7b27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ 2013-12-29 Moritz Bunkus - * mmgL bug fixL the »playlist items« list box in the »select + * mkvextract: bug fix: if the track headers were located at the + end of the file (e.g. after modification with mkvpropedit or mmg's + header editor) then mkvextract was writing files with a length 0 + bytes. + + * mmg: bug fix: the »playlist items« list box in the »select playlist file to add« dialog was showing the items in reversed order. Fixes #952. diff --git a/src/extract/mkvextract.cpp b/src/extract/mkvextract.cpp index 801c5f272..be038048e 100644 --- a/src/extract/mkvextract.cpp +++ b/src/extract/mkvextract.cpp @@ -83,7 +83,7 @@ main(int argc, options_c options = extract_cli_parser_c(command_line_utf8(argc, argv)).run(); if (options_c::em_tracks == options.m_extraction_mode) { - extract_tracks(options.m_file_name, options.m_tracks); + extract_tracks(options.m_file_name, options.m_tracks, options.m_parse_mode); if (0 == verbose) mxinfo(Y("Progress: 100%\n")); diff --git a/src/extract/mkvextract.h b/src/extract/mkvextract.h index 42d41526c..9e29f4d46 100644 --- a/src/extract/mkvextract.h +++ b/src/extract/mkvextract.h @@ -53,7 +53,7 @@ show_error(const boost::format &format) { void find_and_verify_track_uids(KaxTracks &tracks, std::vector &tspecs); -bool extract_tracks(const std::string &file_name, std::vector &tspecs); +bool extract_tracks(const std::string &file_name, std::vector &tspecs, kax_analyzer_c::parse_mode_e parse_mode); void extract_tags(const std::string &file_name, kax_analyzer_c::parse_mode_e parse_mode); void extract_chapters(const std::string &file_name, bool chapter_format_simple, kax_analyzer_c::parse_mode_e parse_mode); void extract_attachments(const std::string &file_name, std::vector &tracks, kax_analyzer_c::parse_mode_e parse_mode); diff --git a/src/extract/tracks.cpp b/src/extract/tracks.cpp index 7a459ba9a..7ba2fcf2b 100644 --- a/src/extract/tracks.cpp +++ b/src/extract/tracks.cpp @@ -330,9 +330,22 @@ find_and_verify_track_uids(KaxTracks &tracks, mxerror(boost::format(Y("No track with the ID %1% was found in the source file.\n")) % tspec.tid); } +static void +handle_segment_info(EbmlMaster *info, + kax_file_c *file, + uint64_t &tc_scale) { + auto ktc_scale = FindChild(info); + if (!ktc_scale) + return; + + tc_scale = ktc_scale->GetValue(); + file->set_timecode_scale(tc_scale); +} + bool extract_tracks(const std::string &file_name, - std::vector &tspecs) { + std::vector &tspecs, + kax_analyzer_c::parse_mode_e parse_mode) { if (tspecs.empty()) mxerror(Y("Nothing to do.\n")); @@ -348,8 +361,30 @@ extract_tracks(const std::string &file_name, } int64_t file_size = in->get_size(); + uint64_t tc_scale = TIMECODE_SCALE; + bool segment_info_found = false, tracks_found = false; + + // open input file + auto analyzer = std::make_shared(static_cast(in.get())); + if (analyzer->process(parse_mode, MODE_READ)) { + auto af_master = ebml_master_cptr{ analyzer->read_all(EBML_INFO(KaxInfo)) }; + auto segment_info = dynamic_cast(af_master.get()); + if (segment_info) { + segment_info_found = true; + handle_segment_info(segment_info, file.get(), tc_scale); + } + + af_master = ebml_master_cptr{ analyzer->read_all(EBML_INFO(KaxTracks)) }; + auto tracks = dynamic_cast(af_master.get()); + if (tracks) { + tracks_found = true; + find_and_verify_track_uids(*tracks, tspecs); + create_extractors(*tracks, tspecs); + } + } try { + in->setFilePointer(0); EbmlStream *es = new EbmlStream(*in); // Find the EbmlHead element. Must be the first one. @@ -383,31 +418,17 @@ extract_tracks(const std::string &file_name, delete l0; } - bool tracks_found = false; EbmlElement *l1 = nullptr; - uint64_t tc_scale = TIMECODE_SCALE; KaxChapters all_chapters; KaxTags all_tags; while ((l1 = file->read_next_level1_element())) { - if (Is(l1)) { - // General info about this Matroska file - show_element(l1, 1, Y("Segment information")); - - auto ktc_scale = FindChild(l1); - if (ktc_scale) { - tc_scale = ktc_scale->GetValue(); - file->set_timecode_scale(tc_scale); - show_element(ktc_scale, 2, boost::format(Y("Timecode scale: %1%")) % tc_scale); - } - - } else if ((Is(l1)) && !tracks_found) { - - // Yep, we've found our KaxTracks element. Now find all tracks - // contained in this segment. - show_element(l1, 1, Y("Segment tracks")); + if (Is(l1) && !segment_info_found) { + segment_info_found = true; + handle_segment_info(static_cast(l1), file.get(), tc_scale); + } else if (Is(l1) && !tracks_found) { tracks_found = true; find_and_verify_track_uids(*dynamic_cast(l1), tspecs); create_extractors(*dynamic_cast(l1), tspecs); diff --git a/tests/results.txt b/tests/results.txt index 8433e01ec..3692e34be 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -262,3 +262,4 @@ T_413memory_resize_nonfree_smaller:c1085152b4b60a197bf93d598d066924:passed:20131 T_414vc1_no_sequence_headers_before_key_frames:48a03189f55b303a98332e6594f7bd31:passed:20131115-164756:0.133015738 T_415create_webm:c1447a8f67f47a0b2d8c21d4208a8f98-5e1abfc5e13a44989a6ff31e51e9eaa9-8ba1b32bd84baef269181ea74cf06f0d-415d91e89e995b02b695e127617d2d8a-AAC@ok-AC3@ok-ALAC@ok-DivX@ok-h.264/AVC@ok-Dirac@ok-DTS@ok-FLV@ok-MP3@ok-MPEG1@ok-MPEG2@ok-PCM@ok-RV4@ok-SSA@ok-PGS@ok-SRT@ok-USF@ok-VC1@ok-WavPack4@ok:passed:20131218-221942:0.832721732 T_416dts_in_mp4:77e4a560d93a9c1a1030318c07ee48e5-60d52627905d83b1e605119152d7bf4e:passed:20131218-231435:1.398112245 +T_417mkvextract_tracks_at_end_of_file:b3bb67d316e20da12926d5c1d628f6e5:passed:20131229-122704:0.04690235 diff --git a/tests/test-417mkvextract_tracks_at_end_of_file.rb b/tests/test-417mkvextract_tracks_at_end_of_file.rb new file mode 100755 index 000000000..b0b5865d0 --- /dev/null +++ b/tests/test-417mkvextract_tracks_at_end_of_file.rb @@ -0,0 +1,8 @@ +#!/usr/bin/ruby -w + +# T_417mkvextract_tracks_at_end_of_file +describe "mkvextract / track headers located at the end of the file" +test "extraction" do + extract "data/mkv/tracks-at-end.mka", 0 => tmp + hash_tmp +end