vdr-plugin-softhddevice-drm-gles 1.6.2
h264parser.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
16#include <cassert>
17#include <set>
18#include <string>
19#include <vector>
20
21extern "C" {
22#include <libavcodec/avcodec.h>
23}
24
25#include "h264parser.h"
26#include "logger.h"
27#include "misc.h"
28
47bool isValidStartCode(const uint8_t *data, int offset, int size, int &startCodeLength)
48{
49 if (offset + 4 <= size && ReadBytes(&data[offset], 4) == 0x00000001) {
51 return true;
52 }
53
54 if (offset + 3 <= size && ReadBytes(&data[offset], 3) == 0x000001) {
56 return true;
57 }
58
59 return false;
60}
61
71static int NalUnitType(const uint8_t *data, int offset, int startCodeLength)
72{
73 return data[offset + startCodeLength] & 0x1F;
74}
75
83{
84 int offset = -1;
85
86 for (int i = 0; i < m_pAvpkt->size; i++) {
87 int startCodeLength = 0;
88
90 continue;
91
92 if (NalUnitType(m_pAvpkt->data, i, startCodeLength) == 7) {
93 offset = i;
94 break;
95 }
96 }
97
98 return offset;
99}
100
108{
109 int offset = -1;
110
111 for (int i = 0; i < m_pAvpkt->size; i++) {
112 int startCodeLength = 0;
113
115 continue;
116
117 if (NalUnitType(m_pAvpkt->data, i, startCodeLength) == 8) {
118 offset = i;
119 break;
120 }
121 }
122
123 return offset;
124}
125
133{
134 int offset = -1;
135
136 for (int i = 0; i < m_pAvpkt->size; i++) {
137 int startCodeLength = 0;
138
140 continue;
141
142 if (NalUnitType(m_pAvpkt->data, i, startCodeLength) == 1 || NalUnitType(m_pAvpkt->data, i, startCodeLength) == 5) {
143 offset = i;
144 break;
145 }
146 }
147
148 return offset;
149}
150
160 : m_pAvpkt(avpkt),
161 m_log2MaxFrameNumMinus4(maxFrameNum),
162 m_ppsNumRefIdxL0DefaultActiveMinus1(refIdxL0),
163 m_ppsNumRefIdxL1DefaultActiveMinus1(refIdxL1)
164{
165 int i;
166
167 // part 1: collect the nalu types in the packet
168 for (i = 0; i < m_pAvpkt->size; i++) {
169 int startCodeLength = 0;
170
172 continue;
173
175 switch (naluType) {
176 case 1: m_naluString += " NON-IDR"; m_nalutype |= NALU_TYPE_NON_IDR; break;
177 case 2: m_naluString += " PART_A"; m_nalutype |= NALU_TYPE_PART_A; break;
178 case 3: m_naluString += " PART_B"; m_nalutype |= NALU_TYPE_PART_B; break;
179 case 4: m_naluString += " PART_C"; m_nalutype |= NALU_TYPE_PART_C; break;
180 case 5: m_naluString += " IDR"; m_nalutype |= NALU_TYPE_IDR; break;
181 case 6: m_naluString += " SEI"; m_nalutype |= NALU_TYPE_SEI; break;
182 case 7: m_naluString += " SPS"; m_nalutype |= NALU_TYPE_SPS; break;
183 case 8: m_naluString += " PPS"; m_nalutype |= NALU_TYPE_PPS; break;
184 case 9: m_naluString += " AUD"; m_nalutype |= NALU_TYPE_AUD; break;
185 default: break;
186 }
187
188 i += startCodeLength - 1;
189 }
190
191 // part 2: parse h264 SPS and get width and height
192 int spsOffset = GetSPSOffset();
193 m_parseError = false;
194
195 // SPS is available
196 if (spsOffset != -1) {
197 m_hasSPS = true;
198 int startCodeLength = 0;
200
201 const uint8_t *nalPayload = &m_pAvpkt->data[spsOffset + startCodeLength + 1];
202 int nalLength = m_pAvpkt->size - spsOffset - startCodeLength -1;
203
205 m_pStart = m_rbsp.data();
206 m_nLength = m_rbsp.size();
207
208 m_nCurrentBit = 0;
209
210 int frameCropLeftOffset = 0;
211 int frameCropRightOffset = 0;
212 int frameCropTopOffset = 0;
213 int frameCropBottomOffset = 0;
214 int chromaFormatIdc = 0;
216
217 int profileIdc = ReadBits(8);
218 ReadBits(16);
220
221 if (profileIdc == 100 || profileIdc == 110 ||
222 profileIdc == 122 || profileIdc == 244 ||
223 profileIdc == 44 || profileIdc == 83 ||
224 profileIdc == 86 || profileIdc == 118) {
225
227 if (chromaFormatIdc == 3)
231 ReadBit();
234 for (int i = 0; i < 8; i++) {
237 int sizeOfScalingList = (i < 6) ? 16 : 64;
238 int lastScale = 8;
239 int nextScale = 8;
240 for (int j = 0; j < sizeOfScalingList; j++) {
241 if (nextScale != 0) {
242 int delta_scale = ReadSE();
243 nextScale = (lastScale + delta_scale + 256) % 256;
244 }
246 }
247 }
248 }
249 }
250 }
253 if (picOrderCntType == 0) {
255 } else if (picOrderCntType == 1) {
256 ReadBit();
257 ReadSE();
258 ReadSE();
260 for (int i = 0; i < numRefFramesInPicOrderCntCycle; i++ ) {
261 ReadSE();
262 }
263 }
265 ReadBit();
269 if (!frameMbsOnlyFlag) {
270 m_mbaff = ReadBit();
271 }
272
273 ReadBit();
275 if (frameCroppingFlag) {
280 }
281
282 int subWidthC = 0;
283 int subHeightC = 0;
284
285 if (chromaFormatIdc == 0 && separateColorPlaneFlag == 0) { // monochrome
286 subWidthC = subHeightC = 2;
287 } else if (chromaFormatIdc == 1 && separateColorPlaneFlag == 0) { // 4:2:0
288 subWidthC = subHeightC = 2;
289 } else if (chromaFormatIdc == 2 && separateColorPlaneFlag == 0) { // 4:2:2
290 subWidthC = 2;
291 subHeightC = 1;
292 } else if (chromaFormatIdc == 3) { // 4:4:4
293 if (separateColorPlaneFlag == 0) {
294 subWidthC = subHeightC = 1;
295 } else if (separateColorPlaneFlag == 1) {
296 subWidthC = subHeightC = 0;
297 }
298 }
299
300 m_width = ((picWidthInMbsMinusOne + 1) * 16) -
302
305
306 //if (m_parseError)
307 // LOGWARNING("SPS parsing error");
308 }
309
310 // part 3: parse h264 PPS
311 int ppsOffset = GetPPSOffset();
312 m_parseError = false;
313
314 // PPS is available
315 if (ppsOffset != -1) {
316 m_hasPPS = true;
317
318 int startCodeLength = 0;
320
321 const uint8_t *nalPayload = &m_pAvpkt->data[ppsOffset + startCodeLength + 1];
322 int nalLength = m_pAvpkt->size - ppsOffset - startCodeLength -1;
323
325
326 m_pStart = m_rbsp.data();
327 m_nLength = m_rbsp.size();
328 m_nCurrentBit = 0;
329
330 ReadExponentialGolombCode(); // PicParameterSetId
331 ReadExponentialGolombCode(); // SeqParameterSetId
332
333 ReadBit(); // entropy_coding_mode_flag
334 ReadBit(); // bottom_field_pic_order_in_frame_present_flag
335
337 if (num_slice_groups_minus1 > 0) {
339
340 if (slice_group_map_type == 0) {
341 for (int i = 0; i <= num_slice_groups_minus1; i++)
342 ReadExponentialGolombCode(); // run_length_minus1
343 } else if (slice_group_map_type == 2) {
344 for (int i = 0; i < num_slice_groups_minus1; i++) {
345 ReadExponentialGolombCode(); // top_left
346 ReadExponentialGolombCode(); // bottom_right
347 }
348 } else if (slice_group_map_type == 3 ||
351 ReadBit(); // slice_group_change_direction_flag
352 ReadExponentialGolombCode(); // slice_group_change_rate_minus1
353 } else if (slice_group_map_type == 6) {
355
356 int bits = 0;
357 while ((1 << bits) < (num_slice_groups_minus1 + 1)) {
358 bits++;
359 }
360
361 for (int i = 0; i <= pic_size_in_map_units_minus1; i++) {
362 for (int b = 0; b < bits; b++) {
363 ReadBit(); // slice_group_id
364 }
365 }
366 }
367 }
368
371
374
375 //if (m_parseError)
376 // LOGWARNING("PPS parsing error");
377 }
378
379 // part 4: parse slice header
381 m_parseError = false;
382
383 // slice is available
384 if (sliceOffset != -1) {
385 int startCodeLength = 0;
387
389 int nalLength = m_pAvpkt->size - sliceOffset - startCodeLength - 1;
390
392
393 m_pStart = m_rbsp.data();
394 m_nLength = m_rbsp.size();
395
397 m_nalRefIdc = (nalHeader >> 5) & 0x03;
398 m_isReference = (m_nalRefIdc != 0);
399 m_isIDR = ((nalHeader & 0x1F) == 5);
400
401 m_nCurrentBit = 0;
402
403 ReadExponentialGolombCode(); // int first_mb_in_slice =
405
406 m_sliceType = slice_type_raw % 5; // normalize
407
408 ReadExponentialGolombCode(); // int pic_parameter_set_id =
409
412 //if (m_parseError) {
413 // LOGWARNING("Slice parsing error -> frameNum");
414 // return;
415 //}
416
417 if (m_isIDR)
418 ReadExponentialGolombCode(); // idr_pic_id
419
420 m_refMods.clear();
421 bool refListModFlagL0;
422 bool refListModFlagL1;
423
424 if (m_sliceType == 0) { // P-slice
425 m_naluString += " -P- ";
426
428
431 else
433
435
436 if (refListModFlagL0) {
437 int idc;
438 do {
440
441 if (idc == 0 || idc == 1) {
442 RefPicMod mod {};
443 mod.list = 0;
444 mod.idc = idc;
445 mod.abs_diff_pic_num_minus1 = ReadExponentialGolombCode();
446 m_refMods.push_back(mod);
447 // ignore long-term ?
448 /*
449 } else if (idc == 2) {
450 RefPicMod mod {};
451 mod.list = 0;
452 mod.idc = idc;
453 mod.long_term_pic_num = ReadExponentialGolombCode();
454 m_refMods.push_back(mod);
455 */
456 }
457 } while (idc != 3);
458 }
459 } else if (m_sliceType == 1) { // B-slice
460 m_naluString += " -B- ";
461
463
467 } else {
470 }
471
472 // ----- List 0 -----
474
475 if (refListModFlagL0) {
476 int idc;
477 do {
479 if (idc == 0 || idc == 1) {
480 RefPicMod mod {};
481 mod.list = 0;
482 mod.idc = idc;
483 mod.abs_diff_pic_num_minus1 = ReadExponentialGolombCode();
484 m_refMods.push_back(mod);
485 // ignore long-term ?
486 /*
487 } else if (idc == 2) {
488 RefPicMod mod {};
489 mod.list = 0;
490 mod.idc = idc;
491 mod.long_term_pic_num = ReadExponentialGolombCode();
492 m_refMods.push_back(mod);
493 */
494 }
495 } while (idc != 3);
496 }
497
498 // ----- List 1 -----
500
501 if (refListModFlagL1) {
502 int idc;
503 do {
505 if (idc == 0 || idc == 1) {
506 RefPicMod mod {};
507 mod.list = 1;
508 mod.idc = idc;
509 mod.abs_diff_pic_num_minus1 = ReadExponentialGolombCode();
510 m_refMods.push_back(mod);
511 // ignore long-term ?
512 /*
513 } else if (idc == 2) {
514 RefPicMod mod {};
515 mod.list = 1;
516 mod.idc = idc;
517 mod.long_term_pic_num = ReadExponentialGolombCode();
518 m_refMods.push_back(mod);
519 */
520 }
521 } while (idc != 3);
522 }
523 } else if (m_sliceType == 2) { // I-slice
524 m_naluString += " -I- ";
525 } else if (m_sliceType == 3) { // SP-slice
526 m_naluString += " -SP- ";
527 } else if (m_sliceType == 4) { // SI-slice
528 m_naluString += " -SI- ";
529 }
530 //if (m_parseError)
531 // LOGWARNING("Slice parsing error");
532 }
533}
534
549
560
567{
569 return;
570
571 m_naluString += " !!!";
572 for (auto r : m_invalidReferences) {
573 if (r < frameNumber) {
574 m_naluString += " ";
575 m_naluString += std::to_string(r);
576 }
577 }
578}
579
584{
586 return;
587
588 m_naluString += " -->";
589 for (auto r : m_validReferences) {
590 m_naluString += " ";
591 m_naluString += std::to_string(r);
592 }
593}
594
601{
602 if (num != -1) {
603 if (num < 10)
604 m_naluString += "# ";
605 else if (num < 100)
606 m_naluString += "# ";
607 else
608 m_naluString += "#";
609 m_naluString += std::to_string(num);
610 } else {
611 m_naluString += " ";
612 }
613}
614
619{
620 const uint8_t *data = m_pAvpkt->data;
621
622 LOGDEBUG("Stream: %02x %02x %02x %02x %02x %02x %02x %02x %02x "
623 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x "
624 "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x size %d",
625 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
626 data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17],
627 data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26],
628 data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], m_pAvpkt->size);
629}
630
635{
636 LOGDEBUG2(L_CODEC, "H264Parser: %s %s (%d x %d)", __FUNCTION__,
637 m_naluString.c_str(), m_width, m_height);
638}
639
644{
645 if (m_nCurrentBit >= m_nLength * 8) {
646 m_parseError = true;
647 return 0;
648 }
649
650 int nIndex = m_nCurrentBit / 8;
651 int nOffset = m_nCurrentBit % 8;
652
654 return (m_pStart[nIndex] >> (7 - nOffset)) & 0x01;
655}
656
660unsigned int cH264Parser::ReadBits(int n)
661{
662 if (m_nCurrentBit + n > m_nLength * 8) {
663 m_parseError = true;
664 return 0;
665 }
666
667 unsigned int r = 0;
668
669 for (int i = 0; i < n; i++) {
670 r = (r << 1) | ReadBit();
671 }
672
673 return r;
674}
675
680{
681 int zeros = 0;
682
683 while (zeros < 32) {
684 if (m_nCurrentBit >= m_nLength * 8) {
685 m_parseError = true;
686 return 0;
687 }
688
689 if (ReadBit() == 0)
690 zeros++;
691 else
692 break;
693 }
694
695 if (zeros == 32) {
696 m_parseError = true;
697 return 0;
698 }
699
700 unsigned int suffix = 0;
701 if (zeros > 0)
703
704 return ((1u << zeros) - 1) + suffix;
705}
706
711{
713
714 if (r & 0x01)
715 r = (r + 1) / 2;
716 else
717 r = -(r / 2);
718
719 return r;
720}
721
723{
724 m_rbsp.clear();
725 m_rbsp.reserve(length);
726
727 int zeroCount = 0;
728
729 for (int i = 0; i < length; i++) {
730 if (zeroCount == 2 && src[i] == 0x03) {
731 // skip emulation prevention byte
732 zeroCount = 0;
733 continue;
734 }
735
736 m_rbsp.push_back(src[i]);
737
738 if (src[i] == 0x00)
739 zeroCount++;
740 else
741 zeroCount = 0;
742 }
743}
744
bool m_hasPPS
Definition h264parser.h:95
std::string m_naluString
Definition h264parser.h:101
bool m_isReference
Definition h264parser.h:97
bool m_hasInvalidBackwardReferences
Definition h264parser.h:110
int m_ppsNumRefIdxL1DefaultActiveMinus1
Definition h264parser.h:115
int m_ppsNumRefIdxL0DefaultActiveMinus1
Definition h264parser.h:114
unsigned short m_nLength
Definition h264parser.h:88
bool m_hasInvalidReferences
Definition h264parser.h:109
int m_log2MaxFrameNumMinus4
Definition h264parser.h:113
const unsigned char * m_pStart
Definition h264parser.h:86
std::vector< uint8_t > m_rbsp
Definition h264parser.h:87
int m_numRefIdxL0Active
Definition h264parser.h:116
bool m_hasSPS
Definition h264parser.h:94
std::vector< RefPicMod > m_refMods
Definition h264parser.h:108
bool m_parseError
Definition h264parser.h:99
std::set< int > m_invalidReferences
Definition h264parser.h:106
int m_nCurrentBit
Definition h264parser.h:89
bool m_hasValidReferences
Definition h264parser.h:111
AVPacket * m_pAvpkt
Definition h264parser.h:85
std::set< int > m_validReferences
Definition h264parser.h:107
int m_numRefIdxL1Active
Definition h264parser.h:117
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
void BuildInvalidReferenceString(int)
Add a whitespace-separated list of all invalid references to the log output string.
unsigned int ReadSE(void)
Read a signed exponential-golomb coded integer.
#define LOGDEBUG
log to LOG_DEBUG
Definition logger.h:40
unsigned int ReadBit(void)
Read the next bit of a stream.
unsigned int ReadBits(int)
Read n number of bits of a stream.
cH264Parser(AVPacket *, int, int, int)
Init the h264 parser and detect the nalu types.
void PrintNalUnits(void)
Print the previously created log output string.
int GetSliceOffset(void)
Get the slice offset.
void ConvertEBSPtoRBSP(const uint8_t *, int)
void AddFrameNumber(int)
Add the frame number to the log output string.
int GetPPSOffset(void)
Get the PPS offset.
void AddValidReference(int)
Adds a valid reference.
static uint32_t ReadBytes(const uint8_t *data, int count)
Return count amount of bytes from data
Definition misc.h:149
void PrintStreamData(void)
Print raw stream data of the first 35 bytes.
static int NalUnitType(const uint8_t *data, int offset, int startCodeLength)
Return the nal unit type.
void BuildValidReferenceString(void)
Add a whitespace-separated list of all valid references to the log output string.
void AddInvalidReference(int, int)
Adds an invalid reference.
unsigned int ReadExponentialGolombCode(void)
Read an unsigned exponential-golomb coded integer.
bool isValidStartCode(const uint8_t *data, int offset, int size, int &startCodeLength)
Check for a 0x000001 or 0x00000001 start code.
int GetSPSOffset(void)
Get the SPS offset.
@ NALU_TYPE_NON_IDR
Definition h264parser.h:29
@ NALU_TYPE_AUD
Definition h264parser.h:37
@ NALU_TYPE_PART_B
Definition h264parser.h:31
@ NALU_TYPE_SEI
Definition h264parser.h:34
@ NALU_TYPE_PART_C
Definition h264parser.h:32
@ NALU_TYPE_PPS
Definition h264parser.h:36
@ NALU_TYPE_SPS
Definition h264parser.h:35
@ NALU_TYPE_PART_A
Definition h264parser.h:30
@ NALU_TYPE_IDR
Definition h264parser.h:33
@ L_CODEC
codec logs
Definition logger.h:56
H.264 Parser Header File.
Logger Header File.
Misc Functions.