mkvextract: look for track header with kax_analyzer_c before processing the clusters

That way the track headers will be found even if they're located at
the end of the file.
This commit is contained in:
Moritz Bunkus 2013-12-29 12:28:56 +01:00
parent 1ab1e68c8a
commit c43882dec5
6 changed files with 57 additions and 22 deletions

View File

@ -1,6 +1,11 @@
2013-12-29 Moritz Bunkus <moritz@bunkus.org>
* 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.

View File

@ -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"));

View File

@ -53,7 +53,7 @@ show_error(const boost::format &format) {
void find_and_verify_track_uids(KaxTracks &tracks, std::vector<track_spec_t> &tspecs);
bool extract_tracks(const std::string &file_name, std::vector<track_spec_t> &tspecs);
bool extract_tracks(const std::string &file_name, std::vector<track_spec_t> &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<track_spec_t> &tracks, kax_analyzer_c::parse_mode_e parse_mode);

View File

@ -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<KaxTimecodeScale>(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<track_spec_t> &tspecs) {
std::vector<track_spec_t> &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<kax_analyzer_c>(static_cast<mm_file_io_c *>(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<KaxInfo *>(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<KaxTracks *>(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<KaxInfo>(l1)) {
// General info about this Matroska file
show_element(l1, 1, Y("Segment information"));
auto ktc_scale = FindChild<KaxTimecodeScale>(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<KaxTracks>(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<KaxInfo>(l1) && !segment_info_found) {
segment_info_found = true;
handle_segment_info(static_cast<EbmlMaster *>(l1), file.get(), tc_scale);
} else if (Is<KaxTracks>(l1) && !tracks_found) {
tracks_found = true;
find_and_verify_track_uids(*dynamic_cast<KaxTracks *>(l1), tspecs);
create_extractors(*dynamic_cast<KaxTracks *>(l1), tspecs);

View File

@ -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

View File

@ -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