packetizer: hevc: don't double store poc prev msb/lsb
[vlc.git] / modules / stream_out / duplicate.c
blob983004d82f03960a695340adf2b08762437dd92e
1 /*****************************************************************************
2 * duplicate.c: duplicate stream output module
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
5 * $Id$
7 * Author: 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 <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_sout.h>
35 #include <vlc_block.h>
37 /*****************************************************************************
38 * Module descriptor
39 *****************************************************************************/
40 static int Open ( vlc_object_t * );
41 static void Close ( vlc_object_t * );
43 vlc_module_begin ()
44 set_description( N_("Duplicate stream output") )
45 set_capability( "sout stream", 50 )
46 add_shortcut( "duplicate", "dup" )
47 set_category( CAT_SOUT )
48 set_subcategory( SUBCAT_SOUT_STREAM )
49 set_callbacks( Open, Close )
50 vlc_module_end ()
53 /*****************************************************************************
54 * Exported prototypes
55 *****************************************************************************/
56 static sout_stream_id_sys_t *Add( sout_stream_t *, const es_format_t * );
57 static void Del ( sout_stream_t *, sout_stream_id_sys_t * );
58 static int Send( sout_stream_t *, sout_stream_id_sys_t *,
59 block_t* );
61 struct sout_stream_sys_t
63 int i_nb_streams;
64 sout_stream_t **pp_streams;
66 int i_nb_last_streams;
67 sout_stream_t **pp_last_streams;
69 int i_nb_select;
70 char **ppsz_select;
73 struct sout_stream_id_sys_t
75 int i_nb_ids;
76 void **pp_ids;
79 static bool ESSelected( const es_format_t *fmt, char *psz_select );
81 /*****************************************************************************
82 * Open:
83 *****************************************************************************/
84 static int Open( vlc_object_t *p_this )
86 sout_stream_t *p_stream = (sout_stream_t*)p_this;
87 sout_stream_sys_t *p_sys;
88 config_chain_t *p_cfg;
90 msg_Dbg( p_stream, "creating 'duplicate'" );
92 p_sys = malloc( sizeof( sout_stream_sys_t ) );
93 if( !p_sys )
94 return VLC_ENOMEM;
96 TAB_INIT( p_sys->i_nb_streams, p_sys->pp_streams );
97 TAB_INIT( p_sys->i_nb_last_streams, p_sys->pp_last_streams );
98 TAB_INIT( p_sys->i_nb_select, p_sys->ppsz_select );
100 for( p_cfg = p_stream->p_cfg; p_cfg != NULL; p_cfg = p_cfg->p_next )
102 if( !strncmp( p_cfg->psz_name, "dst", strlen( "dst" ) ) )
104 sout_stream_t *s, *p_last;
106 msg_Dbg( p_stream, " * adding `%s'", p_cfg->psz_value );
107 s = sout_StreamChainNew( p_stream->p_sout, p_cfg->psz_value,
108 p_stream->p_next, &p_last );
110 if( s )
112 TAB_APPEND( p_sys->i_nb_streams, p_sys->pp_streams, s );
113 TAB_APPEND( p_sys->i_nb_last_streams, p_sys->pp_last_streams,
114 p_last );
115 TAB_APPEND( p_sys->i_nb_select, p_sys->ppsz_select, NULL );
118 else if( !strncmp( p_cfg->psz_name, "select", strlen( "select" ) ) )
120 char *psz = p_cfg->psz_value;
121 if( p_sys->i_nb_select > 0 && psz && *psz )
123 char **ppsz_select = &p_sys->ppsz_select[p_sys->i_nb_select - 1];
125 if( *ppsz_select )
127 msg_Err( p_stream, " * ignore selection `%s' (it already has `%s')",
128 psz, *ppsz_select );
130 else
132 msg_Dbg( p_stream, " * apply selection `%s'", psz );
133 *ppsz_select = strdup( psz );
137 else
139 msg_Err( p_stream, " * ignore unknown option `%s'", p_cfg->psz_name );
143 if( p_sys->i_nb_streams == 0 )
145 msg_Err( p_stream, "no destination given" );
146 free( p_sys );
148 return VLC_EGENERIC;
151 p_stream->pf_add = Add;
152 p_stream->pf_del = Del;
153 p_stream->pf_send = Send;
155 p_stream->p_sys = p_sys;
157 return VLC_SUCCESS;
160 /*****************************************************************************
161 * Close:
162 *****************************************************************************/
163 static void Close( vlc_object_t * p_this )
165 sout_stream_t *p_stream = (sout_stream_t*)p_this;
166 sout_stream_sys_t *p_sys = p_stream->p_sys;
168 msg_Dbg( p_stream, "closing a duplication" );
169 for( int i = 0; i < p_sys->i_nb_streams; i++ )
171 sout_StreamChainDelete(p_sys->pp_streams[i], p_sys->pp_last_streams[i]);
172 free( p_sys->ppsz_select[i] );
174 free( p_sys->pp_streams );
175 free( p_sys->pp_last_streams );
176 free( p_sys->ppsz_select );
178 free( p_sys );
181 /*****************************************************************************
182 * Add:
183 *****************************************************************************/
184 static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
186 sout_stream_sys_t *p_sys = p_stream->p_sys;
187 sout_stream_id_sys_t *id;
188 int i_stream, i_valid_streams = 0;
190 id = malloc( sizeof( sout_stream_id_sys_t ) );
191 if( !id )
192 return NULL;
194 TAB_INIT( id->i_nb_ids, id->pp_ids );
196 msg_Dbg( p_stream, "duplicated a new stream codec=%4.4s (es=%d group=%d)",
197 (char*)&p_fmt->i_codec, p_fmt->i_id, p_fmt->i_group );
199 for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
201 void *id_new = NULL;
203 if( ESSelected( p_fmt, p_sys->ppsz_select[i_stream] ) )
205 sout_stream_t *out = p_sys->pp_streams[i_stream];
207 id_new = (void*)sout_StreamIdAdd( out, p_fmt );
208 if( id_new )
210 msg_Dbg( p_stream, " - added for output %d", i_stream );
211 i_valid_streams++;
213 else
215 msg_Dbg( p_stream, " - failed for output %d", i_stream );
218 else
220 msg_Dbg( p_stream, " - ignored for output %d", i_stream );
223 /* Append failed attempts as well to keep track of which pp_id
224 * belongs to which duplicated stream */
225 TAB_APPEND( id->i_nb_ids, id->pp_ids, id_new );
228 if( i_valid_streams <= 0 )
230 Del( p_stream, id );
231 return NULL;
234 return id;
237 /*****************************************************************************
238 * Del:
239 *****************************************************************************/
240 static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
242 sout_stream_sys_t *p_sys = p_stream->p_sys;
243 int i_stream;
245 for( i_stream = 0; i_stream < p_sys->i_nb_streams; i_stream++ )
247 if( id->pp_ids[i_stream] )
249 sout_stream_t *out = p_sys->pp_streams[i_stream];
250 sout_StreamIdDel( out, id->pp_ids[i_stream] );
254 free( id->pp_ids );
255 free( id );
258 /*****************************************************************************
259 * Send:
260 *****************************************************************************/
261 static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
262 block_t *p_buffer )
264 sout_stream_sys_t *p_sys = p_stream->p_sys;
265 sout_stream_t *p_dup_stream;
266 int i_stream;
268 /* Loop through the linked list of buffers */
269 while( p_buffer )
271 block_t *p_next = p_buffer->p_next;
273 p_buffer->p_next = NULL;
275 for( i_stream = 0; i_stream < p_sys->i_nb_streams - 1; i_stream++ )
277 p_dup_stream = p_sys->pp_streams[i_stream];
279 if( id->pp_ids[i_stream] )
281 block_t *p_dup = block_Duplicate( p_buffer );
283 if( p_dup )
284 sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_dup );
288 if( i_stream < p_sys->i_nb_streams && id->pp_ids[i_stream] )
290 p_dup_stream = p_sys->pp_streams[i_stream];
291 sout_StreamIdSend( p_dup_stream, id->pp_ids[i_stream], p_buffer );
293 else
295 block_Release( p_buffer );
298 p_buffer = p_next;
300 return VLC_SUCCESS;
303 /*****************************************************************************
304 * Divers
305 *****************************************************************************/
306 static bool NumInRange( const char *psz_range, int i_num )
308 int beginRange, endRange;
309 int res = sscanf(psz_range, "%d-%d", &beginRange, &endRange);
310 if (res == 0)
311 return false;
312 else if (res == 1)
313 return beginRange == i_num;
314 return (i_num >= beginRange && i_num <= endRange)
315 || (beginRange > endRange && (i_num <= beginRange && i_num >= endRange));
318 static bool ESSelected( const es_format_t *fmt, char *psz_select )
320 char *psz_dup;
321 char *psz;
323 /* We have tri-state variable : no tested (-1), failed(0), succeed(1) */
324 int i_cat = -1;
325 int i_es = -1;
326 int i_prgm= -1;
328 /* If empty all es are selected */
329 if( psz_select == NULL || *psz_select == '\0' )
331 return true;
333 psz_dup = strdup( psz_select );
334 if( !psz_dup )
335 return false;
336 psz = psz_dup;
338 /* If non empty, parse the selection:
339 * We have selection[,selection[,..]] where following selection are recognized:
340 * (no(-))audio
341 * (no(-))spu
342 * (no(-))video
343 * (no(-))es=[start]-[end] or es=num
344 * (no(-))prgm=[start]-[end] or prgm=num (program works too)
345 * if a negative test failed we exit directly
347 while( psz && *psz )
349 char *p;
351 /* Skip space */
352 while( *psz == ' ' || *psz == '\t' ) psz++;
354 /* Search end */
355 p = strchr( psz, ',' );
356 if( p == psz )
358 /* Empty */
359 psz = p + 1;
360 continue;
362 if( p )
364 *p++ = '\0';
367 if( !strncmp( psz, "no-audio", strlen( "no-audio" ) ) ||
368 !strncmp( psz, "noaudio", strlen( "noaudio" ) ) )
370 if( i_cat == -1 )
372 i_cat = fmt->i_cat != AUDIO_ES ? 1 : 0;
375 else if( !strncmp( psz, "no-video", strlen( "no-video" ) ) ||
376 !strncmp( psz, "novideo", strlen( "novideo" ) ) )
378 if( i_cat == -1 )
380 i_cat = fmt->i_cat != VIDEO_ES ? 1 : 0;
383 else if( !strncmp( psz, "no-spu", strlen( "no-spu" ) ) ||
384 !strncmp( psz, "nospu", strlen( "nospu" ) ) )
386 if( i_cat == -1 )
388 i_cat = fmt->i_cat != SPU_ES ? 1 : 0;
391 else if( !strncmp( psz, "audio", strlen( "audio" ) ) )
393 if( i_cat == -1 )
395 i_cat = fmt->i_cat == AUDIO_ES ? 1 : 0;
398 else if( !strncmp( psz, "video", strlen( "video" ) ) )
400 if( i_cat == -1 )
402 i_cat = fmt->i_cat == VIDEO_ES ? 1 : 0;
405 else if( !strncmp( psz, "spu", strlen( "spu" ) ) )
407 if( i_cat == -1 )
409 i_cat = fmt->i_cat == SPU_ES ? 1 : 0;
412 else if( strchr( psz, '=' ) != NULL )
414 char *psz_arg = strchr( psz, '=' );
415 *psz_arg++ = '\0';
417 if( !strcmp( psz, "no-es" ) || !strcmp( psz, "noes" ) )
419 if( i_es == -1 )
421 i_es = NumInRange( psz_arg, fmt->i_id ) ? 0 : -1;
424 else if( !strcmp( psz, "es" ) )
426 if( i_es == -1 )
428 i_es = NumInRange( psz_arg, fmt->i_id) ? 1 : -1;
431 else if( !strcmp( psz, "no-prgm" ) || !strcmp( psz, "noprgm" ) ||
432 !strcmp( psz, "no-program" ) || !strcmp( psz, "noprogram" ) )
434 if( fmt->i_group >= 0 && i_prgm == -1 )
436 i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 0 : -1;
439 else if( !strcmp( psz, "prgm" ) || !strcmp( psz, "program" ) )
441 if( fmt->i_group >= 0 && i_prgm == -1 )
443 i_prgm = NumInRange( psz_arg, fmt->i_group ) ? 1 : -1;
447 else
449 fprintf( stderr, "unknown args (%s)\n", psz );
451 /* Next */
452 psz = p;
455 free( psz_dup );
457 if( i_cat == 1 || i_es == 1 || i_prgm == 1 )
459 return true;
461 return false;