1 /** MPEG video helper functions (MPEG 1, 2 and 4)
2 
3    mkvmerge -- utility for splicing together matroska files
4    from component media subtypes
5 
6    Distributed under the GPL v2
7    see the file COPYING for details
8    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 
10    \file
11 
12 */
13 
14 #include "common/common_pch.h"
15 
16 #include <cmath>
17 
18 #include "common/bit_reader.h"
19 #include "common/checksums/base_fwd.h"
20 #include "common/endian.h"
21 #include "common/hacks.h"
22 #include "common/math.h"
23 #include "common/mm_io.h"
24 #include "common/mm_file_io.h"
25 #include "common/mpeg.h"
26 #include "common/hevc/util.h"
27 #include "common/hevc/es_parser.h"
28 #include "common/hevc/hevcc.h"
29 #include "common/list_utils.h"
30 #include "common/memory_slice_cursor.h"
31 #include "common/strings/formatting.h"
32 #include "common/timestamp.h"
33 
34 namespace mtx::hevc {
35 
es_parser_c()36 es_parser_c::es_parser_c()
37   : mtx::avc_hevc::es_parser_c{"hevc"s, 3, 64}
38 {
39   init_nalu_names();
40 }
41 
42 bool
headers_parsed() const43 es_parser_c::headers_parsed()
44   const {
45   return m_configuration_record_ready
46       && !m_sps_info_list.empty()
47       && (m_sps_info_list.front().get_width()  > 0)
48       && (m_sps_info_list.front().get_height() > 0);
49 }
50 
51 void
flush()52 es_parser_c::flush() {
53   if (m_unparsed_buffer && (5 <= m_unparsed_buffer->get_size())) {
54     m_parsed_position += m_unparsed_buffer->get_size();
55     auto marker_size   = get_uint32_be(m_unparsed_buffer->get_buffer()) == mtx::avc_hevc::NALU_START_CODE ? 4 : 3;
56     auto nalu_size     = m_unparsed_buffer->get_size() - marker_size;
57     handle_nalu(memory_c::clone(m_unparsed_buffer->get_buffer() + marker_size, nalu_size), m_parsed_position - nalu_size);
58   }
59 
60   m_unparsed_buffer.reset();
61   if (!m_pending_frame_data.empty()) {
62     build_frame_data();
63     m_frames.emplace_back(m_incomplete_frame);
64   }
65 
66   cleanup();
67 }
68 
69 void
clear()70 es_parser_c::clear() {
71   m_unparsed_buffer.reset();
72   m_extra_data_pre.clear();
73   m_extra_data_initial.clear();
74   m_pending_frame_data.clear();
75 
76   m_parsed_position = 0;
77 }
78 
79 void
flush_incomplete_frame()80 es_parser_c::flush_incomplete_frame() {
81   if (m_pending_frame_data.empty() || !m_configuration_record_ready)
82     return;
83 
84   build_frame_data();
85 
86   m_frames.push_back(m_incomplete_frame);
87   m_incomplete_frame.clear();
88 }
89 
90 bool
does_nalu_get_included_in_extra_data(memory_c const & nalu) const91 es_parser_c::does_nalu_get_included_in_extra_data(memory_c const &nalu)
92   const {
93   auto nalu_type = (nalu.get_buffer()[0] >> 1) & 0x3f;
94   return mtx::included_in(nalu_type, NALU_TYPE_VIDEO_PARAM, NALU_TYPE_SEQ_PARAM, NALU_TYPE_PIC_PARAM);
95 }
96 
97 void
handle_slice_nalu(memory_cptr const & nalu,uint64_t nalu_pos)98 es_parser_c::handle_slice_nalu(memory_cptr const &nalu,
99                                uint64_t nalu_pos) {
100   if (!m_configuration_record_ready) {
101     add_nalu_to_unhandled_nalus(nalu, nalu_pos);
102     return;
103   }
104 
105   mtx::avc_hevc::slice_info_t si;
106   if (!parse_slice(nalu, si))   // no conversion to RBSP; the bit reader takes care of it
107     return;
108 
109   if (!m_pending_frame_data.empty() && si.first_slice_segment_in_pic_flag)
110     flush_incomplete_frame();
111 
112   if (!m_pending_frame_data.empty()) {
113     add_nalu_to_pending_frame_data(nalu);
114     return;
115   }
116 
117   auto const &sps_info = m_sps_info_list[si.sps];
118   auto is_i_slice      = (SLICE_TYPE_I == si.slice_type);
119   auto is_slnr_picture = mtx::included_in(si.nalu_type, NALU_TYPE_TRAIL_N, NALU_TYPE_TSA_N, NALU_TYPE_STSA_N, NALU_TYPE_RADL_N, NALU_TYPE_RASL_N, NALU_TYPE_RSV_VCL_N10, NALU_TYPE_RSV_VCL_N12, NALU_TYPE_RSV_VCL_N14);
120   auto is_discardable  = is_slnr_picture && (0 == sps_info.max_sub_layers_minus1);
121 
122   m_incomplete_frame.m_si          =  si;
123   m_incomplete_frame.m_keyframe    =  m_recovery_point_valid
124                                    || (   is_i_slice
125                                        && (   (m_debug_keyframe_detection && !m_b_frames_since_keyframe)
126                                            || (NALU_TYPE_IDR_W_RADL == si.nalu_type)
127                                            || (NALU_TYPE_IDR_N_LP   == si.nalu_type)
128                                            || (NALU_TYPE_CRA_NUT    == si.nalu_type)));
129   m_incomplete_frame.m_type        =  m_incomplete_frame.m_keyframe ? 'I' : is_discardable ? 'B' : 'P';
130   m_incomplete_frame.m_discardable =  is_discardable;
131   m_incomplete_frame.m_position    =  nalu_pos;
132   m_recovery_point_valid           =  false;
133 
134   if (m_incomplete_frame.m_keyframe) {
135     m_first_keyframe_found    = true;
136     m_b_frames_since_keyframe = false;
137     cleanup();
138 
139   } else
140     m_b_frames_since_keyframe |= is_discardable;
141 
142   add_nalu_to_pending_frame_data(nalu);
143 
144   ++m_frame_number;
145 }
146 
147 void
handle_vps_nalu(memory_cptr const & nalu,extra_data_position_e extra_data_position)148 es_parser_c::handle_vps_nalu(memory_cptr const &nalu,
149                              extra_data_position_e extra_data_position) {
150   vps_info_t vps_info;
151 
152   if (!parse_vps(mpeg::nalu_to_rbsp(nalu), vps_info))
153     return;
154 
155   size_t i;
156   for (i = 0; m_vps_info_list.size() > i; ++i)
157     if (m_vps_info_list[i].id == vps_info.id)
158       break;
159 
160   auto update_codec_private = false;
161 
162   if (m_vps_info_list.size() == i) {
163     m_vps_list.push_back(nalu->clone());
164     m_vps_info_list.push_back(vps_info);
165     m_configuration_record_changed = true;
166 
167   } else if (m_vps_info_list[i].checksum != vps_info.checksum) {
168     mxdebug_if(m_debug_parameter_sets, fmt::format("hevc: VPS ID {0:04x} changed; checksum old {1:04x} new {2:04x}\n", vps_info.id, m_vps_info_list[i].checksum, vps_info.checksum));
169 
170     m_vps_info_list[i]             = vps_info;
171     m_vps_list[i]                  = nalu->clone();
172     m_configuration_record_changed = true;
173 
174     // Update codec private if needed
175     if (m_codec_private.vps_data_id == (int) vps_info.id)
176       update_codec_private = true;
177   }
178 
179   // Update codec private if needed
180   if (-1 == m_codec_private.vps_data_id)
181     update_codec_private = true;
182 
183   if (update_codec_private) {
184     m_codec_private.profile_space              = vps_info.profile_space;
185     m_codec_private.tier_flag                  = vps_info.tier_flag;
186     m_codec_private.profile_idc                = vps_info.profile_idc;
187     m_codec_private.profile_compatibility_flag = vps_info.profile_compatibility_flag;
188     m_codec_private.progressive_source_flag    = vps_info.progressive_source_flag;
189     m_codec_private.interlaced_source_flag     = vps_info.interlaced_source_flag;
190     m_codec_private.non_packed_constraint_flag = vps_info.non_packed_constraint_flag;
191     m_codec_private.frame_only_constraint_flag = vps_info.frame_only_constraint_flag;
192     m_codec_private.level_idc                  = vps_info.level_idc;
193     m_codec_private.vps_data_id                = vps_info.id;
194   }
195 
196   add_nalu_to_extra_data(nalu, extra_data_position);
197 }
198 
199 void
handle_sps_nalu(memory_cptr const & nalu,extra_data_position_e extra_data_position)200 es_parser_c::handle_sps_nalu(memory_cptr const &nalu,
201                              extra_data_position_e extra_data_position) {
202   sps_info_t sps_info;
203 
204   auto parsed_nalu = parse_sps(mpeg::nalu_to_rbsp(nalu), sps_info, m_vps_info_list, m_keep_ar_info);
205   if (!parsed_nalu)
206     return;
207 
208   parsed_nalu = mpeg::rbsp_to_nalu(parsed_nalu);
209 
210   size_t i;
211   for (i = 0; m_sps_info_list.size() > i; ++i)
212     if (m_sps_info_list[i].id == sps_info.id)
213       break;
214 
215   auto use_sps_info         = true;
216   auto update_codec_private = false;
217 
218   if (m_sps_info_list.size() == i) {
219     m_sps_list.push_back(parsed_nalu->clone());
220     m_sps_info_list.push_back(sps_info);
221     m_configuration_record_changed = true;
222 
223   } else if (m_sps_info_list[i].checksum != sps_info.checksum) {
224     mxdebug_if(m_debug_parameter_sets, fmt::format("hevc: SPS ID {0:04x} changed; checksum old {1:04x} new {2:04x}\n", sps_info.id, m_sps_info_list[i].checksum, sps_info.checksum));
225 
226     cleanup();
227 
228     m_sps_info_list[i] = sps_info;
229     m_sps_list[i]      = parsed_nalu->clone();
230     m_configuration_record_changed    = true;
231 
232     // Update codec private if needed
233     if (m_codec_private.sps_data_id == (int) sps_info.id)
234       update_codec_private = true;
235 
236   } else
237     use_sps_info = false;
238 
239   add_nalu_to_extra_data(parsed_nalu, extra_data_position);
240 
241   // Update codec private if needed
242   if (-1 == m_codec_private.sps_data_id)
243     update_codec_private = true;
244 
245   if (update_codec_private) {
246     m_codec_private.min_spatial_segmentation_idc = sps_info.min_spatial_segmentation_idc;
247     m_codec_private.chroma_format_idc            = sps_info.chroma_format_idc;
248     m_codec_private.bit_depth_luma_minus8        = sps_info.bit_depth_luma_minus8;
249     m_codec_private.bit_depth_chroma_minus8      = sps_info.bit_depth_chroma_minus8;
250     m_codec_private.max_sub_layers_minus1        = sps_info.max_sub_layers_minus1;
251     m_codec_private.temporal_id_nesting_flag     = sps_info.temporal_id_nesting_flag;
252     m_codec_private.sps_data_id                  = sps_info.id;
253   }
254 
255   if (use_sps_info && m_debug_sps_info)
256     sps_info.dump();
257 
258   if (!use_sps_info)
259     return;
260 
261   if (!has_stream_default_duration()
262       && sps_info.timing_info_valid()) {
263     m_stream_default_duration = sps_info.default_duration();
264     mxdebug_if(m_debug_timestamps, fmt::format("Stream default duration: {0}\n", m_stream_default_duration));
265   }
266 
267   if (!m_par_found
268       && sps_info.ar_found
269       && (0 != sps_info.par_den)) {
270     m_par_found = true;
271     m_par       = mtx_mp_rational_t(sps_info.par_num, sps_info.par_den);
272   }
273 }
274 
275 void
handle_pps_nalu(memory_cptr const & nalu,extra_data_position_e extra_data_position)276 es_parser_c::handle_pps_nalu(memory_cptr const &nalu,
277                              extra_data_position_e extra_data_position) {
278   pps_info_t pps_info;
279 
280   if (!parse_pps(mpeg::nalu_to_rbsp(nalu), pps_info))
281     return;
282 
283   size_t i;
284   for (i = 0; m_pps_info_list.size() > i; ++i)
285     if (m_pps_info_list[i].id == pps_info.id)
286       break;
287 
288   if (m_pps_info_list.size() == i) {
289     m_pps_list.push_back(nalu->clone());
290     m_pps_info_list.push_back(pps_info);
291     m_configuration_record_changed = true;
292 
293   } else if (m_pps_info_list[i].checksum != pps_info.checksum) {
294     mxdebug_if(m_debug_parameter_sets, fmt::format("hevc: PPS ID {0:04x} changed; checksum old {1:04x} new {2:04x}\n", pps_info.id, m_pps_info_list[i].checksum, pps_info.checksum));
295 
296     if (m_pps_info_list[i].sps_id != pps_info.sps_id)
297       cleanup();
298 
299     m_pps_info_list[i]             = pps_info;
300     m_pps_list[i]                  = nalu->clone();
301     m_configuration_record_changed = true;
302   }
303 
304   add_nalu_to_extra_data(nalu, extra_data_position);
305 }
306 
307 void
handle_sei_nalu(memory_cptr const & nalu,extra_data_position_e extra_data_position)308 es_parser_c::handle_sei_nalu(memory_cptr const &nalu,
309                              extra_data_position_e extra_data_position) {
310   if (parse_sei(mpeg::nalu_to_rbsp(nalu), m_user_data))
311     add_nalu_to_extra_data(nalu, extra_data_position);
312 }
313 
314 void
handle_unspec62_nalu(memory_cptr const & nalu)315 es_parser_c::handle_unspec62_nalu(memory_cptr const &nalu) {
316   if (parse_dovi_rpu(mpeg::nalu_to_rbsp(nalu), m_dovi_rpu_data_header))
317     add_nalu_to_pending_frame_data(nalu);
318 }
319 
320 void
handle_nalu_internal(memory_cptr const & nalu,uint64_t nalu_pos)321 es_parser_c::handle_nalu_internal(memory_cptr const &nalu,
322                                   uint64_t nalu_pos) {
323   static debugging_option_c s_debug_discard_access_unit_delimiters{"hevc_discard_access_unit_delimiters"};
324 
325   if (1 > nalu->get_size())
326     return;
327 
328   int type = (*(nalu->get_buffer()) >> 1) & 0x3F;
329 
330   mxdebug_if(m_debug_nalu_types, fmt::format("NALU type 0x{0:02x} ({1}) size {2}\n", type, get_nalu_type_name(type), nalu->get_size()));
331 
332   ++m_stats.num_nalus_by_type[std::min(type, 63)];
333 
334   switch (type) {
335     case NALU_TYPE_VIDEO_PARAM:
336       flush_incomplete_frame();
337       handle_vps_nalu(nalu);
338       break;
339 
340     case NALU_TYPE_SEQ_PARAM:
341       flush_incomplete_frame();
342       handle_sps_nalu(nalu);
343       break;
344 
345     case NALU_TYPE_PIC_PARAM:
346       flush_incomplete_frame();
347       handle_pps_nalu(nalu);
348       break;
349 
350     case NALU_TYPE_PREFIX_SEI:
351       flush_incomplete_frame();
352       handle_sei_nalu(nalu);
353       break;
354 
355     case NALU_TYPE_END_OF_STREAM:
356       flush_incomplete_frame();
357       break;
358 
359     case NALU_TYPE_ACCESS_UNIT:
360       flush_incomplete_frame();
361       if (!s_debug_discard_access_unit_delimiters)
362         add_nalu_to_extra_data(nalu);
363       break;
364 
365     case NALU_TYPE_FILLER_DATA:
366       // Skip these.
367       break;
368 
369     case NALU_TYPE_UNSPEC62:
370       handle_unspec62_nalu(nalu);
371       break;
372 
373     case NALU_TYPE_TRAIL_N:
374     case NALU_TYPE_TRAIL_R:
375     case NALU_TYPE_TSA_N:
376     case NALU_TYPE_TSA_R:
377     case NALU_TYPE_STSA_N:
378     case NALU_TYPE_STSA_R:
379     case NALU_TYPE_RADL_N:
380     case NALU_TYPE_RADL_R:
381     case NALU_TYPE_RASL_N:
382     case NALU_TYPE_RASL_R:
383     case NALU_TYPE_BLA_W_LP:
384     case NALU_TYPE_BLA_W_RADL:
385     case NALU_TYPE_BLA_N_LP:
386     case NALU_TYPE_IDR_W_RADL:
387     case NALU_TYPE_IDR_N_LP:
388     case NALU_TYPE_CRA_NUT:
389       if (!m_configuration_record_ready && !m_vps_info_list.empty() && !m_sps_info_list.empty() && !m_pps_info_list.empty()) {
390         m_configuration_record_ready = true;
391         flush_unhandled_nalus();
392       }
393       handle_slice_nalu(nalu, nalu_pos);
394       break;
395 
396     case NALU_TYPE_END_OF_SEQ:
397     case NALU_TYPE_SUFFIX_SEI:
398     case NALU_TYPE_RSV_NVCL45:
399     case NALU_TYPE_RSV_NVCL46:
400     case NALU_TYPE_RSV_NVCL47:
401     case NALU_TYPE_UNSPEC56:
402     case NALU_TYPE_UNSPEC57:
403     case NALU_TYPE_UNSPEC58:
404     case NALU_TYPE_UNSPEC59:
405     case NALU_TYPE_UNSPEC60:
406     case NALU_TYPE_UNSPEC61:
407     case NALU_TYPE_UNSPEC63:
408       add_nalu_to_pending_frame_data(nalu);
409       break;
410 
411     default:
412       flush_incomplete_frame();
413       if (!m_configuration_record_ready && !m_vps_info_list.empty() && !m_sps_info_list.empty() && !m_pps_info_list.empty()) {
414         m_configuration_record_ready = true;
415         flush_unhandled_nalus();
416       }
417       add_nalu_to_extra_data(nalu);
418 
419       break;
420   }
421 }
422 
423 void
handle_nalu(memory_cptr const & nalu,uint64_t nalu_pos)424 es_parser_c::handle_nalu(memory_cptr const &nalu,
425                          uint64_t nalu_pos) {
426   try {
427     handle_nalu_internal(nalu, nalu_pos);
428 
429   } catch (bool) {
430   } catch (mtx::mm_io::end_of_file_x const &) {
431   }
432 }
433 
434 bool
parse_slice(memory_cptr const & nalu,mtx::avc_hevc::slice_info_t & si)435 es_parser_c::parse_slice(memory_cptr const &nalu,
436                          mtx::avc_hevc::slice_info_t &si) {
437   try {
438     mtx::bits::reader_c r(nalu->get_buffer(), nalu->get_size());
439     r.enable_rbsp_mode();
440 
441     unsigned int i;
442 
443     si.clear();
444 
445     r.get_bits(1);                      // forbidden_zero_bit
446     si.nalu_type = r.get_bits(6);       // nal_unit_type
447     r.get_bits(6);                      // nuh_reserved_zero_6bits
448     si.temporal_id = r.get_bits(3) - 1; // nuh_temporal_id_plus1
449 
450     bool RapPicFlag = (si.nalu_type >= 16 && si.nalu_type <= 23); // RapPicFlag
451     si.first_slice_segment_in_pic_flag = r.get_bits(1); // first_slice_segment_in_pic_flag
452 
453     if (RapPicFlag)
454       r.get_bits(1);  // no_output_of_prior_pics_flag
455 
456     si.pps_id = r.get_unsigned_golomb();  // slice_pic_parameter_set_id
457 
458     size_t pps_idx;
459     for (pps_idx = 0; m_pps_info_list.size() > pps_idx; ++pps_idx)
460       if (m_pps_info_list[pps_idx].id == si.pps_id)
461         break;
462     if (m_pps_info_list.size() == pps_idx) {
463       mxdebug_if(m_debug_parameter_sets, fmt::format("slice parser error: PPS not found: {0}\n", si.pps_id));
464       return false;
465     }
466 
467     pps_info_t &pps = m_pps_info_list[pps_idx];
468     size_t sps_idx;
469     for (sps_idx = 0; m_sps_info_list.size() > sps_idx; ++sps_idx)
470       if (m_sps_info_list[sps_idx].id == pps.sps_id)
471         break;
472     if (m_sps_info_list.size() == sps_idx)
473       return false;
474 
475     si.sps = sps_idx;
476     si.pps = pps_idx;
477 
478     sps_info_t &sps = m_sps_info_list[sps_idx];
479 
480     bool dependent_slice_segment_flag = false;
481     if (!si.first_slice_segment_in_pic_flag) {
482       if (pps.dependent_slice_segments_enabled_flag)
483         dependent_slice_segment_flag = r.get_bits(1); // dependent_slice_segment_flag
484 
485       auto log2_min_cb_size_y   = sps.log2_min_luma_coding_block_size_minus3 + 3;
486       auto log2_ctb_size_y      = log2_min_cb_size_y + sps.log2_diff_max_min_luma_coding_block_size;
487       auto ctb_size_y           = 1 << log2_ctb_size_y;
488       auto pic_width_in_ctbs_y  = ceil(static_cast<double>(sps.width)  / ctb_size_y);
489       auto pic_height_in_ctbs_y = ceil(static_cast<double>(sps.height) / ctb_size_y);
490       auto pic_size_in_ctbs_y   = pic_width_in_ctbs_y * pic_height_in_ctbs_y;
491       auto v                    = mtx::math::int_log2((pic_size_in_ctbs_y - 1) * 2);
492 
493       r.get_bits(v);  // slice_segment_address
494     }
495 
496     if (!dependent_slice_segment_flag) {
497       for (i = 0; i < pps.num_extra_slice_header_bits; i++)
498         r.get_bits(1);  // slice_reserved_undetermined_flag[i]
499 
500       si.slice_type = r.get_unsigned_golomb();  // slice_type
501 
502       if (pps.output_flag_present_flag)
503         r.get_bits(1);    // pic_output_flag
504 
505       if (sps.separate_colour_plane_flag == 1)
506         r.get_bits(1);    // colour_plane_id
507 
508       if ( (si.nalu_type != NALU_TYPE_IDR_W_RADL) && (si.nalu_type != NALU_TYPE_IDR_N_LP) ) {
509         si.pic_order_cnt_lsb = r.get_bits(sps.log2_max_pic_order_cnt_lsb); // slice_pic_order_cnt_lsb
510       }
511 
512       ++m_stats.num_slices_by_type[1 < si.slice_type ? 2 : si.slice_type];
513     }
514 
515     return true;
516   } catch (...) {
517     return false;
518   }
519 }
520 
521 int64_t
duration_for(mtx::avc_hevc::slice_info_t const & si) const522 es_parser_c::duration_for(mtx::avc_hevc::slice_info_t const &si)
523   const {
524   int64_t duration = -1 != m_forced_default_duration                                                  ? m_forced_default_duration * 2
525                    : (m_sps_info_list.size() > si.sps) && m_sps_info_list[si.sps].timing_info_valid() ? m_sps_info_list[si.sps].default_duration()
526                    : -1 != m_stream_default_duration                                                  ? m_stream_default_duration * 2
527                    : -1 != m_container_default_duration                                               ? m_container_default_duration * 2
528                    :                                                                                    20000000 * 2;
529   return duration;
530 }
531 
532 void
calculate_frame_order()533 es_parser_c::calculate_frame_order() {
534   auto frames_begin      = m_frames.begin();
535   auto frames_end        = m_frames.end();
536   auto frame_itr         = frames_begin;
537 
538   auto &idr_si           = frame_itr->m_si;
539   auto &sps              = m_sps_info_list[idr_si.sps];
540 
541   auto idx               = 0u;
542 
543   m_simple_picture_order = false;
544 
545   while (frames_end != frame_itr) {
546     auto &si = frame_itr->m_si;
547 
548     if (si.sps != idr_si.sps) {
549       m_simple_picture_order = true;
550       break;
551     }
552 
553     if ((NALU_TYPE_IDR_W_RADL == si.nalu_type) || (NALU_TYPE_IDR_N_LP == si.nalu_type)) {
554       frame_itr->m_presentation_order = 0;
555       mxdebug_if(m_debug_frame_order, fmt::format("frame order: KEY!\n"));
556 
557     } else {
558       int poc_msb;
559       int max_poc_lsb = 1 << (sps.log2_max_pic_order_cnt_lsb);
560       int poc_lsb     = si.pic_order_cnt_lsb;
561 
562       auto condition1 = poc_lsb < m_prev_pic_order_cnt_lsb && (m_prev_pic_order_cnt_lsb - poc_lsb) >= (max_poc_lsb / 2);
563       auto condition2 = poc_lsb > m_prev_pic_order_cnt_lsb && (poc_lsb - m_prev_pic_order_cnt_lsb) >  (max_poc_lsb / 2);
564 
565       if (condition1)
566         poc_msb = m_prev_pic_order_cnt_msb + max_poc_lsb;
567       else if (condition2)
568         poc_msb = m_prev_pic_order_cnt_msb - max_poc_lsb;
569       else
570         poc_msb = m_prev_pic_order_cnt_msb;
571 
572       if (mtx::included_in(si.nalu_type, NALU_TYPE_BLA_W_LP, NALU_TYPE_BLA_W_RADL, NALU_TYPE_BLA_N_LP))
573         poc_msb = 0;
574 
575       frame_itr->m_presentation_order = poc_lsb + poc_msb;
576 
577       mxdebug_if(m_debug_frame_order,
578                  fmt::format("frame order: {0} lsb {1} msb {2} max_poc_lsb {3} prev_lsb {4} prev_msb {5} cond1 {6} cond2 {7} NALsize {8} type {9} ({10})\n",
579                              frame_itr->m_presentation_order, poc_lsb, poc_msb, max_poc_lsb, m_prev_pic_order_cnt_lsb, m_prev_pic_order_cnt_msb, condition1, condition2, frame_itr->m_data->get_size(), static_cast<unsigned int>(si.nalu_type), get_nalu_type_name(si.nalu_type)));
580 
581       if (   (frame_itr->m_si.temporal_id == 0)
582           && !mtx::included_in(si.nalu_type, NALU_TYPE_TRAIL_N, NALU_TYPE_TSA_N, NALU_TYPE_STSA_N, NALU_TYPE_RADL_N, NALU_TYPE_RASL_N, NALU_TYPE_RADL_R, NALU_TYPE_RASL_R)) {
583         m_prev_pic_order_cnt_lsb = poc_lsb;
584         m_prev_pic_order_cnt_msb = poc_msb;
585       }
586     }
587 
588     frame_itr->m_decode_order = idx;
589 
590     ++frame_itr;
591     ++idx;
592   }
593 }
594 
595 memory_cptr
get_configuration_record() const596 es_parser_c::get_configuration_record()
597   const {
598   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();
599 }
600 
601 void
set_configuration_record(memory_cptr const & bytes)602 es_parser_c::set_configuration_record(memory_cptr const &bytes) {
603   auto hevcc = hevcc_c::unpack(bytes);
604 
605   for (auto const &nalu : hevcc.m_vps_list)
606     handle_vps_nalu(nalu, extra_data_position_e::dont_store);
607 
608   for (auto const &nalu : hevcc.m_sps_list)
609     handle_sps_nalu(nalu, extra_data_position_e::dont_store);
610 
611   for (auto const &nalu : hevcc.m_pps_list)
612     handle_pps_nalu(nalu, extra_data_position_e::dont_store);
613 
614   for (auto const &nalu : hevcc.m_sei_list)
615     handle_sei_nalu(nalu, extra_data_position_e::initial);
616 }
617 
618 void
init_nalu_names() const619 es_parser_c::init_nalu_names()
620   const {
621   if (!ms_nalu_names_by_type.empty())
622     return;
623 
624   ms_nalu_names_by_type = std::unordered_map<int, std::string>{
625     { NALU_TYPE_TRAIL_N,       "trail_n"       },
626     { NALU_TYPE_TRAIL_R,       "trail_r"       },
627     { NALU_TYPE_TSA_N,         "tsa_n"         },
628     { NALU_TYPE_TSA_R,         "tsa_r"         },
629     { NALU_TYPE_STSA_N,        "stsa_n"        },
630     { NALU_TYPE_STSA_R,        "stsa_r"        },
631     { NALU_TYPE_RADL_N,        "radl_n"        },
632     { NALU_TYPE_RADL_R,        "radl_r"        },
633     { NALU_TYPE_RASL_N,        "rasl_n"        },
634     { NALU_TYPE_RASL_R,        "rasl_r"        },
635     { NALU_TYPE_RSV_VCL_N10,   "rsv_vcl_n10"   },
636     { NALU_TYPE_RSV_VCL_N12,   "rsv_vcl_n12"   },
637     { NALU_TYPE_RSV_VCL_N14,   "rsv_vcl_n14"   },
638     { NALU_TYPE_RSV_VCL_R11,   "rsv_vcl_r11"   },
639     { NALU_TYPE_RSV_VCL_R13,   "rsv_vcl_r13"   },
640     { NALU_TYPE_RSV_VCL_R15,   "rsv_vcl_r15"   },
641     { NALU_TYPE_BLA_W_LP,      "bla_w_lp"      },
642     { NALU_TYPE_BLA_W_RADL,    "bla_w_radl"    },
643     { NALU_TYPE_BLA_N_LP,      "bla_n_lp"      },
644     { NALU_TYPE_IDR_W_RADL,    "idr_w_radl"    },
645     { NALU_TYPE_IDR_N_LP,      "idr_n_lp"      },
646     { NALU_TYPE_CRA_NUT,       "cra_nut"       },
647     { NALU_TYPE_RSV_RAP_VCL22, "rsv_rap_vcl22" },
648     { NALU_TYPE_RSV_RAP_VCL23, "rsv_rap_vcl23" },
649     { NALU_TYPE_RSV_VCL24,     "rsv_vcl24"     },
650     { NALU_TYPE_RSV_VCL25,     "rsv_vcl25"     },
651     { NALU_TYPE_RSV_VCL26,     "rsv_vcl26"     },
652     { NALU_TYPE_RSV_VCL27,     "rsv_vcl27"     },
653     { NALU_TYPE_RSV_VCL28,     "rsv_vcl28"     },
654     { NALU_TYPE_RSV_VCL29,     "rsv_vcl29"     },
655     { NALU_TYPE_RSV_VCL30,     "rsv_vcl30"     },
656     { NALU_TYPE_RSV_VCL31,     "rsv_vcl31"     },
657     { NALU_TYPE_VIDEO_PARAM,   "video_param"   },
658     { NALU_TYPE_SEQ_PARAM,     "seq_param"     },
659     { NALU_TYPE_PIC_PARAM,     "pic_param"     },
660     { NALU_TYPE_ACCESS_UNIT,   "access_unit"   },
661     { NALU_TYPE_END_OF_SEQ,    "end_of_seq"    },
662     { NALU_TYPE_END_OF_STREAM, "end_of_stream" },
663     { NALU_TYPE_FILLER_DATA,   "filler_data"   },
664     { NALU_TYPE_PREFIX_SEI,    "prefix_sei"    },
665     { NALU_TYPE_SUFFIX_SEI,    "suffix_sei"    },
666     { NALU_TYPE_RSV_NVCL41,    "rsv_nvcl41"    },
667     { NALU_TYPE_RSV_NVCL42,    "rsv_nvcl42"    },
668     { NALU_TYPE_RSV_NVCL43,    "rsv_nvcl43"    },
669     { NALU_TYPE_RSV_NVCL44,    "rsv_nvcl44"    },
670     { NALU_TYPE_RSV_NVCL45,    "rsv_nvcl45"    },
671     { NALU_TYPE_RSV_NVCL46,    "rsv_nvcl46"    },
672     { NALU_TYPE_RSV_NVCL47,    "rsv_nvcl47"    },
673     { NALU_TYPE_UNSPEC48,      "unspec48"      },
674     { NALU_TYPE_UNSPEC49,      "unspec49"      },
675     { NALU_TYPE_UNSPEC50,      "unspec50"      },
676     { NALU_TYPE_UNSPEC51,      "unspec51"      },
677     { NALU_TYPE_UNSPEC52,      "unspec52"      },
678     { NALU_TYPE_UNSPEC53,      "unspec53"      },
679     { NALU_TYPE_UNSPEC54,      "unspec54"      },
680     { NALU_TYPE_UNSPEC55,      "unspec55"      },
681     { NALU_TYPE_UNSPEC56,      "unspec56"      },
682     { NALU_TYPE_UNSPEC57,      "unspec57"      },
683     { NALU_TYPE_UNSPEC58,      "unspec58"      },
684     { NALU_TYPE_UNSPEC59,      "unspec59"      },
685     { NALU_TYPE_UNSPEC60,      "unspec60"      },
686     { NALU_TYPE_UNSPEC61,      "unspec61"      },
687     { NALU_TYPE_UNSPEC62,      "unspec62"      },
688     { NALU_TYPE_UNSPEC63,      "unspec63"      },
689   };
690 
691   ms_slice_names_by_type[0] = "B";
692   ms_slice_names_by_type[1] = "P";
693   ms_slice_names_by_type[2] = "I";
694   ms_slice_names_by_type[3] = "unknown";
695 }
696 
697 }                              // namespace mtx::hevc
698