/src/vlc/modules/packetizer/mpeg4video.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * mpeg4video.c: mpeg 4 video packetizer |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2001-2006 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Gildas Bazin <gbazin@videolan.org> |
7 | | * Laurent Aimar <fenrir@via.ecp.fr> |
8 | | * Eric Petit <titer@videolan.org> |
9 | | * |
10 | | * This program is free software; you can redistribute it and/or modify it |
11 | | * under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2.1 of the License, or |
13 | | * (at your option) any later version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public License |
21 | | * along with this program; if not, write to the Free Software Foundation, |
22 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
23 | | *****************************************************************************/ |
24 | | |
25 | | /***************************************************************************** |
26 | | * Preamble |
27 | | *****************************************************************************/ |
28 | | |
29 | | #ifdef HAVE_CONFIG_H |
30 | | # include "config.h" |
31 | | #endif |
32 | | |
33 | | #include <vlc_common.h> |
34 | | #include <vlc_plugin.h> |
35 | | #include <vlc_sout.h> |
36 | | #include <vlc_codec.h> |
37 | | #include <vlc_block.h> |
38 | | |
39 | | #include <vlc_bits.h> |
40 | | #include <vlc_block_helper.h> |
41 | | #include "packetizer_helper.h" |
42 | | #include "startcode_helper.h" |
43 | | #include "h26x_nal_common.h" |
44 | | |
45 | | /***************************************************************************** |
46 | | * Module descriptor |
47 | | *****************************************************************************/ |
48 | | static int Open ( vlc_object_t * ); |
49 | | static void Close( vlc_object_t * ); |
50 | | |
51 | 104 | vlc_module_begin () |
52 | 52 | set_subcategory( SUBCAT_SOUT_PACKETIZER ) |
53 | 52 | set_description( N_("MPEG4 video packetizer") ) |
54 | 52 | set_capability( "video packetizer", 50 ) |
55 | 104 | set_callbacks( Open, Close ) |
56 | 52 | vlc_module_end () |
57 | | |
58 | | /**************************************************************************** |
59 | | * Local prototypes |
60 | | ****************************************************************************/ |
61 | | typedef struct |
62 | | { |
63 | | /* |
64 | | * Input properties |
65 | | */ |
66 | | packetizer_t packetizer; |
67 | | |
68 | | /* |
69 | | * Common properties |
70 | | */ |
71 | | vlc_tick_t i_interpolated_pts; |
72 | | vlc_tick_t i_interpolated_dts; |
73 | | vlc_tick_t i_last_ref_pts; |
74 | | int64_t i_last_time_ref; |
75 | | int64_t i_time_ref; |
76 | | int64_t i_last_time; |
77 | | int64_t i_last_timeincr; |
78 | | |
79 | | unsigned int i_flags; |
80 | | |
81 | | int i_fps_num; |
82 | | int i_fps_den; |
83 | | |
84 | | bool b_frame; |
85 | | |
86 | | /* Current frame being built */ |
87 | | block_t *p_frame; |
88 | | block_t **pp_last; |
89 | | } decoder_sys_t; |
90 | | |
91 | | static block_t *Packetize( decoder_t *, block_t ** ); |
92 | | static void PacketizeFlush( decoder_t * ); |
93 | | |
94 | | static void PacketizeReset( void *p_private, bool b_broken ); |
95 | | static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * ); |
96 | | static int PacketizeValidate( void *p_private, block_t * ); |
97 | | |
98 | | static block_t *ParseMPEGBlock( decoder_t *, block_t * ); |
99 | | static int ParseVOL( decoder_t *, es_format_t *, uint8_t *, int ); |
100 | | static int ParseVO( decoder_t *, block_t * ); |
101 | | static int ParseVOP( decoder_t *, block_t * ); |
102 | | static int vlc_log2( unsigned int ); |
103 | | |
104 | | #define VIDEO_OBJECT_MASK 0x01f |
105 | | #define VIDEO_OBJECT_LAYER_MASK 0x00f |
106 | | |
107 | | #define VIDEO_OBJECT_START_CODE 0x100 |
108 | 93.6k | #define VIDEO_OBJECT_LAYER_START_CODE 0x120 |
109 | 34.3k | #define RESERVED_START_CODE 0x130 |
110 | 0 | #define VISUAL_OBJECT_SEQUENCE_START_CODE 0x1b0 |
111 | 0 | #define VISUAL_OBJECT_SEQUENCE_END_CODE 0x1b1 |
112 | 0 | #define USER_DATA_START_CODE 0x1b2 |
113 | | #define GROUP_OF_VOP_START_CODE 0x1b3 |
114 | | #define VIDEO_SESSION_ERROR_CODE 0x1b4 |
115 | 0 | #define VISUAL_OBJECT_START_CODE 0x1b5 |
116 | 0 | #define VOP_START_CODE 0x1b6 |
117 | | #define FACE_OBJECT_START_CODE 0x1ba |
118 | | #define FACE_OBJECT_PLANE_START_CODE 0x1bb |
119 | | #define MESH_OBJECT_START_CODE 0x1bc |
120 | | #define MESH_OBJECT_PLANE_START_CODE 0x1bd |
121 | | #define STILL_TEXTURE_OBJECT_START_CODE 0x1be |
122 | | #define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf |
123 | | #define TEXTURE_SNR_LAYER_START_CODE 0x1c0 |
124 | | |
125 | | static const uint8_t p_mp4v_startcode[3] = { 0x00, 0x00, 0x01 }; |
126 | | |
127 | | /***************************************************************************** |
128 | | * Open: probe the packetizer and return score |
129 | | *****************************************************************************/ |
130 | | static int Open( vlc_object_t *p_this ) |
131 | 28.4k | { |
132 | 28.4k | decoder_t *p_dec = (decoder_t*)p_this; |
133 | 28.4k | decoder_sys_t *p_sys; |
134 | | |
135 | 28.4k | if( p_dec->fmt_in->i_codec != VLC_CODEC_MP4V ) |
136 | 27.5k | return VLC_EGENERIC; |
137 | | |
138 | | /* Allocate the memory needed to store the decoder's structure */ |
139 | 856 | if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) |
140 | 0 | return VLC_ENOMEM; |
141 | 856 | memset( p_sys, 0, sizeof(decoder_sys_t) ); |
142 | | |
143 | | /* Misc init */ |
144 | 856 | packetizer_Init( &p_sys->packetizer, |
145 | 856 | p_mp4v_startcode, sizeof(p_mp4v_startcode), startcode_FindAnnexB, |
146 | 856 | NULL, 0, 4, |
147 | 856 | PacketizeReset, PacketizeParse, PacketizeValidate, NULL, |
148 | 856 | p_dec ); |
149 | | |
150 | 856 | p_sys->p_frame = NULL; |
151 | 856 | p_sys->pp_last = &p_sys->p_frame; |
152 | | |
153 | | /* Setup properties */ |
154 | 856 | es_format_Copy( &p_dec->fmt_out, p_dec->fmt_in ); |
155 | 856 | p_dec->fmt_out.i_codec = VLC_CODEC_MP4V; |
156 | | |
157 | 856 | if( p_dec->fmt_out.i_extra ) |
158 | 610 | { |
159 | | /* We have a vol */ |
160 | 610 | msg_Dbg( p_dec, "opening with vol size: %zu", p_dec->fmt_out.i_extra ); |
161 | 610 | ParseVOL( p_dec, &p_dec->fmt_out, |
162 | 610 | p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); |
163 | 610 | } |
164 | | |
165 | | /* Set callback */ |
166 | 856 | p_dec->pf_packetize = Packetize; |
167 | 856 | p_dec->pf_flush = PacketizeFlush; |
168 | 856 | p_dec->pf_get_cc = NULL; |
169 | | |
170 | 856 | return VLC_SUCCESS; |
171 | 856 | } |
172 | | |
173 | | /***************************************************************************** |
174 | | * Close: clean up the packetizer |
175 | | *****************************************************************************/ |
176 | | static void Close( vlc_object_t *p_this ) |
177 | 856 | { |
178 | 856 | decoder_t *p_dec = (decoder_t*)p_this; |
179 | 856 | decoder_sys_t *p_sys = p_dec->p_sys; |
180 | | |
181 | 856 | packetizer_Clean( &p_sys->packetizer ); |
182 | 856 | if( p_sys->p_frame ) |
183 | 0 | block_ChainRelease( p_sys->p_frame ); |
184 | 856 | free( p_sys ); |
185 | 856 | } |
186 | | |
187 | | /**************************************************************************** |
188 | | * Packetize: the whole thing |
189 | | ****************************************************************************/ |
190 | | static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) |
191 | 0 | { |
192 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
193 | |
|
194 | 0 | return packetizer_Packetize( &p_sys->packetizer, pp_block ); |
195 | 0 | } |
196 | | |
197 | | static void PacketizeFlush( decoder_t *p_dec ) |
198 | 0 | { |
199 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
200 | |
|
201 | 0 | packetizer_Flush( &p_sys->packetizer ); |
202 | 0 | } |
203 | | |
204 | | /***************************************************************************** |
205 | | * Helpers: |
206 | | *****************************************************************************/ |
207 | | static void PacketizeReset( void *p_private, bool b_flush ) |
208 | 0 | { |
209 | 0 | decoder_t *p_dec = p_private; |
210 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
211 | |
|
212 | 0 | if( b_flush ) |
213 | 0 | { |
214 | 0 | if( p_sys->p_frame ) |
215 | 0 | block_ChainRelease( p_sys->p_frame ); |
216 | 0 | p_sys->p_frame = NULL; |
217 | 0 | p_sys->pp_last = &p_sys->p_frame; |
218 | 0 | } |
219 | |
|
220 | 0 | p_sys->i_interpolated_pts = |
221 | 0 | p_sys->i_interpolated_dts = |
222 | 0 | p_sys->i_last_ref_pts = VLC_TICK_INVALID; |
223 | |
|
224 | 0 | p_sys->i_last_time_ref = |
225 | 0 | p_sys->i_time_ref = |
226 | 0 | p_sys->i_last_time = |
227 | 0 | p_sys->i_last_timeincr = 0; |
228 | 0 | } |
229 | | |
230 | | static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) |
231 | 0 | { |
232 | 0 | decoder_t *p_dec = p_private; |
233 | 0 | const vlc_tick_t i_dts = p_block->i_dts; |
234 | 0 | const vlc_tick_t i_pts = p_block->i_pts; |
235 | |
|
236 | 0 | block_t *p_au = ParseMPEGBlock( p_dec, p_block ); |
237 | |
|
238 | 0 | *pb_ts_used = p_au && p_au->i_dts == i_dts && p_au->i_pts == i_pts; |
239 | |
|
240 | 0 | return p_au; |
241 | 0 | } |
242 | | |
243 | | |
244 | | static int PacketizeValidate( void *p_private, block_t *p_au ) |
245 | 0 | { |
246 | 0 | decoder_t *p_dec = p_private; |
247 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
248 | | |
249 | | /* We've just started the stream, wait for the first PTS. |
250 | | * We discard here so we can still get the sequence header. */ |
251 | 0 | if( p_sys->i_interpolated_pts == VLC_TICK_INVALID && |
252 | 0 | p_sys->i_interpolated_dts == VLC_TICK_INVALID ) |
253 | 0 | { |
254 | 0 | msg_Dbg( p_dec, "need a starting pts/dts" ); |
255 | 0 | return VLC_EGENERIC; |
256 | 0 | } |
257 | | |
258 | | /* When starting the stream we can have the first frame with |
259 | | * a null DTS (i_interpolated_pts is initialized to 0) */ |
260 | 0 | if( p_au->i_dts == VLC_TICK_INVALID ) |
261 | 0 | p_au->i_dts = p_au->i_pts; |
262 | 0 | return VLC_SUCCESS; |
263 | 0 | } |
264 | | |
265 | | /***************************************************************************** |
266 | | * ParseMPEGBlock: Re-assemble fragments into a block containing a picture |
267 | | *****************************************************************************/ |
268 | | static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag ) |
269 | 0 | { |
270 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
271 | 0 | block_t *p_pic = NULL; |
272 | |
|
273 | 0 | if( p_frag->i_buffer < 4 ) |
274 | 0 | return p_frag; |
275 | | |
276 | 0 | const uint32_t i_startcode = GetDWBE( p_frag->p_buffer ); |
277 | 0 | if( i_startcode == VISUAL_OBJECT_SEQUENCE_START_CODE || |
278 | 0 | i_startcode == VISUAL_OBJECT_SEQUENCE_END_CODE || |
279 | 0 | i_startcode == USER_DATA_START_CODE ) |
280 | 0 | { /* VOS and USERDATA */ |
281 | | #if 0 |
282 | | /* Remove VOS start/end code from the original stream */ |
283 | | block_Release( p_frag ); |
284 | | #else |
285 | | /* Append the block for now since ts/ps muxers rely on VOL |
286 | | * being present in the stream */ |
287 | 0 | block_ChainLastAppend( &p_sys->pp_last, p_frag ); |
288 | 0 | #endif |
289 | 0 | return NULL; |
290 | 0 | } |
291 | 0 | else if( i_startcode >= VIDEO_OBJECT_LAYER_START_CODE && |
292 | 0 | i_startcode < RESERVED_START_CODE ) |
293 | 0 | { |
294 | | /* Copy the complete VOL */ |
295 | 0 | if( (size_t)p_dec->fmt_out.i_extra != p_frag->i_buffer || |
296 | 0 | ( p_frag->i_buffer && memcmp(p_dec->fmt_out.p_extra, |
297 | 0 | p_frag->p_buffer, p_frag->i_buffer) ) ) |
298 | 0 | { |
299 | 0 | void *p_realloc = realloc( p_dec->fmt_out.p_extra, p_frag->i_buffer ); |
300 | 0 | if( p_realloc ) |
301 | 0 | { |
302 | 0 | p_dec->fmt_out.p_extra = p_realloc; |
303 | 0 | p_dec->fmt_out.i_extra = p_frag->i_buffer; |
304 | 0 | memcpy( p_realloc, p_frag->p_buffer, p_frag->i_buffer ); |
305 | 0 | } |
306 | 0 | } |
307 | 0 | ParseVOL( p_dec, &p_dec->fmt_out, |
308 | 0 | p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); |
309 | |
|
310 | | #if 0 |
311 | | /* Remove from the original stream */ |
312 | | block_Release( p_frag ); |
313 | | #else |
314 | | /* Append the block for now since ts/ps muxers rely on VOL |
315 | | * being present in the stream */ |
316 | 0 | block_ChainLastAppend( &p_sys->pp_last, p_frag ); |
317 | 0 | #endif |
318 | 0 | return NULL; |
319 | 0 | } |
320 | 0 | else |
321 | 0 | { |
322 | 0 | if( !p_dec->fmt_out.i_extra ) |
323 | 0 | { |
324 | 0 | msg_Warn( p_dec, "waiting for VOL" ); |
325 | 0 | block_Release( p_frag ); |
326 | 0 | return NULL; |
327 | 0 | } |
328 | | |
329 | | /* Append the block */ |
330 | 0 | block_ChainLastAppend( &p_sys->pp_last, p_frag ); |
331 | 0 | } |
332 | | |
333 | 0 | if( i_startcode == VISUAL_OBJECT_START_CODE ) |
334 | 0 | { |
335 | 0 | ParseVO( p_dec, p_frag ); |
336 | 0 | } |
337 | 0 | else |
338 | 0 | if( i_startcode == VOP_START_CODE && |
339 | 0 | ParseVOP( p_dec, p_frag ) == VLC_SUCCESS ) |
340 | 0 | { |
341 | | /* We are dealing with a VOP */ |
342 | 0 | p_pic = block_ChainGather( p_sys->p_frame ); |
343 | 0 | p_pic->i_flags = p_sys->i_flags; |
344 | 0 | p_pic->i_pts = p_sys->i_interpolated_pts; |
345 | 0 | p_pic->i_dts = p_sys->i_interpolated_dts; |
346 | |
|
347 | | #if 0 |
348 | | msg_Err( p_dec, "output dts/pts (%"PRId64",%"PRId64")", p_pic->i_dts, p_pic->i_pts ); |
349 | | #endif |
350 | | /* Reset context */ |
351 | 0 | p_sys->p_frame = NULL; |
352 | 0 | p_sys->pp_last = &p_sys->p_frame; |
353 | 0 | } |
354 | |
|
355 | 0 | return p_pic; |
356 | 0 | } |
357 | | |
358 | | /* ParseVOL: */ |
359 | | static int ParseVOL( decoder_t *p_dec, es_format_t *fmt, |
360 | | uint8_t *p_vol, int i_vol ) |
361 | 610 | { |
362 | 610 | decoder_sys_t *p_sys = p_dec->p_sys; |
363 | 610 | int i_vo_ver_id, i_shape; |
364 | 610 | h26x_aspect_ratio_t ar; |
365 | 610 | bs_t s; |
366 | | |
367 | 610 | for( ;; ) |
368 | 46.9k | { |
369 | 46.9k | if( i_vol <= 5 ) |
370 | 93 | return VLC_EGENERIC; |
371 | | |
372 | 46.8k | uint32_t i_startcode = GetDWBE( p_vol ); |
373 | 46.8k | if( i_startcode >= VIDEO_OBJECT_LAYER_START_CODE && |
374 | 34.3k | i_startcode < RESERVED_START_CODE ) |
375 | 517 | break; |
376 | | |
377 | 46.3k | p_vol++; i_vol--; |
378 | 46.3k | } |
379 | | |
380 | 517 | bs_init( &s, &p_vol[4], i_vol - 4 ); |
381 | | |
382 | 517 | bs_skip( &s, 1 ); /* random access */ |
383 | 517 | bs_skip( &s, 8 ); /* vo_type */ |
384 | 517 | if( bs_read1( &s ) ) |
385 | 415 | { |
386 | 415 | i_vo_ver_id = bs_read( &s, 4 ); |
387 | 415 | bs_skip( &s, 3 ); |
388 | 415 | } |
389 | 102 | else |
390 | 102 | { |
391 | 102 | i_vo_ver_id = 1; |
392 | 102 | } |
393 | 517 | ar.aspect_ratio_idc = bs_read( &s, 4 ) & 0xf; |
394 | 517 | if( ar.aspect_ratio_idc == 0xf ) |
395 | 51 | { |
396 | 51 | ar.aspect_ratio_idc = 0xff; // was only coded on 4 bits in MPEG4 |
397 | 51 | ar.sar_width = bs_read( &s, 8 ); |
398 | 51 | ar.sar_height = bs_read( &s, 8 ); |
399 | 51 | } |
400 | 517 | if(!p_dec->fmt_in->video.i_sar_num || |
401 | 19 | !p_dec->fmt_in->video.i_sar_den) |
402 | 498 | { |
403 | 498 | h26x_get_aspect_ratio(&ar, |
404 | 498 | &fmt->video.i_sar_num, |
405 | 498 | &fmt->video.i_sar_den); |
406 | 498 | } |
407 | | |
408 | 517 | if( bs_read1( &s ) ) |
409 | 318 | { |
410 | | /* vol control parameter */ |
411 | 318 | bs_skip( &s, 2 ); /* chroma_format */ |
412 | 318 | bs_skip( &s, 1 ); /* low_delay */ |
413 | | |
414 | 318 | if( bs_read1( &s ) ) |
415 | 98 | { |
416 | 98 | bs_skip( &s, 16 ); |
417 | 98 | bs_skip( &s, 16 ); |
418 | 98 | bs_skip( &s, 16 ); |
419 | 98 | bs_skip( &s, 3 ); |
420 | 98 | bs_skip( &s, 11 ); |
421 | 98 | bs_skip( &s, 1 ); |
422 | 98 | bs_skip( &s, 16 ); |
423 | 98 | } |
424 | 318 | } |
425 | | /* shape 0->RECT, 1->BIN, 2->BIN_ONLY, 3->GRAY */ |
426 | 517 | i_shape = bs_read( &s, 2 ); |
427 | 517 | if( i_shape == 3 && i_vo_ver_id != 1 ) |
428 | 32 | { |
429 | 32 | bs_skip( &s, 4 ); |
430 | 32 | } |
431 | | |
432 | 517 | if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ |
433 | | |
434 | 311 | p_sys->i_fps_num = bs_read( &s, 16 ); /* Time increment resolution*/ |
435 | 311 | if( !p_sys->i_fps_num ) p_sys->i_fps_num = 1; |
436 | | |
437 | 311 | if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ |
438 | | |
439 | 293 | if( bs_read1( &s ) ) |
440 | 248 | { |
441 | 248 | int i_time_increment_bits = vlc_log2( p_sys->i_fps_num - 1 ) + 1; |
442 | | |
443 | 248 | if( i_time_increment_bits < 1 ) i_time_increment_bits = 1; |
444 | | |
445 | 248 | p_sys->i_fps_den = bs_read( &s, i_time_increment_bits ); |
446 | 248 | } |
447 | 293 | if( i_shape == 0 ) |
448 | 237 | { |
449 | 237 | bs_skip( &s, 1 ); |
450 | 237 | fmt->video.i_width = bs_read( &s, 13 ); |
451 | 237 | bs_skip( &s, 1 ); |
452 | 237 | fmt->video.i_height= bs_read( &s, 13 ); |
453 | 237 | bs_skip( &s, 1 ); |
454 | 237 | } |
455 | | |
456 | 293 | return VLC_SUCCESS; |
457 | 311 | } |
458 | | |
459 | | static int ParseVO( decoder_t *p_dec, block_t *p_vo ) |
460 | 0 | { |
461 | 0 | bs_t s; |
462 | 0 | bs_init( &s, &p_vo->p_buffer[4], p_vo->i_buffer - 4 ); |
463 | 0 | if( bs_read1( &s ) ) |
464 | 0 | bs_skip( &s, 7 ); |
465 | |
|
466 | 0 | const uint8_t visual_object_type = bs_read( &s, 4 ); |
467 | 0 | if( visual_object_type == 1 /* video ID */ || |
468 | 0 | visual_object_type == 2 /* still texture ID */ ) |
469 | 0 | { |
470 | 0 | h26x_colour_description_t colour = |
471 | 0 | { |
472 | 0 | .colour_primaries = 1, |
473 | 0 | .transfer_characteristics = 1, |
474 | 0 | .matrix_coeffs = 1, |
475 | 0 | .full_range_flag = 0, |
476 | 0 | }; |
477 | 0 | if( bs_read1( &s ) ) /* video_signal_type */ |
478 | 0 | { |
479 | 0 | bs_skip( &s, 3 ); |
480 | 0 | colour.full_range_flag = bs_read( &s, 1 ); |
481 | 0 | if( bs_read( &s, 1 ) ) /* colour description */ |
482 | 0 | { |
483 | 0 | colour.colour_primaries = bs_read( &s, 8 ); |
484 | 0 | colour.transfer_characteristics = bs_read( &s, 8 ); |
485 | 0 | colour.matrix_coeffs = bs_read( &s, 8 ); |
486 | 0 | } |
487 | 0 | } |
488 | |
|
489 | 0 | if( p_dec->fmt_in->video.primaries == COLOR_PRIMARIES_UNDEF ) |
490 | 0 | { |
491 | 0 | h26x_get_colorimetry( &colour, |
492 | 0 | &p_dec->fmt_out.video.primaries, |
493 | 0 | &p_dec->fmt_out.video.transfer, |
494 | 0 | &p_dec->fmt_out.video.space, |
495 | 0 | &p_dec->fmt_out.video.color_range ); |
496 | 0 | } |
497 | 0 | } |
498 | |
|
499 | 0 | return VLC_SUCCESS; |
500 | 0 | } |
501 | | |
502 | | static int ParseVOP( decoder_t *p_dec, block_t *p_vop ) |
503 | 0 | { |
504 | 0 | decoder_sys_t *p_sys = p_dec->p_sys; |
505 | 0 | int64_t i_time_increment, i_time_ref; |
506 | 0 | int i_modulo_time_base = 0, i_time_increment_bits; |
507 | 0 | bs_t s; |
508 | |
|
509 | 0 | bs_init( &s, &p_vop->p_buffer[4], p_vop->i_buffer - 4 ); |
510 | |
|
511 | 0 | switch( bs_read( &s, 2 ) ) |
512 | 0 | { |
513 | 0 | case 0: |
514 | 0 | p_sys->i_flags = BLOCK_FLAG_TYPE_I; |
515 | 0 | break; |
516 | 0 | case 1: |
517 | 0 | p_sys->i_flags = BLOCK_FLAG_TYPE_P; |
518 | 0 | break; |
519 | 0 | case 2: |
520 | 0 | p_sys->i_flags = BLOCK_FLAG_TYPE_B; |
521 | 0 | p_sys->b_frame = true; |
522 | 0 | break; |
523 | 0 | case 3: /* gni ? */ |
524 | 0 | p_sys->i_flags = BLOCK_FLAG_TYPE_PB; |
525 | 0 | break; |
526 | 0 | } |
527 | | |
528 | 0 | while( bs_read( &s, 1 ) ) i_modulo_time_base++; |
529 | 0 | if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ |
530 | | |
531 | | /* VOP time increment */ |
532 | 0 | i_time_increment_bits = vlc_log2(p_sys->i_fps_num - 1) + 1; |
533 | 0 | if( i_time_increment_bits < 1 ) i_time_increment_bits = 1; |
534 | 0 | i_time_increment = bs_read( &s, i_time_increment_bits ); |
535 | | |
536 | | /* Interpolate PTS/DTS */ |
537 | 0 | if( !(p_sys->i_flags & BLOCK_FLAG_TYPE_B) ) |
538 | 0 | { |
539 | 0 | p_sys->i_last_time_ref = p_sys->i_time_ref; |
540 | 0 | p_sys->i_time_ref += |
541 | 0 | (i_modulo_time_base * p_sys->i_fps_num); |
542 | 0 | i_time_ref = p_sys->i_time_ref; |
543 | 0 | } |
544 | 0 | else |
545 | 0 | { |
546 | 0 | i_time_ref = p_sys->i_last_time_ref + |
547 | 0 | (i_modulo_time_base * p_sys->i_fps_num); |
548 | 0 | } |
549 | |
|
550 | 0 | int64_t i_time_diff = (i_time_ref + i_time_increment) - (p_sys->i_last_time + p_sys->i_last_timeincr); |
551 | 0 | if( p_sys->i_fps_num && i_modulo_time_base == 0 && i_time_diff < 0 && -i_time_diff > p_sys->i_fps_num ) |
552 | 0 | { |
553 | 0 | msg_Warn(p_dec, "missing modulo_time_base update"); |
554 | 0 | i_modulo_time_base += -i_time_diff / p_sys->i_fps_num; |
555 | 0 | p_sys->i_time_ref += (i_modulo_time_base * p_sys->i_fps_num); |
556 | 0 | p_sys->i_time_ref += p_sys->i_last_timeincr % p_sys->i_fps_num; |
557 | 0 | i_time_ref = p_sys->i_time_ref; |
558 | 0 | } |
559 | |
|
560 | 0 | if( p_sys->i_fps_num < 5 && /* Work-around buggy streams */ |
561 | 0 | p_dec->fmt_in->video.i_frame_rate > 0 && |
562 | 0 | p_dec->fmt_in->video.i_frame_rate_base > 0 ) |
563 | 0 | { |
564 | 0 | p_sys->i_interpolated_pts += vlc_tick_from_samples( |
565 | 0 | p_dec->fmt_in->video.i_frame_rate_base, |
566 | 0 | p_dec->fmt_in->video.i_frame_rate); |
567 | 0 | } |
568 | 0 | else if( p_sys->i_fps_num ) |
569 | 0 | { |
570 | 0 | i_time_diff = (i_time_ref + i_time_increment) - (p_sys->i_last_time + p_sys->i_last_timeincr); |
571 | 0 | p_sys->i_interpolated_pts += vlc_tick_from_samples( i_time_diff, p_sys->i_fps_num ); |
572 | 0 | } |
573 | |
|
574 | | #if 0 |
575 | | msg_Err( p_dec, "interp dts/pts (%"PRId64",%"PRId64"), dts/pts (%"PRId64",%"PRId64") %"PRId64" mod %d inc %"PRId64, |
576 | | p_sys->i_interpolated_dts, p_sys->i_interpolated_pts, |
577 | | p_vop->i_dts, p_vop->i_pts, p_sys->i_time_ref, i_modulo_time_base, i_time_increment ); |
578 | | #endif |
579 | |
|
580 | 0 | p_sys->i_last_time = i_time_ref; |
581 | 0 | p_sys->i_last_timeincr = i_time_increment; |
582 | | |
583 | | /* Correct interpolated dts when we receive a new pts/dts */ |
584 | 0 | if( p_vop->i_pts != VLC_TICK_INVALID ) |
585 | 0 | p_sys->i_interpolated_pts = p_vop->i_pts; |
586 | 0 | if( p_vop->i_dts != VLC_TICK_INVALID ) |
587 | 0 | p_sys->i_interpolated_dts = p_vop->i_dts; |
588 | |
|
589 | 0 | if( (p_sys->i_flags & BLOCK_FLAG_TYPE_B) || !p_sys->b_frame ) |
590 | 0 | { |
591 | | /* Trivial case (DTS == PTS) */ |
592 | |
|
593 | 0 | p_sys->i_interpolated_dts = p_sys->i_interpolated_pts; |
594 | |
|
595 | 0 | if( p_vop->i_pts != VLC_TICK_INVALID ) |
596 | 0 | p_sys->i_interpolated_dts = p_vop->i_pts; |
597 | 0 | if( p_vop->i_dts != VLC_TICK_INVALID ) |
598 | 0 | p_sys->i_interpolated_dts = p_vop->i_dts; |
599 | |
|
600 | 0 | p_sys->i_interpolated_pts = p_sys->i_interpolated_dts; |
601 | 0 | } |
602 | 0 | else |
603 | 0 | { |
604 | 0 | if( p_sys->i_last_ref_pts != VLC_TICK_INVALID ) |
605 | 0 | p_sys->i_interpolated_dts = p_sys->i_last_ref_pts; |
606 | |
|
607 | 0 | p_sys->i_last_ref_pts = p_sys->i_interpolated_pts; |
608 | 0 | } |
609 | |
|
610 | 0 | return VLC_SUCCESS; |
611 | 0 | } |
612 | | |
613 | | /* look at libavutil av_log2 ;) */ |
614 | | static int vlc_log2( unsigned int v ) |
615 | 248 | { |
616 | 248 | int n = 0; |
617 | 248 | static const int vlc_log2_table[16] = |
618 | 248 | { |
619 | 248 | 0,0,1,1,2,2,2,2, 3,3,3,3,3,3,3,3 |
620 | 248 | }; |
621 | | |
622 | 248 | if( v&0xffff0000 ) |
623 | 0 | { |
624 | 0 | v >>= 16; |
625 | 0 | n += 16; |
626 | 0 | } |
627 | 248 | if( v&0xff00 ) |
628 | 245 | { |
629 | 245 | v >>= 8; |
630 | 245 | n += 8; |
631 | 245 | } |
632 | 248 | if( v&0xf0 ) |
633 | 244 | { |
634 | 244 | v >>= 4; |
635 | 244 | n += 4; |
636 | 244 | } |
637 | 248 | n += vlc_log2_table[v]; |
638 | | |
639 | 248 | return n; |
640 | 248 | } |