1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // A parser for H.264 bitstream. It will determine will kind of Netowrk
16 // Abstraction Layer Unit (NALU) we have received from the guest.
17
18 #include "host-common/H264NaluParser.h"
19
20 #define H264_DEBUG 0
21
22 #if H264_DEBUG
23 #define RED "\x1B[31m"
24 #define GRN "\x1B[32m"
25 #define YEL "\x1B[33m"
26 #define BLU "\x1B[34m"
27 #define MAG "\x1B[35m"
28 #define CYN "\x1B[36m"
29 #define WHT "\x1B[37m"
30 #define RESET "\x1B[0m"
31 #define H264_PRINT(color,fmt,...) fprintf(stderr, color "H264NaluParser: %s:%d " fmt "\n" RESET, __func__, __LINE__, ##__VA_ARGS__);
32 #else
33 #define H264_PRINT(fmt,...)
34 #endif
35
36 #define H264_INFO(fmt,...) H264_PRINT(RESET, fmt, ##__VA_ARGS__);
37 #define H264_WARN(fmt,...) H264_PRINT(YEL, fmt, ##__VA_ARGS__);
38 #define H264_ERROR(fmt,...) H264_PRINT(RED, fmt, ##__VA_ARGS__);
39
40 namespace android {
41 namespace emulation {
42
43 const std::string H264NaluParser::kNaluTypesStrings[] =
44 {
45 "0: Unspecified (non-VCL)",
46 "1: Coded slice of a non-IDR picture (VCL)", // P frame
47 "2: Coded slice data partition A (VCL)",
48 "3: Coded slice data partition B (VCL)",
49 "4: Coded slice data partition C (VCL)",
50 "5: Coded slice of an IDR picture (VCL)", // I frame
51 "6: Supplemental enhancement information (SEI) (non-VCL)",
52 "7: Sequence parameter set (non-VCL)", // SPS parameter
53 "8: Picture parameter set (non-VCL)", // PPS parameter
54 "9: Access unit delimiter (non-VCL)",
55 "10: End of sequence (non-VCL)",
56 "11: End of stream (non-VCL)",
57 "12: Filler data (non-VCL)",
58 "13: Sequence parameter set extension (non-VCL)",
59 "14: Prefix NAL unit (non-VCL)",
60 "15: Subset sequence parameter set (non-VCL)",
61 "16: Reserved (non-VCL)",
62 "17: Reserved (non-VCL)",
63 "18: Reserved (non-VCL)",
64 "19: Coded slice of an auxiliary coded picture without partitioning (non-VCL)",
65 "20: Coded slice extension (non-VCL)",
66 "21: Coded slice extension for depth view components (non-VCL)",
67 "22: Reserved (non-VCL)",
68 "23: Reserved (non-VCL)",
69 "24: STAP-A Single-time aggregation packet (non-VCL)",
70 "25: STAP-B Single-time aggregation packet (non-VCL)",
71 "26: MTAP16 Multi-time aggregation packet (non-VCL)",
72 "27: MTAP24 Multi-time aggregation packet (non-VCL)",
73 "28: FU-A Fragmentation unit (non-VCL)",
74 "29: FU-B Fragmentation unit (non-VCL)",
75 "30: Unspecified (non-VCL)",
76 "31: Unspecified (non-VCL)",
77 };
78
naluTypeToString(H264NaluType n)79 const std::string& H264NaluParser::naluTypeToString(H264NaluType n) {
80 uint8_t idx = static_cast<uint8_t>(n);
81 H264_WARN("%s", kNaluTypesStrings[idx].c_str());
82 return kNaluTypesStrings[idx];
83 }
84
checkSpsFrame(const uint8_t * frame,size_t szBytes)85 bool H264NaluParser::checkSpsFrame(const uint8_t* frame, size_t szBytes) {
86 H264NaluParser::H264NaluType currNaluType =
87 H264NaluParser::getFrameNaluType(frame, szBytes, NULL);
88 if (currNaluType != H264NaluParser::H264NaluType::SPS) {
89 return false;
90 }
91 H264_INFO("found sps");
92 return true;
93 }
94
checkIFrame(const uint8_t * frame,size_t szBytes)95 bool H264NaluParser::checkIFrame(const uint8_t* frame, size_t szBytes) {
96 H264NaluParser::H264NaluType currNaluType =
97 H264NaluParser::getFrameNaluType(frame, szBytes, NULL);
98 if (currNaluType != H264NaluParser::H264NaluType::CodedSliceIDR) {
99 return false;
100 }
101 H264_INFO("found i frame");
102 return true;
103 }
104
checkPpsFrame(const uint8_t * frame,size_t szBytes)105 bool H264NaluParser::checkPpsFrame(const uint8_t* frame, size_t szBytes) {
106 H264NaluParser::H264NaluType currNaluType =
107 H264NaluParser::getFrameNaluType(frame, szBytes, NULL);
108 if (currNaluType != H264NaluParser::H264NaluType::PPS) {
109 return false;
110 }
111 H264_INFO("found pps");
112 return true;
113 }
114
getFrameNaluType(const uint8_t * frame,size_t szBytes,uint8_t ** data)115 H264NaluParser::H264NaluType H264NaluParser::getFrameNaluType(const uint8_t* frame, size_t szBytes, uint8_t** data) {
116 if (szBytes < 4) {
117 H264_INFO("Not enough bytes for start code header and NALU type");
118 return H264NaluType::Undefined;
119 }
120
121 if (frame[0] != 0 || frame[1] != 0) {
122 H264_INFO("First two bytes of start code header are not zero");
123 return H264NaluType::Undefined;
124 }
125
126 // check for 4-byte start code header
127 if (frame[2] == 0 && frame[3] == 1) {
128 if (szBytes == 4) {
129 H264_INFO("Got start code header but no NALU type");
130 return H264NaluType::Undefined;
131 }
132 // nalu type is the lower 5 bits
133 uint8_t naluType = 0x1f & frame[4];
134 // H264_INFO("frame[4]=0x%2x nalutype=0x%2x", frame[4], naluType);
135 if (data) {
136 *data = const_cast<uint8_t*>(&frame[4]);
137 }
138 return (naluType < static_cast<uint8_t>(H264NaluType::Undefined)) ?
139 static_cast<H264NaluType>(naluType) :
140 H264NaluType::Undefined;
141 }
142
143 // check for three-byte start code header
144 if (frame[2] == 1) {
145 // nalu type is the lower 5 bits
146 uint8_t naluType = 0x1f & frame[3];
147 if (data) {
148 *data = const_cast<uint8_t*>(&frame[3]);
149 }
150 return (naluType < static_cast<uint8_t>(H264NaluType::Undefined)) ?
151 static_cast<H264NaluType>(naluType) :
152 H264NaluType::Undefined;
153 }
154
155 H264_WARN("Frame did not have a start code header");
156 return H264NaluType::Undefined;
157 }
158
getNextStartCodeHeader(const uint8_t * frame,size_t szBytes)159 const uint8_t* H264NaluParser::getNextStartCodeHeader(const uint8_t* frame, size_t szBytes) {
160 // // Start code can either be 0x000001 or 0x00000001. Beware of doing this comparison
161 // // by casting, as the frame may be in network-byte order (big endian).
162 // const uint8_t* res = nullptr;
163 // size_t idx = 0;
164 // const int kHeaderMinSize = 3;
165 // int64_t remaining = szBytes;
166 //
167 // while (remaining >= kHeaderMinSize) {
168 // if (frame[idx] != 0) {
169 // ++idx;
170 // --remaining;
171 // continue;
172 // }
173 //
174 // if (frame[idx + 1] != 0) {
175 // idx += 2;
176 // remaining -= 2;
177 // continue;
178 // }
179 //
180 // if (frame[idx + 2] == 1) {
181 // res = &frame[idx];
182 // break;
183 // }
184 //
185 // // check for four byte header if enough bytes left
186 // if (frame[idx + 2] == 0) {
187 // if (remaining >= 4 && frame[idx + 3] == 1) {
188 // res = &frame[idx];
189 // break;
190 // } else {
191 // idx += 4;
192 // remaining -= 4;
193 // continue;
194 // }
195 // } else {
196 // idx += 3;
197 // remaining -= 3;
198 // continue;
199 // }
200 // }
201 //
202 // return res;
203
204 // This implementation uses bit shifting
205 constexpr uint32_t startHeaderMask = 0x00000001;
206 uint32_t window = 0;
207
208 if (szBytes < 3) {
209 H264_INFO("Not enough bytes for a start code header");
210 return nullptr;
211 }
212
213 // we can't do a cast to 32-bit int because it is in network-byte format (big endian).
214 window |= (uint32_t)frame[0] << 16;
215 window |= (uint32_t)frame[1] << 8;
216 window |= frame[2];
217
218 if (szBytes == 3) {
219 if (!(window ^ startHeaderMask)) {
220 return &frame[0];
221 } else {
222 return nullptr;
223 }
224 }
225
226 size_t remaining = szBytes - 3;
227 while (remaining > 0) {
228 window = (window << 8) | (uint32_t)frame[szBytes - remaining];
229 if (!(window ^ startHeaderMask)) {
230 // four-byte header match
231 return &frame[szBytes - remaining - 3];
232 } else if (!((window & 0x00ffffff) ^ startHeaderMask)) {
233 // three-byte header match
234 return &frame[szBytes - remaining - 2];
235 }
236 --remaining;
237 }
238 return nullptr;
239 }
240
241 } // namespace emulation
242 } // namespace android
243