]> git.sesse.net Git - vlc/blob - modules/demux/avformat/mux.c
58109f939be532258bc906e7cfd9c3d061c57c0c
[vlc] / modules / demux / avformat / mux.c
1 /*****************************************************************************
2  * mux.c: muxer using libavformat
3  *****************************************************************************
4  * Copyright (C) 2006 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@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_block.h>
34 #include <vlc_sout.h>
35
36 #include <libavformat/avformat.h>
37
38 #include "avformat.h"
39 #include "../../codec/avcodec/avcodec.h"
40 #include "../../codec/avcodec/avcommon.h"
41
42
43 //#define AVFORMAT_DEBUG 1
44
45 static const char *const ppsz_mux_options[] = {
46     "mux", "options", NULL
47 };
48
49 /*****************************************************************************
50  * mux_sys_t: mux descriptor
51  *****************************************************************************/
52 struct sout_mux_sys_t
53 {
54     AVIOContext     *io;
55     int             io_buffer_size;
56     uint8_t        *io_buffer;
57
58     AVFormatContext *oc;
59
60     bool     b_write_header;
61     bool     b_error;
62 };
63
64 /*****************************************************************************
65  * Local prototypes
66  *****************************************************************************/
67 static int Control  ( sout_mux_t *, int, va_list );
68 static int AddStream( sout_mux_t *, sout_input_t * );
69 static int DelStream( sout_mux_t *, sout_input_t * );
70 static int Mux      ( sout_mux_t * );
71
72 static int IOWrite( void *opaque, uint8_t *buf, int buf_size );
73 static int64_t IOSeek( void *opaque, int64_t offset, int whence );
74
75 /*****************************************************************************
76  * Open
77  *****************************************************************************/
78 int OpenMux( vlc_object_t *p_this )
79 {
80     AVOutputFormat *file_oformat;
81     sout_mux_t *p_mux = (sout_mux_t*)p_this;
82     sout_mux_sys_t *p_sys;
83     char *psz_mux;
84
85     vlc_init_avformat();
86
87     config_ChainParse( p_mux, "sout-avformat-", ppsz_mux_options, p_mux->p_cfg );
88
89     /* Find the requested muxer */
90     psz_mux = var_GetNonEmptyString( p_mux, "sout-avformat-mux" );
91     if( psz_mux )
92     {
93         file_oformat = av_guess_format( psz_mux, NULL, NULL );
94         free( psz_mux );
95     }
96     else
97     {
98         file_oformat =
99             av_guess_format( NULL, p_mux->p_access->psz_path, NULL);
100     }
101     if (!file_oformat)
102     {
103       msg_Err( p_mux, "unable for find a suitable output format" );
104       return VLC_EGENERIC;
105     }
106
107     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
108     if( !p_sys )
109         return VLC_ENOMEM;
110
111     p_sys->oc = avformat_alloc_context();
112     p_sys->oc->oformat = file_oformat;
113     /* If we use dummy access, let avformat write output */
114     if( !strcmp( p_mux->p_access->psz_access, "dummy") )
115         strcpy( p_sys->oc->filename, p_mux->p_access->psz_path );
116
117     /* Create I/O wrapper */
118     p_sys->io_buffer_size = 32768;  /* FIXME */
119     p_sys->io_buffer = malloc( p_sys->io_buffer_size );
120
121     p_sys->io = avio_alloc_context(
122         p_sys->io_buffer, p_sys->io_buffer_size,
123         0, p_mux, NULL, IOWrite, IOSeek );
124
125     p_sys->oc->pb = p_sys->io;
126     p_sys->oc->nb_streams = 0;
127
128     p_sys->b_write_header = true;
129     p_sys->b_error = false;
130
131     /* Fill p_mux fields */
132     p_mux->pf_control   = Control;
133     p_mux->pf_addstream = AddStream;
134     p_mux->pf_delstream = DelStream;
135     p_mux->pf_mux       = Mux;
136
137     return VLC_SUCCESS;
138 }
139
140 /*****************************************************************************
141  * Close
142  *****************************************************************************/
143 void CloseMux( vlc_object_t *p_this )
144 {
145     sout_mux_t *p_mux = (sout_mux_t*)p_this;
146     sout_mux_sys_t *p_sys = p_mux->p_sys;
147
148     if( !p_sys->b_write_header && !p_sys->b_error && av_write_trailer( p_sys->oc ) < 0 )
149     {
150         msg_Err( p_mux, "could not write trailer" );
151     }
152
153     avformat_free_context(p_sys->oc);
154
155     free( p_sys->io_buffer );
156     free( p_sys );
157 }
158
159 /*****************************************************************************
160  * AddStream
161  *****************************************************************************/
162 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
163 {
164     sout_mux_sys_t *p_sys = p_mux->p_sys;
165     AVCodecContext *codec;
166     AVStream *stream;
167     int i_codec_id;
168
169     msg_Dbg( p_mux, "adding input" );
170
171     if( !GetFfmpegCodec( p_input->p_fmt->i_codec, 0, &i_codec_id, 0 ) )
172     {
173         msg_Dbg( p_mux, "couldn't find codec for fourcc '%4.4s'",
174                  (char *)&p_input->p_fmt->i_codec );
175         return VLC_EGENERIC;
176     }
177
178     p_input->p_sys = malloc( sizeof( int ) );
179     *((int *)p_input->p_sys) = p_sys->oc->nb_streams;
180
181     if( p_input->p_fmt->i_cat != VIDEO_ES && p_input->p_fmt->i_cat != AUDIO_ES)
182     {
183         msg_Warn( p_mux, "Unhandled ES category" );
184         return VLC_EGENERIC;
185     }
186
187     stream = avformat_new_stream( p_sys->oc, NULL);
188     if( !stream )
189     {
190         free( p_input->p_sys );
191         return VLC_EGENERIC;
192     }
193     codec = stream->codec;
194
195     codec->opaque = p_mux;
196
197     switch( p_input->p_fmt->i_cat )
198     {
199     case AUDIO_ES:
200         codec->codec_type = AVMEDIA_TYPE_AUDIO;
201         codec->channels = p_input->p_fmt->audio.i_channels;
202         codec->sample_rate = p_input->p_fmt->audio.i_rate;
203         codec->time_base = (AVRational){1, codec->sample_rate};
204         codec->frame_size = p_input->p_fmt->audio.i_frame_length;
205         break;
206
207     case VIDEO_ES:
208         if( !p_input->p_fmt->video.i_frame_rate ||
209             !p_input->p_fmt->video.i_frame_rate_base )
210         {
211             msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
212             p_input->p_fmt->video.i_frame_rate = 25;
213             p_input->p_fmt->video.i_frame_rate_base = 1;
214         }
215         codec->codec_type = AVMEDIA_TYPE_VIDEO;
216         codec->width = p_input->p_fmt->video.i_width;
217         codec->height = p_input->p_fmt->video.i_height;
218         av_reduce( &codec->sample_aspect_ratio.num,
219                    &codec->sample_aspect_ratio.den,
220                    p_input->p_fmt->video.i_sar_num,
221                    p_input->p_fmt->video.i_sar_den, 1 << 30 /* something big */ );
222         stream->sample_aspect_ratio.den = codec->sample_aspect_ratio.den;
223         stream->sample_aspect_ratio.num = codec->sample_aspect_ratio.num;
224         codec->time_base.den = p_input->p_fmt->video.i_frame_rate;
225         codec->time_base.num = p_input->p_fmt->video.i_frame_rate_base;
226         break;
227
228     }
229
230     codec->bit_rate = p_input->p_fmt->i_bitrate;
231     codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id );
232     if( !codec->codec_tag && i_codec_id == AV_CODEC_ID_MP2 )
233     {
234         i_codec_id = AV_CODEC_ID_MP3;
235         codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id );
236     }
237     codec->codec_id = i_codec_id;
238
239     if( p_input->p_fmt->i_extra )
240     {
241         codec->extradata_size = p_input->p_fmt->i_extra;
242         codec->extradata = av_malloc( p_input->p_fmt->i_extra );
243         memcpy( codec->extradata, p_input->p_fmt->p_extra,
244                 p_input->p_fmt->i_extra );
245     }
246
247     return VLC_SUCCESS;
248 }
249
250 /*****************************************************************************
251  * DelStream
252  *****************************************************************************/
253 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
254 {
255     msg_Dbg( p_mux, "removing input" );
256     free( p_input->p_sys );
257     return VLC_SUCCESS;
258 }
259
260 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
261 {
262     sout_mux_sys_t *p_sys = p_mux->p_sys;
263     block_t *p_data = block_FifoGet( p_input->p_fifo );
264     int i_stream = *((int *)p_input->p_sys);
265     AVStream *p_stream = p_sys->oc->streams[i_stream];
266     AVPacket pkt;
267
268     memset( &pkt, 0, sizeof(AVPacket) );
269
270     av_init_packet(&pkt);
271     pkt.data = p_data->p_buffer;
272     pkt.size = p_data->i_buffer;
273     pkt.stream_index = i_stream;
274
275     if( p_data->i_flags & BLOCK_FLAG_TYPE_I ) pkt.flags |= AV_PKT_FLAG_KEY;
276
277     if( p_data->i_pts > 0 )
278         pkt.pts = p_data->i_pts * p_stream->time_base.den /
279             INT64_C(1000000) / p_stream->time_base.num;
280     if( p_data->i_dts > 0 )
281         pkt.dts = p_data->i_dts * p_stream->time_base.den /
282             INT64_C(1000000) / p_stream->time_base.num;
283
284     /* this is another hack to prevent libavformat from triggering the "non monotone timestamps" check in avformat/utils.c */
285     p_stream->cur_dts = ( p_data->i_dts * p_stream->time_base.den /
286             INT64_C(1000000) / p_stream->time_base.num ) - 1;
287
288     if( av_write_frame( p_sys->oc, &pkt ) < 0 )
289     {
290         msg_Err( p_mux, "could not write frame (pts: %"PRId64", dts: %"PRId64") "
291                  "(pkt pts: %"PRId64", dts: %"PRId64")",
292                  p_data->i_pts, p_data->i_dts, pkt.pts, pkt.dts );
293         block_Release( p_data );
294         return VLC_EGENERIC;
295     }
296
297     block_Release( p_data );
298     return VLC_SUCCESS;
299 }
300
301 /*****************************************************************************
302  * Mux: multiplex available data in input fifos
303  *****************************************************************************/
304 static int Mux( sout_mux_t *p_mux )
305 {
306     sout_mux_sys_t *p_sys = p_mux->p_sys;
307
308     if( p_sys->b_error ) return VLC_EGENERIC;
309
310     if( p_sys->b_write_header )
311     {
312         int error;
313         msg_Dbg( p_mux, "writing header" );
314
315         char *psz_opts = var_GetNonEmptyString( p_mux, "sout-avformat-options" );
316         AVDictionary *options = NULL;
317         if (psz_opts && *psz_opts)
318             options = vlc_av_get_options(psz_opts);
319         free(psz_opts);
320         error = avformat_write_header( p_sys->oc, options ? &options : NULL);
321         AVDictionaryEntry *t = NULL;
322         while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) {
323             msg_Err( p_mux, "Unknown option \"%s\"", t->key );
324         }
325         av_dict_free(&options);
326         if( error < 0 )
327         {
328             errno = AVUNERROR(error);
329             msg_Err( p_mux, "could not write header: %m" );
330             p_sys->b_write_header = false;
331             p_sys->b_error = true;
332             return VLC_EGENERIC;
333         }
334
335         avio_flush( p_sys->oc->pb );
336         p_sys->b_write_header = false;
337     }
338
339     for( ;; )
340     {
341         mtime_t i_dts;
342
343         int i_stream = sout_MuxGetStream( p_mux, 1, &i_dts );
344         if( i_stream < 0 )
345             return VLC_SUCCESS;
346
347         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
348     }
349
350     return VLC_SUCCESS;
351 }
352
353 /*****************************************************************************
354  * Control:
355  *****************************************************************************/
356 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
357 {
358     bool *pb_bool;
359
360     switch( i_query )
361     {
362     case MUX_CAN_ADD_STREAM_WHILE_MUXING:
363         pb_bool = (bool*)va_arg( args, bool * );
364         *pb_bool = false;
365         return VLC_SUCCESS;
366
367     case MUX_GET_ADD_STREAM_WAIT:
368         pb_bool = (bool*)va_arg( args, bool * );
369         *pb_bool = true;
370         return VLC_SUCCESS;
371
372     case MUX_GET_MIME:
373     {
374         char **ppsz = (char**)va_arg( args, char ** );
375         *ppsz = strdup( p_mux->p_sys->oc->oformat->mime_type );
376         return VLC_SUCCESS;
377     }
378
379     default:
380         return VLC_EGENERIC;
381     }
382 }
383
384 /*****************************************************************************
385  * I/O wrappers for libavformat
386  *****************************************************************************/
387 static int IOWrite( void *opaque, uint8_t *buf, int buf_size )
388 {
389     sout_mux_t *p_mux = opaque;
390     int i_ret;
391
392 #ifdef AVFORMAT_DEBUG
393     msg_Dbg( p_mux, "IOWrite %i bytes", buf_size );
394 #endif
395
396     block_t *p_buf = block_Alloc( buf_size );
397     if( buf_size > 0 ) memcpy( p_buf->p_buffer, buf, buf_size );
398
399     if( p_mux->p_sys->b_write_header )
400         p_buf->i_flags |= BLOCK_FLAG_HEADER;
401
402     i_ret = sout_AccessOutWrite( p_mux->p_access, p_buf );
403     return i_ret ? i_ret : -1;
404 }
405
406 static int64_t IOSeek( void *opaque, int64_t offset, int whence )
407 {
408     sout_mux_t *p_mux = opaque;
409
410 #ifdef AVFORMAT_DEBUG
411     msg_Dbg( p_mux, "IOSeek offset: %"PRId64", whence: %i", offset, whence );
412 #endif
413
414     switch( whence )
415     {
416     case SEEK_SET:
417         return sout_AccessOutSeek( p_mux->p_access, offset );
418     case SEEK_CUR:
419     case SEEK_END:
420     default:
421         return -1;
422     }
423 }