]> git.sesse.net Git - vlc/blob - modules/stream_out/stats.c
direct3d11: catch texture mapping errors
[vlc] / modules / stream_out / stats.c
1 /*****************************************************************************
2  * delay.c: delay a stream
3  *****************************************************************************
4  * Copyright © 2014 VLC authors and VideoLAN
5  *
6  * Authors: Ilkka Ollakka <ileoo at videolan dot org>
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_sout.h>
33 #include <vlc_block.h>
34 #include <vlc_md5.h>
35 #include <vlc_fs.h>
36
37 /*****************************************************************************
38  * Module descriptor
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")
44
45 static int  Open    ( vlc_object_t * );
46 static void Close   ( vlc_object_t * );
47
48 #define SOUT_CFG_PREFIX "sout-stats-"
49
50 vlc_module_begin()
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 );
60 vlc_module_end()
61
62
63 /*****************************************************************************
64  * Local prototypes
65  *****************************************************************************/
66 static const char *ppsz_sout_options[] = {
67     "output", "prefix", NULL
68 };
69
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 * );
73
74 struct sout_stream_sys_t
75 {
76     FILE *output;
77     char *prefix;
78 };
79
80 struct sout_stream_id_sys_t
81 {
82     int id;
83     uint64_t segment_number;
84     void *next_id;
85     const char *type;
86     mtime_t previous_dts,track_duration;
87     struct md5_s hash;
88 };
89
90 /*****************************************************************************
91  * Open:
92  *****************************************************************************/
93 static int Open( vlc_object_t *p_this )
94 {
95     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
96     sout_stream_sys_t *p_sys;
97     char              *outputFile;
98
99     p_sys = calloc( 1, sizeof( sout_stream_sys_t ) );
100     if( !p_sys )
101         return VLC_ENOMEM;
102
103
104     config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
105                    p_stream->p_cfg );
106
107
108     outputFile = var_InheritString( p_stream, SOUT_CFG_PREFIX "output" );
109
110     if( outputFile )
111     {
112         p_sys->output = vlc_fopen( outputFile, "wt" );
113         if( !p_sys->output )
114         {
115             msg_Err( p_stream, "Unable to open file '%s' for writing", outputFile );
116             free( p_sys );
117             free( outputFile );
118             return VLC_EGENERIC;
119         } else {
120             fprintf( p_sys->output,"#prefix\ttrack\ttype\tsegment_number\tdts_difference\tlength\tmd5\n");
121         }
122         free( outputFile );
123     }
124     p_sys->prefix = var_InheritString( p_stream, SOUT_CFG_PREFIX "prefix" );
125
126     p_stream->p_sys     = p_sys;
127
128     p_stream->pf_add    = Add;
129     p_stream->pf_del    = Del;
130     p_stream->pf_send   = Send;
131
132
133     return VLC_SUCCESS;
134 }
135
136 /*****************************************************************************
137  * Close:
138  *****************************************************************************/
139 static void Close( vlc_object_t * p_this )
140 {
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;
143
144     if( p_sys->output )
145         fclose( p_sys->output );
146
147     free( p_sys->prefix );
148     free( p_sys );
149 }
150
151 static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
152 {
153     sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
154     sout_stream_id_sys_t *id;
155
156     id = malloc( sizeof( sout_stream_id_sys_t ) );
157     if( unlikely( !id ) )
158         return NULL;
159
160     id->id = p_fmt->i_id;
161     switch( p_fmt->i_cat)
162     {
163     case VIDEO_ES:
164         id->type = "Video";
165         break;
166     case AUDIO_ES:
167         id->type = "Audio";
168         break;
169     case SPU_ES:
170         id->type = "SPU";
171         break;
172     default:
173         id->type = "Data";
174         break;
175     }
176     id->next_id = NULL;
177     id->segment_number = 0;
178     id->previous_dts = VLC_TS_INVALID;
179     id->track_duration = 0;
180     InitMD5( &id->hash );
181
182     msg_Dbg( p_stream, "%s: Adding track type:%s id:%d", p_sys->prefix, id->type, id->id);
183
184     if( p_stream->p_next )
185         id->next_id = sout_StreamIdAdd( p_stream->p_next, p_fmt );
186
187     return id;
188 }
189
190 static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
191 {
192     sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
193
194     EndMD5( &id->hash );
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 );
199     if( p_sys->output )
200     {
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 );
203     } else {
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 );
206     }
207     free( outputhash );
208     if( id->next_id ) sout_StreamIdDel( p_stream->p_next, id->next_id );
209     free( id );
210 }
211
212 static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
213                  block_t *p_buffer )
214 {
215     sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;
216     struct md5_s hash;
217
218     block_t *p_block = p_buffer;
219     while ( p_block != NULL )
220     {
221         InitMD5( &hash );
222         AddMD5( &hash, p_block->p_buffer, p_block->i_buffer );
223         AddMD5( &id->hash, p_block->p_buffer, p_block->i_buffer );
224         EndMD5( &hash );
225         char *outputhash = psz_md5_hash( &hash );
226
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 qt4 messages window
229          */
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;
233         if( p_sys->output )
234         {
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 );
239
240         } else {
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 );
244         }
245         id->track_duration += p_block->i_length ? p_block->i_length : dts_difference;
246         free( outputhash );
247         id->previous_dts = p_block->i_dts;
248         p_block = p_block->p_next;
249     }
250
251     if( p_stream->p_next )
252         return sout_StreamIdSend( p_stream->p_next, id->next_id, p_buffer );
253     else
254         block_Release( p_buffer );
255     return VLC_SUCCESS;
256 }