AVC/h.264: generate timecodes if provided timecodes are not enough

This commit is contained in:
Moritz Bunkus 2011-08-25 15:53:54 +02:00
parent b37a7b3202
commit 787339f03a
5 changed files with 40 additions and 10 deletions

View File

@ -569,6 +569,7 @@ mpeg4::p10::avc_es_parser_c::avc_es_parser_c()
, m_first_keyframe_found(false)
, m_recovery_point_valid(false)
, m_b_frames_since_keyframe(false)
, m_max_timecode(0)
, m_generate_timecodes(false)
, m_have_incomplete_frame(false)
, m_ignore_nalu_size_length_errors(false)
@ -684,6 +685,8 @@ mpeg4::p10::avc_es_parser_c::add_timecode(int64_t timecode) {
--i;
}
m_timecodes.insert(i, timecode);
m_max_timecode = std::max(timecode, m_max_timecode);
}
void
@ -1053,6 +1056,9 @@ mpeg4::p10::avc_es_parser_c::default_cleanup() {
std::deque<avc_frame_t>::iterator i(m_frames.begin());
std::deque<int64_t>::iterator t(m_timecodes.begin());
if (m_frames.size() > m_timecodes.size())
create_missing_timecodes();
int64_t r = i->m_start = i->m_end = *t;
++i;
@ -1094,12 +1100,8 @@ mpeg4::p10::avc_es_parser_c::cleanup() {
// (cluster_helper etc).
i->m_keyframe = true;
if (m_timecodes.size() < m_frames.size()) {
mxverb(4, boost::format("mpeg4::p10::avc_es_parser_c::cleanup() numfr %1% sti %2%\n") % m_frames.size() % m_timecodes.size());
m_timecodes.erase(m_timecodes.begin(), m_timecodes.begin() + m_frames.size());
m_frames.clear();
return;
}
if (m_frames.size() > m_timecodes.size())
create_missing_timecodes();
slice_info_t &idr = i->m_si;
sps_info_t &sps = m_sps_info_list[idr.sps];
@ -1186,7 +1188,7 @@ mpeg4::p10::avc_es_parser_c::cleanup() {
}
m_frames_out.insert(m_frames_out.end(), m_frames.begin(), m_frames.end());
m_timecodes.erase(m_timecodes.begin(), m_timecodes.begin() + m_frames.size());
m_timecodes.erase(m_timecodes.begin(), m_timecodes.begin() + std::min(num_frames, num_timecodes));
m_frames.clear();
}
@ -1300,3 +1302,14 @@ mpeg4::p10::avc_es_parser_c::init_nalu_names() {
m_nalu_names_by_type[NALU_TYPE_END_OF_STREAM] = "end of stream";
m_nalu_names_by_type[NALU_TYPE_FILLER_DATA] = "filler";
}
void
mpeg4::p10::avc_es_parser_c::create_missing_timecodes() {
size_t num_timecodes = m_timecodes.size();
size_t num_frames = m_frames.size();
while (num_timecodes < num_frames) {
++num_timecodes;
add_timecode(m_max_timecode + m_default_duration);
}
}

View File

@ -196,6 +196,7 @@ namespace mpeg4 {
std::deque<avc_frame_t> m_frames, m_frames_out;
std::deque<int64_t> m_timecodes;
int64_t m_max_timecode;
bool m_generate_timecodes;
@ -219,6 +220,10 @@ namespace mpeg4 {
avc_es_parser_c();
~avc_es_parser_c();
void set_default_duration(int64_t default_duration) {
m_default_duration = default_duration;
}
void enable_timecode_generation(int64_t default_duration) {
m_default_duration = default_duration;
m_generate_timecodes = true;
@ -308,6 +313,7 @@ namespace mpeg4 {
void write_nalu_size(unsigned char *buffer, size_t size, int this_nalu_size_length = -1);
memory_cptr create_nalu_with_size(const memory_cptr &src, bool add_extra_data = false);
void init_nalu_names();
void create_missing_timecodes();
};
typedef counted_ptr<avc_es_parser_c> avc_es_parser_cptr;
};

View File

@ -582,7 +582,7 @@ mpeg_ts_reader_c::new_stream_v_avc(unsigned char *buf,
% sps_info.timing_info_present % sps_info.num_units_in_tick % sps_info.time_scale % sps_info.fixed_frame_rate);
if (sps_info.timing_info_present && sps_info.num_units_in_tick)
track->v_frame_rate = sps_info.time_scale / sps_info.num_units_in_tick;
track->v_frame_rate = static_cast<float>(sps_info.time_scale) / sps_info.num_units_in_tick;
if (sps_info.ar_found) {
float aspect_ratio = (float)sps_info.width / (float)sps_info.height * (float)sps_info.par_num / (float)sps_info.par_den;
@ -977,9 +977,13 @@ mpeg_ts_reader_c::create_mpeg4_p10_es_video_packetizer(mpeg_ts_track_ptr &track)
mpeg4_p10_es_video_packetizer_c *avcpacketizer = new mpeg4_p10_es_video_packetizer_c(this, m_ti, track->v_avcc, track->v_width, track->v_height);
track->ptzr = add_packetizer(avcpacketizer);
avcpacketizer->enable_timecode_generation(false);
if (track->v_frame_rate)
avcpacketizer->set_track_default_duration(static_cast<int64_t>(1000000000.0 / track->v_frame_rate));
// This is intentional so that the AVC parser knows the actual
// default duration from above but only generates timecode in
// emergencies.
avcpacketizer->enable_timecode_generation(false);
}
void

View File

@ -92,7 +92,7 @@ mpeg4_p10_es_video_packetizer_c::add_extra_data(memory_cptr data) {
int
mpeg4_p10_es_video_packetizer_c::process(packet_cptr packet) {
try {
if (!m_allow_timecode_generation)
if (packet->has_timecode())
m_parser.add_timecode(packet->timecode);
m_parser.add_bytes(packet->data->get_buffer(), packet->data->get_size());
flush_frames();
@ -168,6 +168,12 @@ mpeg4_p10_es_video_packetizer_c::enable_timecode_generation(bool enable,
}
}
void
mpeg4_p10_es_video_packetizer_c::set_track_default_duration(int64_t default_duration) {
m_parser.set_default_duration(default_duration);
generic_packetizer_c::set_track_default_duration(default_duration);
}
void
mpeg4_p10_es_video_packetizer_c::connect(generic_packetizer_c *src,
int64_t p_append_timecode_offset) {

View File

@ -40,6 +40,7 @@ public:
virtual void enable_timecode_generation(bool enable, int64_t default_duration = -1);
virtual void extract_aspect_ratio();
virtual void set_track_default_duration(int64_t default_duration);
virtual const char *get_format_name() {
return "AVC/h.264";