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