• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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