1 /*****************************************************************************
2 * delay.c: delay a stream
3 *****************************************************************************
4 * Copyright © 2014 VLC authors and VideoLAN
6 * Authors: Ilkka Ollakka <ileoo at videolan dot org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
33 #include <vlc_block.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 #define OUTPUT_TEXT N_("Output file")
41 #define OUTPUT_LONGTEXT N_( \
42 "Writes stats to file instead of stdout" )
43 #define PREFIX_TEXT N_("Prefix to show on output line")
45 static int Open ( vlc_object_t
* );
46 static void Close ( vlc_object_t
* );
48 #define SOUT_CFG_PREFIX "sout-stats-"
51 set_shortname( N_("Stats"))
52 set_description( N_("Writes statistic info about stream"))
53 set_capability( "sout stream", 0 )
54 add_shortcut( "stats" )
55 set_category( CAT_SOUT
)
56 set_subcategory( SUBCAT_SOUT_STREAM
)
57 set_callbacks( Open
, Close
)
58 add_string( SOUT_CFG_PREFIX
"output", "", OUTPUT_TEXT
,OUTPUT_LONGTEXT
, false );
59 add_string( SOUT_CFG_PREFIX
"prefix", "stats", PREFIX_TEXT
,PREFIX_TEXT
, false );
63 /*****************************************************************************
65 *****************************************************************************/
66 static const char *ppsz_sout_options
[] = {
67 "output", "prefix", NULL
70 static sout_stream_id_sys_t
*Add( sout_stream_t
*, const es_format_t
* );
71 static void Del ( sout_stream_t
*, sout_stream_id_sys_t
* );
72 static int Send ( sout_stream_t
*, sout_stream_id_sys_t
*, block_t
* );
74 struct sout_stream_sys_t
80 struct sout_stream_id_sys_t
83 uint64_t segment_number
;
86 mtime_t previous_dts
,track_duration
;
90 /*****************************************************************************
92 *****************************************************************************/
93 static int Open( vlc_object_t
*p_this
)
95 sout_stream_t
*p_stream
= (sout_stream_t
*)p_this
;
96 sout_stream_sys_t
*p_sys
;
99 p_sys
= calloc( 1, sizeof( sout_stream_sys_t
) );
104 config_ChainParse( p_stream
, SOUT_CFG_PREFIX
, ppsz_sout_options
,
108 outputFile
= var_InheritString( p_stream
, SOUT_CFG_PREFIX
"output" );
112 p_sys
->output
= vlc_fopen( outputFile
, "wt" );
115 msg_Err( p_stream
, "Unable to open file '%s' for writing", outputFile
);
120 fprintf( p_sys
->output
,"#prefix\ttrack\ttype\tsegment_number\tdts_difference\tlength\tmd5\n");
124 p_sys
->prefix
= var_InheritString( p_stream
, SOUT_CFG_PREFIX
"prefix" );
126 p_stream
->p_sys
= p_sys
;
128 p_stream
->pf_add
= Add
;
129 p_stream
->pf_del
= Del
;
130 p_stream
->pf_send
= Send
;
136 /*****************************************************************************
138 *****************************************************************************/
139 static void Close( vlc_object_t
* p_this
)
141 sout_stream_t
*p_stream
= (sout_stream_t
*)p_this
;
142 sout_stream_sys_t
*p_sys
= (sout_stream_sys_t
*)p_stream
->p_sys
;
145 fclose( p_sys
->output
);
147 free( p_sys
->prefix
);
151 static sout_stream_id_sys_t
* Add( sout_stream_t
*p_stream
, const es_format_t
*p_fmt
)
153 sout_stream_sys_t
*p_sys
= (sout_stream_sys_t
*)p_stream
->p_sys
;
154 sout_stream_id_sys_t
*id
;
156 id
= malloc( sizeof( sout_stream_id_sys_t
) );
157 if( unlikely( !id
) )
160 id
->id
= p_fmt
->i_id
;
161 switch( p_fmt
->i_cat
)
177 id
->segment_number
= 0;
178 id
->previous_dts
= VLC_TS_INVALID
;
179 id
->track_duration
= 0;
180 InitMD5( &id
->hash
);
182 msg_Dbg( p_stream
, "%s: Adding track type:%s id:%d", p_sys
->prefix
, id
->type
, id
->id
);
184 if( p_stream
->p_next
)
185 id
->next_id
= sout_StreamIdAdd( p_stream
->p_next
, p_fmt
);
190 static void Del( sout_stream_t
*p_stream
, sout_stream_id_sys_t
*id
)
192 sout_stream_sys_t
*p_sys
= (sout_stream_sys_t
*)p_stream
->p_sys
;
195 char *outputhash
= psz_md5_hash( &id
->hash
);
196 unsigned int num
,den
;
197 vlc_ureduce( &num
, &den
, id
->track_duration
, id
->segment_number
, 0 );
198 msg_Dbg( p_stream
, "%s: Removing track type:%s id:%d", p_sys
->prefix
, id
->type
, id
->id
);
201 fprintf( p_sys
->output
,"#%s: final type:%s id:%d segments:%"PRIu64
" total_duration:%"PRId64
" avg_track:%d/%d md5:%16s\n",
202 p_sys
->prefix
, id
->type
, id
->id
, id
->segment_number
, id
->track_duration
, num
, den
, outputhash
);
204 msg_Info( p_stream
, "%s: final type:%s id:%d segments:%"PRIu64
" total_duration:%"PRId64
" avg_track:%d/%d md5:%16s",
205 p_sys
->prefix
, id
->type
, id
->id
, id
->segment_number
, id
->track_duration
, num
, den
, outputhash
);
208 if( id
->next_id
) sout_StreamIdDel( p_stream
->p_next
, id
->next_id
);
212 static int Send( sout_stream_t
*p_stream
, sout_stream_id_sys_t
*id
,
215 sout_stream_sys_t
*p_sys
= (sout_stream_sys_t
*)p_stream
->p_sys
;
218 block_t
*p_block
= p_buffer
;
219 while ( p_block
!= NULL
)
222 AddMD5( &hash
, p_block
->p_buffer
, p_block
->i_buffer
);
223 AddMD5( &id
->hash
, p_block
->p_buffer
, p_block
->i_buffer
);
225 char *outputhash
= psz_md5_hash( &hash
);
227 /* We could just set p_sys->output to stdout and remove user of msg_Dbg
228 * if we don't need ability to output info to gui modules (like qt messages window
230 mtime_t dts_difference
= VLC_TS_INVALID
;
231 if( likely( id
->previous_dts
!= VLC_TS_INVALID
) )
232 dts_difference
= p_block
->i_dts
- id
->previous_dts
;
235 /* Write data in a form that it's easy to plot for example with gnuplot*/
236 fprintf( p_sys
->output
, "%s\t%d\t%s\t%"PRIu64
"\t%"PRId64
"\t%"PRId64
"\t%16s\n",
237 p_sys
->prefix
, id
->id
, id
->type
, ++id
->segment_number
, dts_difference
,
238 p_block
->i_length
, outputhash
);
241 msg_Dbg( p_stream
, "%s: track:%d type:%s segment_number:%"PRIu64
" dts_difference:%"PRId64
" length:%"PRId64
" md5:%16s",
242 p_sys
->prefix
, id
->id
, id
->type
, ++id
->segment_number
, dts_difference
,
243 p_block
->i_length
, outputhash
);
245 id
->track_duration
+= p_block
->i_length
? p_block
->i_length
: dts_difference
;
247 id
->previous_dts
= p_block
->i_dts
;
248 p_block
= p_block
->p_next
;
251 if( p_stream
->p_next
)
252 return sout_StreamIdSend( p_stream
->p_next
, id
->next_id
, p_buffer
);
254 block_Release( p_buffer
);