• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2009-2011 Intel Corporation.  All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "VideoDecoderAVCSecure.h"
18 #include "VideoDecoderTrace.h"
19 #include <string.h>
20 
21 
22 #define STARTCODE_00                0x00
23 #define STARTCODE_01                0x01
24 #define STARTCODE_PREFIX_LEN        3
25 #define NALU_TYPE_MASK              0x1F
26 
27 
28 // mask for little endian, to mast the second and fourth bytes in the byte stream
29 #define STARTCODE_MASK0             0xFF000000 //0x00FF0000
30 #define STARTCODE_MASK1             0x0000FF00  //0x000000FF
31 
32 
33 typedef enum {
34     NAL_UNIT_TYPE_unspecified0 = 0,
35     NAL_UNIT_TYPE_SLICE,
36     NAL_UNIT_TYPE_DPA,
37     NAL_UNIT_TYPE_DPB,
38     NAL_UNIT_TYPE_DPC,
39     NAL_UNIT_TYPE_IDR,
40     NAL_UNIT_TYPE_SEI,
41     NAL_UNIT_TYPE_SPS,
42     NAL_UNIT_TYPE_PPS,
43     NAL_UNIT_TYPE_Acc_unit_delimiter,
44     NAL_UNIT_TYPE_EOSeq,
45     NAL_UNIT_TYPE_EOstream,
46     NAL_UNIT_TYPE_filler_data,
47     NAL_UNIT_TYPE_SPS_extension,
48     NAL_UNIT_TYPE_Reserved14,
49     NAL_UNIT_TYPE_Reserved15,
50     NAL_UNIT_TYPE_Reserved16,
51     NAL_UNIT_TYPE_Reserved17,
52     NAL_UNIT_TYPE_Reserved18,
53     NAL_UNIT_TYPE_ACP,
54     NAL_UNIT_TYPE_Reserved20,
55     NAL_UNIT_TYPE_Reserved21,
56     NAL_UNIT_TYPE_Reserved22,
57     NAL_UNIT_TYPE_Reserved23,
58     NAL_UNIT_TYPE_unspecified24,
59 } NAL_UNIT_TYPE;
60 
61 #ifndef min
62 #define min(X, Y)  ((X) <(Y) ? (X) : (Y))
63 #endif
64 
65 
66 static const uint8_t startcodePrefix[STARTCODE_PREFIX_LEN] = {0x00, 0x00, 0x01};
67 
68 
VideoDecoderAVCSecure(const char * mimeType)69 VideoDecoderAVCSecure::VideoDecoderAVCSecure(const char *mimeType)
70     : VideoDecoderAVC(mimeType),
71       mNaluHeaderBuffer(NULL),
72       mInputBuffer(NULL) {
73 
74     memset(&mMetadata, 0, sizeof(NaluMetadata));
75     memset(&mByteStream, 0, sizeof(NaluByteStream));
76 }
77 
~VideoDecoderAVCSecure()78 VideoDecoderAVCSecure::~VideoDecoderAVCSecure() {
79 }
80 
start(VideoConfigBuffer * buffer)81 Decode_Status VideoDecoderAVCSecure::start(VideoConfigBuffer *buffer) {
82     Decode_Status status = VideoDecoderAVC::start(buffer);
83     if (status != DECODE_SUCCESS) {
84         return status;
85     }
86 
87     mMetadata.naluInfo = new NaluInfo [MAX_NALU_NUMBER];
88     mByteStream.byteStream = new uint8_t [MAX_NALU_HEADER_BUFFER];
89     mNaluHeaderBuffer = new uint8_t [MAX_NALU_HEADER_BUFFER];
90 
91     if (mMetadata.naluInfo == NULL ||
92         mByteStream.byteStream == NULL ||
93         mNaluHeaderBuffer == NULL) {
94         ETRACE("Failed to allocate memory.");
95         // TODO: release all allocated memory
96         return DECODE_MEMORY_FAIL;
97     }
98     return status;
99 }
100 
stop(void)101 void VideoDecoderAVCSecure::stop(void) {
102     VideoDecoderAVC::stop();
103 
104     if (mMetadata.naluInfo) {
105         delete [] mMetadata.naluInfo;
106         mMetadata.naluInfo = NULL;
107     }
108 
109     if (mByteStream.byteStream) {
110         delete [] mByteStream.byteStream;
111         mByteStream.byteStream = NULL;
112     }
113 
114     if (mNaluHeaderBuffer) {
115         delete [] mNaluHeaderBuffer;
116         mNaluHeaderBuffer = NULL;
117     }
118 }
119 
decode(VideoDecodeBuffer * buffer)120 Decode_Status VideoDecoderAVCSecure::decode(VideoDecodeBuffer *buffer) {
121     Decode_Status status;
122     int32_t sizeAccumulated = 0;
123     int32_t sizeLeft = 0;
124     uint8_t *pByteStream = NULL;
125     NaluInfo *pNaluInfo = mMetadata.naluInfo;
126 
127     if (buffer->flag & IS_SECURE_DATA) {
128         pByteStream = buffer->data;
129         sizeLeft = buffer->size;
130         mInputBuffer = NULL;
131     } else {
132         status = parseAnnexBStream(buffer->data, buffer->size, &mByteStream);
133         CHECK_STATUS("parseAnnexBStream");
134         pByteStream = mByteStream.byteStream;
135         sizeLeft = mByteStream.streamPos;
136         mInputBuffer = buffer->data;
137     }
138     if (sizeLeft < 4) {
139         ETRACE("Not enough data to read number of NALU.");
140         return DECODE_INVALID_DATA;
141     }
142 
143     // read number of NALU
144     memcpy(&(mMetadata.naluNumber), pByteStream, sizeof(int32_t));
145     pByteStream += 4;
146     sizeLeft -= 4;
147 
148     if (mMetadata.naluNumber == 0) {
149         WTRACE("Number of NALU is ZERO!");
150         return DECODE_SUCCESS;
151     }
152 
153     for (int32_t i = 0; i < mMetadata.naluNumber; i++) {
154         if (sizeLeft < 12) {
155             ETRACE("Not enough data to parse NALU offset, size, header length for NALU %d, left = %d", i, sizeLeft);
156             return DECODE_INVALID_DATA;
157         }
158         sizeLeft -= 12;
159         // read NALU offset
160         memcpy(&(pNaluInfo->naluOffset), pByteStream, sizeof(int32_t));
161         pByteStream += 4;
162 
163         // read NALU size
164         memcpy(&(pNaluInfo->naluLen), pByteStream, sizeof(int32_t));
165         pByteStream += 4;
166 
167         // read NALU header length
168         memcpy(&(pNaluInfo->naluHeaderLen), pByteStream, sizeof(int32_t));
169         pByteStream += 4;
170 
171         if (sizeLeft < pNaluInfo->naluHeaderLen) {
172             ETRACE("Not enough data to copy NALU header for %d, left = %d, header len = %d", i, sizeLeft, pNaluInfo->naluHeaderLen);
173             return DECODE_INVALID_DATA;
174         }
175 
176         sizeLeft -=  pNaluInfo->naluHeaderLen;
177 
178         if (pNaluInfo->naluHeaderLen) {
179             // copy start code prefix to buffer
180             memcpy(mNaluHeaderBuffer + sizeAccumulated,
181                 startcodePrefix,
182                 STARTCODE_PREFIX_LEN);
183             sizeAccumulated += STARTCODE_PREFIX_LEN;
184 
185             // copy NALU header
186             memcpy(mNaluHeaderBuffer + sizeAccumulated, pByteStream, pNaluInfo->naluHeaderLen);
187             pByteStream += pNaluInfo->naluHeaderLen;
188 
189             sizeAccumulated += pNaluInfo->naluHeaderLen;
190         } else {
191             WTRACE("header len is zero for NALU %d", i);
192         }
193 
194         // for next NALU
195         pNaluInfo++;
196     }
197 
198     buffer->data = mNaluHeaderBuffer;
199     buffer->size = sizeAccumulated;
200 
201     return VideoDecoderAVC::decode(buffer);
202 }
203 
204 
decodeSlice(vbp_data_h264 * data,uint32_t picIndex,uint32_t sliceIndex)205 Decode_Status VideoDecoderAVCSecure::decodeSlice(vbp_data_h264 *data, uint32_t picIndex, uint32_t sliceIndex) {
206 
207     Decode_Status status;
208     VAStatus vaStatus;
209     uint32_t bufferIDCount = 0;
210     // maximum 4 buffers to render a slice: picture parameter, IQMatrix, slice parameter, slice data
211     VABufferID bufferIDs[4];
212 
213     vbp_picture_data_h264 *picData = &(data->pic_data[picIndex]);
214     vbp_slice_data_h264 *sliceData = &(picData->slc_data[sliceIndex]);
215     VAPictureParameterBufferH264 *picParam = picData->pic_parms;
216     VASliceParameterBufferH264 *sliceParam = &(sliceData->slc_parms);
217 
218     if (sliceParam->first_mb_in_slice == 0 || mDecodingFrame == false) {
219         // either condition indicates start of a new frame
220         if (sliceParam->first_mb_in_slice != 0) {
221             WTRACE("The first slice is lost.");
222             // TODO: handle the first slice lost
223         }
224         if (mDecodingFrame) {
225             // interlace content, complete decoding the first field
226             vaStatus = vaEndPicture(mVADisplay, mVAContext);
227             CHECK_VA_STATUS("vaEndPicture");
228 
229             // for interlace content, top field may be valid only after the second field is parsed
230             mAcquiredBuffer->pictureOrder= picParam->CurrPic.TopFieldOrderCnt;
231         }
232 
233         // Check there is no reference frame loss before decoding a frame
234 
235         // Update  the reference frames and surface IDs for DPB and current frame
236         status = updateDPB(picParam);
237         CHECK_STATUS("updateDPB");
238 
239         //We have to provide a hacked DPB rather than complete DPB for libva as workaround
240         status = updateReferenceFrames(picData);
241         CHECK_STATUS("updateReferenceFrames");
242 
243         vaStatus = vaBeginPicture(mVADisplay, mVAContext, mAcquiredBuffer->renderBuffer.surface);
244         CHECK_VA_STATUS("vaBeginPicture");
245 
246         // start decoding a frame
247         mDecodingFrame = true;
248 
249         vaStatus = vaCreateBuffer(
250             mVADisplay,
251             mVAContext,
252             VAPictureParameterBufferType,
253             sizeof(VAPictureParameterBufferH264),
254             1,
255             picParam,
256             &bufferIDs[bufferIDCount]);
257         CHECK_VA_STATUS("vaCreatePictureParameterBuffer");
258         bufferIDCount++;
259 
260         vaStatus = vaCreateBuffer(
261             mVADisplay,
262             mVAContext,
263             VAIQMatrixBufferType,
264             sizeof(VAIQMatrixBufferH264),
265             1,
266             data->IQ_matrix_buf,
267             &bufferIDs[bufferIDCount]);
268         CHECK_VA_STATUS("vaCreateIQMatrixBuffer");
269         bufferIDCount++;
270     }
271 
272     status = setReference(sliceParam);
273     CHECK_STATUS("setReference");
274 
275     // find which naluinfo is correlated to current slice
276     int naluIndex = 0;
277     uint32_t accumulatedHeaderLen = 0;
278     uint32_t headerLen = 0;
279     for (; naluIndex < mMetadata.naluNumber; naluIndex++)  {
280         headerLen = mMetadata.naluInfo[naluIndex].naluHeaderLen;
281         if (headerLen == 0) {
282             WTRACE("lenght of current NAL unit is 0.");
283             continue;
284         }
285         accumulatedHeaderLen += STARTCODE_PREFIX_LEN;
286         if (accumulatedHeaderLen + headerLen > sliceData->slice_offset) {
287             break;
288         }
289         accumulatedHeaderLen += headerLen;
290     }
291 
292     if (sliceData->slice_offset != accumulatedHeaderLen) {
293         WTRACE("unexpected slice offset %d, accumulatedHeaderLen = %d", sliceData->slice_offset, accumulatedHeaderLen);
294     }
295 
296     sliceParam->slice_data_size = mMetadata.naluInfo[naluIndex].naluLen;
297     sliceData->slice_size = sliceParam->slice_data_size;
298 
299     // no need to update:
300     // sliceParam->slice_data_offset - 0 always
301     // sliceParam->slice_data_bit_offset - relative to  sliceData->slice_offset
302 
303     vaStatus = vaCreateBuffer(
304         mVADisplay,
305         mVAContext,
306         VASliceParameterBufferType,
307         sizeof(VASliceParameterBufferH264),
308         1,
309         sliceParam,
310         &bufferIDs[bufferIDCount]);
311     CHECK_VA_STATUS("vaCreateSliceParameterBuffer");
312     bufferIDCount++;
313 
314     // sliceData->slice_offset - accumulatedHeaderLen is the absolute offset to start codes of current NAL unit
315     // offset points to first byte of NAL unit
316     uint32_t sliceOffset = mMetadata.naluInfo[naluIndex].naluOffset;
317     if (mInputBuffer != NULL) {
318         vaStatus = vaCreateBuffer(
319             mVADisplay,
320             mVAContext,
321             VASliceDataBufferType,
322             sliceData->slice_size, //size
323             1,        //num_elements
324             mInputBuffer  + sliceOffset,
325             &bufferIDs[bufferIDCount]);
326     } else {
327         vaStatus = vaCreateBuffer(
328             mVADisplay,
329             mVAContext,
330             VAProtectedSliceDataBufferType,
331             sliceData->slice_size, //size
332             1,        //num_elements
333             (uint8_t*)sliceOffset, // IMR offset
334             &bufferIDs[bufferIDCount]);
335     }
336     CHECK_VA_STATUS("vaCreateSliceDataBuffer");
337     bufferIDCount++;
338 
339     vaStatus = vaRenderPicture(
340         mVADisplay,
341         mVAContext,
342         bufferIDs,
343         bufferIDCount);
344     CHECK_VA_STATUS("vaRenderPicture");
345 
346     return DECODE_SUCCESS;
347 }
348 
349 
350 // Parse byte string pattern "0x000001" (3 bytes)  in the current buffer.
351 // Returns offset of position following  the pattern in the buffer if pattern is found or -1 if not found.
findNalUnitOffset(uint8_t * stream,int32_t offset,int32_t length)352 int32_t VideoDecoderAVCSecure::findNalUnitOffset(uint8_t *stream, int32_t offset, int32_t length) {
353     uint8_t *ptr;
354     uint32_t left = 0, data = 0, phase = 0;
355     uint8_t mask1 = 0, mask2 = 0;
356 
357     /* Meaning of phase:
358         0: initial status, "0x000001" bytes are not found so far;
359         1: one "0x00" byte is found;
360         2: two or more consecutive "0x00" bytes" are found;
361         3: "0x000001" patten is found ;
362         4: if there is one more byte after "0x000001";
363        */
364 
365     left = length;
366     ptr = (uint8_t *) (stream + offset);
367     phase = 0;
368 
369     // parse until there is more data and start code not found
370     while ((left > 0) && (phase < 3)) {
371         // Check if the address is 32-bit aligned & phase=0, if thats the case we can check 4 bytes instead of one byte at a time.
372         if (((((uint32_t)ptr) & 0x3) == 0) && (phase == 0)) {
373             while (left > 3) {
374                 data = *((uint32_t *)ptr);
375                 mask1 = (STARTCODE_00 != (data & STARTCODE_MASK0));
376                 mask2 = (STARTCODE_00 != (data & STARTCODE_MASK1));
377                 // If second byte and fourth byte are not zero's then we cannot have a start code here,
378                 //  as we need two consecutive zero bytes for a start code pattern.
379                 if (mask1 && mask2) {
380                     // skip 4 bytes and start over
381                     ptr += 4;
382                     left -=4;
383                     continue;
384                 } else {
385                     break;
386                 }
387             }
388         }
389 
390         // At this point either data is not on a 32-bit boundary or phase > 0 so we look at one byte at a time
391         if (left > 0) {
392             if (*ptr == STARTCODE_00) {
393                 phase++;
394                 if (phase > 2) {
395                     // more than 2 consecutive '0x00' bytes is found
396                     phase = 2;
397                 }
398             } else if ((*ptr == STARTCODE_01) && (phase == 2)) {
399                 // start code is found
400                 phase = 3;
401             } else {
402                 // reset lookup
403                 phase = 0;
404             }
405             ptr++;
406             left--;
407         }
408     }
409 
410     if ((left > 0) && (phase == 3)) {
411         phase = 4;
412         // return offset of position following the pattern in the buffer which matches "0x000001" byte string
413         return (int32_t)(ptr - stream);
414     }
415     return -1;
416 }
417 
418 
copyNaluHeader(uint8_t * stream,NaluByteStream * naluStream)419 Decode_Status VideoDecoderAVCSecure::copyNaluHeader(uint8_t *stream, NaluByteStream *naluStream) {
420     uint8_t naluType;
421     int32_t naluHeaderLen;
422 
423     naluType = *(uint8_t *)(stream + naluStream->naluOffset);
424     naluType &= NALU_TYPE_MASK;
425     // first update nalu header length based on nalu type
426     if (naluType >= NAL_UNIT_TYPE_SLICE && naluType <= NAL_UNIT_TYPE_IDR) {
427         // coded slice, return only up to MAX_SLICE_HEADER_SIZE bytes
428         naluHeaderLen = min(naluStream->naluLen, MAX_SLICE_HEADER_SIZE);
429     } else if (naluType >= NAL_UNIT_TYPE_SEI && naluType <= NAL_UNIT_TYPE_PPS) {
430         //sps, pps, sei, etc, return the entire NAL unit in clear
431         naluHeaderLen = naluStream->naluLen;
432     } else {
433         return DECODE_FRAME_DROPPED;
434     }
435 
436     memcpy(naluStream->byteStream + naluStream->streamPos, &(naluStream->naluOffset), sizeof(int32_t));
437     naluStream->streamPos += 4;
438 
439     memcpy(naluStream->byteStream + naluStream->streamPos, &(naluStream->naluLen), sizeof(int32_t));
440     naluStream->streamPos += 4;
441 
442     memcpy(naluStream->byteStream + naluStream->streamPos, &naluHeaderLen, sizeof(int32_t));
443     naluStream->streamPos += 4;
444 
445     if (naluHeaderLen) {
446         memcpy(naluStream->byteStream + naluStream->streamPos, (uint8_t*)(stream + naluStream->naluOffset), naluHeaderLen);
447         naluStream->streamPos += naluHeaderLen;
448     }
449     return DECODE_SUCCESS;
450 }
451 
452 
453 // parse start-code prefixed stream, also knowns as Annex B byte stream, commonly used in AVI, ES, MPEG2 TS container
parseAnnexBStream(uint8_t * stream,int32_t length,NaluByteStream * naluStream)454 Decode_Status VideoDecoderAVCSecure::parseAnnexBStream(uint8_t *stream, int32_t length, NaluByteStream *naluStream) {
455     int32_t naluOffset, offset, left;
456     NaluInfo *info;
457     uint32_t ret = DECODE_SUCCESS;
458 
459     naluOffset = 0;
460     offset = 0;
461     left = length;
462 
463     // leave 4 bytes to copy nalu count
464     naluStream->streamPos = 4;
465     naluStream->naluCount = 0;
466     memset(naluStream->byteStream, 0, MAX_NALU_HEADER_BUFFER);
467 
468     for (; ;) {
469         naluOffset = findNalUnitOffset(stream, offset, left);
470         if (naluOffset == -1) {
471             break;
472         }
473 
474         if (naluStream->naluCount == 0) {
475             naluStream->naluOffset = naluOffset;
476         } else {
477             naluStream->naluLen = naluOffset - naluStream->naluOffset - STARTCODE_PREFIX_LEN;
478             ret = copyNaluHeader(stream, naluStream);
479             if (ret != DECODE_SUCCESS && ret != DECODE_FRAME_DROPPED) {
480                 LOGW("copyNaluHeader returned %d", ret);
481                 return ret;
482             }
483             // starting position for next NALU
484             naluStream->naluOffset = naluOffset;
485         }
486 
487         if (ret == DECODE_SUCCESS) {
488             naluStream->naluCount++;
489         }
490 
491         // update next lookup position and length
492         offset = naluOffset + 1; // skip one byte of NAL unit type
493         left = length - offset;
494     }
495 
496     if (naluStream->naluCount > 0) {
497         naluStream->naluLen = length - naluStream->naluOffset;
498         memcpy(naluStream->byteStream, &(naluStream->naluCount), sizeof(int32_t));
499         // ignore return value, either DECODE_SUCCESS or DECODE_FRAME_DROPPED
500         copyNaluHeader(stream, naluStream);
501         return DECODE_SUCCESS;
502     }
503 
504     LOGW("number of valid NALU is 0!");
505     return DECODE_SUCCESS;
506 }
507 
508