1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/** \file
29 * Implementation of an ISO 14496-15 to Annexe-B AVC video packetizer.
30 */
31
32#include <stdlib.h>
33#include <string.h>
34
35#include "containers/packetizers.h"
36#include "containers/core/packetizers_private.h"
37#include "containers/core/containers_common.h"
38#include "containers/core/containers_logging.h"
39#include "containers/core/containers_utils.h"
40#include "containers/core/containers_bytestream.h"
41
42#ifndef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
43//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
44#endif
45
46/** Arbitrary number which should be sufficiently high so that no sane frame will
47 * be bigger than that. */
48#define MAX_FRAME_SIZE (1920*1088*2)
49
50VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T * );
51
52/*****************************************************************************/
53typedef struct VC_PACKETIZER_MODULE_T {
54 enum {
55 STATE_FRAME_WAIT = 0,
56 STATE_BUFFER_INIT,
57 STATE_NAL_START,
58 STATE_NAL_DATA,
59 } state;
60
61 unsigned int length_size;
62
63 unsigned int frame_size;
64 unsigned int bytes_read;
65 unsigned int start_code_bytes_left;
66 unsigned int nal_bytes_left;
67
68} VC_PACKETIZER_MODULE_T;
69
70static const uint8_t h264_start_code[] = {0, 0, 0, 1};
71
72/*****************************************************************************/
73static VC_CONTAINER_STATUS_T avc1_packetizer_close( VC_PACKETIZER_T *p_ctx )
74{
75 free(p_ctx->priv->module);
76 return VC_CONTAINER_SUCCESS;
77}
78
79/*****************************************************************************/
80static VC_CONTAINER_STATUS_T avc1_packetizer_reset( VC_PACKETIZER_T *p_ctx )
81{
82 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
83 module->state = STATE_FRAME_WAIT;
84 module->frame_size = 0;
85 module->bytes_read = 0;
86 return VC_CONTAINER_SUCCESS;
87}
88
89/*****************************************************************************/
90static VC_CONTAINER_STATUS_T avc1_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
91 VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
92{
93 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
94 VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
95 VC_CONTAINER_PACKET_T *packet;
96 unsigned int offset, size, nal_num;
97 uint8_t data[4];
98 VC_CONTAINER_PARAM_UNUSED(nal_num);
99
100 while(1) switch (module->state)
101 {
102 case STATE_FRAME_WAIT:
103 for (packet = stream->current, size = 0;
104 packet && !(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END);
105 packet = packet->next)
106 size += packet->size;
107 if (!packet)
108 return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
109
110 size += packet->size;
111
112 /* We now have a complete frame available */
113
114 module->nal_bytes_left = 0;
115 module->start_code_bytes_left = 0;
116
117 /* Find out the number of NAL units and size of the frame */
118 for (offset = nal_num = 0; offset + module->length_size < size; nal_num++)
119 {
120 unsigned int nal_size;
121
122 bytestream_peek_at(stream, offset, data, module->length_size);
123 offset += module->length_size;
124
125 nal_size = data[0];
126 if (module->length_size > 1)
127 nal_size = (nal_size << 8)|data[1];
128 if (module->length_size > 2)
129 nal_size = (nal_size << 8)|data[2];
130 if (module->length_size > 3)
131 nal_size = (nal_size << 8)|data[3];
132 if (offset + nal_size > size)
133 nal_size = size - offset;
134
135 offset += nal_size;
136 module->frame_size += nal_size + sizeof(h264_start_code);
137#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
138 LOG_DEBUG(0, "nal unit size %u", nal_size);
139#endif
140 }
141 LOG_DEBUG(0, "frame size: %u(%u/%u), pts: %"PRIi64, module->frame_size,
142 size, nal_num, stream->current->pts);
143
144 /* fall through to the next state */
145 module->state = STATE_BUFFER_INIT;
146
147 case STATE_BUFFER_INIT:
148 packet = stream->current;
149 out->size = module->frame_size - module->bytes_read;
150 out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
151 out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
152
153 if (!module->bytes_read)
154 {
155 out->pts = packet->pts;
156 out->dts = packet->dts;
157 out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
158 }
159
160 if (flags & VC_PACKETIZER_FLAG_INFO)
161 return VC_CONTAINER_SUCCESS;
162
163 if (flags & VC_PACKETIZER_FLAG_SKIP)
164 {
165 /* The easiest is to just drop all the packets belonging to the frame */
166 while (!(stream->current->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END))
167 bytestream_skip_packet(stream);
168 bytestream_skip_packet(stream);
169
170 module->frame_size = 0;
171 module->bytes_read = 0;
172 return VC_CONTAINER_SUCCESS;
173 }
174
175 /* We now know that we'll have to read some data so reset the output size */
176 out->size = 0;
177
178 /* Go to the next relevant state */
179 module->state = STATE_NAL_START;
180 if (module->nal_bytes_left || module->bytes_read == module->frame_size)
181 module->state = STATE_NAL_DATA;
182 break;
183
184 case STATE_NAL_START:
185 /* Extract the size of the current NAL */
186 bytestream_get(stream, data, module->length_size);
187
188 module->nal_bytes_left = data[0];
189 if (module->length_size > 1)
190 module->nal_bytes_left = (module->nal_bytes_left << 8)|data[1];
191 if (module->length_size > 2)
192 module->nal_bytes_left = (module->nal_bytes_left << 8)|data[2];
193 if (module->length_size > 3)
194 module->nal_bytes_left = (module->nal_bytes_left << 8)|data[3];
195
196 if (module->bytes_read + module->nal_bytes_left + sizeof(h264_start_code) >
197 module->frame_size)
198 {
199 LOG_ERROR(0, "truncating nal (%u/%u)", module->nal_bytes_left,
200 module->frame_size - module->bytes_read - sizeof(h264_start_code));
201 module->nal_bytes_left = module->frame_size - sizeof(h264_start_code);
202 }
203
204#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
205 LOG_DEBUG(0, "nal unit size %u", module->nal_bytes_left);
206#endif
207
208 module->start_code_bytes_left = sizeof(h264_start_code);
209
210 /* fall through to the next state */
211 module->state = STATE_NAL_DATA;
212
213 case STATE_NAL_DATA:
214 /* Start by adding the start code */
215 if (module->start_code_bytes_left)
216 {
217 size = MIN(out->buffer_size - out->size, module->start_code_bytes_left);
218 memcpy(out->data + out->size, h264_start_code + sizeof(h264_start_code) -
219 module->start_code_bytes_left, size);
220 module->start_code_bytes_left -= size;
221 module->bytes_read += size;
222 out->size += size;
223 }
224
225 /* Then append the NAL unit itself */
226 if (module->nal_bytes_left)
227 {
228 size = MIN(out->buffer_size - out->size, module->nal_bytes_left);
229 bytestream_get( stream, out->data + out->size, size );
230 module->nal_bytes_left -= size;
231 module->bytes_read += size;
232 out->size += size;
233 }
234
235 /* Check whether we're done */
236 if (module->bytes_read == module->frame_size)
237 {
238 bytestream_skip_packet(stream);
239 module->state = STATE_FRAME_WAIT;
240 module->frame_size = 0;
241 module->bytes_read = 0;
242 return VC_CONTAINER_SUCCESS;
243 }
244 else if (out->buffer_size == out->size)
245 {
246 out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
247 module->state = STATE_BUFFER_INIT;
248 return VC_CONTAINER_SUCCESS;
249 }
250
251 /* We're not done, go to the next relevant state */
252 module->state = STATE_NAL_START;
253 break;
254
255 default:
256 break;
257 };
258
259 return VC_CONTAINER_SUCCESS;
260}
261
262/*****************************************************************************/
263static VC_CONTAINER_STATUS_T avc1_packetizer_codecconfig( VC_PACKETIZER_T *p_ctx )
264{
265 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
266 VC_CONTAINER_STATUS_T status;
267 uint8_t *out, *extra = p_ctx->in->extradata + 5;
268 uint8_t *extra_end = extra + p_ctx->in->extradata_size - 5;
269 unsigned int i, j, nal_size, out_size = 0;
270
271 if (p_ctx->in->extradata_size <= 5 ||
272 p_ctx->in->extradata[0] != 1 /* configurationVersion */)
273 return VC_CONTAINER_ERROR_FORMAT_INVALID;
274
275 status = vc_container_format_extradata_alloc(p_ctx->out, p_ctx->in->extradata_size);
276 if (status != VC_CONTAINER_SUCCESS)
277 return status;
278
279 out = p_ctx->out->extradata;
280 module->length_size = (*(p_ctx->in->extradata + 4) & 0x3) + 1;
281
282 for (i = 0; i < 2 && extra < extra_end - 1; i++)
283 {
284 j = *(extra++) & (!i ? 0x1F : 0xFF);
285 for (; j > 0 && extra < extra_end - 2; j--)
286 {
287 nal_size = (extra[0] << 8) | extra[1]; extra += 2;
288 if (extra + nal_size > extra_end)
289 {
290 extra = extra_end;
291 break;
292 }
293
294 out[0] = out[1] = out[2] = 0; out[3] = 1;
295 memcpy(out + 4, extra, nal_size);
296 out += nal_size + 4; extra += nal_size;
297 out_size += nal_size + 4;
298 }
299 }
300
301 p_ctx->out->extradata_size = out_size;
302 return VC_CONTAINER_SUCCESS;
303}
304
305/*****************************************************************************/
306VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T *p_ctx )
307{
308 VC_PACKETIZER_MODULE_T *module;
309 VC_CONTAINER_STATUS_T status;
310
311 if(p_ctx->in->codec != VC_CONTAINER_CODEC_H264 &&
312 p_ctx->out->codec != VC_CONTAINER_CODEC_H264)
313 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
314 if(p_ctx->in->codec_variant != VC_CONTAINER_VARIANT_H264_AVC1 &&
315 p_ctx->out->codec_variant != VC_CONTAINER_VARIANT_H264_DEFAULT)
316 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
317 if(!(p_ctx->in->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
318 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
319
320 p_ctx->priv->module = module = malloc(sizeof(*module));
321 if(!module)
322 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
323 memset(module, 0, sizeof(*module));
324
325 vc_container_format_copy(p_ctx->out, p_ctx->in, 0);
326 status = avc1_packetizer_codecconfig(p_ctx);
327 if (status != VC_CONTAINER_SUCCESS)
328 {
329 free(module);
330 return status;
331 }
332
333 p_ctx->out->codec_variant = VC_CONTAINER_VARIANT_H264_DEFAULT;
334 p_ctx->max_frame_size = MAX_FRAME_SIZE;
335 p_ctx->priv->pf_close = avc1_packetizer_close;
336 p_ctx->priv->pf_packetize = avc1_packetizer_packetize;
337 p_ctx->priv->pf_reset = avc1_packetizer_reset;
338 LOG_DEBUG(0, "using avc1 video packetizer");
339 return VC_CONTAINER_SUCCESS;
340}
341
342/*****************************************************************************/
343VC_PACKETIZER_REGISTER(avc1_packetizer_open, "avc1");
344