]> git.sesse.net Git - vlc/blob - modules/stream_out/switcher.c
Merge branch 'master' of git@git.videolan.org:vlc
[vlc] / modules / stream_out / switcher.c
1 /*****************************************************************************
2  * switcher.c: MPEG2 video switcher module
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <math.h>
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_sout.h>
35 #include <vlc_vout.h>
36
37 #include <vlc_charset.h>
38 #include <vlc_network.h>
39
40 #define HAVE_MMX
41 #ifdef HAVE_LIBAVCODEC_AVCODEC_H
42 #   include <libavcodec/avcodec.h>
43 #elif defined(HAVE_FFMPEG_AVCODEC_H)
44 #   include <ffmpeg/avcodec.h>
45 #else
46 #   include <avcodec.h>
47 #endif
48
49 #ifdef HAVE_POSTPROC_POSTPROCESS_H
50 #   include <postproc/postprocess.h>
51 #else
52 #   include <libpostproc/postprocess.h>
53 #endif
54
55 #define SOUT_CFG_PREFIX "sout-switcher-"
56 #define MAX_PICTURES 10
57 #define MAX_AUDIO 30
58 #define MAX_THRESHOLD 99999999
59
60 /*****************************************************************************
61  * Local prototypes
62  *****************************************************************************/
63 static int      Open    ( vlc_object_t * );
64 static void     Close   ( vlc_object_t * );
65
66 static sout_stream_id_t *Add( sout_stream_t *, es_format_t * );
67 static int Del( sout_stream_t *, sout_stream_id_t * );
68 static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
69
70 static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
71                         mtime_t i_max_dts );
72 static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file,
73                            int i_width, int i_height,
74                            picture_t *p_pic );
75 static void NetCommand( sout_stream_t *p_stream );
76 static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id );
77 static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
78                                 block_t *p_buffer );
79 static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
80                                 block_t *p_buffer );
81
82 /*****************************************************************************
83  * Module descriptor
84  *****************************************************************************/
85 #define FILES_TEXT N_("Files")
86 #define FILES_LONGTEXT N_( \
87     "Full paths of the files separated by colons." )
88 #define SIZES_TEXT N_("Sizes")
89 #define SIZES_LONGTEXT N_( \
90     "List of sizes separated by colons (720x576:480x576)." )
91 #define RATIO_TEXT N_("Aspect ratio")
92 #define RATIO_LONGTEXT N_( \
93     "Aspect ratio (4:3, 16:9)." )
94 #define PORT_TEXT N_("Command UDP port")
95 #define PORT_LONGTEXT N_( \
96     "UDP port to listen to for commands." )
97 #define COMMAND_TEXT N_("Command")
98 #define COMMAND_LONGTEXT N_( \
99     "Initial command to execute." )
100 #define GOP_TEXT N_("GOP size")
101 #define GOP_LONGTEXT N_( \
102     "Number of P frames between two I frames." )
103 #define QSCALE_TEXT N_("Quantizer scale")
104 #define QSCALE_LONGTEXT N_( \
105     "Fixed quantizer scale to use." )
106 #define AUDIO_TEXT N_("Mute audio")
107 #define AUDIO_LONGTEXT N_( \
108     "Mute audio when command is not 0." )
109
110 vlc_module_begin();
111     set_description( _("MPEG2 video switcher stream output") );
112     set_capability( "sout stream", 50 );
113     add_shortcut( "switcher" );
114     set_callbacks( Open, Close );
115
116     add_string( SOUT_CFG_PREFIX "files", "", NULL, FILES_TEXT,
117                 FILES_LONGTEXT, false );
118     add_string( SOUT_CFG_PREFIX "sizes", "", NULL, SIZES_TEXT,
119                 SIZES_LONGTEXT, false );
120     add_string( SOUT_CFG_PREFIX "aspect-ratio", "4:3", NULL, RATIO_TEXT,
121                 RATIO_LONGTEXT, false );
122     add_integer( SOUT_CFG_PREFIX "port", 5001, NULL,
123                  PORT_TEXT, PORT_LONGTEXT, true );
124     add_integer( SOUT_CFG_PREFIX "command", 0, NULL,
125                  COMMAND_TEXT, COMMAND_LONGTEXT, true );
126     add_integer( SOUT_CFG_PREFIX "gop", 8, NULL,
127                  GOP_TEXT, GOP_LONGTEXT, true );
128     add_integer( SOUT_CFG_PREFIX "qscale", 5, NULL,
129                  QSCALE_TEXT, QSCALE_LONGTEXT, true );
130     add_bool( SOUT_CFG_PREFIX "mute-audio", 1, NULL,
131               AUDIO_TEXT, AUDIO_LONGTEXT, true );
132 vlc_module_end();
133
134 static const char *ppsz_sout_options[] = {
135     "files", "sizes", "aspect-ratio", "port", "command", "gop", "qscale",
136     "mute-audio", NULL
137 };
138
139 struct sout_stream_sys_t
140 {
141     sout_stream_t   *p_out;
142     int             i_gop;
143     int             i_qscale;
144     int             i_aspect;
145     sout_stream_id_t *pp_audio_ids[MAX_AUDIO];
146     bool      b_audio;
147
148     /* Pictures */
149     picture_t       p_pictures[MAX_PICTURES];
150     int             i_nb_pictures;
151
152     /* Command */
153     int             i_fd;
154     int             i_cmd, i_old_cmd;
155 };
156
157 struct sout_stream_id_t
158 {
159     void            *id;
160     bool      b_switcher_video;
161     bool      b_switcher_audio;
162     es_format_t     f_src;
163     block_t         *p_queued;
164
165     /* ffmpeg part */
166     AVCodec         *ff_enc;
167     AVCodecContext  *ff_enc_c;
168     AVFrame         *p_frame;
169     uint8_t         *p_buffer_out;
170     int             i_nb_pred;
171     int16_t         *p_samples;
172 };
173
174 /*****************************************************************************
175  * Open:
176  *****************************************************************************/
177 static int Open( vlc_object_t *p_this )
178 {
179     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
180     sout_stream_sys_t *p_sys;
181     vlc_value_t       val;
182     char              *psz_files, *psz_sizes;
183     int               i_height = 0, i_width = 0;
184
185     p_sys = malloc( sizeof(sout_stream_sys_t) );
186     memset( p_sys, 0, sizeof(sout_stream_sys_t) );
187
188     p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
189     if( !p_sys->p_out )
190     {
191         msg_Err( p_stream, "cannot create chain" );
192         free( p_sys );
193         return VLC_EGENERIC;
194     }
195
196     config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
197                    p_stream->p_cfg );
198
199     var_Get( p_stream, SOUT_CFG_PREFIX "files", &val );
200     psz_files = val.psz_string;
201     var_Get( p_stream, SOUT_CFG_PREFIX "sizes", &val );
202     psz_sizes = val.psz_string;
203
204     p_sys->i_nb_pictures = 0;
205     while ( psz_files && *psz_files )
206     {
207         char * psz_file = psz_files;
208         char * psz_size = psz_sizes;
209
210         while ( *psz_files && *psz_files != ':' )
211             psz_files++;
212         if ( *psz_files == ':' )
213            *psz_files++ = '\0';
214
215         if ( *psz_sizes )
216         {
217             while ( *psz_sizes && *psz_sizes != ':' )
218                 psz_sizes++;
219             if ( *psz_sizes == ':' )
220                 *psz_sizes++ = '\0';
221             if ( sscanf( psz_size, "%dx%d", &i_width, &i_height ) != 2 )
222             {
223                 msg_Err( p_stream, "bad size %s for file %s", psz_size,
224                          psz_file );
225                 free( p_sys );
226                 return VLC_EGENERIC;
227             }
228         }
229
230         if ( UnpackFromFile( p_stream, psz_file, i_width, i_height,
231                              &p_sys->p_pictures[p_sys->i_nb_pictures] ) < 0 )
232         {
233             free( p_sys );
234             return VLC_EGENERIC;
235         }
236         p_sys->i_nb_pictures++;
237     }
238
239     var_Get( p_stream, SOUT_CFG_PREFIX "aspect-ratio", &val );
240     if ( val.psz_string )
241     {
242         char *psz_parser = strchr( val.psz_string, ':' );
243
244         if( psz_parser )
245         {
246             *psz_parser++ = '\0';
247             p_sys->i_aspect = atoi( val.psz_string ) * VOUT_ASPECT_FACTOR
248                 / atoi( psz_parser );
249         }
250         else
251         {
252             msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
253             p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
254         }
255
256         free( val.psz_string );
257     }
258     else
259     {
260         p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
261     }
262
263     var_Get( p_stream, SOUT_CFG_PREFIX "port", &val );
264     p_sys->i_fd = net_ListenUDP1( p_stream, NULL, val.i_int );
265     if ( p_sys->i_fd < 0 )
266     {
267         free( p_sys );
268         return VLC_EGENERIC;
269     }
270
271     var_Get( p_stream, SOUT_CFG_PREFIX "command", &val );
272     p_sys->i_cmd = val.i_int;
273     p_sys->i_old_cmd = 0;
274
275     var_Get( p_stream, SOUT_CFG_PREFIX "gop", &val );
276     p_sys->i_gop = val.i_int;
277
278     var_Get( p_stream, SOUT_CFG_PREFIX "qscale", &val );
279     p_sys->i_qscale = val.i_int;
280
281     var_Get( p_stream, SOUT_CFG_PREFIX "mute-audio", &val );
282     p_sys->b_audio = val.b_bool;
283
284     p_stream->pf_add    = Add;
285     p_stream->pf_del    = Del;
286     p_stream->pf_send   = Send;
287     p_stream->p_sys     = p_sys;
288
289     avcodec_init();
290     avcodec_register_all();
291
292     return VLC_SUCCESS;
293 }
294
295 /*****************************************************************************
296  * Close:
297  *****************************************************************************/
298 static void Close( vlc_object_t * p_this )
299 {
300     sout_stream_t       *p_stream = (sout_stream_t *)p_this;
301     sout_stream_sys_t   *p_sys = p_stream->p_sys;
302
303     sout_StreamDelete( p_sys->p_out );
304
305     free( p_sys );
306 }
307
308 /*****************************************************************************
309  * Add: Add an input elementary stream
310  *****************************************************************************/
311 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
312 {
313     sout_stream_sys_t   *p_sys = p_stream->p_sys;
314     sout_stream_id_t    *id;
315
316     id = malloc( sizeof( sout_stream_id_t ) );
317     memset( id, 0, sizeof( sout_stream_id_t ) );
318     id->id = NULL;
319
320     if ( p_fmt->i_cat == VIDEO_ES
321             && (p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v')
322                  || p_fmt->i_codec == VLC_FOURCC('f', 'a', 'k', 'e')) )
323     {
324         id->b_switcher_video = true;
325         p_fmt->i_codec = VLC_FOURCC('m', 'p', 'g', 'v');
326         msg_Dbg( p_stream,
327                  "creating video switcher for fcc=`%4.4s' cmd:%d",
328                  (char*)&p_fmt->i_codec, p_sys->i_cmd );
329     }
330     else if ( p_fmt->i_cat == AUDIO_ES
331                && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'a')
332                && p_sys->b_audio )
333     {
334         int i_ff_codec = CODEC_ID_MP2;
335         int i;
336
337         id->b_switcher_audio = true;
338         msg_Dbg( p_stream,
339                  "creating audio switcher for fcc=`%4.4s' cmd:%d",
340                  (char*)&p_fmt->i_codec, p_sys->i_cmd );
341
342         /* Allocate the encoder right now. */
343         if( i_ff_codec == 0 )
344         {
345             msg_Err( p_stream, "cannot find encoder" );
346             return NULL;
347         }
348
349         id->ff_enc = avcodec_find_encoder( i_ff_codec );
350         if( !id->ff_enc )
351         {
352             msg_Err( p_stream, "cannot find encoder (avcodec)" );
353             return NULL;
354         }
355
356         id->ff_enc_c = avcodec_alloc_context();
357
358         /* Set CPU capabilities */
359         unsigned i_cpu = vlc_CPU();
360         id->ff_enc_c->dsp_mask = 0;
361         if( !(i_cpu & CPU_CAPABILITY_MMX) )
362         {
363             id->ff_enc_c->dsp_mask |= FF_MM_MMX;
364         }
365         if( !(i_cpu & CPU_CAPABILITY_MMXEXT) )
366         {
367             id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT;
368         }
369         if( !(i_cpu & CPU_CAPABILITY_3DNOW) )
370         {
371             id->ff_enc_c->dsp_mask |= FF_MM_3DNOW;
372         }
373         if( !(i_cpu & CPU_CAPABILITY_SSE) )
374         {
375             id->ff_enc_c->dsp_mask |= FF_MM_SSE;
376             id->ff_enc_c->dsp_mask |= FF_MM_SSE2;
377         }
378
379         id->ff_enc_c->sample_rate = p_fmt->audio.i_rate;
380         id->ff_enc_c->channels    = p_fmt->audio.i_channels;
381         id->ff_enc_c->bit_rate    = p_fmt->i_bitrate;
382
383         if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
384         {
385             msg_Err( p_stream, "cannot open encoder" );
386             return NULL;
387         }
388
389         id->p_buffer_out = malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * 2 );
390         id->p_samples = malloc( id->ff_enc_c->frame_size
391                                  * p_fmt->audio.i_channels * sizeof(int16_t) );
392         memset( id->p_samples, 0,
393                 id->ff_enc_c->frame_size * p_fmt->audio.i_channels
394                  * sizeof(int16_t) );
395
396         for ( i = 0; i < MAX_AUDIO; i++ )
397         {
398             if ( p_sys->pp_audio_ids[i] == NULL )
399             {
400                 p_sys->pp_audio_ids[i] = id;
401                 break;
402             }
403         }
404         if ( i == MAX_AUDIO )
405         {
406             msg_Err( p_stream, "too many audio streams!" );
407             free( id );
408             return NULL;
409         }
410     }
411     else
412     {
413         msg_Dbg( p_stream, "do not know what to do when switching (fcc=`%4.4s')",
414                  (char*)&p_fmt->i_codec );
415     }
416
417     /* src format */
418     memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) );
419
420     /* open output stream */
421     id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
422
423     if ( id->id == NULL )
424     {
425         free( id );
426         return NULL;
427     }
428
429     return id;
430 }
431
432 /*****************************************************************************
433  * Del: Del an elementary stream
434  *****************************************************************************/
435 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
436 {
437     sout_stream_sys_t   *p_sys = p_stream->p_sys;
438
439     if ( id->b_switcher_audio )
440     {
441         int i;
442         for ( i = 0; i < MAX_AUDIO; i++ )
443         {
444             if ( p_sys->pp_audio_ids[i] == id )
445             {
446                 p_sys->pp_audio_ids[i] = NULL;
447                 break;
448             }
449         }
450     }
451
452     if ( id->ff_enc )
453     {
454         avcodec_close( id->ff_enc_c );
455         av_free( id->ff_enc_c );
456         av_free( id->p_frame );
457         free( id->p_buffer_out );
458     }
459
460     if ( id->id )
461     {
462         p_sys->p_out->pf_del( p_sys->p_out, id->id );
463     }
464     free( id );
465
466     return VLC_SUCCESS;
467 }
468
469 /*****************************************************************************
470  * Send: Process an input packet
471  *****************************************************************************/
472 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
473                  block_t *p_buffer )
474 {
475     sout_stream_sys_t *p_sys = p_stream->p_sys;
476
477     if ( !id->id )
478     {
479         block_Release( p_buffer );
480         return VLC_EGENERIC;
481     }
482
483     if ( !id->b_switcher_video && !id->b_switcher_audio )
484     {
485         return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
486     }
487
488     block_ChainAppend( &id->p_queued, p_buffer );
489
490     if ( id->b_switcher_video )
491     {
492         /* Check for commands for every video frame. */
493         NetCommand( p_stream );
494
495         while ( id->p_queued != NULL )
496         {
497             mtime_t i_dts = 0;
498             int i;
499
500             if ( p_sys->i_old_cmd != p_sys->i_cmd )
501             {
502                 i_dts = VideoCommand( p_stream, id );
503             }
504
505             i_dts = Process( p_stream, id, i_dts );
506
507             for ( i = 0; i < MAX_AUDIO; i++ )
508             {
509                 if ( p_sys->pp_audio_ids[i] != NULL )
510                     Process( p_stream, p_sys->pp_audio_ids[i], i_dts );
511             }
512         }
513     }
514
515     return VLC_SUCCESS;
516 }
517
518 /*****************************************************************************
519  * Process: Process and dispatch buffers
520  *****************************************************************************/
521 static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
522                         mtime_t i_max_dts )
523 {
524     sout_stream_sys_t *p_sys = p_stream->p_sys;
525     mtime_t i_dts = 0;
526     block_t *p_blocks = NULL;
527     block_t *p_blocks_out = NULL;
528
529     /* Find out the blocks we need. */
530     while ( id->p_queued != NULL
531              && (!i_max_dts || id->p_queued->i_dts <= i_max_dts) )
532     {
533         block_t *p_next = id->p_queued->p_next;
534         id->p_queued->p_next = NULL;
535         i_dts = id->p_queued->i_dts;
536         block_ChainAppend( &p_blocks, id->p_queued );
537         id->p_queued = p_next;
538     }
539
540     if ( p_sys->i_old_cmd == 0 )
541     {
542         /* Full forward */
543         if ( p_blocks != NULL )
544             p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks );
545         return i_dts;
546     }
547
548     if ( p_sys->i_old_cmd == -1 )
549     {
550         /* No output at all */
551         while ( p_blocks != NULL )
552         {
553             block_t * p_next = p_blocks->p_next;
554             block_Release( p_blocks );
555             p_blocks = p_next;
556         }
557         return i_dts;
558     }
559
560     while ( p_blocks != NULL )
561     {
562         block_t * p_next = p_blocks->p_next;
563         block_t * p_out;
564
565         if ( id->b_switcher_video )
566         {
567             p_out = VideoGetBuffer( p_stream, id, p_blocks );
568         }
569         else
570         {
571             p_out = AudioGetBuffer( p_stream, id, p_blocks );
572         }
573         p_blocks = p_next;
574         if ( p_out != NULL )
575         {
576             block_ChainAppend( &p_blocks_out, p_out );
577         }
578     }
579
580     if ( p_blocks_out != NULL )
581         p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out );
582     return i_dts;
583 }
584
585 /*****************************************************************************
586  * UnpackFromFile: Read a YUV picture and store it in our format
587  *****************************************************************************/
588 static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file,
589                            int i_width, int i_height,
590                            picture_t *p_pic )
591 {
592     int i, j;
593     FILE *p_file = utf8_fopen( psz_file, "r" );
594
595     if ( p_file == NULL )
596     {
597         msg_Err( p_stream, "file %s not found", psz_file );
598         return -1;
599     }
600
601     vout_InitPicture( VLC_OBJECT(p_stream), p_pic, VLC_FOURCC('I','4','2','0'),
602                       i_width, i_height,
603                       i_width * VOUT_ASPECT_FACTOR / i_height );
604     for ( i = 0; i < p_pic->i_planes; i++ )
605     {
606         p_pic->p[i].p_pixels = malloc( p_pic->p[i].i_lines *
607                                            p_pic->p[i].i_pitch );
608         memset( p_pic->p[i].p_pixels, 0, p_pic->p[i].i_lines *
609                     p_pic->p[i].i_pitch );
610     }
611
612     for ( i = 0; i < i_height; i++ )
613     {
614         int i_chroma;
615         uint8_t p_buffer[i_width * 2];
616         uint8_t *p_char = p_buffer;
617         uint8_t *p_y = &p_pic->p[0].p_pixels[i * p_pic->p[0].i_pitch];
618         uint8_t *p_u = &p_pic->p[1].p_pixels[i/2 * p_pic->p[1].i_pitch];
619         uint8_t *p_v = &p_pic->p[2].p_pixels[i/2 * p_pic->p[2].i_pitch];
620
621         if ( fread( p_buffer, 2, i_width, p_file ) != (size_t)i_width )
622         {
623             msg_Err( p_stream, "premature end of file %s", psz_file );
624             fclose( p_file );
625             for ( i = 0; i < p_pic->i_planes; i++ )
626             {
627                 free( p_pic->p[i].p_pixels );
628             }
629             return -1;
630         }
631
632         i_chroma = 0;
633         for ( j = 0; j < i_width; j++ )
634         {
635             uint8_t **pp_chroma = i_chroma ? &p_v : &p_u;
636             i_chroma = !i_chroma;
637             if ( i & 1 )
638                 **pp_chroma = (**pp_chroma + *p_char + 1) / 2;
639             else
640                 **pp_chroma = *p_char;
641             (*pp_chroma)++;
642             p_char++;
643             *p_y++ = *p_char++;
644         }
645     }
646
647     fclose( p_file );
648     return 0;
649 }
650
651 /*****************************************************************************
652  * NetCommand: Get a command from the network
653  *****************************************************************************/
654 static void NetCommand( sout_stream_t *p_stream )
655 {
656     sout_stream_sys_t *p_sys = p_stream->p_sys;
657     char psz_buffer[11];
658     int i_len = recv( p_sys->i_fd, psz_buffer, sizeof( psz_buffer ) - 1, 0 );
659
660     if ( i_len > 0 )
661     {
662         psz_buffer[i_len] = '\0';
663         int i_cmd = strtol( psz_buffer, NULL, 0 );
664         if ( i_cmd < -1 || i_cmd > p_sys->i_nb_pictures )
665         {
666             msg_Err( p_stream, "got a wrong command (%d)", i_cmd );
667             return;
668         }
669
670         p_sys->i_cmd = i_cmd;
671
672         msg_Dbg( p_stream, "new command: %d old:%d", p_sys->i_cmd,
673                  p_sys->i_old_cmd );
674     }
675 }
676
677 /*****************************************************************************
678  * VideoCommand: Create/Delete a video encoder
679  *****************************************************************************/
680 static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id )
681 {
682     sout_stream_sys_t *p_sys = p_stream->p_sys;
683
684     if ( p_sys->i_cmd == 0 && !(id->p_queued->i_flags & BLOCK_FLAG_TYPE_I) )
685     {
686         mtime_t i_dts = id->p_queued->i_dts;
687         block_t *p_block = id->p_queued->p_next;
688
689         while ( p_block != NULL )
690         {
691             if ( p_block->i_flags & BLOCK_FLAG_TYPE_I )
692                 return i_dts;
693             i_dts = p_block->i_dts;
694             p_block = p_block->p_next;
695         }
696
697         return 0;
698     }
699
700     p_sys->i_old_cmd = p_sys->i_cmd;
701
702     if ( id->ff_enc )
703     {
704         avcodec_close( id->ff_enc_c );
705         av_free( id->ff_enc_c );
706         av_free( id->p_frame );
707         free( id->p_buffer_out );
708         id->ff_enc = NULL;
709     }
710
711     if ( p_sys->i_cmd > 0 )
712     {
713         /* Create a new encoder. */
714         int i_ff_codec = CODEC_ID_MPEG2VIDEO;
715         int i_aspect_num, i_aspect_den;
716
717         if( i_ff_codec == 0 )
718         {
719             msg_Err( p_stream, "cannot find encoder" );
720             return 0;
721         }
722
723         id->ff_enc = avcodec_find_encoder( i_ff_codec );
724         if( !id->ff_enc )
725         {
726             msg_Err( p_stream, "cannot find encoder (avcodec)" );
727             return 0;
728         }
729
730         id->ff_enc_c = avcodec_alloc_context();
731
732         /* Set CPU capabilities */
733         unsigned i_cpu = vlc_CPU();
734         id->ff_enc_c->dsp_mask = 0;
735         if( !(i_cpu & CPU_CAPABILITY_MMX) )
736         {
737             id->ff_enc_c->dsp_mask |= FF_MM_MMX;
738         }
739         if( !(i_cpu & CPU_CAPABILITY_MMXEXT) )
740         {
741             id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT;
742         }
743         if( !(i_cpu & CPU_CAPABILITY_3DNOW) )
744         {
745             id->ff_enc_c->dsp_mask |= FF_MM_3DNOW;
746         }
747         if( !(i_cpu & CPU_CAPABILITY_SSE) )
748         {
749             id->ff_enc_c->dsp_mask |= FF_MM_SSE;
750             id->ff_enc_c->dsp_mask |= FF_MM_SSE2;
751         }
752
753         id->ff_enc_c->width = p_sys->p_pictures[p_sys->i_cmd-1].format.i_width;
754         id->ff_enc_c->height = p_sys->p_pictures[p_sys->i_cmd-1].format.i_height;
755         av_reduce( &i_aspect_num, &i_aspect_den,
756                    p_sys->i_aspect,
757                    VOUT_ASPECT_FACTOR, 1 << 30 /* something big */ );
758         av_reduce( &id->ff_enc_c->sample_aspect_ratio.num,
759                    &id->ff_enc_c->sample_aspect_ratio.den,
760                    i_aspect_num * (int64_t)id->ff_enc_c->height,
761                    i_aspect_den * (int64_t)id->ff_enc_c->width, 1 << 30 );
762
763 #if LIBAVCODEC_BUILD >= 4754
764         id->ff_enc_c->time_base.num = 1;
765         id->ff_enc_c->time_base.den = 25; /* FIXME */
766 #else
767         id->ff_enc_c->frame_rate    = 25; /* FIXME */
768         id->ff_enc_c->frame_rate_base = 1;
769 #endif
770
771         id->ff_enc_c->gop_size = 200;
772         id->ff_enc_c->max_b_frames = 0;
773
774         id->ff_enc_c->flags |= CODEC_FLAG_QSCALE
775                             | CODEC_FLAG_INPUT_PRESERVED
776                             | CODEC_FLAG_LOW_DELAY;
777
778         id->ff_enc_c->mb_decision = FF_MB_DECISION_SIMPLE;
779         id->ff_enc_c->pix_fmt = PIX_FMT_YUV420P;
780
781         if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
782         {
783             msg_Err( p_stream, "cannot open encoder" );
784             return 0;
785         }
786
787         id->p_buffer_out = malloc( id->ff_enc_c->width * id->ff_enc_c->height * 3 );
788         id->p_frame = avcodec_alloc_frame();
789         id->p_frame->linesize[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].i_pitch;
790         id->p_frame->linesize[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].i_pitch;
791         id->p_frame->linesize[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].i_pitch;
792         id->p_frame->data[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].p_pixels;
793         id->p_frame->data[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].p_pixels;
794         id->p_frame->data[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].p_pixels;
795
796         id->i_nb_pred = p_sys->i_gop;
797     }
798
799     return 0;
800 }
801
802 /*****************************************************************************
803  * VideoGetBuffer: Build an alternate video buffer
804  *****************************************************************************/
805 static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
806                                 block_t *p_buffer )
807 {
808     sout_stream_sys_t *p_sys = p_stream->p_sys;
809     int i_out;
810     block_t *p_out;
811
812     id->p_frame->quality = p_sys->i_qscale * powf(2.0, FF_LAMBDA_SHIFT + 7.0)
813                             / 139.0;
814     id->p_frame->interlaced_frame = 0;
815     id->p_frame->top_field_first = 1;
816     id->p_frame->pts = p_buffer->i_dts;
817
818     if ( id->i_nb_pred >= p_sys->i_gop )
819     {
820         id->p_frame->pict_type = FF_I_TYPE;
821 #if 0
822         id->p_frame->me_threshold = 0;
823         id->p_frame->mb_threshold = 0;
824 #endif
825         id->i_nb_pred = 0;
826     }
827     else
828     {
829         id->p_frame->pict_type = FF_P_TYPE;
830 #if 0
831         if ( id->p_frame->mb_type != NULL )
832         {
833             id->p_frame->me_threshold = MAX_THRESHOLD;
834             id->p_frame->mb_threshold = MAX_THRESHOLD;
835         }
836 #endif
837         id->i_nb_pred++;
838     }
839
840     i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer_out,
841                                   id->ff_enc_c->width * id->ff_enc_c->height * 3,
842                                   id->p_frame );
843
844     if ( i_out <= 0 )
845         return NULL;
846
847 #if 0
848     if ( id->p_frame->mb_type == NULL
849           && id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE )
850     {
851         int mb_width = (id->ff_enc_c->width + 15) / 16;
852         int mb_height = (id->ff_enc_c->height + 15) / 16;
853         int h_chroma_shift, v_chroma_shift;
854         int i;
855
856         avcodec_get_chroma_sub_sample( id->ff_enc_c->pix_fmt, &h_chroma_shift,
857                                        &v_chroma_shift );
858
859         id->p_frame->motion_subsample_log2
860             = id->ff_enc_c->coded_frame->motion_subsample_log2;
861         id->p_frame->mb_type = malloc( ((mb_width + 1) * (mb_height + 1) + 1)
862                                     * sizeof(uint32_t) );
863         p_stream->p_libvlc->pf_memcpy( id->p_frame->mb_type,
864                                     id->ff_enc_c->coded_frame->mb_type,
865                                     (mb_width + 1) * mb_height
866                                       * sizeof(id->p_frame->mb_type[0]));
867
868         for ( i = 0; i < 2; i++ )
869         {
870             int stride = ((16 * mb_width )
871                     >> id->ff_enc_c->coded_frame->motion_subsample_log2) + 1;
872             int height = ((16 * mb_height)
873                     >> id->ff_enc_c->coded_frame->motion_subsample_log2);
874             int b8_stride = mb_width * 2 + 1;
875
876             if ( id->ff_enc_c->coded_frame->motion_val[i] )
877             {
878                 id->p_frame->motion_val[i] = malloc( 2 * stride * height
879                                                 * sizeof(int16_t) );
880                 p_stream->p_libvlc->pf_memcpy( id->p_frame->motion_val[i],
881                                      id->ff_enc_c->coded_frame->motion_val[i],
882                                      2 * stride * height * sizeof(int16_t) );
883             }
884             if ( id->ff_enc_c->coded_frame->ref_index[i] )
885             {
886                 id->p_frame->ref_index[i] = malloc( b8_stride * 2 * mb_height
887                                                * sizeof(int8_t) );
888                 p_stream->p_libvlc->pf_memcpy( id->p_frame->ref_index[i],
889                                  id->ff_enc_c->coded_frame->ref_index[i],
890                                  b8_stride * 2 * mb_height * sizeof(int8_t));
891             }
892         }
893     }
894 #endif
895
896     p_out = block_New( p_stream, i_out );
897     p_stream->p_libvlc->pf_memcpy( p_out->p_buffer, id->p_buffer_out, i_out );
898     p_out->i_length = p_buffer->i_length;
899     p_out->i_pts = p_buffer->i_dts;
900     p_out->i_dts = p_buffer->i_dts;
901     p_out->i_rate = p_buffer->i_rate;
902
903     switch ( id->ff_enc_c->coded_frame->pict_type )
904     {
905     case FF_I_TYPE:
906         p_out->i_flags |= BLOCK_FLAG_TYPE_I;
907         break;
908     case FF_P_TYPE:
909         p_out->i_flags |= BLOCK_FLAG_TYPE_P;
910         break;
911     case FF_B_TYPE:
912         p_out->i_flags |= BLOCK_FLAG_TYPE_B;
913         break;
914     default:
915         break;
916     }
917
918     block_Release( p_buffer );
919
920     return p_out;
921 }
922
923 /*****************************************************************************
924  * AudioGetBuffer: Build an alternate audio buffer
925  *****************************************************************************/
926 static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
927                                 block_t *p_buffer )
928 {
929     int i_out;
930     block_t *p_out;
931
932     i_out = avcodec_encode_audio( id->ff_enc_c, id->p_buffer_out,
933                                   2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
934                                   id->p_samples );
935
936     if ( i_out <= 0 )
937         return NULL;
938
939     p_out = block_New( p_stream, i_out );
940     p_stream->p_libvlc->pf_memcpy( p_out->p_buffer, id->p_buffer_out, i_out );
941     p_out->i_length = p_buffer->i_length;
942     p_out->i_pts = p_buffer->i_dts;
943     p_out->i_dts = p_buffer->i_dts;
944     p_out->i_rate = p_buffer->i_rate;
945
946     block_Release( p_buffer );
947
948     return p_out;
949 }