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