2 Copyright (c) 2012, Broadcom Europe Ltd
5 Redistribution and use in source and binary forms, with or without
6 modification, 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.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON 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
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Implementation of an MPEG1/2 video packetizer.
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"
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)
47 static uint8_t mpgv_startcode[3] = {0x0, 0x0, 0x1};
49 #define PICTURE_CODING_TYPE_I 0x1
50 #define PICTURE_CODING_TYPE_P 0x2
51 #define PICTURE_CODING_TYPE_B 0x3
53 VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T * );
55 /*****************************************************************************/
56 typedef struct VC_PACKETIZER_MODULE_T {
73 unsigned int seen_sequence_header;
74 unsigned int seen_picture_header;
75 unsigned int seen_slice;
76 unsigned int lost_sync;
78 unsigned int picture_type;
79 unsigned int picture_temporal_ref;
85 unsigned int width, height;
86 unsigned int frame_rate_num, frame_rate_den;
87 unsigned int aspect_ratio_num, aspect_ratio_den;
90 } VC_PACKETIZER_MODULE_T;
92 /*****************************************************************************/
93 static VC_CONTAINER_STATUS_T mpgv_packetizer_close( VC_PACKETIZER_T *p_ctx )
95 free(p_ctx->priv->module);
96 return VC_CONTAINER_SUCCESS;
99 /*****************************************************************************/
100 static VC_CONTAINER_STATUS_T mpgv_packetizer_reset( VC_PACKETIZER_T *p_ctx )
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;
108 /*****************************************************************************/
109 static 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)
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} };
123 VC_CONTAINER_STATUS_T status;
124 unsigned int w, h, fr, ar;
125 int64_t ar_num, ar_den, div;
128 status = bytestream_peek_at( stream, offset, header, sizeof(header));
129 if(status != VC_CONTAINER_SUCCESS)
132 w = (header[4] << 4) | (header[5] >> 4);
133 h = ((header[5]&0x0f) << 8) | header[6];
136 if (!w || !h || !ar || !fr)
137 return VC_CONTAINER_ERROR_CORRUPTED;
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);
151 *aspect_ratio_num = ar_num;
152 *aspect_ratio_den = ar_den;
154 return VC_CONTAINER_SUCCESS;
157 /*****************************************************************************/
158 static VC_CONTAINER_STATUS_T mpgv_read_picture_header(VC_CONTAINER_BYTESTREAM_T *stream,
159 size_t offset, unsigned int *type, unsigned int *temporal_ref)
161 VC_CONTAINER_STATUS_T status;
164 status = bytestream_peek_at(stream, offset + sizeof(mpgv_startcode) + 1, h, sizeof(h));
165 if(status != VC_CONTAINER_SUCCESS)
168 *temporal_ref = (h[0] << 2) | (h[1] >> 6);
169 *type = (h[1] >> 3) & 0x7;
170 return VC_CONTAINER_SUCCESS;
173 /*****************************************************************************/
174 static VC_CONTAINER_STATUS_T mpgv_update_format( VC_PACKETIZER_T *p_ctx )
176 VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
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);
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;
191 /*****************************************************************************/
192 static VC_CONTAINER_STATUS_T mpgv_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
193 VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
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;
202 while(1) switch (module->state)
206 status = bytestream_find_startcode( stream, &offset,
207 mpgv_startcode, sizeof(mpgv_startcode) );
209 if(offset && !module->lost_sync)
210 LOG_DEBUG(0, "lost sync");
212 bytestream_skip(stream, offset);
213 module->lost_sync += offset;
215 if(status != VC_CONTAINER_SUCCESS)
216 return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
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 */
226 case STATE_UNIT_HEADER:
227 status = bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
228 if(status != VC_CONTAINER_SUCCESS)
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;
237 #if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
238 LOG_DEBUG(0, "found unit (%x)", header[3]);
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 */))
246 module->state = STATE_FRAME_DONE;
250 module->frame_size += sizeof(mpgv_startcode);
251 module->state = STATE_SYNC_NEXT;
252 /* fall through to the next state */
254 case STATE_SYNC_NEXT:
255 status = bytestream_find_startcode( stream, &module->frame_size,
256 mpgv_startcode, sizeof(mpgv_startcode) );
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)
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;
267 if(status != VC_CONTAINER_SUCCESS)
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;
276 bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
278 /* Drop everything until we've seen a sequence header */
279 if(header[3] != 0xB3 && !module->seen_sequence_header)
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;
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;
297 module->state = STATE_UNIT_OTHER;
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)
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;
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;
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;
327 case STATE_UNIT_SLICE:
328 module->seen_slice = true;
329 module->state = STATE_UNIT_HEADER;
330 module->unit_offset = module->frame_size;
333 case STATE_UNIT_GROUP:
334 case STATE_UNIT_OTHER:
335 module->state = STATE_UNIT_HEADER;
336 module->unit_offset = module->frame_size;
339 case STATE_FRAME_DONE:
340 bytestream_get_timestamps(stream, &module->pts, &module->dts, false);
342 if(module->picture_type == PICTURE_CODING_TYPE_B || module->low_delay)
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;
349 vc_container_time_set(time, module->pts);
351 module->bytes_read = 0;
352 module->state = STATE_DATA;
353 module->seen_slice = false;
354 module->seen_picture_header = false;
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);
360 /* fall through to the next state */
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;
367 if(!module->bytes_read)
369 out->pts = module->pts;
370 out->dts = module->dts;
371 out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
374 if(flags & VC_PACKETIZER_FLAG_INFO)
375 return VC_CONTAINER_SUCCESS;
377 if(flags & VC_PACKETIZER_FLAG_SKIP)
379 bytestream_skip( stream, out->size );
383 out->size = MIN(out->size, out->buffer_size);
384 bytestream_get( stream, out->data, out->size );
386 module->bytes_read += out->size;
388 if(module->bytes_read == module->frame_size)
390 vc_container_time_add(time, 1);
391 module->state = STATE_UNIT_HEADER;
392 module->frame_size = 0;
393 module->unit_offset = 0;
396 out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
398 return VC_CONTAINER_SUCCESS;
404 return VC_CONTAINER_SUCCESS;
407 /*****************************************************************************/
408 VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T *p_ctx )
410 VC_PACKETIZER_MODULE_T *module;
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;
416 p_ctx->priv->module = module = malloc(sizeof(*module));
418 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
419 memset(module, 0, sizeof(*module));
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;
430 /*****************************************************************************/
431 VC_PACKETIZER_REGISTER(mpgv_packetizer_open, "mpgv");