mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2025-01-04 01:03:33 +00:00
AVC/HEVC ES packetizers: move shared code to common base class
This commit is contained in:
parent
9da7cb3080
commit
b9b94d0149
@ -608,11 +608,22 @@ es_parser_c::create_nalu_with_size(const memory_cptr &src,
|
||||
}
|
||||
|
||||
memory_cptr
|
||||
es_parser_c::get_avcc()
|
||||
es_parser_c::get_configuration_record()
|
||||
const {
|
||||
return avcc_c{static_cast<unsigned int>(m_nalu_size_length), m_sps_list, m_pps_list}.pack();
|
||||
}
|
||||
|
||||
void
|
||||
es_parser_c::set_configuration_record(memory_cptr const &bytes) {
|
||||
auto avcc = avcc_c::unpack(bytes);
|
||||
|
||||
for (auto const &nalu : avcc.m_sps_list)
|
||||
handle_sps_nalu(nalu); // TODO: , extra_data_position_e::dont_store);
|
||||
|
||||
for (auto const &nalu : avcc.m_pps_list)
|
||||
handle_pps_nalu(nalu); // TODO: , extra_data_position_e::dont_store);
|
||||
}
|
||||
|
||||
void
|
||||
es_parser_c::dump_info()
|
||||
const {
|
||||
|
@ -58,7 +58,8 @@ public:
|
||||
virtual void flush() override;
|
||||
virtual void clear() override;
|
||||
|
||||
memory_cptr get_avcc() const;
|
||||
virtual void set_configuration_record(memory_cptr const &bytes) override;
|
||||
virtual memory_cptr get_configuration_record() const override;
|
||||
|
||||
virtual int get_width() const override {
|
||||
assert(!m_sps_info_list.empty());
|
||||
|
@ -123,6 +123,8 @@ public:
|
||||
|
||||
virtual void handle_nalu(memory_cptr const &nalu, uint64_t nalu_pos) = 0;
|
||||
|
||||
virtual void set_configuration_record(memory_cptr const &bytes) = 0;
|
||||
virtual memory_cptr get_configuration_record() const = 0;
|
||||
virtual int get_width() const = 0;
|
||||
virtual int get_height() const = 0;
|
||||
|
||||
|
@ -694,14 +694,14 @@ es_parser_c::calculate_frame_order() {
|
||||
}
|
||||
|
||||
memory_cptr
|
||||
es_parser_c::get_hevcc()
|
||||
es_parser_c::get_configuration_record()
|
||||
const {
|
||||
return hevcc_c{static_cast<unsigned int>(m_nalu_size_length), m_vps_list, m_sps_list, m_pps_list, m_user_data, m_codec_private}.pack();
|
||||
}
|
||||
|
||||
void
|
||||
es_parser_c::set_hevcc(memory_cptr const &hevcc_bytes) {
|
||||
auto hevcc = hevcc_c::unpack(hevcc_bytes);
|
||||
es_parser_c::set_configuration_record(memory_cptr const &bytes) {
|
||||
auto hevcc = hevcc_c::unpack(bytes);
|
||||
|
||||
for (auto const &nalu : hevcc.m_vps_list)
|
||||
handle_vps_nalu(nalu, extra_data_position_e::dont_store);
|
||||
|
@ -53,8 +53,8 @@ public:
|
||||
virtual void flush() override;
|
||||
virtual void clear() override;
|
||||
|
||||
void set_hevcc(memory_cptr const &hevcc_bytes);
|
||||
memory_cptr get_hevcc() const;
|
||||
virtual void set_configuration_record(memory_cptr const &bytes) override;
|
||||
virtual memory_cptr get_configuration_record() const override;
|
||||
|
||||
virtual int get_width() const override {
|
||||
assert(!m_sps_info_list.empty());
|
||||
|
@ -39,7 +39,7 @@ xtr_hevc_c::create_file(xtr_base_c *master,
|
||||
mxerror(fmt::format(Y("Track {0} CodecPrivate is too small.\n"), m_tid));
|
||||
|
||||
m_parser.normalize_parameter_sets(m_normalize_parameter_sets);
|
||||
m_parser.set_hevcc(m_decoded_codec_private);
|
||||
m_parser.set_configuration_record(m_decoded_codec_private);
|
||||
|
||||
m_nal_size_size = 1 + (m_decoded_codec_private->get_buffer()[21] & 3);
|
||||
}
|
||||
|
@ -3395,7 +3395,7 @@ qtmp4_demuxer_c::check_for_hevc_video_annex_b_bitstream() {
|
||||
}
|
||||
|
||||
priv.clear();
|
||||
priv.emplace_back(parser.get_hevcc());
|
||||
priv.emplace_back(parser.get_configuration_record());
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3527,7 +3527,7 @@ qtmp4_demuxer_c::derive_track_params_from_avc_bitstream() {
|
||||
parser.flush();
|
||||
|
||||
if (parser.headers_parsed())
|
||||
priv.emplace_back(parser.get_avcc());
|
||||
priv.emplace_back(parser.get_configuration_record());
|
||||
|
||||
mxdebug_if(m_debug_headers, fmt::format("derive_track_params_from_avc_bitstream: avcC derived? size {0} bytes\n", !priv.empty() && priv[0] ? priv[0]->get_size() : 0));
|
||||
|
||||
|
@ -38,28 +38,8 @@ avc_es_video_packetizer_c(generic_reader_c *p_reader,
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::process_impl(packet_cptr const &packet) {
|
||||
try {
|
||||
if (packet->has_timestamp())
|
||||
m_parser.add_timestamp(packet->timestamp);
|
||||
m_parser.add_bytes(packet->data->get_buffer(), packet->data->get_size());
|
||||
flush_frames();
|
||||
|
||||
} catch (mtx::exception &error) {
|
||||
mxerror_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format(Y("mkvmerge encountered broken or unparsable data in this AVC/H.264 video track. "
|
||||
"Either your file is damaged (which mkvmerge cannot cope with yet) or this is a bug in mkvmerge itself. "
|
||||
"The error message was:\n{0}\n"), error.error()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::handle_delayed_headers() {
|
||||
if (0 < m_parser.get_num_skipped_frames())
|
||||
mxwarn_tid(m_ti.m_fname, m_ti.m_id, fmt::format(Y("This AVC/H.264 track does not start with a key frame. The first {0} frames have been skipped.\n"), m_parser.get_num_skipped_frames()));
|
||||
|
||||
set_codec_private(m_parser.get_avcc());
|
||||
|
||||
avc_es_video_packetizer_c::check_if_default_duration_available()
|
||||
const {
|
||||
if ( !m_reader->is_providing_timestamps()
|
||||
&& !m_timestamp_factory
|
||||
&& !m_parser.is_default_duration_forced()
|
||||
@ -69,88 +49,6 @@ avc_es_video_packetizer_c::handle_delayed_headers() {
|
||||
mxwarn_tid(m_ti.m_fname, m_ti.m_id, Y("This AVC/H.264 track's timing information indicates that it uses a variable frame rate. "
|
||||
"However, no default duration nor an external timestamp file has been provided for it, nor does the source container provide timestamps. "
|
||||
"The resulting timestamps may not be useful.\n"));
|
||||
|
||||
handle_aspect_ratio();
|
||||
handle_actual_default_duration();
|
||||
|
||||
rerender_track_headers();
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::handle_aspect_ratio() {
|
||||
mxdebug_if(m_debug_aspect_ratio, fmt::format("already set? {0} has par been found? {1}\n", display_dimensions_or_aspect_ratio_set(), m_parser.has_par_been_found()));
|
||||
|
||||
if (display_dimensions_or_aspect_ratio_set() || !m_parser.has_par_been_found())
|
||||
return;
|
||||
|
||||
auto dimensions = m_parser.get_display_dimensions(m_hvideo_pixel_width, m_hvideo_pixel_height);
|
||||
set_video_display_dimensions(dimensions.first, dimensions.second, generic_packetizer_c::ddu_pixels, OPTION_SOURCE_BITSTREAM);
|
||||
|
||||
mxinfo_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format(Y("Extracted the aspect ratio information from the MPEG-4 layer 10 (AVC) video data "
|
||||
"and set the display dimensions to {0}/{1}.\n"), m_ti.m_display_width, m_ti.m_display_height));
|
||||
|
||||
mxdebug_if(m_debug_aspect_ratio,
|
||||
fmt::format("PAR {0} pixel_width/hgith {1}/{2} display_width/height {3}/{4}\n",
|
||||
m_parser.get_par(), m_hvideo_pixel_width, m_hvideo_pixel_height, m_ti.m_display_width, m_ti.m_display_height));
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::handle_actual_default_duration() {
|
||||
int64_t actual_default_duration = m_parser.get_most_often_used_duration();
|
||||
mxdebug_if(m_debug_timestamps, fmt::format("Most often used duration: {0} forced? {1} current default duration: {2}\n", actual_default_duration, m_default_duration_forced, m_htrack_default_duration));
|
||||
|
||||
if ( !m_default_duration_forced
|
||||
&& (0 < actual_default_duration)
|
||||
&& (m_htrack_default_duration != actual_default_duration))
|
||||
set_track_default_duration(actual_default_duration);
|
||||
|
||||
else if ( m_default_duration_forced
|
||||
&& (0 < m_default_duration_for_interlaced_content)
|
||||
&& (std::abs(actual_default_duration - m_default_duration_for_interlaced_content) <= 20000)) {
|
||||
m_default_duration_forced = false;
|
||||
set_track_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::flush_frames() {
|
||||
while (m_parser.frame_available()) {
|
||||
if (m_first_frame) {
|
||||
handle_delayed_headers();
|
||||
m_first_frame = false;
|
||||
}
|
||||
|
||||
auto frame = m_parser.get_frame();
|
||||
auto duration = frame.m_end > frame.m_start ? frame.m_end - frame.m_start : m_htrack_default_duration;
|
||||
auto packet = std::make_shared<packet_t>(frame.m_data, frame.m_start, duration,
|
||||
frame.is_i_frame() ? -1 : frame.m_start + frame.m_ref1,
|
||||
!frame.is_b_frame() ? -1 : frame.m_start + frame.m_ref2);
|
||||
packet->key_flag = frame.is_key_frame();
|
||||
packet->discardable_flag = frame.is_discardable();
|
||||
|
||||
add_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_es_video_packetizer_c::connect(generic_packetizer_c *src,
|
||||
int64_t p_append_timestamp_offset) {
|
||||
generic_packetizer_c::connect(src, p_append_timestamp_offset);
|
||||
|
||||
if (2 != m_connected_to)
|
||||
return;
|
||||
|
||||
avc_es_video_packetizer_c *real_src = dynamic_cast<avc_es_video_packetizer_c *>(src);
|
||||
assert(real_src);
|
||||
|
||||
m_htrack_default_duration = real_src->m_htrack_default_duration;
|
||||
m_default_duration_forced = real_src->m_default_duration_forced;
|
||||
|
||||
if (m_default_duration_forced && (-1 != m_htrack_default_duration)) {
|
||||
m_default_duration_for_interlaced_content = m_htrack_default_duration / 2;
|
||||
m_parser.force_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
||||
connection_result_e
|
||||
|
@ -25,18 +25,12 @@ protected:
|
||||
public:
|
||||
avc_es_video_packetizer_c(generic_reader_c *p_reader, track_info_c &p_ti);
|
||||
|
||||
virtual void flush_frames() override;
|
||||
|
||||
virtual translatable_string_c get_format_name() const {
|
||||
virtual translatable_string_c get_format_name() const override {
|
||||
return YT("AVC/H.264 (unframed)");
|
||||
};
|
||||
|
||||
virtual void connect(generic_packetizer_c *src, int64_t p_append_timestamp_offset = -1);
|
||||
virtual connection_result_e can_connect_to(generic_packetizer_c *src, std::string &error_message);
|
||||
virtual connection_result_e can_connect_to(generic_packetizer_c *src, std::string &error_message) override;
|
||||
|
||||
protected:
|
||||
virtual void process_impl(packet_cptr const &packet) override;
|
||||
virtual void handle_delayed_headers();
|
||||
virtual void handle_aspect_ratio();
|
||||
virtual void handle_actual_default_duration();
|
||||
virtual void check_if_default_duration_available() const override;
|
||||
};
|
||||
|
@ -83,24 +83,124 @@ avc_hevc_es_video_packetizer_c::add_extra_data(memory_cptr const &data) {
|
||||
m_parser_base->add_bytes(data->get_buffer(), data->get_size());
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::process_impl(packet_cptr const &packet) {
|
||||
try {
|
||||
if (packet->has_timestamp())
|
||||
m_parser_base->add_timestamp(packet->timestamp);
|
||||
m_parser_base->add_bytes(packet->data->get_buffer(), packet->data->get_size());
|
||||
flush_frames();
|
||||
|
||||
} catch (mtx::exception &error) {
|
||||
mxerror_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format("{0} {1}\n{2}\n",
|
||||
Y("mkvmerge encountered broken or unparsable data in this video track."),
|
||||
Y("The error message was:"),
|
||||
error.error()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::flush_impl() {
|
||||
m_parser_base->flush();
|
||||
flush_frames();
|
||||
}
|
||||
|
||||
// void
|
||||
// hevc_es_video_packetizer_c::flush_frames() {
|
||||
// while (m_parser_base->frame_available()) {
|
||||
// if (m_first_frame) {
|
||||
// handle_delayed_headers();
|
||||
// m_first_frame = false;
|
||||
// }
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::flush_frames() {
|
||||
while (m_parser_base->frame_available()) {
|
||||
if (m_first_frame) {
|
||||
handle_delayed_headers();
|
||||
m_first_frame = false;
|
||||
}
|
||||
|
||||
// auto frame = m_parser_base->get_frame();
|
||||
// add_packet(std::make_shared<packet_t>(frame.m_data, frame.m_start,
|
||||
// frame.m_end > frame.m_start ? frame.m_end - frame.m_start : m_htrack_default_duration,
|
||||
// frame.is_key_frame() ? -1 : frame.m_start + frame.m_ref1,
|
||||
// !frame.is_b_frame() ? -1 : frame.m_start + frame.m_ref2));
|
||||
// }
|
||||
// }
|
||||
auto frame = m_parser_base->get_frame();
|
||||
auto duration = frame.m_end > frame.m_start ? frame.m_end - frame.m_start : m_htrack_default_duration;
|
||||
auto packet = std::make_shared<packet_t>(frame.m_data, frame.m_start, duration,
|
||||
frame.is_key_frame() ? -1 : frame.m_start + frame.m_ref1,
|
||||
!frame.is_b_frame() ? -1 : frame.m_start + frame.m_ref2);
|
||||
|
||||
packet->key_flag = frame.is_key_frame();
|
||||
packet->discardable_flag = frame.is_discardable();
|
||||
|
||||
add_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::check_if_default_duration_available()
|
||||
const {
|
||||
// No default implementation, but not required either.
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::handle_delayed_headers() {
|
||||
if (0 < m_parser_base->get_num_skipped_frames())
|
||||
mxwarn_tid(m_ti.m_fname, m_ti.m_id, fmt::format(Y("This AVC/H.264 track does not start with a key frame. The first {0} frames have been skipped.\n"), m_parser_base->get_num_skipped_frames()));
|
||||
|
||||
set_codec_private(m_parser_base->get_configuration_record());
|
||||
|
||||
check_if_default_duration_available();
|
||||
|
||||
handle_aspect_ratio();
|
||||
handle_actual_default_duration();
|
||||
|
||||
rerender_track_headers();
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::handle_aspect_ratio() {
|
||||
mxdebug_if(m_debug_aspect_ratio, fmt::format("already set? {0} has par been found? {1}\n", display_dimensions_or_aspect_ratio_set(), m_parser_base->has_par_been_found()));
|
||||
|
||||
if (display_dimensions_or_aspect_ratio_set() || !m_parser_base->has_par_been_found())
|
||||
return;
|
||||
|
||||
auto dimensions = m_parser_base->get_display_dimensions(m_hvideo_pixel_width, m_hvideo_pixel_height);
|
||||
set_video_display_dimensions(dimensions.first, dimensions.second, generic_packetizer_c::ddu_pixels, OPTION_SOURCE_BITSTREAM);
|
||||
|
||||
mxinfo_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format(Y("Extracted the aspect ratio information from the video bitstream and set the display dimensions to {0}/{1}.\n"),
|
||||
m_ti.m_display_width, m_ti.m_display_height));
|
||||
|
||||
mxdebug_if(m_debug_aspect_ratio,
|
||||
fmt::format("PAR {0} pixel_width/hgith {1}/{2} display_width/height {3}/{4}\n",
|
||||
m_parser_base->get_par(), m_hvideo_pixel_width, m_hvideo_pixel_height, m_ti.m_display_width, m_ti.m_display_height));
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::handle_actual_default_duration() {
|
||||
int64_t actual_default_duration = m_parser_base->get_most_often_used_duration();
|
||||
mxdebug_if(m_debug_timestamps, fmt::format("Most often used duration: {0} forced? {1} current default duration: {2}\n", actual_default_duration, m_default_duration_forced, m_htrack_default_duration));
|
||||
|
||||
if ( !m_default_duration_forced
|
||||
&& (0 < actual_default_duration)
|
||||
&& (m_htrack_default_duration != actual_default_duration))
|
||||
set_track_default_duration(actual_default_duration);
|
||||
|
||||
else if ( m_default_duration_forced
|
||||
&& (0 < m_default_duration_for_interlaced_content)
|
||||
&& (std::abs(actual_default_duration - m_default_duration_for_interlaced_content) <= 20000)) {
|
||||
m_default_duration_forced = false;
|
||||
set_track_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
avc_hevc_es_video_packetizer_c::connect(generic_packetizer_c *src,
|
||||
int64_t p_append_timestamp_offset) {
|
||||
generic_packetizer_c::connect(src, p_append_timestamp_offset);
|
||||
|
||||
if (2 != m_connected_to)
|
||||
return;
|
||||
|
||||
auto real_src = dynamic_cast<avc_hevc_es_video_packetizer_c *>(src);
|
||||
assert(real_src);
|
||||
|
||||
m_htrack_default_duration = real_src->m_htrack_default_duration;
|
||||
m_default_duration_forced = real_src->m_default_duration_forced;
|
||||
|
||||
if (m_default_duration_forced && (-1 != m_htrack_default_duration)) {
|
||||
m_default_duration_for_interlaced_content = m_htrack_default_duration / 2;
|
||||
m_parser_base->force_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,17 @@ public:
|
||||
virtual void set_container_default_field_duration(int64_t default_duration);
|
||||
virtual unsigned int get_nalu_size_length() const;
|
||||
|
||||
virtual void flush_frames() = 0;
|
||||
virtual void connect(generic_packetizer_c *src, int64_t p_append_timestamp_offset) override;
|
||||
|
||||
protected:
|
||||
virtual void process_impl(packet_cptr const &packet) override;
|
||||
|
||||
virtual void flush_impl() override;
|
||||
virtual void flush_frames();
|
||||
|
||||
virtual void check_if_default_duration_available() const;
|
||||
|
||||
virtual void handle_delayed_headers();
|
||||
virtual void handle_aspect_ratio();
|
||||
virtual void handle_actual_default_duration();
|
||||
};
|
||||
|
@ -49,7 +49,7 @@ hevc_video_packetizer_c(generic_reader_c *p_reader,
|
||||
set_codec_private(m_ti.m_private_data);
|
||||
|
||||
p.parser->normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS));
|
||||
p.parser->set_hevcc(m_hcodec_private);
|
||||
p.parser->set_configuration_record(m_hcodec_private);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -34,113 +34,6 @@ hevc_es_video_packetizer_c::hevc_es_video_packetizer_c(generic_reader_c *p_reade
|
||||
m_parser.normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS));
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::process_impl(packet_cptr const &packet) {
|
||||
try {
|
||||
if (packet->has_timestamp())
|
||||
m_parser.add_timestamp(packet->timestamp);
|
||||
m_parser.add_bytes(packet->data->get_buffer(), packet->data->get_size());
|
||||
flush_frames();
|
||||
|
||||
} catch (mtx::exception &error) {
|
||||
mxerror_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format(Y("mkvmerge encountered broken or unparsable data in this HEVC video track. "
|
||||
"Either your file is damaged (which mkvmerge cannot cope with yet) or this is a bug in mkvmerge itself. "
|
||||
"The error message was:\n{0}\n"), error.error()));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::handle_delayed_headers() {
|
||||
if (0 < m_parser.get_num_skipped_frames())
|
||||
mxwarn_tid(m_ti.m_fname, m_ti.m_id, fmt::format(Y("This HEVC track does not start with a key frame. The first {0} frames have been skipped.\n"), m_parser.get_num_skipped_frames()));
|
||||
|
||||
set_codec_private(m_parser.get_hevcc());
|
||||
|
||||
handle_aspect_ratio();
|
||||
handle_actual_default_duration();
|
||||
|
||||
rerender_track_headers();
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::handle_aspect_ratio() {
|
||||
mxdebug_if(m_debug_aspect_ratio, fmt::format("already set? {0} has par been found? {1}\n", display_dimensions_or_aspect_ratio_set(), m_parser.has_par_been_found()));
|
||||
|
||||
if (display_dimensions_or_aspect_ratio_set() || !m_parser.has_par_been_found())
|
||||
return;
|
||||
|
||||
auto dimensions = m_parser.get_display_dimensions(m_hvideo_pixel_width, m_hvideo_pixel_height);
|
||||
set_video_display_dimensions(dimensions.first, dimensions.second, generic_packetizer_c::ddu_pixels, OPTION_SOURCE_BITSTREAM);
|
||||
|
||||
mxinfo_tid(m_ti.m_fname, m_ti.m_id,
|
||||
fmt::format(Y("Extracted the aspect ratio information from the HEVC video data "
|
||||
"and set the display dimensions to {0}/{1}.\n"), m_ti.m_display_width, m_ti.m_display_height));
|
||||
|
||||
mxdebug_if(m_debug_aspect_ratio,
|
||||
fmt::format("PAR {0} pixel_width/hgith {1}/{2} display_width/height {3}/{4}\n",
|
||||
m_parser.get_par(), m_hvideo_pixel_width, m_hvideo_pixel_height, m_ti.m_display_width, m_ti.m_display_height));
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::handle_actual_default_duration() {
|
||||
int64_t actual_default_duration = m_parser.get_most_often_used_duration();
|
||||
mxdebug_if(m_debug_timestamps, fmt::format("Most often used duration: {0} forced? {1} current default duration: {2}\n", actual_default_duration, m_default_duration_forced, m_htrack_default_duration));
|
||||
|
||||
if ( !m_default_duration_forced
|
||||
&& (0 < actual_default_duration)
|
||||
&& (m_htrack_default_duration != actual_default_duration))
|
||||
set_track_default_duration(actual_default_duration);
|
||||
|
||||
else if ( m_default_duration_forced
|
||||
&& (0 < m_default_duration_for_interlaced_content)
|
||||
&& (std::abs(actual_default_duration - m_default_duration_for_interlaced_content) <= 20000)) {
|
||||
m_default_duration_forced = false;
|
||||
set_track_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::flush_frames() {
|
||||
while (m_parser_base->frame_available()) {
|
||||
if (m_first_frame) {
|
||||
handle_delayed_headers();
|
||||
m_first_frame = false;
|
||||
}
|
||||
|
||||
auto frame = m_parser_base->get_frame();
|
||||
auto duration = frame.m_end > frame.m_start ? frame.m_end - frame.m_start : m_htrack_default_duration;
|
||||
auto packet = std::make_shared<packet_t>(frame.m_data, frame.m_start, duration,
|
||||
frame.is_key_frame() ? -1 : frame.m_start + frame.m_ref1,
|
||||
!frame.is_b_frame() ? -1 : frame.m_start + frame.m_ref2);
|
||||
|
||||
packet->key_flag = frame.is_key_frame();
|
||||
packet->discardable_flag = frame.is_discardable();
|
||||
|
||||
add_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hevc_es_video_packetizer_c::connect(generic_packetizer_c *src,
|
||||
int64_t p_append_timestamp_offset) {
|
||||
generic_packetizer_c::connect(src, p_append_timestamp_offset);
|
||||
|
||||
if (2 != m_connected_to)
|
||||
return;
|
||||
|
||||
auto *real_src = dynamic_cast<hevc_es_video_packetizer_c *>(src);
|
||||
assert(real_src);
|
||||
|
||||
m_htrack_default_duration = real_src->m_htrack_default_duration;
|
||||
m_default_duration_forced = real_src->m_default_duration_forced;
|
||||
|
||||
if (m_default_duration_forced && (-1 != m_htrack_default_duration)) {
|
||||
m_default_duration_for_interlaced_content = m_htrack_default_duration / 2;
|
||||
m_parser.force_default_duration(m_default_duration_for_interlaced_content);
|
||||
}
|
||||
}
|
||||
|
||||
connection_result_e
|
||||
hevc_es_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
|
||||
[[maybe_unused]] std::string &error_message) {
|
||||
|
@ -24,18 +24,9 @@ protected:
|
||||
public:
|
||||
hevc_es_video_packetizer_c(generic_reader_c *p_reader, track_info_c &p_ti);
|
||||
|
||||
virtual void flush_frames() override;
|
||||
|
||||
virtual translatable_string_c get_format_name() const {
|
||||
virtual translatable_string_c get_format_name() const override {
|
||||
return YT("HEVC/H.265 (unframed)");
|
||||
};
|
||||
|
||||
virtual void connect(generic_packetizer_c *src, int64_t p_append_timestamp_offset = -1);
|
||||
virtual connection_result_e can_connect_to(generic_packetizer_c *src, std::string &error_message);
|
||||
|
||||
protected:
|
||||
virtual void process_impl(packet_cptr const &packet) override;
|
||||
virtual void handle_delayed_headers();
|
||||
virtual void handle_aspect_ratio();
|
||||
virtual void handle_actual_default_duration();
|
||||
virtual connection_result_e can_connect_to(generic_packetizer_c *src, std::string &error_message) override;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user