xref: /aosp_15_r20/external/webrtc/common_video/h264/h264_common.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "common_video/h264/h264_common.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
16*d9f75844SAndroid Build Coastguard Worker namespace H264 {
17*d9f75844SAndroid Build Coastguard Worker 
18*d9f75844SAndroid Build Coastguard Worker const uint8_t kNaluTypeMask = 0x1F;
19*d9f75844SAndroid Build Coastguard Worker 
FindNaluIndices(const uint8_t * buffer,size_t buffer_size)20*d9f75844SAndroid Build Coastguard Worker std::vector<NaluIndex> FindNaluIndices(const uint8_t* buffer,
21*d9f75844SAndroid Build Coastguard Worker                                        size_t buffer_size) {
22*d9f75844SAndroid Build Coastguard Worker   // This is sorta like Boyer-Moore, but with only the first optimization step:
23*d9f75844SAndroid Build Coastguard Worker   // given a 3-byte sequence we're looking at, if the 3rd byte isn't 1 or 0,
24*d9f75844SAndroid Build Coastguard Worker   // skip ahead to the next 3-byte sequence. 0s and 1s are relatively rare, so
25*d9f75844SAndroid Build Coastguard Worker   // this will skip the majority of reads/checks.
26*d9f75844SAndroid Build Coastguard Worker   std::vector<NaluIndex> sequences;
27*d9f75844SAndroid Build Coastguard Worker   if (buffer_size < kNaluShortStartSequenceSize)
28*d9f75844SAndroid Build Coastguard Worker     return sequences;
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker   static_assert(kNaluShortStartSequenceSize >= 2,
31*d9f75844SAndroid Build Coastguard Worker                 "kNaluShortStartSequenceSize must be larger or equals to 2");
32*d9f75844SAndroid Build Coastguard Worker   const size_t end = buffer_size - kNaluShortStartSequenceSize;
33*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < end;) {
34*d9f75844SAndroid Build Coastguard Worker     if (buffer[i + 2] > 1) {
35*d9f75844SAndroid Build Coastguard Worker       i += 3;
36*d9f75844SAndroid Build Coastguard Worker     } else if (buffer[i + 2] == 1) {
37*d9f75844SAndroid Build Coastguard Worker       if (buffer[i + 1] == 0 && buffer[i] == 0) {
38*d9f75844SAndroid Build Coastguard Worker         // We found a start sequence, now check if it was a 3 of 4 byte one.
39*d9f75844SAndroid Build Coastguard Worker         NaluIndex index = {i, i + 3, 0};
40*d9f75844SAndroid Build Coastguard Worker         if (index.start_offset > 0 && buffer[index.start_offset - 1] == 0)
41*d9f75844SAndroid Build Coastguard Worker           --index.start_offset;
42*d9f75844SAndroid Build Coastguard Worker 
43*d9f75844SAndroid Build Coastguard Worker         // Update length of previous entry.
44*d9f75844SAndroid Build Coastguard Worker         auto it = sequences.rbegin();
45*d9f75844SAndroid Build Coastguard Worker         if (it != sequences.rend())
46*d9f75844SAndroid Build Coastguard Worker           it->payload_size = index.start_offset - it->payload_start_offset;
47*d9f75844SAndroid Build Coastguard Worker 
48*d9f75844SAndroid Build Coastguard Worker         sequences.push_back(index);
49*d9f75844SAndroid Build Coastguard Worker       }
50*d9f75844SAndroid Build Coastguard Worker 
51*d9f75844SAndroid Build Coastguard Worker       i += 3;
52*d9f75844SAndroid Build Coastguard Worker     } else {
53*d9f75844SAndroid Build Coastguard Worker       ++i;
54*d9f75844SAndroid Build Coastguard Worker     }
55*d9f75844SAndroid Build Coastguard Worker   }
56*d9f75844SAndroid Build Coastguard Worker 
57*d9f75844SAndroid Build Coastguard Worker   // Update length of last entry, if any.
58*d9f75844SAndroid Build Coastguard Worker   auto it = sequences.rbegin();
59*d9f75844SAndroid Build Coastguard Worker   if (it != sequences.rend())
60*d9f75844SAndroid Build Coastguard Worker     it->payload_size = buffer_size - it->payload_start_offset;
61*d9f75844SAndroid Build Coastguard Worker 
62*d9f75844SAndroid Build Coastguard Worker   return sequences;
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker 
ParseNaluType(uint8_t data)65*d9f75844SAndroid Build Coastguard Worker NaluType ParseNaluType(uint8_t data) {
66*d9f75844SAndroid Build Coastguard Worker   return static_cast<NaluType>(data & kNaluTypeMask);
67*d9f75844SAndroid Build Coastguard Worker }
68*d9f75844SAndroid Build Coastguard Worker 
ParseRbsp(const uint8_t * data,size_t length)69*d9f75844SAndroid Build Coastguard Worker std::vector<uint8_t> ParseRbsp(const uint8_t* data, size_t length) {
70*d9f75844SAndroid Build Coastguard Worker   std::vector<uint8_t> out;
71*d9f75844SAndroid Build Coastguard Worker   out.reserve(length);
72*d9f75844SAndroid Build Coastguard Worker 
73*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < length;) {
74*d9f75844SAndroid Build Coastguard Worker     // Be careful about over/underflow here. byte_length_ - 3 can underflow, and
75*d9f75844SAndroid Build Coastguard Worker     // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_
76*d9f75844SAndroid Build Coastguard Worker     // above, and that expression will produce the number of bytes left in
77*d9f75844SAndroid Build Coastguard Worker     // the stream including the byte at i.
78*d9f75844SAndroid Build Coastguard Worker     if (length - i >= 3 && !data[i] && !data[i + 1] && data[i + 2] == 3) {
79*d9f75844SAndroid Build Coastguard Worker       // Two rbsp bytes.
80*d9f75844SAndroid Build Coastguard Worker       out.push_back(data[i++]);
81*d9f75844SAndroid Build Coastguard Worker       out.push_back(data[i++]);
82*d9f75844SAndroid Build Coastguard Worker       // Skip the emulation byte.
83*d9f75844SAndroid Build Coastguard Worker       i++;
84*d9f75844SAndroid Build Coastguard Worker     } else {
85*d9f75844SAndroid Build Coastguard Worker       // Single rbsp byte.
86*d9f75844SAndroid Build Coastguard Worker       out.push_back(data[i++]);
87*d9f75844SAndroid Build Coastguard Worker     }
88*d9f75844SAndroid Build Coastguard Worker   }
89*d9f75844SAndroid Build Coastguard Worker   return out;
90*d9f75844SAndroid Build Coastguard Worker }
91*d9f75844SAndroid Build Coastguard Worker 
WriteRbsp(const uint8_t * bytes,size_t length,rtc::Buffer * destination)92*d9f75844SAndroid Build Coastguard Worker void WriteRbsp(const uint8_t* bytes, size_t length, rtc::Buffer* destination) {
93*d9f75844SAndroid Build Coastguard Worker   static const uint8_t kZerosInStartSequence = 2;
94*d9f75844SAndroid Build Coastguard Worker   static const uint8_t kEmulationByte = 0x03u;
95*d9f75844SAndroid Build Coastguard Worker   size_t num_consecutive_zeros = 0;
96*d9f75844SAndroid Build Coastguard Worker   destination->EnsureCapacity(destination->size() + length);
97*d9f75844SAndroid Build Coastguard Worker 
98*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < length; ++i) {
99*d9f75844SAndroid Build Coastguard Worker     uint8_t byte = bytes[i];
100*d9f75844SAndroid Build Coastguard Worker     if (byte <= kEmulationByte &&
101*d9f75844SAndroid Build Coastguard Worker         num_consecutive_zeros >= kZerosInStartSequence) {
102*d9f75844SAndroid Build Coastguard Worker       // Need to escape.
103*d9f75844SAndroid Build Coastguard Worker       destination->AppendData(kEmulationByte);
104*d9f75844SAndroid Build Coastguard Worker       num_consecutive_zeros = 0;
105*d9f75844SAndroid Build Coastguard Worker     }
106*d9f75844SAndroid Build Coastguard Worker     destination->AppendData(byte);
107*d9f75844SAndroid Build Coastguard Worker     if (byte == 0) {
108*d9f75844SAndroid Build Coastguard Worker       ++num_consecutive_zeros;
109*d9f75844SAndroid Build Coastguard Worker     } else {
110*d9f75844SAndroid Build Coastguard Worker       num_consecutive_zeros = 0;
111*d9f75844SAndroid Build Coastguard Worker     }
112*d9f75844SAndroid Build Coastguard Worker   }
113*d9f75844SAndroid Build Coastguard Worker }
114*d9f75844SAndroid Build Coastguard Worker 
115*d9f75844SAndroid Build Coastguard Worker }  // namespace H264
116*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
117