From c8ceb5dd8708f5a38da7fb95c69e547e97fa9a6f Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Wed, 27 Aug 2003 17:44:33 +0000 Subject: [PATCH] Support for re-creating dropped frames when extracting video to an AVI. Works only well if the frame durations in the source file are multiples of the frame rate, of course. --- ChangeLog | 4 ++++ src/mkvextract.h | 2 ++ src/mkvextract_tracks.cpp | 37 +++++++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index a0fbbfaff..aa9107b68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2003-08-27 Moritz Bunkus + * mkvextract: Support for re-creating dropped frames when + extracting video to an AVI. Works only well if the frame durations + in the source file are multiples of the frame rate, of course. + * mkvmerge: The MP3 packetizer did not start at 0 with its timecodes. It does now. diff --git a/src/mkvextract.h b/src/mkvextract.h index ce842e923..a2f038cca 100644 --- a/src/mkvextract.h +++ b/src/mkvextract.h @@ -67,6 +67,8 @@ typedef struct { float v_fps; int v_width, v_height; + int64_t default_duration; + int srt_num; int conv_handle; vector ssa_lines; diff --git a/src/mkvextract_tracks.cpp b/src/mkvextract_tracks.cpp index b77fc2b3a..7ed9e89c0 100644 --- a/src/mkvextract_tracks.cpp +++ b/src/mkvextract_tracks.cpp @@ -127,6 +127,13 @@ static void create_output_files() { // Video tracks: if (tracks[i].track_type == 'v') { tracks[i].type = TYPEAVI; + if (strcmp(tracks[i].codec_id, MKV_V_MSCOMP)) { + mxwarn("Extraction of video tracks with a CodecId " + "other than " MKV_V_MSCOMP " is not supported at the " + "moment. Skipping track %lld.\n", tracks[i].tid); + continue; + } + if ((tracks[i].v_width == 0) || (tracks[i].v_height == 0) || (tracks[i].v_fps == 0.0) || (tracks[i].private_data == NULL) || (tracks[i].private_size < sizeof(alBITMAPINFOHEADER))) { @@ -135,13 +142,6 @@ static void create_output_files() { continue; } - if (strcmp(tracks[i].codec_id, MKV_V_MSCOMP)) { - mxwarn("Extraction of video tracks with a CodecId " - "other than " MKV_V_MSCOMP " is not supported at the " - "moment. Skipping track %lld.\n", tracks[i].tid); - continue; - } - } else if (tracks[i].track_type == 'a') { if ((tracks[i].a_sfreq == 0.0) || (tracks[i].a_channels == 0)) { mxwarn("Track ID %lld is missing some critical " @@ -415,10 +415,15 @@ static void create_output_files() { // {{{ FUNCTION handle_data() +#define myrnd(a) ((int)(a) == (int)((a) + 0.5) ? (int)(a) : (int)((a) + 0.5)) +#define myabs(a) ((a) < 0 ? (a) * -1 : (a)) + +static int dropped = 0; + static void handle_data(KaxBlock *block, int64_t block_duration, bool has_ref) { kax_track_t *track; - int i, len, num; + int i, k, len, num; int64_t start, end; char *s, buffer[200], *s2, adts[56 / 8]; vector fields; @@ -431,6 +436,9 @@ static void handle_data(KaxBlock *block, int64_t block_duration, return; } + if (block_duration == -1) + block_duration = track->default_duration; + start = block->GlobalTimecode() / 1000000; // in ms end = start + block_duration; @@ -440,6 +448,11 @@ static void handle_data(KaxBlock *block, int64_t block_duration, case TYPEAVI: AVI_write_frame(track->avi, (char *)data.Buffer(), data.Size(), has_ref ? 0 : 1); + if (myabs(block_duration - (int64_t)(1000.0 / track->v_fps)) > 1) { + int nfr = myrnd(block_duration * track->v_fps / 1000.0); + for (k = 2; k <= nfr; k++) + AVI_write_frame(track->avi, "", 0, 0); + } break; case TYPEOGM: @@ -693,6 +706,8 @@ static void close_files() { } } } + + mxinfo("\nDROPPED: %u\n", dropped); } // }}} @@ -1028,8 +1043,10 @@ bool extract_tracks(const char *file_name) { "a video track)", (float)uint64(def_duration) / 1000000.0, 1000000000.0 / (float)uint64(def_duration)); - if (track != NULL) + if (track != NULL) { track->v_fps = 1000000000.0 / (float)uint64(def_duration); + track->default_duration = uint64(def_duration) / 1000000; + } } else l3->SkipData(*es, l3->Generic().Context); @@ -1119,7 +1136,7 @@ bool extract_tracks(const char *file_name) { } else if (EbmlId(*l2) == KaxBlockGroup::ClassInfos.GlobalId) { show_element(l2, 2, "Block group"); - block_duration = 0; + block_duration = -1; has_reference = false; l3 = es->FindNextElement(l2->Generic().Context, upper_lvl_el, 0xFFFFFFFFL, false, 1);