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 MPEG1/2 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_time.h"
40#include "containers/core/containers_utils.h"
41#include "containers/core/containers_bytestream.h"
42
43/** Arbitrary number which should be sufficiently high so that no sane frame will
44 * be bigger than that. */
45#define MAX_FRAME_SIZE (1920*1088*2)
46
47static uint8_t mpgv_startcode[3] = {0x0, 0x0, 0x1};
48
49#define PICTURE_CODING_TYPE_I 0x1
50#define PICTURE_CODING_TYPE_P 0x2
51#define PICTURE_CODING_TYPE_B 0x3
52
53VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T * );
54
55/*****************************************************************************/
56typedef struct VC_PACKETIZER_MODULE_T {
57 enum {
58 STATE_SYNC = 0,
59 STATE_SYNC_NEXT,
60 STATE_FRAME_DONE,
61 STATE_UNIT_HEADER,
62 STATE_UNIT_SEQUENCE,
63 STATE_UNIT_GROUP,
64 STATE_UNIT_PICTURE,
65 STATE_UNIT_SLICE,
66 STATE_UNIT_OTHER,
67 STATE_DATA,
68 } state;
69
70 size_t frame_size;
71 size_t unit_offset;
72
73 unsigned int seen_sequence_header;
74 unsigned int seen_picture_header;
75 unsigned int seen_slice;
76 unsigned int lost_sync;
77
78 unsigned int picture_type;
79 unsigned int picture_temporal_ref;
80 int64_t pts;
81 int64_t dts;
82
83 uint32_t bytes_read;
84
85 unsigned int width, height;
86 unsigned int frame_rate_num, frame_rate_den;
87 unsigned int aspect_ratio_num, aspect_ratio_den;
88 bool low_delay;
89
90} VC_PACKETIZER_MODULE_T;
91
92/*****************************************************************************/
93static VC_CONTAINER_STATUS_T mpgv_packetizer_close( VC_PACKETIZER_T *p_ctx )
94{
95 free(p_ctx->priv->module);
96 return VC_CONTAINER_SUCCESS;
97}
98
99/*****************************************************************************/
100static VC_CONTAINER_STATUS_T mpgv_packetizer_reset( VC_PACKETIZER_T *p_ctx )
101{
102 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
103 module->lost_sync = 0;
104 module->state = STATE_SYNC;
105 return VC_CONTAINER_SUCCESS;
106}
107
108/*****************************************************************************/
109static VC_CONTAINER_STATUS_T mpgv_read_sequence_header(VC_CONTAINER_BYTESTREAM_T *stream,
110 size_t offset, unsigned int *width, unsigned int *height,
111 unsigned int *frame_rate_num, unsigned int *frame_rate_den,
112 unsigned int *aspect_ratio_num, unsigned int *aspect_ratio_den)
113{
114 static const int frame_rate[16][2] =
115 { {0, 0}, {24000, 1001}, {24, 1}, {25, 1}, {30000, 1001}, {30, 1}, {50, 1},
116 {60000, 1001}, {60, 1},
117 /* Unofficial values */
118 {15, 1001}, /* From Xing */
119 {5, 1001}, {10, 1001}, {12, 1001}, {15, 1001} /* From libmpeg3 */ };
120 static const int aspect_ratio[16][2] =
121 { {0, 0}, {1, 1}, {4, 3}, {16, 9}, {221, 100} };
122
123 VC_CONTAINER_STATUS_T status;
124 unsigned int w, h, fr, ar;
125 int64_t ar_num, ar_den, div;
126 uint8_t header[8];
127
128 status = bytestream_peek_at( stream, offset, header, sizeof(header));
129 if(status != VC_CONTAINER_SUCCESS)
130 return status;
131
132 w = (header[4] << 4) | (header[5] >> 4);
133 h = ((header[5]&0x0f) << 8) | header[6];
134 ar = header[7] >> 4;
135 fr = header[7]&0x0f;
136 if (!w || !h || !ar || !fr)
137 return VC_CONTAINER_ERROR_CORRUPTED;
138
139 *width = w;
140 *height = h;
141 *frame_rate_num = frame_rate[fr][0];
142 *frame_rate_den = frame_rate[fr][1];
143 ar_num = (int64_t)aspect_ratio[ar][0] * h;
144 ar_den = (int64_t)aspect_ratio[ar][1] * w;
145 div = vc_container_maths_gcd(ar_num, ar_den);
146 if (div)
147 {
148 ar_num /= div;
149 ar_den /= div;
150 }
151 *aspect_ratio_num = ar_num;
152 *aspect_ratio_den = ar_den;
153
154 return VC_CONTAINER_SUCCESS;
155}
156
157/*****************************************************************************/
158static VC_CONTAINER_STATUS_T mpgv_read_picture_header(VC_CONTAINER_BYTESTREAM_T *stream,
159 size_t offset, unsigned int *type, unsigned int *temporal_ref)
160{
161 VC_CONTAINER_STATUS_T status;
162 uint8_t h[2];
163
164 status = bytestream_peek_at(stream, offset + sizeof(mpgv_startcode) + 1, h, sizeof(h));
165 if(status != VC_CONTAINER_SUCCESS)
166 return status;
167
168 *temporal_ref = (h[0] << 2) | (h[1] >> 6);
169 *type = (h[1] >> 3) & 0x7;
170 return VC_CONTAINER_SUCCESS;
171}
172
173/*****************************************************************************/
174static VC_CONTAINER_STATUS_T mpgv_update_format( VC_PACKETIZER_T *p_ctx )
175{
176 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
177
178 LOG_DEBUG(0, "mpgv format: width %i, height %i, rate %i/%i, ar %i/%i",
179 module->width, module->height, module->frame_rate_num, module->frame_rate_den,
180 module->aspect_ratio_num, module->aspect_ratio_den);
181
182 p_ctx->out->type->video.width = p_ctx->out->type->video.visible_width = module->width;
183 p_ctx->out->type->video.height = p_ctx->out->type->video.visible_height = module->height;
184 p_ctx->out->type->video.par_num = module->aspect_ratio_num;
185 p_ctx->out->type->video.par_den = module->aspect_ratio_den;
186 p_ctx->out->type->video.frame_rate_num = module->frame_rate_num;
187 p_ctx->out->type->video.frame_rate_den = module->frame_rate_den;
188 return VC_CONTAINER_SUCCESS;
189}
190
191/*****************************************************************************/
192static VC_CONTAINER_STATUS_T mpgv_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
193 VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
194{
195 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
196 VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
197 VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
198 VC_CONTAINER_STATUS_T status;
199 uint8_t header[4];
200 size_t offset;
201
202 while(1) switch (module->state)
203 {
204 case STATE_SYNC:
205 offset = 0;
206 status = bytestream_find_startcode( stream, &offset,
207 mpgv_startcode, sizeof(mpgv_startcode) );
208
209 if(offset && !module->lost_sync)
210 LOG_DEBUG(0, "lost sync");
211
212 bytestream_skip(stream, offset);
213 module->lost_sync += offset;
214
215 if(status != VC_CONTAINER_SUCCESS)
216 return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
217
218 if(module->lost_sync)
219 LOG_DEBUG(0, "recovered sync after %i bytes", module->lost_sync);
220 module->lost_sync = 0;
221 module->state = STATE_UNIT_HEADER;
222 module->frame_size = 0;
223 module->unit_offset = 0;
224 /* fall through to the next state */
225
226 case STATE_UNIT_HEADER:
227 status = bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
228 if(status != VC_CONTAINER_SUCCESS)
229 {
230 if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
231 !module->seen_picture_header || !module->seen_slice)
232 return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
233 module->state = STATE_FRAME_DONE;
234 break;
235 }
236
237#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
238 LOG_DEBUG(0, "found unit (%x)", header[3]);
239#endif
240
241 /* Detect start of new frame */
242 if(module->seen_picture_header && module->seen_slice &&
243 (header[3] == 0x00 /* A picture header */ ||
244 (header[3] > 0xAF && header[3] != 0xB7) /* Not a slice or sequence end */))
245 {
246 module->state = STATE_FRAME_DONE;
247 break;
248 }
249
250 module->frame_size += sizeof(mpgv_startcode);
251 module->state = STATE_SYNC_NEXT;
252 /* fall through to the next state */
253
254 case STATE_SYNC_NEXT:
255 status = bytestream_find_startcode( stream, &module->frame_size,
256 mpgv_startcode, sizeof(mpgv_startcode) );
257
258 /* Sanity check the size of frames. This makes sure we don't endlessly accumulate data
259 * to make up a new frame. */
260 if(module->frame_size > p_ctx->max_frame_size)
261 {
262 LOG_ERROR(0, "frame too big (%i/%i), dropping", module->frame_size, p_ctx->max_frame_size);
263 bytestream_skip(stream, module->frame_size);
264 module->state = STATE_SYNC;
265 break;
266 }
267 if(status != VC_CONTAINER_SUCCESS)
268 {
269 if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
270 !module->seen_picture_header || !module->seen_slice)
271 return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
272 module->state = STATE_FRAME_DONE;
273 break;
274 }
275
276 bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
277
278 /* Drop everything until we've seen a sequence header */
279 if(header[3] != 0xB3 && !module->seen_sequence_header)
280 {
281 LOG_DEBUG(0, "waiting for sequence header, dropping %i bytes", module->frame_size);
282 module->state = STATE_UNIT_HEADER;
283 bytestream_skip(stream, module->frame_size);
284 module->unit_offset = module->frame_size = 0;
285 break;
286 }
287
288 if(header[3] == 0x00)
289 module->state = STATE_UNIT_PICTURE;
290 else if(header[3] >= 0x01 && header[3] <= 0xAF)
291 module->state = STATE_UNIT_SLICE;
292 else if(header[3] == 0xB3)
293 module->state = STATE_UNIT_SEQUENCE;
294 else if(header[3] == 0xB8)
295 module->state = STATE_UNIT_GROUP;
296 else
297 module->state = STATE_UNIT_OTHER;
298 break;
299
300 case STATE_UNIT_SEQUENCE:
301 status = mpgv_read_sequence_header(stream, module->unit_offset, &module->width, &module->height,
302 &module->frame_rate_num, &module->frame_rate_den, &module->aspect_ratio_num, &module->aspect_ratio_den);
303 if(status != VC_CONTAINER_SUCCESS && !module->seen_sequence_header)
304 {
305 /* We need a sequence header so drop everything until we see one */
306 LOG_DEBUG(0, "invalid first sequence header, dropping %i bytes", module->frame_size);
307 bytestream_skip(stream, module->frame_size);
308 module->state = STATE_SYNC;
309 break;
310 }
311 mpgv_update_format(p_ctx);
312 module->seen_sequence_header = true;
313 vc_container_time_set_samplerate(time, module->frame_rate_num, module->frame_rate_den);
314 module->state = STATE_UNIT_HEADER;
315 module->unit_offset = module->frame_size;
316 break;
317
318 case STATE_UNIT_PICTURE:
319 status = mpgv_read_picture_header(stream, module->unit_offset, &module->picture_type, &module->picture_temporal_ref);
320 if(status != VC_CONTAINER_SUCCESS)
321 return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
322 module->seen_picture_header = true;
323 module->state = STATE_UNIT_HEADER;
324 module->unit_offset = module->frame_size;
325 break;
326
327 case STATE_UNIT_SLICE:
328 module->seen_slice = true;
329 module->state = STATE_UNIT_HEADER;
330 module->unit_offset = module->frame_size;
331 break;
332
333 case STATE_UNIT_GROUP:
334 case STATE_UNIT_OTHER:
335 module->state = STATE_UNIT_HEADER;
336 module->unit_offset = module->frame_size;
337 break;
338
339 case STATE_FRAME_DONE:
340 bytestream_get_timestamps(stream, &module->pts, &module->dts, false);
341
342 if(module->picture_type == PICTURE_CODING_TYPE_B || module->low_delay)
343 {
344 if(module->pts == VC_CONTAINER_TIME_UNKNOWN)
345 module->pts = module->dts;
346 if(module->dts == VC_CONTAINER_TIME_UNKNOWN)
347 module->dts = module->pts;
348 }
349 vc_container_time_set(time, module->pts);
350
351 module->bytes_read = 0;
352 module->state = STATE_DATA;
353 module->seen_slice = false;
354 module->seen_picture_header = false;
355
356#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
357 LOG_DEBUG(0, "new frame, type %x, size %i, temp_ref %i)", module->picture_type,
358 module->frame_size, module->picture_temporal_ref);
359#endif
360 /* fall through to the next state */
361
362 case STATE_DATA:
363 out->size = module->frame_size - module->bytes_read;
364 out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
365 out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
366
367 if(!module->bytes_read)
368 {
369 out->pts = module->pts;
370 out->dts = module->dts;
371 out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
372 }
373
374 if(flags & VC_PACKETIZER_FLAG_INFO)
375 return VC_CONTAINER_SUCCESS;
376
377 if(flags & VC_PACKETIZER_FLAG_SKIP)
378 {
379 bytestream_skip( stream, out->size );
380 }
381 else
382 {
383 out->size = MIN(out->size, out->buffer_size);
384 bytestream_get( stream, out->data, out->size );
385 }
386 module->bytes_read += out->size;
387
388 if(module->bytes_read == module->frame_size)
389 {
390 vc_container_time_add(time, 1);
391 module->state = STATE_UNIT_HEADER;
392 module->frame_size = 0;
393 module->unit_offset = 0;
394 }
395 else
396 out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
397
398 return VC_CONTAINER_SUCCESS;
399
400 default:
401 break;
402 };
403
404 return VC_CONTAINER_SUCCESS;
405}
406
407/*****************************************************************************/
408VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T *p_ctx )
409{
410 VC_PACKETIZER_MODULE_T *module;
411
412 if(p_ctx->in->codec != VC_CONTAINER_CODEC_MP1V &&
413 p_ctx->in->codec != VC_CONTAINER_CODEC_MP2V)
414 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
415
416 p_ctx->priv->module = module = malloc(sizeof(*module));
417 if(!module)
418 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
419 memset(module, 0, sizeof(*module));
420
421 vc_container_format_copy( p_ctx->out, p_ctx->in, 0);
422 p_ctx->max_frame_size = MAX_FRAME_SIZE;
423 p_ctx->priv->pf_close = mpgv_packetizer_close;
424 p_ctx->priv->pf_packetize = mpgv_packetizer_packetize;
425 p_ctx->priv->pf_reset = mpgv_packetizer_reset;
426 LOG_DEBUG(0, "using mpeg video packetizer");
427 return VC_CONTAINER_SUCCESS;
428}
429
430/*****************************************************************************/
431VC_PACKETIZER_REGISTER(mpgv_packetizer_open, "mpgv");
432