root/modules/demux/avformat/mux.c

Revision f7d5f3e7cab176a0d68b736e05dece392d611161, 15.3 kB (checked in by Antoine Cellerier <dionoea@videolan.org>, 6 months ago)

Move avcodec module files to modules/codec/avcodec. (The 3 shared
headers, avutil.h, chroma.h and fourcc.h are also located in that
directory.) This should be the last commit in the "Move all the old
ffmpeg modules source code files around to make it seem like you're
working while you're not".

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