1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
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. |
15 | |
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. |
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 | |
47 | static 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 | |
53 | VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T * ); |
54 | |
55 | /*****************************************************************************/ |
56 | typedef struct VC_PACKETIZER_MODULE_T { |
57 | enum { |
58 | STATE_SYNC = 0, |
59 | STATE_SYNC_NEXT, |
60 | STATE_FRAME_DONE, |
61 | , |
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 ; |
74 | unsigned int ; |
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 | /*****************************************************************************/ |
93 | static 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 | /*****************************************************************************/ |
100 | static 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 | /*****************************************************************************/ |
109 | static VC_CONTAINER_STATUS_T (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 [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 | /*****************************************************************************/ |
158 | static VC_CONTAINER_STATUS_T (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 | /*****************************************************************************/ |
174 | static 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 | /*****************************************************************************/ |
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) |
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 [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 | /*****************************************************************************/ |
408 | VC_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 | /*****************************************************************************/ |
431 | VC_PACKETIZER_REGISTER(mpgv_packetizer_open, "mpgv" ); |
432 | |