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