/src/vlc/modules/demux/mpeg/h26x.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * h26x.c : raw H264 and HEVC Video demuxers |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2002-2004, 2014-2015 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * Denis Charmet <typx@videolan.org> |
8 | | * |
9 | | * This program is free software; you can redistribute it and/or modify it |
10 | | * under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 of the License, or |
12 | | * (at your option) any later version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, write to the Free Software Foundation, |
21 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
22 | | *****************************************************************************/ |
23 | | |
24 | | /***************************************************************************** |
25 | | * Preamble |
26 | | *****************************************************************************/ |
27 | | |
28 | | #ifdef HAVE_CONFIG_H |
29 | | # include "config.h" |
30 | | #endif |
31 | | |
32 | | #include <vlc_common.h> |
33 | | #include <vlc_plugin.h> |
34 | | #include <vlc_demux.h> |
35 | | #include <vlc_codec.h> |
36 | | #include "../../packetizer/hevc_nal.h" /* definitions, inline helpers */ |
37 | | #include "../../packetizer/h264_nal.h" /* definitions, inline helpers */ |
38 | | |
39 | | /***************************************************************************** |
40 | | * Module descriptor |
41 | | *****************************************************************************/ |
42 | | static int OpenH264 ( vlc_object_t * ); |
43 | | static int OpenHEVC ( vlc_object_t * ); |
44 | | static void Close( vlc_object_t * ); |
45 | | |
46 | | #define FPS_TEXT N_("Frames per Second") |
47 | | #define FPS_LONGTEXT N_("Desired frame rate for the stream.") |
48 | | |
49 | 4 | vlc_module_begin () |
50 | 2 | set_shortname( "H264") |
51 | 2 | set_subcategory( SUBCAT_INPUT_DEMUX ) |
52 | 2 | set_description( N_("H264 video demuxer" ) ) |
53 | 2 | set_capability( "demux", 8 ) |
54 | 2 | set_section( N_("H264 video demuxer" ), NULL ) |
55 | 2 | add_float( "h264-fps", 0.0, FPS_TEXT, FPS_LONGTEXT ) |
56 | 2 | set_callbacks( OpenH264, Close ) |
57 | 2 | add_shortcut( "h264" ) |
58 | 2 | add_file_extension("h264") |
59 | | |
60 | 2 | add_submodule() |
61 | 2 | set_shortname( "HEVC") |
62 | 2 | set_subcategory( SUBCAT_INPUT_DEMUX ) |
63 | 2 | set_description( N_("HEVC/H.265 video demuxer" ) ) |
64 | 2 | set_capability( "demux", 8 ) |
65 | 2 | set_section( N_("HEVC/H.265 video demuxer" ), NULL ) |
66 | 2 | add_float( "hevc-fps", 0.0, FPS_TEXT, FPS_LONGTEXT ) |
67 | 2 | set_callbacks( OpenHEVC, Close ) |
68 | 2 | add_shortcut( "hevc", "h265" ) |
69 | | |
70 | 2 | vlc_module_end () |
71 | | |
72 | | /***************************************************************************** |
73 | | * Local prototypes |
74 | | *****************************************************************************/ |
75 | | typedef struct |
76 | | { |
77 | | es_out_id_t *p_es; |
78 | | |
79 | | date_t feed_dts; |
80 | | date_t output_dts; |
81 | | unsigned frame_rate_num; |
82 | | unsigned frame_rate_den; |
83 | | |
84 | | decoder_t *p_packetizer; |
85 | | } demux_sys_t; |
86 | | |
87 | | static int Demux( demux_t * ); |
88 | | static int Control( demux_t *, int, va_list ); |
89 | | |
90 | 0 | #define H26X_PACKET_SIZE 2048 |
91 | 0 | #define H26X_PEEK_CHUNK (H26X_PACKET_SIZE * 4) |
92 | 0 | #define H26X_MIN_PEEK (4 + 7 + 10) |
93 | 0 | #define H26X_MAX_PEEK (H26X_PEEK_CHUNK * 8) /* max data to check */ |
94 | 0 | #define H26X_NAL_COUNT 8 /* max # or NAL to check */ |
95 | | |
96 | | /***************************************************************************** |
97 | | * Probing |
98 | | *****************************************************************************/ |
99 | | typedef struct |
100 | | { |
101 | | bool b_sps; |
102 | | bool b_pps; |
103 | | bool b_vps; |
104 | | } hevc_probe_ctx_t; |
105 | | |
106 | | typedef struct |
107 | | { |
108 | | bool b_sps; |
109 | | bool b_pps; |
110 | | } h264_probe_ctx_t; |
111 | | |
112 | | static int ProbeHEVC( const uint8_t *p_peek, size_t i_peek, void *p_priv ) |
113 | 0 | { |
114 | 0 | hevc_probe_ctx_t *p_ctx = (hevc_probe_ctx_t *) p_priv; |
115 | |
|
116 | 0 | if( i_peek < 2 ) |
117 | 0 | return -1; |
118 | | |
119 | 0 | if( p_peek[0] & 0x80 ) |
120 | 0 | return -1; |
121 | | |
122 | 0 | const uint8_t i_type = hevc_getNALType( p_peek ); |
123 | 0 | const uint8_t i_layer = hevc_getNALLayer( p_peek ); |
124 | |
|
125 | 0 | if ( i_type == HEVC_NAL_VPS ) /* VPS */ |
126 | 0 | { |
127 | 0 | if( i_layer != 0 || i_peek < 6 || |
128 | 0 | p_peek[4] != 0xFF || p_peek[5] != 0xFF ) /* Check reserved bits */ |
129 | 0 | return -1; |
130 | 0 | p_ctx->b_vps = true; |
131 | 0 | return 0; |
132 | 0 | } |
133 | 0 | else if( i_type == HEVC_NAL_SPS ) /* SPS */ |
134 | 0 | { |
135 | 0 | if( i_layer != 0 ) |
136 | 0 | return -1; |
137 | 0 | p_ctx->b_sps = true; |
138 | 0 | return 0; |
139 | 0 | } |
140 | 0 | else if( i_type == HEVC_NAL_PPS ) /* PPS */ |
141 | 0 | { |
142 | 0 | if( i_layer != 0 ) |
143 | 0 | return -1; |
144 | 0 | p_ctx->b_pps = true; |
145 | 0 | return 0; |
146 | 0 | } |
147 | 0 | else if( i_type >= HEVC_NAL_BLA_W_LP && i_type <= HEVC_NAL_CRA ) /* Key Frame */ |
148 | 0 | { |
149 | 0 | if( p_ctx->b_vps && p_ctx->b_sps && p_ctx->b_pps && i_layer == 0 ) |
150 | 0 | return 1; |
151 | 0 | } |
152 | 0 | else if( i_type == HEVC_NAL_AUD ) /* AU */ |
153 | 0 | { |
154 | 0 | if( i_peek < H26X_MIN_PEEK || |
155 | 0 | p_peek[4] != 0 || p_peek[5] != 0 ) /* Must prefix another NAL */ |
156 | 0 | return -1; |
157 | 0 | } |
158 | 0 | else if( i_type == HEVC_NAL_PREF_SEI ) /* Prefix SEI */ |
159 | 0 | { |
160 | 0 | if( p_peek[2] == 0xFF ) /* empty SEI */ |
161 | 0 | return -1; |
162 | 0 | } |
163 | 0 | else |
164 | 0 | { |
165 | 0 | return -1; /* See 7.4.2.4.4 for sequence order */ |
166 | 0 | } |
167 | | |
168 | 0 | return 0; /* Probe more */ |
169 | 0 | } |
170 | | |
171 | | static int ProbeH264( const uint8_t *p_peek, size_t i_peek, void *p_priv ) |
172 | 0 | { |
173 | 0 | h264_probe_ctx_t *p_ctx = (h264_probe_ctx_t *) p_priv; |
174 | |
|
175 | 0 | if( i_peek < 1 ) |
176 | 0 | return -1; |
177 | 0 | const uint8_t i_nal_type = p_peek[0] & 0x1F; |
178 | 0 | const uint8_t i_ref_idc = p_peek[0] & 0x60; |
179 | |
|
180 | 0 | if( (p_peek[0] & 0x80) ) /* reserved 0 */ |
181 | 0 | return -1; |
182 | | |
183 | | /* ( !i_ref_idc && (i_nal_type < 6 || i_nal_type == 7 || i_nal_type == 8) ) || |
184 | | ( i_ref_idc && (i_nal_type == 6 || i_nal_type >= 9) ) */ |
185 | | |
186 | 0 | if( i_nal_type == H264_NAL_SPS ) |
187 | 0 | { |
188 | 0 | if( i_ref_idc == 0 || i_peek < 3 || |
189 | 0 | (p_peek[2] & 0x03) /* reserved 0 bits */ ) |
190 | 0 | return -1; |
191 | 0 | p_ctx->b_sps = true; |
192 | 0 | } |
193 | 0 | else if( i_nal_type == H264_NAL_PPS ) |
194 | 0 | { |
195 | 0 | if( i_ref_idc == 0 ) |
196 | 0 | return -1; |
197 | 0 | p_ctx->b_pps = true; |
198 | 0 | } |
199 | 0 | else if( i_nal_type == H264_NAL_SLICE_IDR ) |
200 | 0 | { |
201 | 0 | if( i_ref_idc == 0 || ! p_ctx->b_pps || ! p_ctx->b_sps ) |
202 | 0 | return -1; |
203 | 0 | else |
204 | 0 | return 1; |
205 | 0 | } |
206 | 0 | else if( i_nal_type == H264_NAL_AU_DELIMITER ) |
207 | 0 | { |
208 | 0 | if( i_ref_idc ) |
209 | 0 | return -1; |
210 | 0 | } |
211 | 0 | else if ( i_nal_type == H264_NAL_SEI ) |
212 | 0 | { |
213 | 0 | if( i_ref_idc ) |
214 | 0 | return -1; |
215 | 0 | } |
216 | | /* 7.4.1.1 */ |
217 | 0 | else if ( i_nal_type == H264_NAL_SPS_EXT || |
218 | 0 | i_nal_type == H264_NAL_SUBSET_SPS ) |
219 | 0 | { |
220 | 0 | if( i_ref_idc == 0 || !p_ctx->b_sps ) |
221 | 0 | return -1; |
222 | 0 | } |
223 | 0 | else if( i_nal_type == H264_NAL_PREFIX ) |
224 | 0 | { |
225 | 0 | if( i_ref_idc == 0 || !p_ctx->b_pps || !p_ctx->b_sps ) |
226 | 0 | return -1; |
227 | 0 | } |
228 | 0 | else return -1; /* see 7.4.1.2.3 for sequence */ |
229 | | |
230 | 0 | return 0; |
231 | 0 | } |
232 | | |
233 | | /***************************************************************************** |
234 | | * Shared Open code |
235 | | *****************************************************************************/ |
236 | | static inline bool check_Property( demux_t *p_demux, const char **pp_psz, |
237 | | bool(*pf_check)(demux_t *, const char *) ) |
238 | 0 | { |
239 | 0 | while( *pp_psz ) |
240 | 0 | { |
241 | 0 | if( pf_check( p_demux, *pp_psz ) ) |
242 | 0 | return true; |
243 | 0 | pp_psz++; |
244 | 0 | } |
245 | 0 | return false; |
246 | 0 | } |
247 | | |
248 | | static int GenericOpen( demux_t *p_demux, const char *psz_module, |
249 | | vlc_fourcc_t i_codec, |
250 | | int(*pf_probe)(const uint8_t *, size_t, void *), |
251 | | void *p_ctx, |
252 | | const char **pp_psz_exts, |
253 | | const char **pp_psz_mimes ) |
254 | 0 | { |
255 | 0 | demux_sys_t *p_sys; |
256 | 0 | const uint8_t *p_peek; |
257 | 0 | es_format_t fmt; |
258 | 0 | uint8_t annexb_startcode[] = {0,0,0,1}; |
259 | 0 | int i_ret = 0; |
260 | | |
261 | | /* Restrict by type first */ |
262 | 0 | if( !p_demux->obj.force && |
263 | 0 | !check_Property( p_demux, pp_psz_exts, demux_IsPathExtension ) && |
264 | 0 | !check_Property( p_demux, pp_psz_mimes, demux_IsContentType ) ) |
265 | 0 | { |
266 | 0 | return VLC_EGENERIC; |
267 | 0 | } |
268 | | |
269 | | /* First check for first AnnexB header */ |
270 | 0 | if( vlc_stream_Peek( p_demux->s, &p_peek, H26X_MIN_PEEK ) == H26X_MIN_PEEK && |
271 | 0 | !memcmp( p_peek, annexb_startcode, 4 ) ) |
272 | 0 | { |
273 | 0 | size_t i_peek = H26X_MIN_PEEK; |
274 | 0 | size_t i_peek_target = H26X_MIN_PEEK; |
275 | 0 | size_t i_probe_offset = 4; |
276 | 0 | const uint8_t *p_probe = p_peek; |
277 | 0 | bool b_synced = true; |
278 | 0 | unsigned i_bitflow = 0; |
279 | |
|
280 | 0 | for( unsigned i=0; i<H26X_NAL_COUNT; i++ ) |
281 | 0 | { |
282 | 0 | while( !b_synced ) |
283 | 0 | { |
284 | 0 | if( i_probe_offset + H26X_MIN_PEEK >= i_peek && |
285 | 0 | i_peek_target + H26X_PEEK_CHUNK <= H26X_MAX_PEEK ) |
286 | 0 | { |
287 | 0 | i_peek_target += H26X_PEEK_CHUNK; |
288 | 0 | i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_peek_target ); |
289 | 0 | } |
290 | |
|
291 | 0 | if( i_probe_offset + H26X_MIN_PEEK >= i_peek ) |
292 | 0 | break; |
293 | | |
294 | 0 | p_probe = &p_peek[i_probe_offset]; |
295 | 0 | i_bitflow = (i_bitflow << 1) | (!p_probe[0]); |
296 | | /* Check for annexB */ |
297 | 0 | if( p_probe[0] == 0x01 && ((i_bitflow & 0x06) == 0x06) ) |
298 | 0 | b_synced = true; |
299 | |
|
300 | 0 | i_probe_offset++; |
301 | 0 | } |
302 | |
|
303 | 0 | if( b_synced ) |
304 | 0 | { |
305 | 0 | p_probe = &p_peek[i_probe_offset]; |
306 | 0 | i_ret = pf_probe( p_probe, i_peek - i_probe_offset, p_ctx ); |
307 | 0 | } |
308 | |
|
309 | 0 | if( i_ret != 0 ) |
310 | 0 | break; |
311 | | |
312 | 0 | i_probe_offset += 4; |
313 | 0 | b_synced = false; |
314 | 0 | } |
315 | 0 | } |
316 | |
|
317 | 0 | if( i_ret < 1 ) |
318 | 0 | { |
319 | 0 | if( !p_demux->obj.force ) |
320 | 0 | { |
321 | 0 | msg_Warn( p_demux, "%s module discarded (no startcode)", psz_module ); |
322 | 0 | return VLC_EGENERIC; |
323 | 0 | } |
324 | | |
325 | 0 | msg_Err( p_demux, "this doesn't look like a %s ES stream, " |
326 | 0 | "continuing anyway", psz_module ); |
327 | 0 | } |
328 | | |
329 | 0 | p_demux->pf_demux = Demux; |
330 | 0 | p_demux->pf_control= Control; |
331 | 0 | p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); |
332 | 0 | p_sys->p_es = NULL; |
333 | 0 | p_sys->frame_rate_num = 0; |
334 | 0 | p_sys->frame_rate_den = 0; |
335 | |
|
336 | 0 | float f_fps = 0; |
337 | 0 | char *psz_fpsvar; |
338 | 0 | if( asprintf( &psz_fpsvar, "%s-fps", psz_module ) != -1 ) |
339 | 0 | { |
340 | 0 | f_fps = var_CreateGetFloat( p_demux, psz_fpsvar ); |
341 | 0 | free( psz_fpsvar ); |
342 | 0 | } |
343 | |
|
344 | 0 | if( f_fps ) |
345 | 0 | { |
346 | 0 | if ( f_fps < 0.001f ) f_fps = 0.001f; |
347 | 0 | p_sys->frame_rate_den = 1000; |
348 | 0 | p_sys->frame_rate_num = 2000 * f_fps; |
349 | 0 | date_Init( &p_sys->feed_dts, p_sys->frame_rate_num, p_sys->frame_rate_den ); |
350 | 0 | } |
351 | 0 | else |
352 | 0 | date_Init( &p_sys->feed_dts, 25000, 1000 ); |
353 | 0 | date_Set( &p_sys->feed_dts, VLC_TICK_0 ); |
354 | 0 | p_sys->output_dts = p_sys->feed_dts; |
355 | | |
356 | | /* Load the mpegvideo packetizer */ |
357 | 0 | es_format_Init( &fmt, VIDEO_ES, i_codec ); |
358 | 0 | if( f_fps ) |
359 | 0 | { |
360 | 0 | fmt.video.i_frame_rate = p_sys->feed_dts.i_divider_num; |
361 | 0 | fmt.video.i_frame_rate_base = p_sys->feed_dts.i_divider_den; |
362 | 0 | } |
363 | 0 | p_sys->p_packetizer = demux_PacketizerNew( VLC_OBJECT(p_demux), &fmt, psz_module ); |
364 | 0 | if( !p_sys->p_packetizer ) |
365 | 0 | { |
366 | 0 | free( p_sys ); |
367 | 0 | return VLC_EGENERIC; |
368 | 0 | } |
369 | | |
370 | 0 | return VLC_SUCCESS; |
371 | 0 | } |
372 | | |
373 | | /***************************************************************************** |
374 | | * Open: initializes demux structures |
375 | | *****************************************************************************/ |
376 | | static int OpenH264( vlc_object_t * p_this ) |
377 | 0 | { |
378 | 0 | h264_probe_ctx_t ctx = { 0, 0 }; |
379 | 0 | const char *rgi_psz_ext[] = { ".h264", ".264", ".bin", ".bit", ".raw", NULL }; |
380 | 0 | const char *rgi_psz_mime[] = { "video/H264", "video/h264", "video/avc", NULL }; |
381 | |
|
382 | 0 | return GenericOpen( (demux_t*)p_this, "h264", VLC_CODEC_H264, ProbeH264, |
383 | 0 | &ctx, rgi_psz_ext, rgi_psz_mime ); |
384 | 0 | } |
385 | | |
386 | | static int OpenHEVC( vlc_object_t * p_this ) |
387 | 0 | { |
388 | 0 | hevc_probe_ctx_t ctx = { 0, 0, 0 }; |
389 | 0 | const char *rgi_psz_ext[] = { ".h265", ".265", ".hevc", ".bin", ".bit", ".raw", NULL }; |
390 | 0 | const char *rgi_psz_mime[] = { "video/h265", "video/hevc", "video/HEVC", NULL }; |
391 | |
|
392 | 0 | return GenericOpen( (demux_t*)p_this, "hevc", VLC_CODEC_HEVC, ProbeHEVC, |
393 | 0 | &ctx, rgi_psz_ext, rgi_psz_mime ); |
394 | 0 | } |
395 | | |
396 | | /***************************************************************************** |
397 | | * Close: frees unused data |
398 | | *****************************************************************************/ |
399 | | static void Close( vlc_object_t * p_this ) |
400 | 0 | { |
401 | 0 | demux_t *p_demux = (demux_t*)p_this; |
402 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
403 | |
|
404 | 0 | demux_PacketizerDestroy( p_sys->p_packetizer ); |
405 | 0 | free( p_sys ); |
406 | 0 | } |
407 | | |
408 | | /***************************************************************************** |
409 | | * Demux: reads and demuxes data packets |
410 | | ***************************************************************************** |
411 | | * Returns -1 in case of error, 0 in case of EOF, 1 otherwise |
412 | | *****************************************************************************/ |
413 | | static int Demux( demux_t *p_demux) |
414 | 0 | { |
415 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
416 | 0 | block_t *p_block_in, *p_block_out; |
417 | 0 | bool b_eof = false; |
418 | |
|
419 | 0 | p_block_in = vlc_stream_Block( p_demux->s, H26X_PACKET_SIZE ); |
420 | 0 | if( p_block_in == NULL ) |
421 | 0 | { |
422 | 0 | b_eof = true; |
423 | 0 | } |
424 | 0 | else |
425 | 0 | { |
426 | 0 | p_block_in->i_dts = date_Get( &p_sys->feed_dts ); |
427 | 0 | } |
428 | |
|
429 | 0 | while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, |
430 | 0 | p_block_in ? &p_block_in : NULL )) ) |
431 | 0 | { |
432 | 0 | while( p_block_out ) |
433 | 0 | { |
434 | 0 | block_t *p_next = p_block_out->p_next; |
435 | 0 | p_block_out->p_next = NULL; |
436 | |
|
437 | 0 | if( p_sys->p_packetizer->fmt_out.video.i_frame_rate_base && |
438 | 0 | p_sys->p_packetizer->fmt_out.video.i_frame_rate_base != p_sys->frame_rate_den && |
439 | 0 | p_sys->p_packetizer->fmt_out.video.i_frame_rate && |
440 | 0 | p_sys->p_packetizer->fmt_out.video.i_frame_rate_base != p_sys->frame_rate_num ) |
441 | 0 | { |
442 | 0 | p_sys->frame_rate_num = p_sys->p_packetizer->fmt_out.video.i_frame_rate; |
443 | 0 | p_sys->frame_rate_den = p_sys->p_packetizer->fmt_out.video.i_frame_rate_base; |
444 | 0 | date_Change( &p_sys->feed_dts, 2 * p_sys->frame_rate_num, p_sys->frame_rate_den ); |
445 | 0 | date_Change( &p_sys->output_dts, 2 * p_sys->frame_rate_num, p_sys->frame_rate_den ); |
446 | 0 | msg_Dbg( p_demux, "using %.2f fps", (double) p_sys->frame_rate_num / p_sys->frame_rate_den ); |
447 | 0 | } |
448 | | |
449 | | /* we only want to use the pts-dts offset and length from packetizer */ |
450 | 0 | vlc_tick_t dtsdiff = p_block_out->i_pts > p_block_out->i_dts |
451 | 0 | ? p_block_out->i_pts - p_block_out->i_dts |
452 | 0 | : 0; |
453 | | /* Always start frame N=1 so we get PCR on N=0 */ |
454 | 0 | date_t dtsdate = p_sys->output_dts; |
455 | 0 | vlc_tick_t dts = date_Increment( &dtsdate, 2 ); |
456 | |
|
457 | 0 | p_block_out->i_dts = dts; |
458 | 0 | if( p_block_out->i_pts != VLC_TICK_INVALID ) |
459 | 0 | p_block_out->i_pts = dts + dtsdiff; |
460 | |
|
461 | 0 | if( p_block_in ) |
462 | 0 | { |
463 | 0 | p_block_in->i_dts = date_Get( &p_sys->feed_dts ); |
464 | 0 | p_block_in->i_pts = VLC_TICK_INVALID; |
465 | 0 | } |
466 | |
|
467 | 0 | if( p_sys->p_es == NULL ) |
468 | 0 | { |
469 | 0 | p_sys->p_packetizer->fmt_out.b_packetized = true; |
470 | 0 | p_sys->p_packetizer->fmt_out.i_id = 0; |
471 | 0 | p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out ); |
472 | 0 | if( !p_sys->p_es ) |
473 | 0 | { |
474 | 0 | block_ChainRelease( p_block_out ); |
475 | 0 | return VLC_DEMUXER_EOF; |
476 | 0 | } |
477 | 0 | } |
478 | | |
479 | | /* h264 packetizer does merge multiple NAL into AU, but slice flag persists */ |
480 | 0 | bool frame = p_block_out->i_flags & BLOCK_FLAG_TYPE_MASK; |
481 | 0 | const vlc_tick_t i_frame_length = p_block_out->i_length; |
482 | | |
483 | | /* first output */ |
484 | 0 | if( date_Get( &p_sys->output_dts ) == VLC_TICK_0 ) |
485 | 0 | es_out_SetPCR( p_demux->out, date_Get( &p_sys->output_dts ) ); |
486 | |
|
487 | 0 | es_out_Send( p_demux->out, p_sys->p_es, p_block_out ); |
488 | |
|
489 | 0 | vlc_tick_t pcr = b_eof ? dts : date_Get( &p_sys->output_dts ); |
490 | |
|
491 | 0 | if( frame ) |
492 | 0 | { |
493 | 0 | unsigned i_nb_fields; |
494 | 0 | if( i_frame_length > 0 ) |
495 | 0 | { |
496 | 0 | i_nb_fields = round( (double)i_frame_length * 2 * p_sys->frame_rate_num / |
497 | 0 | ( p_sys->frame_rate_den * CLOCK_FREQ ) ); |
498 | 0 | } |
499 | 0 | else i_nb_fields = 2; |
500 | 0 | if( i_nb_fields <= 6 ) /* in the legit range */ |
501 | 0 | { |
502 | 0 | date_Increment( &p_sys->output_dts, i_nb_fields ); |
503 | 0 | } |
504 | 0 | } |
505 | |
|
506 | 0 | es_out_SetPCR( p_demux->out, pcr ); |
507 | |
|
508 | 0 | p_block_out = p_next; |
509 | 0 | } |
510 | 0 | } |
511 | 0 | return (b_eof) ? VLC_DEMUXER_EOF : VLC_DEMUXER_SUCCESS; |
512 | 0 | } |
513 | | |
514 | | /***************************************************************************** |
515 | | * Control: |
516 | | *****************************************************************************/ |
517 | | static int Control( demux_t *p_demux, int i_query, va_list args ) |
518 | 0 | { |
519 | | /* demux_sys_t *p_sys = p_demux->p_sys; */ |
520 | | /* FIXME calculate the bitrate */ |
521 | 0 | if( i_query == DEMUX_SET_TIME ) |
522 | 0 | return VLC_EGENERIC; |
523 | 0 | else |
524 | 0 | return demux_vaControlHelper( p_demux->s, |
525 | 0 | 0, -1, |
526 | 0 | 0, 1, i_query, args ); |
527 | 0 | } |
528 | | |