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