OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/formats/mp4/avc.h" | 5 #include "media/formats/mp4/avc.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
| 10 #include "base/logging.h" |
| 11 #include "media/base/decrypt_config.h" |
| 12 #include "media/filters/h264_parser.h" |
10 #include "media/formats/mp4/box_definitions.h" | 13 #include "media/formats/mp4/box_definitions.h" |
11 #include "media/formats/mp4/box_reader.h" | 14 #include "media/formats/mp4/box_reader.h" |
12 | 15 |
13 namespace media { | 16 namespace media { |
14 namespace mp4 { | 17 namespace mp4 { |
15 | 18 |
16 static const uint8 kAnnexBStartCode[] = {0, 0, 0, 1}; | 19 static const uint8 kAnnexBStartCode[] = {0, 0, 0, 1}; |
17 static const int kAnnexBStartCodeSize = 4; | 20 static const int kAnnexBStartCodeSize = 4; |
18 | 21 |
19 static bool ConvertAVCToAnnexBInPlaceForLengthSize4(std::vector<uint8>* buf) { | 22 static bool ConvertAVCToAnnexBInPlaceForLengthSize4(std::vector<uint8>* buf) { |
20 const int kLengthSize = 4; | 23 const int kLengthSize = 4; |
21 size_t pos = 0; | 24 size_t pos = 0; |
22 while (pos + kLengthSize < buf->size()) { | 25 while (pos + kLengthSize < buf->size()) { |
23 int nal_size = (*buf)[pos]; | 26 uint32 nal_size = (*buf)[pos]; |
24 nal_size = (nal_size << 8) + (*buf)[pos+1]; | 27 nal_size = (nal_size << 8) + (*buf)[pos+1]; |
25 nal_size = (nal_size << 8) + (*buf)[pos+2]; | 28 nal_size = (nal_size << 8) + (*buf)[pos+2]; |
26 nal_size = (nal_size << 8) + (*buf)[pos+3]; | 29 nal_size = (nal_size << 8) + (*buf)[pos+3]; |
| 30 |
| 31 if (nal_size == 0) { |
| 32 DVLOG(1) << "nal_size is 0"; |
| 33 return false; |
| 34 } |
| 35 |
27 std::copy(kAnnexBStartCode, kAnnexBStartCode + kAnnexBStartCodeSize, | 36 std::copy(kAnnexBStartCode, kAnnexBStartCode + kAnnexBStartCodeSize, |
28 buf->begin() + pos); | 37 buf->begin() + pos); |
29 pos += kLengthSize + nal_size; | 38 pos += kLengthSize + nal_size; |
30 } | 39 } |
31 return pos == buf->size(); | 40 return pos == buf->size(); |
32 } | 41 } |
33 | 42 |
34 // static | 43 // static |
35 bool AVC::ConvertFrameToAnnexB(int length_size, std::vector<uint8>* buffer) { | 44 bool AVC::ConvertFrameToAnnexB(int length_size, std::vector<uint8>* buffer) { |
36 RCHECK(length_size == 1 || length_size == 2 || length_size == 4); | 45 RCHECK(length_size == 1 || length_size == 2 || length_size == 4); |
37 | 46 |
38 if (length_size == 4) | 47 if (length_size == 4) |
39 return ConvertAVCToAnnexBInPlaceForLengthSize4(buffer); | 48 return ConvertAVCToAnnexBInPlaceForLengthSize4(buffer); |
40 | 49 |
41 std::vector<uint8> temp; | 50 std::vector<uint8> temp; |
42 temp.swap(*buffer); | 51 temp.swap(*buffer); |
43 buffer->reserve(temp.size() + 32); | 52 buffer->reserve(temp.size() + 32); |
44 | 53 |
45 size_t pos = 0; | 54 size_t pos = 0; |
46 while (pos + length_size < temp.size()) { | 55 while (pos + length_size < temp.size()) { |
47 int nal_size = temp[pos]; | 56 int nal_size = temp[pos]; |
48 if (length_size == 2) nal_size = (nal_size << 8) + temp[pos+1]; | 57 if (length_size == 2) nal_size = (nal_size << 8) + temp[pos+1]; |
49 pos += length_size; | 58 pos += length_size; |
50 | 59 |
| 60 if (nal_size == 0) { |
| 61 DVLOG(1) << "nal_size is 0"; |
| 62 return false; |
| 63 } |
| 64 |
51 RCHECK(pos + nal_size <= temp.size()); | 65 RCHECK(pos + nal_size <= temp.size()); |
52 buffer->insert(buffer->end(), kAnnexBStartCode, | 66 buffer->insert(buffer->end(), kAnnexBStartCode, |
53 kAnnexBStartCode + kAnnexBStartCodeSize); | 67 kAnnexBStartCode + kAnnexBStartCodeSize); |
54 buffer->insert(buffer->end(), temp.begin() + pos, | 68 buffer->insert(buffer->end(), temp.begin() + pos, |
55 temp.begin() + pos + nal_size); | 69 temp.begin() + pos + nal_size); |
56 pos += nal_size; | 70 pos += nal_size; |
57 } | 71 } |
58 return pos == temp.size(); | 72 return pos == temp.size(); |
59 } | 73 } |
60 | 74 |
61 // static | 75 // static |
| 76 bool AVC::InsertParamSetsAnnexB(const AVCDecoderConfigurationRecord& avc_config, |
| 77 std::vector<uint8>* buffer, |
| 78 std::vector<SubsampleEntry>* subsamples) { |
| 79 DCHECK(AVC::IsValidAnnexB(*buffer)); |
| 80 |
| 81 scoped_ptr<H264Parser> parser(new H264Parser()); |
| 82 const uint8* start = &(*buffer)[0]; |
| 83 parser->SetStream(start, buffer->size()); |
| 84 |
| 85 H264NALU nalu; |
| 86 if (parser->AdvanceToNextNALU(&nalu) != H264Parser::kOk) |
| 87 return false; |
| 88 |
| 89 std::vector<uint8>::iterator config_insert_point = buffer->begin(); |
| 90 std::vector<SubsampleEntry>::iterator subsamples_insert_point = |
| 91 subsamples->begin(); |
| 92 |
| 93 if (nalu.nal_unit_type == H264NALU::kAUD) { |
| 94 // Move insert point to just after the AUD. |
| 95 config_insert_point += (nalu.data + nalu.size) - start; |
| 96 |
| 97 if (!subsamples->empty()) { |
| 98 int64 first_subsample_size = |
| 99 (*subsamples)[0].clear_bytes + (*subsamples)[0].cypher_bytes; |
| 100 |
| 101 if (first_subsample_size != (config_insert_point - buffer->begin())) |
| 102 return false; |
| 103 |
| 104 subsamples_insert_point++; |
| 105 } |
| 106 |
| 107 } |
| 108 |
| 109 // Clear |parser| and |start| since they aren't needed anymore and |
| 110 // will hold stale pointers once the insert happens. |
| 111 parser.reset(); |
| 112 start = NULL; |
| 113 |
| 114 std::vector<uint8> param_sets; |
| 115 std::vector<SubsampleEntry> config_subsamples; |
| 116 RCHECK(AVC::ConvertConfigToAnnexB(avc_config, |
| 117 ¶m_sets, |
| 118 &config_subsamples)); |
| 119 |
| 120 if (!subsamples->empty()) { |
| 121 subsamples->insert(subsamples_insert_point, |
| 122 config_subsamples.begin(), |
| 123 config_subsamples.end()); |
| 124 } |
| 125 |
| 126 buffer->insert(config_insert_point, |
| 127 param_sets.begin(), param_sets.end()); |
| 128 |
| 129 DCHECK(AVC::IsValidAnnexB(*buffer)); |
| 130 return true; |
| 131 } |
| 132 |
| 133 // static |
62 bool AVC::ConvertConfigToAnnexB( | 134 bool AVC::ConvertConfigToAnnexB( |
63 const AVCDecoderConfigurationRecord& avc_config, | 135 const AVCDecoderConfigurationRecord& avc_config, |
64 std::vector<uint8>* buffer) { | 136 std::vector<uint8>* buffer, |
| 137 std::vector<SubsampleEntry>* subsamples) { |
65 DCHECK(buffer->empty()); | 138 DCHECK(buffer->empty()); |
66 buffer->clear(); | 139 buffer->clear(); |
67 int total_size = 0; | 140 int total_size = 0; |
68 for (size_t i = 0; i < avc_config.sps_list.size(); i++) | 141 for (size_t i = 0; i < avc_config.sps_list.size(); i++) |
69 total_size += avc_config.sps_list[i].size() + kAnnexBStartCodeSize; | 142 total_size += avc_config.sps_list[i].size() + kAnnexBStartCodeSize; |
70 for (size_t i = 0; i < avc_config.pps_list.size(); i++) | 143 for (size_t i = 0; i < avc_config.pps_list.size(); i++) |
71 total_size += avc_config.pps_list[i].size() + kAnnexBStartCodeSize; | 144 total_size += avc_config.pps_list[i].size() + kAnnexBStartCodeSize; |
72 buffer->reserve(total_size); | 145 buffer->reserve(total_size); |
73 | 146 |
74 for (size_t i = 0; i < avc_config.sps_list.size(); i++) { | 147 for (size_t i = 0; i < avc_config.sps_list.size(); i++) { |
75 buffer->insert(buffer->end(), kAnnexBStartCode, | 148 buffer->insert(buffer->end(), kAnnexBStartCode, |
76 kAnnexBStartCode + kAnnexBStartCodeSize); | 149 kAnnexBStartCode + kAnnexBStartCodeSize); |
77 buffer->insert(buffer->end(), avc_config.sps_list[i].begin(), | 150 buffer->insert(buffer->end(), avc_config.sps_list[i].begin(), |
78 avc_config.sps_list[i].end()); | 151 avc_config.sps_list[i].end()); |
| 152 |
| 153 SubsampleEntry entry; |
| 154 entry.clear_bytes = kAnnexBStartCodeSize + avc_config.sps_list[i].size(); |
| 155 entry.cypher_bytes = 0; |
| 156 subsamples->push_back(entry); |
79 } | 157 } |
80 | 158 |
81 for (size_t i = 0; i < avc_config.pps_list.size(); i++) { | 159 for (size_t i = 0; i < avc_config.pps_list.size(); i++) { |
82 buffer->insert(buffer->end(), kAnnexBStartCode, | 160 buffer->insert(buffer->end(), kAnnexBStartCode, |
83 kAnnexBStartCode + kAnnexBStartCodeSize); | 161 kAnnexBStartCode + kAnnexBStartCodeSize); |
84 buffer->insert(buffer->end(), avc_config.pps_list[i].begin(), | 162 buffer->insert(buffer->end(), avc_config.pps_list[i].begin(), |
85 avc_config.pps_list[i].end()); | 163 avc_config.pps_list[i].end()); |
| 164 |
| 165 SubsampleEntry entry; |
| 166 entry.clear_bytes = kAnnexBStartCodeSize + avc_config.pps_list[i].size(); |
| 167 entry.cypher_bytes = 0; |
| 168 subsamples->push_back(entry); |
86 } | 169 } |
87 return true; | 170 return true; |
88 } | 171 } |
89 | 172 |
| 173 // Verifies AnnexB NALU order according to ISO/IEC 14496-10 Section 7.4.1.2.3 |
| 174 bool AVC::IsValidAnnexB(const std::vector<uint8>& buffer) { |
| 175 DVLOG(1) << __FUNCTION__; |
| 176 |
| 177 if (buffer.empty()) |
| 178 return true; |
| 179 |
| 180 H264Parser parser; |
| 181 parser.SetStream(&buffer[0], buffer.size()); |
| 182 |
| 183 typedef enum { |
| 184 kAUDAllowed, |
| 185 kBeforeFirstVCL, // VCL == nal_unit_types 1-5 |
| 186 kAfterFirstVCL, |
| 187 kEOStreamAllowed, |
| 188 kNoMoreDataAllowed, |
| 189 } NALUOrderState; |
| 190 |
| 191 H264NALU nalu; |
| 192 NALUOrderState order_state = kAUDAllowed; |
| 193 int last_nalu_type = H264NALU::kUnspecified; |
| 194 bool done = false; |
| 195 while (!done) { |
| 196 switch (parser.AdvanceToNextNALU(&nalu)) { |
| 197 case H264Parser::kOk: |
| 198 DVLOG(1) << "nal_unit_type " << nalu.nal_unit_type; |
| 199 |
| 200 switch (nalu.nal_unit_type) { |
| 201 case H264NALU::kAUD: |
| 202 if (order_state > kAUDAllowed) { |
| 203 DVLOG(1) << "Unexpected AUD in order_state " << order_state; |
| 204 return false; |
| 205 } |
| 206 order_state = kBeforeFirstVCL; |
| 207 break; |
| 208 |
| 209 case H264NALU::kSEIMessage: |
| 210 case H264NALU::kReserved14: |
| 211 case H264NALU::kReserved15: |
| 212 case H264NALU::kReserved16: |
| 213 case H264NALU::kReserved17: |
| 214 case H264NALU::kReserved18: |
| 215 case H264NALU::kPPS: |
| 216 case H264NALU::kSPS: |
| 217 if (order_state > kBeforeFirstVCL) { |
| 218 DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type |
| 219 << " in order_state " << order_state; |
| 220 return false; |
| 221 } |
| 222 order_state = kBeforeFirstVCL; |
| 223 break; |
| 224 |
| 225 case H264NALU::kSPSExt: |
| 226 if (last_nalu_type != H264NALU::kSPS) { |
| 227 DVLOG(1) << "SPS extension does not follow an SPS."; |
| 228 return false; |
| 229 } |
| 230 break; |
| 231 |
| 232 case H264NALU::kNonIDRSlice: |
| 233 case H264NALU::kSliceDataA: |
| 234 case H264NALU::kSliceDataB: |
| 235 case H264NALU::kSliceDataC: |
| 236 case H264NALU::kIDRSlice: |
| 237 if (order_state > kAfterFirstVCL) { |
| 238 DVLOG(1) << "Unexpected VCL in order_state " << order_state; |
| 239 return false; |
| 240 } |
| 241 order_state = kAfterFirstVCL; |
| 242 break; |
| 243 |
| 244 case H264NALU::kCodedSliceAux: |
| 245 if (order_state != kAfterFirstVCL) { |
| 246 DVLOG(1) << "Unexpected extension in order_state " << order_state; |
| 247 return false; |
| 248 } |
| 249 break; |
| 250 |
| 251 case H264NALU::kEOSeq: |
| 252 if (order_state != kAfterFirstVCL) { |
| 253 DVLOG(1) << "Unexpected EOSeq in order_state " << order_state; |
| 254 return false; |
| 255 } |
| 256 order_state = kEOStreamAllowed; |
| 257 break; |
| 258 |
| 259 case H264NALU::kEOStream: |
| 260 if (order_state < kAfterFirstVCL) { |
| 261 DVLOG(1) << "Unexpected EOStream in order_state " << order_state; |
| 262 return false; |
| 263 } |
| 264 order_state = kNoMoreDataAllowed; |
| 265 break; |
| 266 |
| 267 case H264NALU::kFiller: |
| 268 case H264NALU::kUnspecified: |
| 269 if (!(order_state >= kAfterFirstVCL && |
| 270 order_state < kEOStreamAllowed)) { |
| 271 DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type |
| 272 << " in order_state " << order_state; |
| 273 return false; |
| 274 } |
| 275 break; |
| 276 |
| 277 default: |
| 278 DCHECK_GE(nalu.nal_unit_type, 20); |
| 279 if (nalu.nal_unit_type >= 20 && nalu.nal_unit_type <= 31 && |
| 280 order_state != kAfterFirstVCL) { |
| 281 DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type |
| 282 << " in order_state " << order_state; |
| 283 return false; |
| 284 } |
| 285 } |
| 286 last_nalu_type = nalu.nal_unit_type; |
| 287 break; |
| 288 |
| 289 case H264Parser::kInvalidStream: |
| 290 return false; |
| 291 |
| 292 case H264Parser::kUnsupportedStream: |
| 293 NOTREACHED() << "AdvanceToNextNALU() returned kUnsupportedStream!"; |
| 294 return false; |
| 295 |
| 296 case H264Parser::kEOStream: |
| 297 done = true; |
| 298 } |
| 299 } |
| 300 |
| 301 return order_state >= kAfterFirstVCL; |
| 302 } |
| 303 |
90 } // namespace mp4 | 304 } // namespace mp4 |
91 } // namespace media | 305 } // namespace media |
OLD | NEW |