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