packetizer: hevc: don't double store poc prev msb/lsb
[vlc.git] / modules / stream_out / record.c
blobb8d6b94359a1c194a88c1611e5a3af595c838143
1 /*****************************************************************************
2 * record.c: record stream output module
3 *****************************************************************************
4 * Copyright (C) 2008-2009 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <limits.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_block.h>
37 #include <vlc_sout.h>
38 #include <vlc_fs.h>
39 #include <assert.h>
41 /*****************************************************************************
42 * Exported prototypes
43 *****************************************************************************/
44 static int Open ( vlc_object_t * );
45 static void Close ( vlc_object_t * );
47 /*****************************************************************************
48 * Module descriptor
49 *****************************************************************************/
50 #define DST_PREFIX_TEXT N_("Destination prefix")
51 #define DST_PREFIX_LONGTEXT N_( \
52 "Prefix of the destination file automatically generated" )
54 #define SOUT_CFG_PREFIX "sout-record-"
56 vlc_module_begin ()
57 set_description( N_("Record stream output") )
58 set_capability( "sout stream", 0 )
59 add_shortcut( "record" )
60 set_shortname( N_("Record") )
62 set_category( CAT_SOUT )
63 set_subcategory( SUBCAT_SOUT_STREAM )
65 add_string( SOUT_CFG_PREFIX "dst-prefix", "", DST_PREFIX_TEXT,
66 DST_PREFIX_LONGTEXT, true )
68 set_callbacks( Open, Close )
69 vlc_module_end ()
71 /* */
72 static const char *const ppsz_sout_options[] = {
73 "dst-prefix",
74 NULL
77 /* */
78 static sout_stream_id_sys_t *Add( sout_stream_t *, const es_format_t * );
79 static void Del ( sout_stream_t *, sout_stream_id_sys_t * );
80 static int Send( sout_stream_t *, sout_stream_id_sys_t *, block_t* );
82 /* */
83 struct sout_stream_id_sys_t
85 es_format_t fmt;
87 block_t *p_first;
88 block_t **pp_last;
90 sout_stream_id_sys_t *id;
92 bool b_wait_key;
93 bool b_wait_start;
96 struct sout_stream_sys_t
98 char *psz_prefix;
100 sout_stream_t *p_out;
102 mtime_t i_date_start;
103 size_t i_size;
105 mtime_t i_max_wait;
106 size_t i_max_size;
108 bool b_drop;
110 int i_id;
111 sout_stream_id_sys_t **id;
112 mtime_t i_dts_start;
115 static void OutputStart( sout_stream_t *p_stream );
116 static void OutputSend( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t * );
118 /*****************************************************************************
119 * Open:
120 *****************************************************************************/
121 static int Open( vlc_object_t *p_this )
123 sout_stream_t *p_stream = (sout_stream_t*)p_this;
124 sout_stream_sys_t *p_sys;
126 p_stream->pf_add = Add;
127 p_stream->pf_del = Del;
128 p_stream->pf_send = Send;
130 p_stream->p_sys = p_sys = malloc( sizeof(*p_sys) );
131 if( !p_sys )
132 return VLC_ENOMEM;
134 config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg );
136 p_sys->p_out = NULL;
137 p_sys->psz_prefix = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "dst-prefix" );
138 if( !p_sys->psz_prefix )
140 p_sys->psz_prefix = strdup( "sout-record-" );
141 if( !p_sys->psz_prefix )
143 free( p_sys );
144 return VLC_ENOMEM;
148 p_sys->i_date_start = -1;
149 p_sys->i_size = 0;
150 #ifdef OPTIMIZE_MEMORY
151 p_sys->i_max_wait = 5*CLOCK_FREQ; /* 5s */
152 p_sys->i_max_size = 1*1024*1024; /* 1 MiB */
153 #else
154 p_sys->i_max_wait = 30*CLOCK_FREQ; /* 30s */
155 p_sys->i_max_size = 20*1024*1024; /* 20 MiB */
156 #endif
157 p_sys->b_drop = false;
158 p_sys->i_dts_start = 0;
159 TAB_INIT( p_sys->i_id, p_sys->id );
161 return VLC_SUCCESS;
164 /*****************************************************************************
165 * Close:
166 *****************************************************************************/
167 static void Close( vlc_object_t * p_this )
169 sout_stream_t *p_stream = (sout_stream_t*)p_this;
170 sout_stream_sys_t *p_sys = p_stream->p_sys;
172 if( p_sys->p_out )
173 sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );
175 TAB_CLEAN( p_sys->i_id, p_sys->id );
176 free( p_sys->psz_prefix );
177 free( p_sys );
180 /*****************************************************************************
182 *****************************************************************************/
183 static sout_stream_id_sys_t *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
185 sout_stream_sys_t *p_sys = p_stream->p_sys;
186 sout_stream_id_sys_t *id;
188 id = malloc( sizeof(*id) );
189 if( !id )
190 return NULL;
192 es_format_Copy( &id->fmt, p_fmt );
193 id->p_first = NULL;
194 id->pp_last = &id->p_first;
195 id->id = NULL;
196 id->b_wait_key = true;
197 id->b_wait_start = true;
199 TAB_APPEND( p_sys->i_id, p_sys->id, id );
201 return id;
204 static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
206 sout_stream_sys_t *p_sys = p_stream->p_sys;
208 if( !p_sys->p_out )
209 OutputStart( p_stream );
211 if( id->p_first )
212 block_ChainRelease( id->p_first );
214 assert( !id->id || p_sys->p_out );
215 if( id->id )
216 sout_StreamIdDel( p_sys->p_out, id->id );
218 es_format_Clean( &id->fmt );
220 TAB_REMOVE( p_sys->i_id, p_sys->id, id );
222 if( p_sys->i_id <= 0 )
224 if( !p_sys->p_out )
225 p_sys->b_drop = false;
228 free( id );
231 static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
232 block_t *p_buffer )
234 sout_stream_sys_t *p_sys = p_stream->p_sys;
236 if( p_sys->i_date_start < 0 )
237 p_sys->i_date_start = mdate();
238 if( !p_sys->p_out &&
239 ( mdate() - p_sys->i_date_start > p_sys->i_max_wait ||
240 p_sys->i_size > p_sys->i_max_size ) )
242 msg_Dbg( p_stream, "Starting recording, waited %ds and %dbyte",
243 (int)((mdate() - p_sys->i_date_start)/1000000), (int)p_sys->i_size );
244 OutputStart( p_stream );
247 OutputSend( p_stream, id, p_buffer );
249 return VLC_SUCCESS;
252 /*****************************************************************************
254 *****************************************************************************/
255 typedef struct
257 const char psz_muxer[4];
258 const char psz_extension[4];
259 int i_es_max;
260 vlc_fourcc_t codec[128];
261 } muxer_properties_t;
263 #define M(muxer, ext, count, ... ) { .psz_muxer = muxer, .psz_extension = ext, .i_es_max = count, .codec = { __VA_ARGS__, 0 } }
264 /* Table of native codec support,
265 * Do not do non native and non standard association !
266 * Muxer will be probe if no entry found */
267 static const muxer_properties_t p_muxers[] = {
268 M( "raw", "mp3", 1, VLC_CODEC_MPGA ),
269 M( "raw", "a52", 1, VLC_CODEC_A52 ),
270 M( "raw", "dts", 1, VLC_CODEC_DTS ),
271 M( "raw", "mpc", 1, VLC_CODEC_MUSEPACK7, VLC_CODEC_MUSEPACK8 ),
272 M( "raw", "ape", 1, VLC_CODEC_APE ),
274 M( "wav", "wav", 1, VLC_CODEC_U8, VLC_CODEC_S16L,
275 VLC_CODEC_S24L, VLC_CODEC_S32L, VLC_CODEC_FL32 ),
277 //M( "avformat{mux=flac}", "flac", 1, VLC_CODEC_FLAC ), BROKEN
279 M( "ogg", "ogg", INT_MAX, VLC_CODEC_VORBIS, VLC_CODEC_SPEEX, VLC_CODEC_FLAC,
280 VLC_CODEC_SUBT, VLC_CODEC_THEORA, VLC_CODEC_DIRAC,
281 VLC_CODEC_OPUS ),
283 M( "asf", "asf", 127, VLC_CODEC_WMA1, VLC_CODEC_WMA2, VLC_CODEC_WMAP, VLC_CODEC_WMAL, VLC_CODEC_WMAS,
284 VLC_CODEC_WMV1, VLC_CODEC_WMV2, VLC_CODEC_WMV3, VLC_CODEC_VC1 ),
286 M( "mp4", "mp4", INT_MAX, VLC_CODEC_MP4A, VLC_CODEC_H264, VLC_CODEC_MP4V, VLC_CODEC_HEVC,
287 VLC_CODEC_SUBT ),
289 M( "ps", "mpg", 16/* FIXME*/,VLC_CODEC_MPGV,
290 VLC_CODEC_MPGA, VLC_CODEC_DVD_LPCM, VLC_CODEC_A52,
291 VLC_CODEC_DTS,
292 VLC_CODEC_SPU ),
294 M( "avi", "avi", 100, VLC_CODEC_A52, VLC_CODEC_MPGA,
295 VLC_CODEC_WMA1, VLC_CODEC_WMA2, VLC_CODEC_WMAP, VLC_CODEC_WMAL,
296 VLC_CODEC_U8, VLC_CODEC_S16L, VLC_CODEC_S24L,
297 VLC_CODEC_MP4V ),
299 M( "ts", "ts", 8000, VLC_CODEC_MPGV,
300 VLC_CODEC_H264, VLC_CODEC_HEVC,
301 VLC_CODEC_MPGA, VLC_CODEC_DVD_LPCM, VLC_CODEC_A52,
302 VLC_CODEC_DTS, VLC_CODEC_MP4A,
303 VLC_CODEC_DVBS, VLC_CODEC_TELETEXT ),
305 M( "mkv", "mkv", 32, VLC_CODEC_H264, VLC_CODEC_HEVC, VLC_CODEC_VP8, VLC_CODEC_MP4V,
306 VLC_CODEC_A52, VLC_CODEC_MP4A, VLC_CODEC_VORBIS, VLC_CODEC_FLAC ),
308 #undef M
310 static int OutputNew( sout_stream_t *p_stream,
311 const char *psz_muxer, const char *psz_prefix, const char *psz_extension )
313 sout_stream_sys_t *p_sys = p_stream->p_sys;
314 char *psz_file = NULL, *psz_tmp = NULL;
315 char *psz_output = NULL;
316 int i_count;
318 if( asprintf( &psz_tmp, "%s%s%s",
319 psz_prefix, psz_extension ? "." : "", psz_extension ? psz_extension : "" ) < 0 )
321 goto error;
324 psz_file = config_StringEscape( psz_tmp );
325 if( !psz_file )
327 free( psz_tmp );
328 goto error;
330 free( psz_tmp );
332 if( asprintf( &psz_output,
333 "std{access=file{no-append,no-format,no-overwrite},"
334 "mux='%s',dst='%s'}", psz_muxer, psz_file ) < 0 )
336 psz_output = NULL;
337 goto error;
340 /* Create the output */
341 msg_Dbg( p_stream, "Using record output `%s'", psz_output );
343 p_sys->p_out = sout_StreamChainNew( p_stream->p_sout, psz_output, NULL, NULL );
345 if( !p_sys->p_out )
346 goto error;
348 /* Add es */
349 i_count = 0;
350 for( int i = 0; i < p_sys->i_id; i++ )
352 sout_stream_id_sys_t *id = p_sys->id[i];
354 id->id = sout_StreamIdAdd( p_sys->p_out, &id->fmt );
355 if( id->id )
356 i_count++;
359 if( psz_file && psz_extension )
360 var_SetString( p_stream->obj.libvlc, "record-file", psz_file );
362 free( psz_file );
363 free( psz_output );
365 return i_count;
367 error:
369 free( psz_file );
370 free( psz_output );
371 return -1;
375 static void OutputStart( sout_stream_t *p_stream )
377 sout_stream_sys_t *p_sys = p_stream->p_sys;
379 /* */
380 if( p_sys->b_drop )
381 return;
383 /* From now on drop packet that cannot be handled */
384 p_sys->b_drop = true;
386 /* Detect streams to smart select muxer */
387 const char *psz_muxer = NULL;
388 const char *psz_extension = NULL;
390 /* Look for preferred muxer
391 * TODO we could insert transcode in a few cases like
392 * s16l <-> s16b
394 for( unsigned i = 0; i < sizeof(p_muxers) / sizeof(*p_muxers); i++ )
396 bool b_ok;
397 if( p_sys->i_id > p_muxers[i].i_es_max )
398 continue;
400 b_ok = true;
401 for( int j = 0; j < p_sys->i_id; j++ )
403 es_format_t *p_fmt = &p_sys->id[j]->fmt;
405 b_ok = false;
406 for( int k = 0; p_muxers[i].codec[k] != 0; k++ )
408 if( p_fmt->i_codec == p_muxers[i].codec[k] )
410 b_ok = true;
411 break;
414 if( !b_ok )
415 break;
417 if( !b_ok )
418 continue;
420 psz_muxer = p_muxers[i].psz_muxer;
421 psz_extension = p_muxers[i].psz_extension;
422 break;
425 /* If failed, brute force our demuxers and select the one that
426 * keeps most of our stream */
427 if( !psz_muxer || !psz_extension )
429 static const char ppsz_muxers[][2][4] = {
430 { "avi", "avi" }, { "mp4", "mp4" }, { "ogg", "ogg" },
431 { "asf", "asf" }, { "ts", "ts" }, { "ps", "mpg" },
432 { "mkv", "mkv" },
433 #if 0
434 // XXX ffmpeg sefault really easily if you try an unsupported codec
435 // mov and avi at least segfault
436 { "avformat{mux=avi}", "avi" },
437 { "avformat{mux=mov}", "mov" },
438 { "avformat{mux=mp4}", "mp4" },
439 { "avformat{mux=nsv}", "nsv" },
440 { "avformat{mux=flv}", "flv" },
441 #endif
443 int i_best = 0;
444 int i_best_es = 0;
446 msg_Warn( p_stream, "failed to find an adequate muxer, probing muxers" );
447 for( unsigned i = 0; i < sizeof(ppsz_muxers) / sizeof(*ppsz_muxers); i++ )
449 char *psz_file;
450 int i_es;
452 psz_file = tempnam( NULL, "vlc" );
453 if( !psz_file )
454 continue;
456 msg_Dbg( p_stream, "probing muxer %s", ppsz_muxers[i][0] );
457 i_es = OutputNew( p_stream, ppsz_muxers[i][0], psz_file, NULL );
459 if( i_es < 0 )
461 vlc_unlink( psz_file );
462 free( psz_file );
463 continue;
466 /* */
467 for( int j = 0; j < p_sys->i_id; j++ )
469 sout_stream_id_sys_t *id = p_sys->id[j];
471 if( id->id )
472 sout_StreamIdDel( p_sys->p_out, id->id );
473 id->id = NULL;
475 if( p_sys->p_out )
476 sout_StreamChainDelete( p_sys->p_out, p_sys->p_out );
477 p_sys->p_out = NULL;
479 if( i_es > i_best_es )
481 i_best_es = i_es;
482 i_best = i;
484 if( i_best_es >= p_sys->i_id )
485 break;
487 vlc_unlink( psz_file );
488 free( psz_file );
491 /* */
492 psz_muxer = ppsz_muxers[i_best][0];
493 psz_extension = ppsz_muxers[i_best][1];
494 msg_Dbg( p_stream, "using muxer %s with extension %s (%d/%d streams accepted)",
495 psz_muxer, psz_extension, i_best_es, p_sys->i_id );
498 /* Create the output */
499 if( OutputNew( p_stream, psz_muxer, p_sys->psz_prefix, psz_extension ) < 0 )
501 msg_Err( p_stream, "failed to open output");
502 return;
505 /* Compute highest timestamp of first I over all streams */
506 p_sys->i_dts_start = 0;
507 mtime_t i_highest_head_dts = 0;
508 for( int i = 0; i < p_sys->i_id; i++ )
510 sout_stream_id_sys_t *id = p_sys->id[i];
512 if( !id->id || !id->p_first )
513 continue;
515 const block_t *p_block = id->p_first;
516 mtime_t i_dts = p_block->i_dts;
518 if( i_dts > i_highest_head_dts &&
519 ( id->fmt.i_cat == AUDIO_ES || id->fmt.i_cat == VIDEO_ES ) )
521 i_highest_head_dts = i_dts;
524 for( ; p_block != NULL; p_block = p_block->p_next )
526 if( p_block->i_flags & BLOCK_FLAG_TYPE_I )
528 i_dts = p_block->i_dts;
529 break;
533 if( i_dts > p_sys->i_dts_start )
534 p_sys->i_dts_start = i_dts;
537 if( p_sys->i_dts_start == 0 )
538 p_sys->i_dts_start = i_highest_head_dts;
540 sout_stream_id_sys_t *p_cand;
543 /* dequeue candidate */
544 p_cand = NULL;
546 /* Send buffered data in dts order */
547 for( int i = 0; i < p_sys->i_id; i++ )
549 sout_stream_id_sys_t *id = p_sys->id[i];
551 if( !id->id || id->p_first == NULL )
552 continue;
554 if( p_cand == NULL || id->p_first->i_dts < p_cand->p_first->i_dts )
555 p_cand = id;
558 if( p_cand != NULL )
560 block_t *p_block = p_cand->p_first;
561 p_cand->p_first = p_block->p_next;
562 if( p_cand->p_first == NULL )
563 p_cand->pp_last = &p_cand->p_first;
564 p_block->p_next = NULL;
566 if( p_block->i_dts >= p_sys->i_dts_start )
567 OutputSend( p_stream, p_cand, p_block );
568 else
569 block_Release( p_block );
572 } while( p_cand != NULL );
575 static void OutputSend( sout_stream_t *p_stream, sout_stream_id_sys_t *id, block_t *p_block )
577 sout_stream_sys_t *p_sys = p_stream->p_sys;
579 if( id->id )
581 /* We wait until the first key frame (if needed) and
582 * to be beyong i_dts_start (for stream without key frame) */
583 if( unlikely( id->b_wait_key ) )
585 if( p_block->i_flags & BLOCK_FLAG_TYPE_I )
587 id->b_wait_key = false;
588 id->b_wait_start = false;
591 if( ( p_block->i_flags & BLOCK_FLAG_TYPE_MASK ) == 0 )
592 id->b_wait_key = false;
594 if( unlikely( id->b_wait_start ) )
596 if( p_block->i_dts >=p_sys->i_dts_start )
597 id->b_wait_start = false;
599 if( unlikely( id->b_wait_key || id->b_wait_start ) )
600 block_ChainRelease( p_block );
601 else
602 sout_StreamIdSend( p_sys->p_out, id->id, p_block );
604 else if( p_sys->b_drop )
606 block_ChainRelease( p_block );
608 else
610 size_t i_size;
612 block_ChainProperties( p_block, NULL, &i_size, NULL );
613 p_sys->i_size += i_size;
614 block_ChainLastAppend( &id->pp_last, p_block );