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