• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "media/formats/mp4/avc.h"
6 
7 #include <algorithm>
8 #include <vector>
9 
10 #include "base/logging.h"
11 #include "media/base/decrypt_config.h"
12 #include "media/filters/h264_parser.h"
13 #include "media/formats/mp4/box_definitions.h"
14 #include "media/formats/mp4/box_reader.h"
15 
16 namespace media {
17 namespace mp4 {
18 
19 static const uint8 kAnnexBStartCode[] = {0, 0, 0, 1};
20 static const int kAnnexBStartCodeSize = 4;
21 
ConvertAVCToAnnexBInPlaceForLengthSize4(std::vector<uint8> * buf)22 static bool ConvertAVCToAnnexBInPlaceForLengthSize4(std::vector<uint8>* buf) {
23   const int kLengthSize = 4;
24   size_t pos = 0;
25   while (pos + kLengthSize < buf->size()) {
26     uint32 nal_size = (*buf)[pos];
27     nal_size = (nal_size << 8) + (*buf)[pos+1];
28     nal_size = (nal_size << 8) + (*buf)[pos+2];
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 
36     std::copy(kAnnexBStartCode, kAnnexBStartCode + kAnnexBStartCodeSize,
37               buf->begin() + pos);
38     pos += kLengthSize + nal_size;
39   }
40   return pos == buf->size();
41 }
42 
43 // static
ConvertFrameToAnnexB(int length_size,std::vector<uint8> * buffer)44 bool AVC::ConvertFrameToAnnexB(int length_size, std::vector<uint8>* buffer) {
45   RCHECK(length_size == 1 || length_size == 2 || length_size == 4);
46 
47   if (length_size == 4)
48     return ConvertAVCToAnnexBInPlaceForLengthSize4(buffer);
49 
50   std::vector<uint8> temp;
51   temp.swap(*buffer);
52   buffer->reserve(temp.size() + 32);
53 
54   size_t pos = 0;
55   while (pos + length_size < temp.size()) {
56     int nal_size = temp[pos];
57     if (length_size == 2) nal_size = (nal_size << 8) + temp[pos+1];
58     pos += length_size;
59 
60     if (nal_size == 0) {
61       DVLOG(1) << "nal_size is 0";
62       return false;
63     }
64 
65     RCHECK(pos + nal_size <= temp.size());
66     buffer->insert(buffer->end(), kAnnexBStartCode,
67                    kAnnexBStartCode + kAnnexBStartCodeSize);
68     buffer->insert(buffer->end(), temp.begin() + pos,
69                    temp.begin() + pos + nal_size);
70     pos += nal_size;
71   }
72   return pos == temp.size();
73 }
74 
75 // static
InsertParamSetsAnnexB(const AVCDecoderConfigurationRecord & avc_config,std::vector<uint8> * buffer,std::vector<SubsampleEntry> * subsamples)76 bool AVC::InsertParamSetsAnnexB(const AVCDecoderConfigurationRecord& avc_config,
77                                 std::vector<uint8>* buffer,
78                                 std::vector<SubsampleEntry>* subsamples) {
79   DCHECK(AVC::IsValidAnnexB(*buffer, *subsamples));
80 
81   scoped_ptr<H264Parser> parser(new H264Parser());
82   const uint8* start = &(*buffer)[0];
83   parser->SetEncryptedStream(start, buffer->size(), *subsamples);
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                                     &param_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, *subsamples));
130   return true;
131 }
132 
133 // static
ConvertConfigToAnnexB(const AVCDecoderConfigurationRecord & avc_config,std::vector<uint8> * buffer,std::vector<SubsampleEntry> * subsamples)134 bool AVC::ConvertConfigToAnnexB(
135     const AVCDecoderConfigurationRecord& avc_config,
136     std::vector<uint8>* buffer,
137     std::vector<SubsampleEntry>* subsamples) {
138   DCHECK(buffer->empty());
139   buffer->clear();
140   int total_size = 0;
141   for (size_t i = 0; i < avc_config.sps_list.size(); i++)
142     total_size += avc_config.sps_list[i].size() + kAnnexBStartCodeSize;
143   for (size_t i = 0; i < avc_config.pps_list.size(); i++)
144     total_size += avc_config.pps_list[i].size() + kAnnexBStartCodeSize;
145   buffer->reserve(total_size);
146 
147   for (size_t i = 0; i < avc_config.sps_list.size(); i++) {
148     buffer->insert(buffer->end(), kAnnexBStartCode,
149                 kAnnexBStartCode + kAnnexBStartCodeSize);
150     buffer->insert(buffer->end(), avc_config.sps_list[i].begin(),
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);
157   }
158 
159   for (size_t i = 0; i < avc_config.pps_list.size(); i++) {
160     buffer->insert(buffer->end(), kAnnexBStartCode,
161                    kAnnexBStartCode + kAnnexBStartCodeSize);
162     buffer->insert(buffer->end(), avc_config.pps_list[i].begin(),
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);
169   }
170   return true;
171 }
172 
173 // Verifies AnnexB NALU order according to ISO/IEC 14496-10 Section 7.4.1.2.3
IsValidAnnexB(const std::vector<uint8> & buffer,const std::vector<SubsampleEntry> & subsamples)174 bool AVC::IsValidAnnexB(const std::vector<uint8>& buffer,
175                         const std::vector<SubsampleEntry>& subsamples) {
176   return IsValidAnnexB(&buffer[0], buffer.size(), subsamples);
177 }
178 
IsValidAnnexB(const uint8 * buffer,size_t size,const std::vector<SubsampleEntry> & subsamples)179 bool AVC::IsValidAnnexB(const uint8* buffer, size_t size,
180                         const std::vector<SubsampleEntry>& subsamples) {
181   DVLOG(1) << __FUNCTION__;
182   DCHECK(buffer);
183 
184   if (size == 0)
185     return true;
186 
187   H264Parser parser;
188   parser.SetEncryptedStream(buffer, size, subsamples);
189 
190   typedef enum {
191     kAUDAllowed,
192     kBeforeFirstVCL,  // VCL == nal_unit_types 1-5
193     kAfterFirstVCL,
194     kEOStreamAllowed,
195     kNoMoreDataAllowed,
196   } NALUOrderState;
197 
198   H264NALU nalu;
199   NALUOrderState order_state = kAUDAllowed;
200   int last_nalu_type = H264NALU::kUnspecified;
201   bool done = false;
202   while (!done) {
203     switch (parser.AdvanceToNextNALU(&nalu)) {
204       case H264Parser::kOk:
205         DVLOG(1) << "nal_unit_type " << nalu.nal_unit_type;
206 
207         switch (nalu.nal_unit_type) {
208           case H264NALU::kAUD:
209             if (order_state > kAUDAllowed) {
210               DVLOG(1) << "Unexpected AUD in order_state " << order_state;
211               return false;
212             }
213             order_state = kBeforeFirstVCL;
214             break;
215 
216           case H264NALU::kSEIMessage:
217           case H264NALU::kReserved14:
218           case H264NALU::kReserved15:
219           case H264NALU::kReserved16:
220           case H264NALU::kReserved17:
221           case H264NALU::kReserved18:
222           case H264NALU::kPPS:
223           case H264NALU::kSPS:
224             if (order_state > kBeforeFirstVCL) {
225               DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type
226                        << " in order_state " << order_state;
227               return false;
228             }
229             order_state = kBeforeFirstVCL;
230             break;
231 
232           case H264NALU::kSPSExt:
233             if (last_nalu_type != H264NALU::kSPS) {
234               DVLOG(1) << "SPS extension does not follow an SPS.";
235               return false;
236             }
237             break;
238 
239           case H264NALU::kNonIDRSlice:
240           case H264NALU::kSliceDataA:
241           case H264NALU::kSliceDataB:
242           case H264NALU::kSliceDataC:
243           case H264NALU::kIDRSlice:
244             if (order_state > kAfterFirstVCL) {
245               DVLOG(1) << "Unexpected VCL in order_state " << order_state;
246               return false;
247             }
248             order_state = kAfterFirstVCL;
249             break;
250 
251           case H264NALU::kCodedSliceAux:
252             if (order_state != kAfterFirstVCL) {
253               DVLOG(1) << "Unexpected extension in order_state " << order_state;
254               return false;
255             }
256             break;
257 
258           case H264NALU::kEOSeq:
259             if (order_state != kAfterFirstVCL) {
260               DVLOG(1) << "Unexpected EOSeq in order_state " << order_state;
261               return false;
262             }
263             order_state = kEOStreamAllowed;
264             break;
265 
266           case H264NALU::kEOStream:
267             if (order_state < kAfterFirstVCL) {
268               DVLOG(1) << "Unexpected EOStream in order_state " << order_state;
269               return false;
270             }
271             order_state = kNoMoreDataAllowed;
272             break;
273 
274           case H264NALU::kFiller:
275           case H264NALU::kUnspecified:
276             if (!(order_state >= kAfterFirstVCL &&
277                   order_state < kEOStreamAllowed)) {
278               DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type
279                        << " in order_state " << order_state;
280               return false;
281             }
282             break;
283 
284           default:
285             DCHECK_GE(nalu.nal_unit_type, 20);
286             if (nalu.nal_unit_type >= 20 && nalu.nal_unit_type <= 31 &&
287                 order_state != kAfterFirstVCL) {
288               DVLOG(1) << "Unexpected NALU type " << nalu.nal_unit_type
289                        << " in order_state " << order_state;
290               return false;
291             }
292         }
293         last_nalu_type = nalu.nal_unit_type;
294         break;
295 
296       case H264Parser::kInvalidStream:
297         return false;
298 
299       case H264Parser::kUnsupportedStream:
300         NOTREACHED() << "AdvanceToNextNALU() returned kUnsupportedStream!";
301         return false;
302 
303       case H264Parser::kEOStream:
304         done = true;
305     }
306   }
307 
308   return order_state >= kAfterFirstVCL;
309 }
310 }  // namespace mp4
311 }  // namespace media
312