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