1 /*
2  * Copyright (C) 2009 The Android Open Source Project
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 /*------------------------------------------------------------------------------
18 
19     Table of contents
20 
21      1. Include headers
22      2. External compiler flags
23      3. Module defines
24      4. Local function prototypes
25      5. Functions
26           ExtractNalUnit
27 
28 ------------------------------------------------------------------------------*/
29 
30 /*------------------------------------------------------------------------------
31     1. Include headers
32 ------------------------------------------------------------------------------*/
33 
34 #include "h264bsd_byte_stream.h"
35 #include "h264bsd_util.h"
36 
37 /*------------------------------------------------------------------------------
38     2. External compiler flags
39 --------------------------------------------------------------------------------
40 
41 --------------------------------------------------------------------------------
42     3. Module defines
43 ------------------------------------------------------------------------------*/
44 
45 #define BYTE_STREAM_ERROR  0xFFFFFFFF
46 
47 /*------------------------------------------------------------------------------
48     4. Local function prototypes
49 ------------------------------------------------------------------------------*/
50 
51 /*------------------------------------------------------------------------------
52 
53     Function name: ExtractNalUnit
54 
55         Functional description:
56             Extracts one NAL unit from the byte stream buffer. Removes
57             emulation prevention bytes if present. The original stream buffer
58             is used directly and is therefore modified if emulation prevention
59             bytes are present in the stream.
60 
61             Stream buffer is assumed to contain either exactly one NAL unit
62             and nothing else, or one or more NAL units embedded in byte
63             stream format described in the Annex B of the standard. Function
64             detects which one is used based on the first bytes in the buffer.
65 
66         Inputs:
67             pByteStream     pointer to byte stream buffer
68             len             length of the stream buffer (in bytes)
69 
70         Outputs:
71             pStrmData       stream information is stored here
72             readBytes       number of bytes "consumed" from the stream buffer
73 
74         Returns:
75             HANTRO_OK       success
76             HANTRO_NOK      error in byte stream
77 
78 ------------------------------------------------------------------------------*/
79 
h264bsdExtractNalUnit(u8 * pByteStream,u32 len,strmData_t * pStrmData,u32 * readBytes)80 u32 h264bsdExtractNalUnit(u8 *pByteStream, u32 len, strmData_t *pStrmData,
81     u32 *readBytes)
82 {
83 
84 /* Variables */
85 
86     u32 i, tmp;
87     u32 byteCount,initByteCount;
88     u32 zeroCount;
89     u8  byte;
90     u32 hasEmulation = HANTRO_FALSE;
91     u32 invalidStream = HANTRO_FALSE;
92     u8 *readPtr, *writePtr;
93 
94 /* Code */
95 
96     ASSERT(pByteStream);
97     ASSERT(len);
98     ASSERT(len < BYTE_STREAM_ERROR);
99     ASSERT(pStrmData);
100 
101     /* byte stream format if starts with 0x000001 or 0x000000 */
102     if (len > 3 && pByteStream[0] == 0x00 && pByteStream[1] == 0x00 &&
103         (pByteStream[2]&0xFE) == 0x00)
104     {
105         /* search for NAL unit start point, i.e. point after first start code
106          * prefix in the stream */
107         zeroCount = byteCount = 2;
108         readPtr = pByteStream + 2;
109         /*lint -e(716) while(1) used consciously */
110         while (1)
111         {
112             byte = *readPtr++;
113             byteCount++;
114 
115             if (byteCount == len)
116             {
117                 /* no start code prefix found -> error */
118                 *readBytes = len;
119                 return(HANTRO_NOK);
120             }
121 
122             if (!byte)
123                 zeroCount++;
124             else if ((byte == 0x01) && (zeroCount >= 2))
125                 break;
126             else
127                 zeroCount = 0;
128         }
129 
130         initByteCount = byteCount;
131 
132         /* determine size of the NAL unit. Search for next start code prefix
133          * or end of stream and ignore possible trailing zero bytes */
134         zeroCount = 0;
135         /*lint -e(716) while(1) used consciously */
136         while (1)
137         {
138             byte = *readPtr++;
139             byteCount++;
140             if (!byte)
141                 zeroCount++;
142 
143             if ( (byte == 0x03) && (zeroCount == 2) )
144             {
145                 hasEmulation = HANTRO_TRUE;
146             }
147 
148             if ( (byte == 0x01) && (zeroCount >= 2 ) )
149             {
150                 pStrmData->strmBuffSize =
151                     byteCount - initByteCount - zeroCount - 1;
152                 zeroCount -= MIN(zeroCount, 3);
153                 break;
154             }
155             else if (byte)
156             {
157                 if (zeroCount >= 3)
158                     invalidStream = HANTRO_TRUE;
159                 zeroCount = 0;
160             }
161 
162             if (byteCount == len)
163             {
164                 pStrmData->strmBuffSize = byteCount - initByteCount - zeroCount;
165                 break;
166             }
167 
168         }
169     }
170     /* separate NAL units as input -> just set stream params */
171     else
172     {
173         initByteCount = 0;
174         zeroCount = 0;
175         pStrmData->strmBuffSize = len;
176         hasEmulation = HANTRO_TRUE;
177     }
178 
179     pStrmData->pStrmBuffStart    = pByteStream + initByteCount;
180     pStrmData->pStrmCurrPos      = pStrmData->pStrmBuffStart;
181     pStrmData->bitPosInWord      = 0;
182     pStrmData->strmBuffReadBits  = 0;
183 
184     /* return number of bytes "consumed" */
185     *readBytes = pStrmData->strmBuffSize + initByteCount + zeroCount;
186 
187     if (invalidStream)
188     {
189         return(HANTRO_NOK);
190     }
191 
192     /* remove emulation prevention bytes before rbsp processing */
193     if (hasEmulation)
194     {
195         tmp = pStrmData->strmBuffSize;
196         readPtr = writePtr = pStrmData->pStrmBuffStart;
197         zeroCount = 0;
198         for (i = tmp; i--;)
199         {
200             if ((zeroCount == 2) && (*readPtr == 0x03))
201             {
202                 /* emulation prevention byte shall be followed by one of the
203                  * following bytes: 0x00, 0x01, 0x02, 0x03. This implies that
204                  * emulation prevention 0x03 byte shall not be the last byte
205                  * of the stream. */
206                 if ( (i == 0) || (*(readPtr+1) > 0x03) )
207                     return(HANTRO_NOK);
208 
209                 /* do not write emulation prevention byte */
210                 readPtr++;
211                 zeroCount = 0;
212             }
213             else
214             {
215                 /* NAL unit shall not contain byte sequences 0x000000,
216                  * 0x000001 or 0x000002 */
217                 if ( (zeroCount == 2) && (*readPtr <= 0x02) )
218                     return(HANTRO_NOK);
219 
220                 if (*readPtr == 0)
221                     zeroCount++;
222                 else
223                     zeroCount = 0;
224 
225                 *writePtr++ = *readPtr++;
226             }
227         }
228 
229         /* (readPtr - writePtr) indicates number of "removed" emulation
230          * prevention bytes -> subtract from stream buffer size */
231         pStrmData->strmBuffSize -= (u32)(readPtr - writePtr);
232     }
233 
234     return(HANTRO_OK);
235 
236 }
237 
238