diff --git a/ChangeLog b/ChangeLog index 46eab1c2c..7e8535181 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2004-03-27 Moritz Bunkus + + * mkvmerge: new feature: If using MPEG4 video and no aspect + ratio or display dimensions are given mkvmerge will extract the + aspect ratio information from the stream and automatically set the + display dimensions accordingly. + 2004-03-22 Moritz Bunkus * mkvmerge: bug fix: Using audio sync on AC3 tracks read from diff --git a/src/output/p_video.cpp b/src/output/p_video.cpp index 4db8aca3f..332618d9f 100644 --- a/src/output/p_video.cpp +++ b/src/output/p_video.cpp @@ -60,6 +60,7 @@ video_packetizer_c::video_packetizer_c(generic_reader_c *nreader, duration_shift = 0; bref_frame.type = '?'; fref_frame.type = '?'; + aspect_ratio_extracted = false; set_track_type(track_video); } @@ -198,6 +199,9 @@ video_packetizer_c::process(memory_c &mem, return EMOREDATA; } + if (is_mpeg4 && !aspect_ratio_extracted) + extract_mpeg4_aspect_ratio(mem); + if (old_timecode == -1) timecode = (int64_t)(1000000000.0 * frames_output / fps) + duration_shift; else @@ -243,6 +247,76 @@ video_packetizer_c::flush() { flush_frames(true); } +void +video_packetizer_c::extract_mpeg4_aspect_ratio(memory_c &mem) { + const uint32_t ar_nums[16] = {0, 1, 12, 10, 16, 40, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + const uint32_t ar_dens[16] = {1, 1, 11, 11, 11, 33, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1}; + uint32_t marker, aspect_ratio_info, num, den; + bool b; + bit_cursor_c bits(mem.data, mem.size); + + aspect_ratio_extracted = true; + if (ti->aspect_ratio_given || ti->display_dimensions_given) + return; + + while (!bits.eof()) { + if (!bits.peek_bits(32, marker)) + break; + + if ((marker & 0xffffff00) != 0x00000100) { + bits.skip_bits(8); + continue; + } + + marker &= 0xff; + if ((marker < 0x20) || (marker > 0x2f)) { + bits.skip_bits(8); + continue; + } + + mxverb(2, "mpeg4 AR: found VOL header at %u\n", + bits.get_bit_position() / 8); + bits.skip_bits(32); + + // VOL header + bits.skip_bits(1); // random access + bits.skip_bits(8); // vo_type + bits.get_bit(b); + if (b != 0) { // is_old_id + bits.skip_bits(4); // vo_ver_id + bits.skip_bits(3); // vo_priority + } + + if (bits.get_bits(4, aspect_ratio_info)) { + mxverb(2, "mpeg4 AR: aspect_ratio_info: %u\n", aspect_ratio_info); + if (aspect_ratio_info == 15) { // ASPECT_EXTENDED + bits.get_bits(8, num); + bits.get_bits(8, den); + } else { + num = ar_nums[aspect_ratio_info]; + den = ar_dens[aspect_ratio_info]; + } + mxverb(2, "mpeg4 AR: %u den: %u\n", num, den); + + if ((num != 0) && (den != 0) && ((num != 1) || (den != 1)) && + (((float)num / (float)den) != 1.0)) { + ti->aspect_ratio_given = true; + ti->aspect_ratio = (float)hvideo_pixel_width / + (float)hvideo_pixel_height * (float)num / (float)den; + generic_packetizer_c::set_headers(); + rerender_track_headers(); + mxinfo("Track %lld of '%s': Extracted the aspect ratio information " + "from the MPEG4 data and set the display dimensions to " + "%u/%u.\n", ti->id, ti->fname, ti->display_width, + ti->display_height); + } + } + return; + } +} + void video_packetizer_c::find_mpeg4_frame_types(unsigned char *buf, int size, diff --git a/src/output/p_video.h b/src/output/p_video.h index e37ed49ff..c20a15dfa 100644 --- a/src/output/p_video.h +++ b/src/output/p_video.h @@ -43,6 +43,7 @@ private: int width, height, bpp, frames_output; int64_t ref_timecode, duration_shift; bool avi_compat_mode, bframes, pass_through, is_mpeg4; + bool aspect_ratio_extracted; char *codec_id; vector queued_frames; video_frame_t bref_frame, fref_frame; @@ -66,6 +67,7 @@ protected: virtual void find_mpeg4_frame_types(unsigned char *buf, int size, vector &frames); virtual void flush_frames(char next_frame = '?', bool flush_all = false); + virtual void extract_mpeg4_aspect_ratio(memory_c &mem); }; #endif // __P_VIDEO_H diff --git a/src/pr_generic.cpp b/src/pr_generic.cpp index ebea36598..40f42e988 100644 --- a/src/pr_generic.cpp +++ b/src/pr_generic.cpp @@ -586,11 +586,13 @@ void generic_packetizer_c::set_headers() { GetChild(video); *(static_cast(&dwidth)) = disp_width; dwidth.SetDefaultSize(4); + ti->display_width = disp_width; KaxVideoDisplayHeight &dheight = GetChild(video); *(static_cast(&dheight)) = disp_height; dheight.SetDefaultSize(4); + ti->display_height = disp_height; } } else if (htrack_type == track_audio) {