]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/mux.c
Don't pretend to have ffmpeg based muxers and demuxers if you don't.
[vlc] / modules / codec / ffmpeg / mux.c
1 /*****************************************************************************
2  * mux.c: muxer using ffmpeg (libavformat).
3  *****************************************************************************
4  * Copyright (C) 2006 the VideoLAN team
5  * $Id: demux.c 8444 2004-08-17 08:21:07Z gbazin $
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #include <vlc/vlc.h>
29 #include <vlc_block.h>
30 #include <vlc_sout.h>
31
32 /* ffmpeg header */
33 #ifdef HAVE_FFMPEG_AVFORMAT_H
34 #   include <ffmpeg/avformat.h>
35 #elif defined(HAVE_LIBAVFORMAT_TREE)
36 #   include <avformat.h>
37 #endif
38
39 #include "ffmpeg.h"
40
41 //#define AVFORMAT_DEBUG 1
42
43 /* Version checking */
44 #if defined(HAVE_FFMPEG_AVFORMAT_H) || defined(HAVE_LIBAVFORMAT_TREE)
45
46 static const char *ppsz_mux_options[] = {
47     "mux", NULL
48 };
49
50 /*****************************************************************************
51  * mux_sys_t: mux descriptor
52  *****************************************************************************/
53 struct sout_mux_sys_t
54 {
55     ByteIOContext   io;
56     int             io_buffer_size;
57     uint8_t        *io_buffer;
58
59     AVFormatContext *oc;
60     URLContext     url;
61     URLProtocol    prot;
62
63     vlc_bool_t     b_write_header;
64     vlc_bool_t     b_error;
65
66     int64_t        i_initial_dts;
67 };
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72 static int Control  ( sout_mux_t *, int, va_list );
73 static int AddStream( sout_mux_t *, sout_input_t * );
74 static int DelStream( sout_mux_t *, sout_input_t * );
75 static int Mux      ( sout_mux_t * );
76
77 static int IOWrite( void *opaque, uint8_t *buf, int buf_size );
78 static offset_t IOSeek( void *opaque, offset_t offset, int whence );
79
80 /*****************************************************************************
81  * Open
82  *****************************************************************************/
83 int E_(OpenMux)( vlc_object_t *p_this )
84 {
85     AVOutputFormat *file_oformat;
86     sout_mux_t *p_mux = (sout_mux_t*)p_this;
87     sout_mux_sys_t *p_sys;
88     AVFormatParameters params, *ap = &params;
89     char *psz_mux;
90
91     /* Should we call it only once ? */
92     av_register_all();
93     av_log_set_callback( E_(LibavcodecCallback) );
94
95     config_ChainParse( p_mux, "ffmpeg-", ppsz_mux_options, p_mux->p_cfg );
96
97     /* Find the requested muxer */
98     psz_mux = var_GetNonEmptyString( p_mux, "ffmpeg-mux" );
99     if( psz_mux )
100     {
101         file_oformat = guess_format( psz_mux, NULL, NULL );
102     }
103     else
104     {
105         file_oformat =
106             guess_format(NULL, p_mux->p_access->psz_path, NULL);
107     }
108     if (!file_oformat)
109     {
110       msg_Err( p_mux, "unable for find a suitable output format" );
111       return VLC_EGENERIC;
112     }
113
114     /* Fill p_mux fields */
115     p_mux->pf_control   = Control;
116     p_mux->pf_addstream = AddStream;
117     p_mux->pf_delstream = DelStream;
118     p_mux->pf_mux       = Mux;
119     p_mux->p_sys = p_sys = malloc( sizeof( sout_mux_sys_t ) );
120
121     p_sys->oc = av_alloc_format_context();
122     p_sys->oc->oformat = file_oformat;
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     p_sys->url.priv_data = p_mux;
128     p_sys->url.prot = &p_sys->prot;
129     p_sys->url.prot->name = "VLC I/O wrapper";
130     p_sys->url.prot->url_open = 0;
131     p_sys->url.prot->url_read = 0;
132     p_sys->url.prot->url_write =
133                     (int (*) (URLContext *, unsigned char *, int))IOWrite;
134     p_sys->url.prot->url_seek =
135                     (offset_t (*) (URLContext *, offset_t, int))IOSeek;
136     p_sys->url.prot->url_close = 0;
137     p_sys->url.prot->next = 0;
138     init_put_byte( &p_sys->io, p_sys->io_buffer, p_sys->io_buffer_size,
139                    1, &p_sys->url, NULL, IOWrite, IOSeek );
140
141     memset( ap, 0, sizeof(*ap) );
142     if( av_set_parameters( p_sys->oc, ap ) < 0 )
143     {
144         msg_Err( p_mux, "invalid encoding parameters" );
145         av_free( p_sys->oc );
146         free( p_sys->io_buffer );
147         free( p_sys );
148         return VLC_EGENERIC;
149     }
150
151 #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0)
152     p_sys->oc->pb = &p_sys->io;
153 #else
154     p_sys->oc->pb = p_sys->io;
155 #endif
156     p_sys->oc->nb_streams = 0;
157
158     p_sys->b_write_header = VLC_TRUE;
159     p_sys->b_error = VLC_FALSE;
160     p_sys->i_initial_dts = 0;
161
162     return VLC_SUCCESS;
163 }
164
165 /*****************************************************************************
166  * Close
167  *****************************************************************************/
168 void E_(CloseMux)( vlc_object_t *p_this )
169 {
170     sout_mux_t *p_mux = (sout_mux_t*)p_this;
171     sout_mux_sys_t *p_sys = p_mux->p_sys;
172     unsigned int i;
173
174     if( av_write_trailer( p_sys->oc ) < 0 )
175     {
176         msg_Err( p_mux, "could not write trailer" );
177     }
178
179     for( i = 0 ; i < p_sys->oc->nb_streams; i++ )
180     {
181         if( p_sys->oc->streams[i]->codec->extradata )
182             av_free( p_sys->oc->streams[i]->codec->extradata );
183         av_free( p_sys->oc->streams[i]->codec );
184         av_free( p_sys->oc->streams[i] );
185     }
186     av_free( p_sys->oc );
187
188     free( p_sys->io_buffer );
189     free( p_sys );
190 }
191
192 /*****************************************************************************
193  * AddStream
194  *****************************************************************************/
195 static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
196 {
197     sout_mux_sys_t *p_sys = p_mux->p_sys;
198     AVCodecContext *codec;
199     AVStream *stream;
200     int i_codec_id, i_aspect_num, i_aspect_den;
201
202     msg_Dbg( p_mux, "adding input" );
203
204     if( !E_(GetFfmpegCodec)( p_input->p_fmt->i_codec, 0, &i_codec_id, 0 ) )
205     {
206         msg_Dbg( p_mux, "couldn't find codec for fourcc '%4.4s'",
207                  (char *)&p_input->p_fmt->i_codec );
208         return VLC_EGENERIC;
209     }
210
211     p_input->p_sys = malloc( sizeof( int ) );
212     *((int *)p_input->p_sys) = p_sys->oc->nb_streams;
213
214     stream = av_new_stream( p_sys->oc, p_sys->oc->nb_streams);
215     if( !stream )
216     {
217         free( p_input->p_sys );
218         return VLC_EGENERIC;
219     }
220     codec = stream->codec;
221
222     /* This is used by LibavcodecCallback (ffmpeg.c) to print messages */
223     codec->opaque = (void*)p_mux;
224
225     switch( p_input->p_fmt->i_cat )
226     {
227     case AUDIO_ES:
228         codec->codec_type = CODEC_TYPE_AUDIO;
229         codec->channels = p_input->p_fmt->audio.i_channels;
230         codec->sample_rate = p_input->p_fmt->audio.i_rate;
231         codec->time_base = (AVRational){1, codec->sample_rate};
232         break;
233
234     case VIDEO_ES:
235         if( !p_input->p_fmt->video.i_frame_rate ||
236             !p_input->p_fmt->video.i_frame_rate_base )
237         {
238             msg_Warn( p_mux, "Missing frame rate, assuming 25fps" );
239             p_input->p_fmt->video.i_frame_rate = 25;
240             p_input->p_fmt->video.i_frame_rate_base = 1;
241         }
242         codec->codec_type = CODEC_TYPE_VIDEO;
243         codec->width = p_input->p_fmt->video.i_width;
244         codec->height = p_input->p_fmt->video.i_height;
245         av_reduce( &i_aspect_num, &i_aspect_den,
246                    p_input->p_fmt->video.i_aspect,
247                    VOUT_ASPECT_FACTOR, 1 << 30 /* something big */ );
248         av_reduce( &codec->sample_aspect_ratio.num,
249                    &codec->sample_aspect_ratio.den,
250                    i_aspect_num * (int64_t)codec->height,
251                    i_aspect_den * (int64_t)codec->width, 1 << 30 );
252         codec->time_base.den = p_input->p_fmt->video.i_frame_rate;
253         codec->time_base.num = p_input->p_fmt->video.i_frame_rate_base;
254         break;
255
256     default:
257         msg_Warn( p_mux, "Unhandled ES category" );
258     }
259
260     codec->bit_rate = p_input->p_fmt->i_bitrate;
261 #if LIBAVFORMAT_VERSION_INT >= ((51<<16)+(8<<8)+0)
262     codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id );
263     if( !codec->codec_tag && i_codec_id == CODEC_ID_MP2 )
264     {
265         i_codec_id = CODEC_ID_MP3;
266         codec->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id );
267     }
268 #else
269 #   warning "WARNING!!!!!!!"
270 #   warning "Using libavformat muxing with versions older than 51.8.0 (r7593) might produce broken files."
271     /* This is a hack */
272     if( i_codec_id == CODEC_ID_MP2 )
273         i_codec_id = CODEC_ID_MP3;
274     codec->codec_tag = p_input->p_fmt->i_codec;
275 #endif
276     codec->codec_id = i_codec_id;
277
278     if( p_input->p_fmt->i_extra )
279     {
280         codec->extradata_size = p_input->p_fmt->i_extra;
281         codec->extradata = av_malloc( p_input->p_fmt->i_extra );
282         memcpy( codec->extradata, p_input->p_fmt->p_extra,
283                 p_input->p_fmt->i_extra );
284     }
285
286     return VLC_SUCCESS;
287 }
288
289 /*****************************************************************************
290  * DelStream
291  *****************************************************************************/
292 static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
293 {
294     msg_Dbg( p_mux, "removing input" );
295     free( p_input->p_sys );
296     return VLC_SUCCESS;
297 }
298
299 /*
300  * TODO  move this function to src/stream_output.c (used by nearly all muxers)
301  */
302 static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
303 {
304     mtime_t i_dts;
305     int     i_stream, i;
306
307     for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
308     {
309         block_fifo_t  *p_fifo;
310
311         p_fifo = p_mux->pp_inputs[i]->p_fifo;
312
313         /* We don't really need to have anything in the SPU fifo */
314         if( p_mux->pp_inputs[i]->p_fmt->i_cat == SPU_ES &&
315             block_FifoCount( p_fifo ) == 0 ) continue;
316
317         if( block_FifoCount( p_fifo ) )
318         {
319             block_t *p_buf;
320
321             p_buf = block_FifoShow( p_fifo );
322             if( i_stream < 0 || p_buf->i_dts < i_dts )
323             {
324                 i_dts = p_buf->i_dts;
325                 i_stream = i;
326             }
327         }
328         else return -1;
329
330     }
331     if( pi_stream ) *pi_stream = i_stream;
332     if( pi_dts ) *pi_dts = i_dts;
333     if( !p_mux->p_sys->i_initial_dts ) p_mux->p_sys->i_initial_dts = i_dts;
334     return i_stream;
335 }
336
337 static int MuxBlock( sout_mux_t *p_mux, sout_input_t *p_input )
338 {
339     sout_mux_sys_t *p_sys = p_mux->p_sys;
340     block_t *p_data = block_FifoGet( p_input->p_fifo );
341     int i_stream = *((int *)p_input->p_sys);
342     AVStream *p_stream = p_sys->oc->streams[i_stream];
343     AVPacket pkt;
344
345     memset( &pkt, 0, sizeof(AVPacket) );
346
347     av_init_packet(&pkt);
348     pkt.data = p_data->p_buffer;
349     pkt.size = p_data->i_buffer;
350     pkt.stream_index = i_stream;
351
352     if( p_data->i_flags & BLOCK_FLAG_TYPE_I ) pkt.flags |= PKT_FLAG_KEY;
353
354     /* avformat expects pts/dts which start from 0 */
355     p_data->i_dts -= p_mux->p_sys->i_initial_dts;
356     p_data->i_pts -= p_mux->p_sys->i_initial_dts;
357
358     if( p_data->i_pts > 0 )
359         pkt.pts = p_data->i_pts * p_stream->time_base.den /
360             I64C(1000000) / p_stream->time_base.num;
361     if( p_data->i_dts > 0 )
362         pkt.dts = p_data->i_dts * p_stream->time_base.den /
363             I64C(1000000) / p_stream->time_base.num;
364
365     /* this is another hack to prevent libavformat from triggering the "non monotone timestamps" check in avformat/utils.c */
366     p_stream->cur_dts = AV_NOPTS_VALUE;
367
368     if( av_write_frame( p_sys->oc, &pkt ) < 0 )
369     {
370         msg_Err( p_mux, "could not write frame (pts: "I64Fd", dts: "I64Fd") "
371                  "(pkt pts: "I64Fd", dts: "I64Fd")",
372                  p_data->i_pts, p_data->i_dts, pkt.pts, pkt.dts );
373         block_Release( p_data );
374         return VLC_EGENERIC;
375     }
376
377     block_Release( p_data );
378     return VLC_SUCCESS;
379 }
380
381 /*****************************************************************************
382  * Mux: multiplex available data in input fifos
383  *****************************************************************************/
384 static int Mux( sout_mux_t *p_mux )
385 {
386     sout_mux_sys_t *p_sys = p_mux->p_sys;
387     int i_stream;
388
389     if( p_sys->b_error ) return VLC_EGENERIC;
390
391     if( p_sys->b_write_header )
392     {
393         msg_Dbg( p_mux, "writing header" );
394
395         if( av_write_header( p_sys->oc ) < 0 )
396         {
397             msg_Err( p_mux, "could not write header" );
398             p_sys->b_write_header = VLC_FALSE;
399             p_sys->b_error = VLC_TRUE;
400             return VLC_EGENERIC;
401         }
402
403 #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0)
404         put_flush_packet( p_sys->oc->pb );
405 #else
406         put_flush_packet( &p_sys->oc->pb );
407 #endif
408         p_sys->b_write_header = VLC_FALSE;
409     }
410
411     for( ;; )
412     {
413         if( MuxGetStream( p_mux, &i_stream, 0 ) < 0 ) return VLC_SUCCESS;
414         MuxBlock( p_mux, p_mux->pp_inputs[i_stream] );
415     }
416
417     return VLC_SUCCESS;
418 }
419
420 /*****************************************************************************
421  * Control:
422  *****************************************************************************/
423 static int Control( sout_mux_t *p_mux, int i_query, va_list args )
424 {
425     vlc_bool_t *pb_bool;
426
427     switch( i_query )
428     {
429     case MUX_CAN_ADD_STREAM_WHILE_MUXING:
430         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
431         *pb_bool = VLC_FALSE;
432         return VLC_SUCCESS;
433
434     case MUX_GET_ADD_STREAM_WAIT:
435         pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
436         *pb_bool = VLC_TRUE;
437         return VLC_SUCCESS;
438
439     case MUX_GET_MIME:
440     {
441         char **ppsz = (char**)va_arg( args, char ** );
442         *ppsz = strdup( p_mux->p_sys->oc->oformat->mime_type );
443         return VLC_SUCCESS;
444     }
445
446     default:
447         return VLC_EGENERIC;
448     }
449 }
450
451 /*****************************************************************************
452  * I/O wrappers for libavformat
453  *****************************************************************************/
454 static int IOWrite( void *opaque, uint8_t *buf, int buf_size )
455 {
456     URLContext *p_url = opaque;
457     sout_mux_t *p_mux = p_url->priv_data;
458     int i_ret;
459
460 #ifdef AVFORMAT_DEBUG
461     msg_Dbg( p_mux, "IOWrite %i bytes", buf_size );
462 #endif
463
464     block_t *p_buf = block_New( p_mux->p_sout, buf_size );
465     if( buf_size > 0 ) memcpy( p_buf->p_buffer, buf, buf_size );
466
467     if( p_mux->p_sys->b_write_header )
468         p_buf->i_flags |= BLOCK_FLAG_HEADER;
469
470     i_ret = sout_AccessOutWrite( p_mux->p_access, p_buf );
471     return i_ret ? i_ret : -1;
472 }
473
474 static offset_t IOSeek( void *opaque, offset_t offset, int whence )
475 {
476     URLContext *p_url = opaque;
477     sout_mux_t *p_mux = p_url->priv_data;
478     int64_t i_absolute;
479
480 #ifdef AVFORMAT_DEBUG
481     msg_Dbg( p_mux, "IOSeek offset: "I64Fd", whence: %i", offset, whence );
482 #endif
483
484     switch( whence )
485     {
486     case SEEK_SET:
487         i_absolute = offset;
488         break;
489     case SEEK_CUR:
490     case SEEK_END:
491     default:
492         return -1;
493     }
494
495     if( sout_AccessOutSeek( p_mux->p_access, i_absolute ) )
496     {
497         return -1;
498     }
499
500     return 0;
501 }
502
503 #endif /* HAVE_FFMPEG_AVFORMAT_H */