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