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