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