mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-02-03 15:59:38 +00:00
Parse and apply audio encoder delay information in MP4 files
Fix for bug 715.
This commit is contained in:
parent
371ca103bd
commit
0ffdd3a6bf
@ -1,3 +1,9 @@
|
||||
2012-02-06 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: new feature: mkvmerge will parse and apply the audio
|
||||
encoder delay in MP4 files that contain said information in the
|
||||
format that iTunes writes it. Fix for bug 715.
|
||||
|
||||
2012-02-02 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: new feature: Implemented support for treating several
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "common/iso639.h"
|
||||
#include "common/matroska.h"
|
||||
#include "common/strings/formatting.h"
|
||||
#include "common/strings/parsing.h"
|
||||
#include "input/r_qtmp4.h"
|
||||
#include "merge/output_control.h"
|
||||
#include "output/p_aac.h"
|
||||
@ -110,6 +111,7 @@ qtmp4_reader_c::qtmp4_reader_c(const track_info_c &ti,
|
||||
, m_time_scale(1)
|
||||
, m_compression_algorithm(0)
|
||||
, m_main_dmx(-1)
|
||||
, m_audio_encoder_delay_samples(0)
|
||||
, m_debug_chapters( debugging_requested("qtmp4") || debugging_requested("qtmp4_full") || debugging_requested("qtmp4_chapters"))
|
||||
, m_debug_headers( debugging_requested("qtmp4") || debugging_requested("qtmp4_full") || debugging_requested("qtmp4_headers"))
|
||||
, m_debug_tables( debugging_requested("qtmp4_full") || debugging_requested("qtmp4_tables"))
|
||||
@ -344,6 +346,15 @@ qtmp4_reader_c::calculate_timecodes() {
|
||||
dmx->build_index();
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::handle_audio_encoder_delay(qtmp4_demuxer_cptr &dmx) {
|
||||
if ((0 == m_audio_encoder_delay_samples) || (0 == dmx->a_samplerate) || (-1 == dmx->ptzr))
|
||||
return;
|
||||
|
||||
PTZR(dmx->ptzr)->m_ti.m_tcsync.displacement -= (m_audio_encoder_delay_samples * 1000000000ll) / dmx->a_samplerate;
|
||||
m_audio_encoder_delay_samples = 0;
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::parse_video_header_priv_atoms(qtmp4_demuxer_cptr &dmx,
|
||||
unsigned char *mem,
|
||||
@ -735,6 +746,9 @@ qtmp4_reader_c::handle_udta_atom(qt_atom_t parent,
|
||||
if (FOURCC('c', 'h', 'p', 'l') == atom.fourcc)
|
||||
handle_chpl_atom(atom.to_parent(), level + 1);
|
||||
|
||||
else if (FOURCC('m', 'e', 't', 'a') == atom.fourcc)
|
||||
handle_meta_atom(atom.to_parent(), level + 1);
|
||||
|
||||
skip_atom();
|
||||
parent.size -= atom.size;
|
||||
}
|
||||
@ -772,6 +786,94 @@ qtmp4_reader_c::handle_chpl_atom(qt_atom_t,
|
||||
process_chapter_entries(level, entries);
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::handle_meta_atom(qt_atom_t parent,
|
||||
int level) {
|
||||
m_in->skip(1 + 3); // version & flags
|
||||
|
||||
while (8 <= parent.size) {
|
||||
qt_atom_t atom = read_atom();
|
||||
print_basic_atom_info();
|
||||
|
||||
if (FOURCC('i', 'l', 's', 't') == atom.fourcc)
|
||||
handle_ilst_atom(atom.to_parent(), level + 1);
|
||||
|
||||
skip_atom();
|
||||
parent.size -= atom.size;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::handle_ilst_atom(qt_atom_t parent,
|
||||
int level) {
|
||||
while (8 <= parent.size) {
|
||||
qt_atom_t atom = read_atom();
|
||||
print_basic_atom_info();
|
||||
|
||||
if (FOURCC('-', '-', '-', '-') == atom.fourcc)
|
||||
handle_4dashes_atom(atom.to_parent(), level + 1);
|
||||
|
||||
skip_atom();
|
||||
parent.size -= atom.size;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
qtmp4_reader_c::read_string_atom(qt_atom_t atom,
|
||||
size_t num_skipped) {
|
||||
if ((num_skipped + atom.hsize) > atom.size)
|
||||
return "";
|
||||
|
||||
std::string string;
|
||||
size_t length = atom.size - atom.hsize - num_skipped;
|
||||
|
||||
m_in->skip(num_skipped);
|
||||
m_in->read(string, length);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::handle_4dashes_atom(qt_atom_t parent,
|
||||
int level) {
|
||||
std::string name, mean, data;
|
||||
|
||||
while (8 <= parent.size) {
|
||||
qt_atom_t atom = read_atom();
|
||||
print_basic_atom_info();
|
||||
|
||||
if (FOURCC('n', 'a', 'm', 'e') == atom.fourcc)
|
||||
name = read_string_atom(atom, 4);
|
||||
|
||||
else if (FOURCC('m', 'e', 'a', 'n') == atom.fourcc)
|
||||
mean = read_string_atom(atom, 4);
|
||||
|
||||
else if (FOURCC('d', 'a', 't', 'a') == atom.fourcc)
|
||||
data = read_string_atom(atom, 8);
|
||||
|
||||
skip_atom();
|
||||
parent.size -= atom.size;
|
||||
}
|
||||
|
||||
mxdebug_if(m_debug_headers, boost::format("'----' content: name=%1% mean=%2% data=%3%\n") % name % mean % data);
|
||||
|
||||
if (name == "iTunSMPB")
|
||||
parse_itunsmpb(data);
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::parse_itunsmpb(std::string data) {
|
||||
data = boost::regex_replace(data, boost::regex("[^\\da-fA-F]+", boost::regex::perl), "");
|
||||
|
||||
if (16 > data.length())
|
||||
return;
|
||||
|
||||
try {
|
||||
m_audio_encoder_delay_samples = from_hex(data.substr(8, 8));
|
||||
} catch (std::bad_cast &) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qtmp4_reader_c::read_chapter_track() {
|
||||
if (m_ti.m_no_chapters || (NULL != m_chapters) || !m_chapter_dmx.is_set())
|
||||
@ -1593,6 +1695,8 @@ qtmp4_reader_c::create_packetizer(int64_t tid) {
|
||||
|
||||
else
|
||||
create_audio_packetizer_passthrough(dmx);
|
||||
|
||||
handle_audio_encoder_delay(dmx);
|
||||
}
|
||||
|
||||
if (packetizer_ok && (-1 == m_main_dmx))
|
||||
|
@ -280,6 +280,8 @@ private:
|
||||
uint32_t m_time_scale, m_compression_algorithm;
|
||||
int m_main_dmx;
|
||||
|
||||
unsigned int m_audio_encoder_delay_samples;
|
||||
|
||||
bool m_debug_chapters, m_debug_headers, m_debug_tables, m_debug_interleaving;
|
||||
|
||||
public:
|
||||
@ -308,6 +310,7 @@ protected:
|
||||
virtual void parse_audio_header_priv_atoms(qtmp4_demuxer_cptr &dmx, unsigned char *mem, size_t size, int level);
|
||||
virtual bool parse_esds_atom(mm_mem_io_c &memio, qtmp4_demuxer_cptr &dmx, int level);
|
||||
virtual uint32_t read_esds_descr_len(mm_mem_io_c &memio);
|
||||
virtual void parse_itunsmpb(std::string data);
|
||||
|
||||
virtual void handle_cmov_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_cmvd_atom(qt_atom_t parent, int level);
|
||||
@ -321,6 +324,9 @@ protected:
|
||||
virtual void handle_mvhd_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_udta_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_chpl_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_meta_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_ilst_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_4dashes_atom(qt_atom_t parent, int level);
|
||||
virtual void handle_stbl_atom(qtmp4_demuxer_cptr &new_dmx, qt_atom_t parent, int level);
|
||||
virtual void handle_stco_atom(qtmp4_demuxer_cptr &new_dmx, qt_atom_t parent, int level);
|
||||
virtual void handle_co64_atom(qtmp4_demuxer_cptr &new_dmx, qt_atom_t parent, int level);
|
||||
@ -349,12 +355,16 @@ protected:
|
||||
virtual void create_video_packetizer_standard(qtmp4_demuxer_cptr &dmx);
|
||||
virtual void create_video_packetizer_svq1(qtmp4_demuxer_cptr &dmx);
|
||||
|
||||
virtual void handle_audio_encoder_delay(qtmp4_demuxer_cptr &dmx);
|
||||
|
||||
virtual std::string decode_and_verify_language(uint16_t coded_language);
|
||||
virtual void read_chapter_track();
|
||||
virtual void recode_chapter_entries(std::vector<qtmp4_chapter_entry_t> &entries);
|
||||
virtual void process_chapter_entries(int level, std::vector<qtmp4_chapter_entry_t> &entries);
|
||||
|
||||
virtual void detect_interleaving();
|
||||
|
||||
virtual std::string read_string_atom(qt_atom_t atom, size_t num_skipped);
|
||||
};
|
||||
|
||||
#endif // __R_QTMP4_H
|
||||
|
@ -179,3 +179,4 @@ T_330dts_detection:38c941b579418e6c874950f4c55f84ce:passed:20120107-210130:1.227
|
||||
T_331read_buffer_underflow:3bdec07b9e45cafe2c35561e7f8ad2db:passed:20120125-232902:0.407400904
|
||||
T_332eac3_misdetected_as_avc:b4e0ac5954dbf57e4ad941f01c7de462:passed:20120131-145550:0.452730804
|
||||
T_333wavpack_with_correction:c561a04a67042b048f7059a80d1c366d-e33897409384ca5fd8ed5e497f8c3883+37f802510b43b2ab4bd7d8356a7ac606-ok:passed:20120131-164845:0.299865433
|
||||
T_334mp4_audio_encoder_delay:2afe7b533c9f1ed35168e60aaca20dff:passed:20120206-100443:0.195628019
|
||||
|
6
tests/test-334mp4_audio_encoder_delay.rb
Normal file
6
tests/test-334mp4_audio_encoder_delay.rb
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/ruby -w
|
||||
|
||||
# T_334mp4_audio_encoder_delay
|
||||
describe "mkvmerge / MP4 files & audio encoder delay information"
|
||||
|
||||
test_merge "data/mp4/aac_encoder_delay_sample.m4a"
|
Loading…
Reference in New Issue
Block a user