00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <math.h>
00030
00031 #include <vlc/vlc.h>
00032 #include <vlc/sout.h>
00033 #include <vlc/vout.h>
00034
00035 #include "network.h"
00036
00037 #define HAVE_MMX
00038 #ifdef HAVE_FFMPEG_AVCODEC_H
00039 # include <ffmpeg/avcodec.h>
00040 #else
00041 # include <avcodec.h>
00042 #endif
00043
00044 #ifdef HAVE_POSTPROC_POSTPROCESS_H
00045 # include <postproc/postprocess.h>
00046 #else
00047 # include <libpostproc/postprocess.h>
00048 #endif
00049
00050 #define SOUT_CFG_PREFIX "sout-switcher-"
00051 #define MAX_PICTURES 10
00052 #define MAX_AUDIO 30
00053 #define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)
00054 #define MAX_THRESHOLD 99999999
00055
00056
00057
00058
00059 static int Open ( vlc_object_t * );
00060 static void Close ( vlc_object_t * );
00061
00062 static sout_stream_id_t *Add( sout_stream_t *, es_format_t * );
00063 static int Del( sout_stream_t *, sout_stream_id_t * );
00064 static int Send( sout_stream_t *, sout_stream_id_t *, block_t * );
00065
00066 static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
00067 mtime_t i_max_dts );
00068 static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file,
00069 int i_width, int i_height,
00070 picture_t *p_pic );
00071 static void NetCommand( sout_stream_t *p_stream );
00072 static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id );
00073 static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
00074 block_t *p_buffer );
00075 static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
00076 block_t *p_buffer );
00077
00078
00079
00080
00081 #define FILES_TEXT N_("Files")
00082 #define FILES_LONGTEXT N_( \
00083 "Full paths of the files separated by colons." )
00084 #define SIZES_TEXT N_("Sizes")
00085 #define SIZES_LONGTEXT N_( \
00086 "List of sizes separated by colons (720x576:480x576)." )
00087 #define RATIO_TEXT N_("Aspect ratio")
00088 #define RATIO_LONGTEXT N_( \
00089 "Aspect ratio (4:3, 16:9)." )
00090 #define PORT_TEXT N_("Command UDP port")
00091 #define PORT_LONGTEXT N_( \
00092 "UDP port to listen to for commands." )
00093 #define COMMAND_TEXT N_("Command")
00094 #define COMMAND_LONGTEXT N_( \
00095 "Initial command to execute." )
00096 #define GOP_TEXT N_("GOP size")
00097 #define GOP_LONGTEXT N_( \
00098 "Number of P frames between two I frames." )
00099 #define QSCALE_TEXT N_("Quantizer scale")
00100 #define QSCALE_LONGTEXT N_( \
00101 "Fixed quantizer scale to use." )
00102 #define AUDIO_TEXT N_("Mute audio")
00103 #define AUDIO_LONGTEXT N_( \
00104 "Mute audio when command is not 0." )
00105
00106 vlc_module_begin();
00107 set_description( _("MPEG2 video switcher stream output") );
00108 set_capability( "sout stream", 50 );
00109 add_shortcut( "switcher" );
00110 set_callbacks( Open, Close );
00111
00112 add_string( SOUT_CFG_PREFIX "files", "", NULL, FILES_TEXT,
00113 FILES_LONGTEXT, VLC_FALSE );
00114 add_string( SOUT_CFG_PREFIX "sizes", "", NULL, SIZES_TEXT,
00115 SIZES_LONGTEXT, VLC_FALSE );
00116 add_string( SOUT_CFG_PREFIX "aspect-ratio", "4:3", NULL, RATIO_TEXT,
00117 RATIO_LONGTEXT, VLC_FALSE );
00118 add_integer( SOUT_CFG_PREFIX "port", 5001, NULL,
00119 PORT_TEXT, PORT_LONGTEXT, VLC_TRUE );
00120 add_integer( SOUT_CFG_PREFIX "command", 0, NULL,
00121 COMMAND_TEXT, COMMAND_LONGTEXT, VLC_TRUE );
00122 add_integer( SOUT_CFG_PREFIX "gop", 8, NULL,
00123 GOP_TEXT, GOP_LONGTEXT, VLC_TRUE );
00124 add_integer( SOUT_CFG_PREFIX "qscale", 5, NULL,
00125 QSCALE_TEXT, QSCALE_LONGTEXT, VLC_TRUE );
00126 add_bool( SOUT_CFG_PREFIX "mute-audio", 1, NULL,
00127 AUDIO_TEXT, AUDIO_LONGTEXT, VLC_TRUE );
00128 vlc_module_end();
00129
00130 static const char *ppsz_sout_options[] = {
00131 "files", "sizes", "aspect-ratio", "port", "command", "gop", "qscale",
00132 "mute-audio", NULL
00133 };
00134
00135 struct sout_stream_sys_t
00136 {
00137 sout_stream_t *p_out;
00138 int i_gop;
00139 int i_qscale;
00140 int i_aspect;
00141 sout_stream_id_t *pp_audio_ids[MAX_AUDIO];
00142 vlc_bool_t b_audio;
00143
00144
00145 picture_t p_pictures[MAX_PICTURES];
00146 int i_nb_pictures;
00147
00148
00149 int i_fd;
00150 int i_cmd, i_old_cmd;
00151 };
00152
00153 struct sout_stream_id_t
00154 {
00155 void *id;
00156 vlc_bool_t b_switcher_video;
00157 vlc_bool_t b_switcher_audio;
00158 es_format_t f_src;
00159 block_t *p_queued;
00160
00161
00162 AVCodec *ff_enc;
00163 AVCodecContext *ff_enc_c;
00164 AVFrame *p_frame;
00165 char *p_buffer_out;
00166 int i_nb_pred;
00167 int16_t *p_samples;
00168 };
00169
00170
00171
00172
00173 static int Open( vlc_object_t *p_this )
00174 {
00175 sout_stream_t *p_stream = (sout_stream_t*)p_this;
00176 sout_stream_sys_t *p_sys;
00177 vlc_value_t val;
00178 char *psz_files, *psz_sizes;
00179 int i_height = 0, i_width = 0;
00180
00181 p_sys = malloc( sizeof(sout_stream_sys_t) );
00182 memset( p_sys, 0, sizeof(sout_stream_sys_t) );
00183
00184 p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
00185 if( !p_sys->p_out )
00186 {
00187 msg_Err( p_stream, "cannot create chain" );
00188 free( p_sys );
00189 return VLC_EGENERIC;
00190 }
00191
00192 sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
00193 p_stream->p_cfg );
00194
00195 var_Get( p_stream, SOUT_CFG_PREFIX "files", &val );
00196 psz_files = val.psz_string;
00197 var_Get( p_stream, SOUT_CFG_PREFIX "sizes", &val );
00198 psz_sizes = val.psz_string;
00199
00200 p_sys->i_nb_pictures = 0;
00201 while ( psz_files && *psz_files )
00202 {
00203 char * psz_file = psz_files;
00204 char * psz_size = psz_sizes;
00205
00206 while ( *psz_files && *psz_files != ':' )
00207 psz_files++;
00208 if ( *psz_files == ':' )
00209 *psz_files++ = '\0';
00210
00211 if ( *psz_sizes )
00212 {
00213 while ( *psz_sizes && *psz_sizes != ':' )
00214 psz_sizes++;
00215 if ( *psz_sizes == ':' )
00216 *psz_sizes++ = '\0';
00217 if ( sscanf( psz_size, "%dx%d", &i_width, &i_height ) != 2 )
00218 {
00219 msg_Err( p_stream, "bad size %s for file %s", psz_size,
00220 psz_file );
00221 free( p_sys );
00222 return VLC_EGENERIC;
00223 }
00224 }
00225
00226 if ( UnpackFromFile( p_stream, psz_file, i_width, i_height,
00227 &p_sys->p_pictures[p_sys->i_nb_pictures] ) < 0 )
00228 {
00229 free( p_sys );
00230 return VLC_EGENERIC;
00231 }
00232 p_sys->i_nb_pictures++;
00233 }
00234
00235 var_Get( p_stream, SOUT_CFG_PREFIX "aspect-ratio", &val );
00236 if ( val.psz_string )
00237 {
00238 char *psz_parser = strchr( val.psz_string, ':' );
00239
00240 if( psz_parser )
00241 {
00242 *psz_parser++ = '\0';
00243 p_sys->i_aspect = atoi( val.psz_string ) * VOUT_ASPECT_FACTOR
00244 / atoi( psz_parser );
00245 }
00246 else
00247 {
00248 msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
00249 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
00250 }
00251
00252 free( val.psz_string );
00253 }
00254 else
00255 {
00256 p_sys->i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
00257 }
00258
00259 var_Get( p_stream, SOUT_CFG_PREFIX "port", &val );
00260 p_sys->i_fd = net_OpenUDP( p_stream, NULL, val.i_int, NULL, 0 );
00261 if ( p_sys->i_fd < 0 )
00262 {
00263 free( p_sys );
00264 return VLC_EGENERIC;
00265 }
00266
00267 var_Get( p_stream, SOUT_CFG_PREFIX "command", &val );
00268 p_sys->i_cmd = val.i_int;
00269 p_sys->i_old_cmd = 0;
00270
00271 var_Get( p_stream, SOUT_CFG_PREFIX "gop", &val );
00272 p_sys->i_gop = val.i_int;
00273
00274 var_Get( p_stream, SOUT_CFG_PREFIX "qscale", &val );
00275 p_sys->i_qscale = val.i_int;
00276
00277 var_Get( p_stream, SOUT_CFG_PREFIX "mute-audio", &val );
00278 p_sys->b_audio = val.b_bool;
00279
00280 p_stream->pf_add = Add;
00281 p_stream->pf_del = Del;
00282 p_stream->pf_send = Send;
00283 p_stream->p_sys = p_sys;
00284
00285 avcodec_init();
00286 avcodec_register_all();
00287
00288 return VLC_SUCCESS;
00289 }
00290
00291
00292
00293
00294 static void Close( vlc_object_t * p_this )
00295 {
00296 sout_stream_t *p_stream = (sout_stream_t *)p_this;
00297 sout_stream_sys_t *p_sys = p_stream->p_sys;
00298
00299 sout_StreamDelete( p_sys->p_out );
00300
00301 free( p_sys );
00302 }
00303
00304
00305
00306
00307 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
00308 {
00309 sout_stream_sys_t *p_sys = p_stream->p_sys;
00310 sout_stream_id_t *id;
00311
00312 id = malloc( sizeof( sout_stream_id_t ) );
00313 memset( id, 0, sizeof( sout_stream_id_t ) );
00314 id->id = NULL;
00315
00316 if ( p_fmt->i_cat == VIDEO_ES
00317 && (p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'v')
00318 || p_fmt->i_codec == VLC_FOURCC('f', 'a', 'k', 'e')) )
00319 {
00320 id->b_switcher_video = VLC_TRUE;
00321 p_fmt->i_codec = VLC_FOURCC('m', 'p', 'g', 'v');
00322 msg_Dbg( p_stream,
00323 "creating video switcher for fcc=`%4.4s'",
00324 (char*)&p_fmt->i_codec );
00325 }
00326 else if ( p_fmt->i_cat == AUDIO_ES
00327 && p_fmt->i_codec == VLC_FOURCC('m', 'p', 'g', 'a')
00328 && p_sys->b_audio )
00329 {
00330 int i_ff_codec = CODEC_ID_MP2;
00331 int i;
00332
00333 id->b_switcher_audio = VLC_TRUE;
00334 msg_Dbg( p_stream,
00335 "creating audio switcher for fcc=`%4.4s'",
00336 (char*)&p_fmt->i_codec );
00337
00338
00339 if( i_ff_codec == 0 )
00340 {
00341 msg_Err( p_stream, "cannot find encoder" );
00342 return NULL;
00343 }
00344
00345 id->ff_enc = avcodec_find_encoder( i_ff_codec );
00346 if( !id->ff_enc )
00347 {
00348 msg_Err( p_stream, "cannot find encoder (avcodec)" );
00349 return NULL;
00350 }
00351
00352 id->ff_enc_c = avcodec_alloc_context();
00353
00354
00355 id->ff_enc_c->dsp_mask = 0;
00356 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )
00357 {
00358 id->ff_enc_c->dsp_mask |= FF_MM_MMX;
00359 }
00360 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )
00361 {
00362 id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT;
00363 }
00364 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) )
00365 {
00366 id->ff_enc_c->dsp_mask |= FF_MM_3DNOW;
00367 }
00368 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )
00369 {
00370 id->ff_enc_c->dsp_mask |= FF_MM_SSE;
00371 id->ff_enc_c->dsp_mask |= FF_MM_SSE2;
00372 }
00373
00374 id->ff_enc_c->sample_rate = p_fmt->audio.i_rate;
00375 id->ff_enc_c->channels = p_fmt->audio.i_channels;
00376 id->ff_enc_c->bit_rate = p_fmt->i_bitrate;
00377
00378 if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
00379 {
00380 msg_Err( p_stream, "cannot open encoder" );
00381 return NULL;
00382 }
00383
00384 id->p_buffer_out = malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * 2 );
00385 id->p_samples = malloc( id->ff_enc_c->frame_size
00386 * p_fmt->audio.i_channels * sizeof(int16_t) );
00387 memset( id->p_samples, 0,
00388 id->ff_enc_c->frame_size * p_fmt->audio.i_channels
00389 * sizeof(int16_t) );
00390
00391 for ( i = 0; i < MAX_AUDIO; i++ )
00392 {
00393 if ( p_sys->pp_audio_ids[i] == NULL )
00394 {
00395 p_sys->pp_audio_ids[i] = id;
00396 break;
00397 }
00398 }
00399 if ( i == MAX_AUDIO )
00400 {
00401 msg_Err( p_stream, "too many audio streams !" );
00402 free( id );
00403 return NULL;
00404 }
00405 }
00406 else
00407 {
00408 msg_Dbg( p_stream, "do not know what to do when switching (fcc=`%4.4s')",
00409 (char*)&p_fmt->i_codec );
00410 }
00411
00412
00413 memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) );
00414
00415
00416 id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
00417
00418 if ( id->id == NULL )
00419 {
00420 free( id );
00421 return NULL;
00422 }
00423
00424 return id;
00425 }
00426
00427
00428
00429
00430 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
00431 {
00432 sout_stream_sys_t *p_sys = p_stream->p_sys;
00433
00434 if ( id->b_switcher_audio )
00435 {
00436 int i;
00437 for ( i = 0; i < MAX_AUDIO; i++ )
00438 {
00439 if ( p_sys->pp_audio_ids[i] == id )
00440 {
00441 p_sys->pp_audio_ids[i] = NULL;
00442 break;
00443 }
00444 }
00445 }
00446
00447 if ( id->ff_enc )
00448 {
00449 avcodec_close( id->ff_enc_c );
00450 av_free( id->ff_enc_c );
00451 av_free( id->p_frame );
00452 free( id->p_buffer_out );
00453 }
00454
00455 if ( id->id )
00456 {
00457 p_sys->p_out->pf_del( p_sys->p_out, id->id );
00458 }
00459 free( id );
00460
00461 return VLC_SUCCESS;
00462 }
00463
00464
00465
00466
00467 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
00468 block_t *p_buffer )
00469 {
00470 sout_stream_sys_t *p_sys = p_stream->p_sys;
00471
00472 if ( !id->id )
00473 {
00474 block_Release( p_buffer );
00475 return VLC_EGENERIC;
00476 }
00477
00478 if ( !id->b_switcher_video && !id->b_switcher_audio )
00479 {
00480 return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
00481 }
00482
00483 block_ChainAppend( &id->p_queued, p_buffer );
00484
00485 if ( id->b_switcher_video )
00486 {
00487
00488 NetCommand( p_stream );
00489
00490 while ( id->p_queued != NULL )
00491 {
00492 mtime_t i_dts = 0;
00493 int i;
00494
00495 if ( p_sys->i_old_cmd != p_sys->i_cmd )
00496 {
00497 i_dts = VideoCommand( p_stream, id );
00498 }
00499
00500 i_dts = Process( p_stream, id, i_dts );
00501
00502 for ( i = 0; i < MAX_AUDIO; i++ )
00503 {
00504 if ( p_sys->pp_audio_ids[i] != NULL )
00505 Process( p_stream, p_sys->pp_audio_ids[i], i_dts );
00506 }
00507 }
00508 }
00509
00510 return VLC_SUCCESS;
00511 }
00512
00513
00514
00515
00516 static mtime_t Process( sout_stream_t *p_stream, sout_stream_id_t *id,
00517 mtime_t i_max_dts )
00518 {
00519 sout_stream_sys_t *p_sys = p_stream->p_sys;
00520 mtime_t i_dts = 0;
00521 block_t *p_blocks = NULL;
00522 block_t *p_blocks_out = NULL;
00523
00524
00525 while ( id->p_queued != NULL
00526 && (!i_max_dts || id->p_queued->i_dts <= i_max_dts) )
00527 {
00528 block_t *p_next = id->p_queued->p_next;
00529 id->p_queued->p_next = NULL;
00530 i_dts = id->p_queued->i_dts;
00531 block_ChainAppend( &p_blocks, id->p_queued );
00532 id->p_queued = p_next;
00533 }
00534
00535 if ( p_sys->i_old_cmd == 0 )
00536 {
00537
00538 if ( p_blocks != NULL )
00539 p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks );
00540 return i_dts;
00541 }
00542
00543 if ( p_sys->i_old_cmd == -1 )
00544 {
00545
00546 while ( p_blocks != NULL )
00547 {
00548 block_t * p_next = p_blocks->p_next;
00549 block_Release( p_blocks );
00550 p_blocks = p_next;
00551 }
00552 return i_dts;
00553 }
00554
00555 while ( p_blocks != NULL )
00556 {
00557 block_t * p_next = p_blocks->p_next;
00558 block_t * p_out;
00559
00560 if ( id->b_switcher_video )
00561 {
00562 p_out = VideoGetBuffer( p_stream, id, p_blocks );
00563 }
00564 else
00565 {
00566 p_out = AudioGetBuffer( p_stream, id, p_blocks );
00567 }
00568 p_blocks = p_next;
00569 if ( p_out != NULL )
00570 {
00571 block_ChainAppend( &p_blocks_out, p_out );
00572 }
00573 }
00574
00575 if ( p_blocks_out != NULL )
00576 p_sys->p_out->pf_send( p_sys->p_out, id->id, p_blocks_out );
00577 return i_dts;
00578 }
00579
00580
00581
00582
00583 static int UnpackFromFile( sout_stream_t *p_stream, const char *psz_file,
00584 int i_width, int i_height,
00585 picture_t *p_pic )
00586 {
00587 int i, j;
00588 FILE *p_file = fopen( psz_file, "r" );
00589
00590 if ( p_file == NULL )
00591 {
00592 msg_Err( p_stream, "file %s not found", psz_file );
00593 return -1;
00594 }
00595
00596 vout_InitPicture( VLC_OBJECT(p_stream), p_pic, VLC_FOURCC('I','4','2','0'),
00597 i_width, i_height,
00598 i_width * VOUT_ASPECT_FACTOR / i_height );
00599 for ( i = 0; i < p_pic->i_planes; i++ )
00600 {
00601 p_pic->p[i].p_pixels = malloc( p_pic->p[i].i_lines *
00602 p_pic->p[i].i_pitch );
00603 memset( p_pic->p[i].p_pixels, 0, p_pic->p[i].i_lines *
00604 p_pic->p[i].i_pitch );
00605 }
00606
00607 for ( i = 0; i < i_height; i++ )
00608 {
00609 int i_chroma;
00610 uint8_t p_buffer[i_width * 2];
00611 uint8_t *p_char = p_buffer;
00612 uint8_t *p_y = &p_pic->p[0].p_pixels[i * p_pic->p[0].i_pitch];
00613 uint8_t *p_u = &p_pic->p[1].p_pixels[i/2 * p_pic->p[1].i_pitch];
00614 uint8_t *p_v = &p_pic->p[2].p_pixels[i/2 * p_pic->p[2].i_pitch];
00615
00616 if ( fread( p_buffer, 2, i_width, p_file ) != (size_t)i_width )
00617 {
00618 msg_Err( p_stream, "premature end of file %s", psz_file );
00619 fclose( p_file );
00620 for ( i = 0; i < p_pic->i_planes; i++ )
00621 {
00622 free( p_pic->p[i].p_pixels );
00623 }
00624 return -1;
00625 }
00626
00627 i_chroma = 0;
00628 for ( j = 0; j < i_width; j++ )
00629 {
00630 uint8_t **pp_chroma = i_chroma ? &p_v : &p_u;
00631 i_chroma = !i_chroma;
00632 if ( i & 1 )
00633 **pp_chroma = (**pp_chroma + *p_char + 1) / 2;
00634 else
00635 **pp_chroma = *p_char;
00636 (*pp_chroma)++;
00637 p_char++;
00638 *p_y++ = *p_char++;
00639 }
00640 }
00641
00642 fclose( p_file );
00643 return 0;
00644 }
00645
00646
00647
00648
00649 static void NetCommand( sout_stream_t *p_stream )
00650 {
00651 sout_stream_sys_t *p_sys = p_stream->p_sys;
00652 char psz_buffer[10];
00653 int i_len = net_ReadNonBlock( p_stream, p_sys->i_fd, NULL, psz_buffer,
00654 sizeof( psz_buffer ), 0 );
00655
00656 if ( i_len > 0 )
00657 {
00658 int i_cmd = strtol( psz_buffer, NULL, 0 );
00659 if ( i_cmd < -1 || i_cmd > p_sys->i_nb_pictures )
00660 {
00661 msg_Err( p_stream, "got a wrong command (%d)", i_cmd );
00662 return;
00663 }
00664
00665 p_sys->i_cmd = i_cmd;
00666 }
00667 }
00668
00669
00670
00671
00672 static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id )
00673 {
00674 sout_stream_sys_t *p_sys = p_stream->p_sys;
00675
00676 if ( p_sys->i_cmd == 0 && !(id->p_queued->i_flags & BLOCK_FLAG_TYPE_I) )
00677 {
00678 mtime_t i_dts = id->p_queued->i_dts;
00679 block_t *p_block = id->p_queued->p_next;
00680
00681 while ( p_block != NULL )
00682 {
00683 if ( p_block->i_flags & BLOCK_FLAG_TYPE_I )
00684 return i_dts;
00685 i_dts = p_block->i_dts;
00686 p_block = p_block->p_next;
00687 }
00688
00689 return 0;
00690 }
00691
00692 p_sys->i_old_cmd = p_sys->i_cmd;
00693
00694 if ( id->ff_enc )
00695 {
00696 avcodec_close( id->ff_enc_c );
00697 av_free( id->ff_enc_c );
00698 av_free( id->p_frame );
00699 free( id->p_buffer_out );
00700 id->ff_enc = NULL;
00701 }
00702
00703 if ( p_sys->i_cmd > 0 )
00704 {
00705
00706 int i_ff_codec = CODEC_ID_MPEG2VIDEO;
00707 int i_aspect_num, i_aspect_den;
00708
00709 if( i_ff_codec == 0 )
00710 {
00711 msg_Err( p_stream, "cannot find encoder" );
00712 return 0;
00713 }
00714
00715 id->ff_enc = avcodec_find_encoder( i_ff_codec );
00716 if( !id->ff_enc )
00717 {
00718 msg_Err( p_stream, "cannot find encoder (avcodec)" );
00719 return 0;
00720 }
00721
00722 id->ff_enc_c = avcodec_alloc_context();
00723
00724
00725 id->ff_enc_c->dsp_mask = 0;
00726 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )
00727 {
00728 id->ff_enc_c->dsp_mask |= FF_MM_MMX;
00729 }
00730 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )
00731 {
00732 id->ff_enc_c->dsp_mask |= FF_MM_MMXEXT;
00733 }
00734 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) )
00735 {
00736 id->ff_enc_c->dsp_mask |= FF_MM_3DNOW;
00737 }
00738 if( !(p_stream->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )
00739 {
00740 id->ff_enc_c->dsp_mask |= FF_MM_SSE;
00741 id->ff_enc_c->dsp_mask |= FF_MM_SSE2;
00742 }
00743
00744 id->ff_enc_c->width = p_sys->p_pictures[p_sys->i_cmd-1].format.i_width;
00745 id->ff_enc_c->height = p_sys->p_pictures[p_sys->i_cmd-1].format.i_height;
00746 av_reduce( &i_aspect_num, &i_aspect_den,
00747 p_sys->i_aspect,
00748 VOUT_ASPECT_FACTOR, 1 << 30 );
00749 av_reduce( &id->ff_enc_c->sample_aspect_ratio.num,
00750 &id->ff_enc_c->sample_aspect_ratio.den,
00751 i_aspect_num * (int64_t)id->ff_enc_c->height,
00752 i_aspect_den * (int64_t)id->ff_enc_c->width, 1 << 30 );
00753
00754 #if LIBAVCODEC_BUILD >= 4754
00755 id->ff_enc_c->time_base.num = 1;
00756 id->ff_enc_c->time_base.den = 25;
00757 #else
00758 id->ff_enc_c->frame_rate = 25;
00759 id->ff_enc_c->frame_rate_base = 1;
00760 #endif
00761
00762 id->ff_enc_c->gop_size = 200;
00763 id->ff_enc_c->max_b_frames = 0;
00764
00765 id->ff_enc_c->flags |= CODEC_FLAG_QSCALE
00766 | CODEC_FLAG_INPUT_PRESERVED
00767 | CODEC_FLAG_LOW_DELAY;
00768
00769 id->ff_enc_c->mb_decision = FF_MB_DECISION_SIMPLE;
00770 id->ff_enc_c->pix_fmt = PIX_FMT_YUV420P;
00771
00772 if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
00773 {
00774 msg_Err( p_stream, "cannot open encoder" );
00775 return 0;
00776 }
00777
00778 id->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );
00779 id->p_frame = avcodec_alloc_frame();
00780 id->p_frame->linesize[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].i_pitch;
00781 id->p_frame->linesize[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].i_pitch;
00782 id->p_frame->linesize[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].i_pitch;
00783 id->p_frame->data[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].p_pixels;
00784 id->p_frame->data[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].p_pixels;
00785 id->p_frame->data[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].p_pixels;
00786
00787 id->i_nb_pred = p_sys->i_gop;
00788 }
00789
00790 return 0;
00791 }
00792
00793
00794
00795
00796 static block_t *VideoGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
00797 block_t *p_buffer )
00798 {
00799 sout_stream_sys_t *p_sys = p_stream->p_sys;
00800 int i_out;
00801 block_t *p_out;
00802
00803 id->p_frame->quality = p_sys->i_qscale * powf(2.0, FF_LAMBDA_SHIFT + 7.0)
00804 / 139.0;
00805 id->p_frame->interlaced_frame = 0;
00806 id->p_frame->top_field_first = 1;
00807 id->p_frame->pts = p_buffer->i_dts;
00808
00809 if ( id->i_nb_pred >= p_sys->i_gop )
00810 {
00811 id->p_frame->pict_type = FF_I_TYPE;
00812 #if 0
00813 id->p_frame->me_threshold = 0;
00814 id->p_frame->mb_threshold = 0;
00815 #endif
00816 id->i_nb_pred = 0;
00817 }
00818 else
00819 {
00820 id->p_frame->pict_type = FF_P_TYPE;
00821 #if 0
00822 if ( id->p_frame->mb_type != NULL )
00823 {
00824 id->p_frame->me_threshold = MAX_THRESHOLD;
00825 id->p_frame->mb_threshold = MAX_THRESHOLD;
00826 }
00827 #endif
00828 id->i_nb_pred++;
00829 }
00830
00831 i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer_out,
00832 AVCODEC_MAX_VIDEO_FRAME_SIZE,
00833 id->p_frame );
00834
00835 if ( i_out <= 0 )
00836 return NULL;
00837
00838 #if 0
00839 if ( id->p_frame->mb_type == NULL
00840 && id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE )
00841 {
00842 int mb_width = (id->ff_enc_c->width + 15) / 16;
00843 int mb_height = (id->ff_enc_c->height + 15) / 16;
00844 int h_chroma_shift, v_chroma_shift;
00845 int i;
00846
00847 avcodec_get_chroma_sub_sample( id->ff_enc_c->pix_fmt, &h_chroma_shift,
00848 &v_chroma_shift );
00849
00850 id->p_frame->motion_subsample_log2
00851 = id->ff_enc_c->coded_frame->motion_subsample_log2;
00852 id->p_frame->mb_type = malloc( ((mb_width + 1) * (mb_height + 1) + 1)
00853 * sizeof(uint32_t) );
00854 p_stream->p_vlc->pf_memcpy( id->p_frame->mb_type,
00855 id->ff_enc_c->coded_frame->mb_type,
00856 (mb_width + 1) * mb_height
00857 * sizeof(id->p_frame->mb_type[0]));
00858
00859 for ( i = 0; i < 2; i++ )
00860 {
00861 int stride = ((16 * mb_width )
00862 >> id->ff_enc_c->coded_frame->motion_subsample_log2) + 1;
00863 int height = ((16 * mb_height)
00864 >> id->ff_enc_c->coded_frame->motion_subsample_log2);
00865 int b8_stride = mb_width * 2 + 1;
00866
00867 if ( id->ff_enc_c->coded_frame->motion_val[i] )
00868 {
00869 id->p_frame->motion_val[i] = malloc( 2 * stride * height
00870 * sizeof(int16_t) );
00871 p_stream->p_vlc->pf_memcpy( id->p_frame->motion_val[i],
00872 id->ff_enc_c->coded_frame->motion_val[i],
00873 2 * stride * height * sizeof(int16_t) );
00874 }
00875 if ( id->ff_enc_c->coded_frame->ref_index[i] )
00876 {
00877 id->p_frame->ref_index[i] = malloc( b8_stride * 2 * mb_height
00878 * sizeof(int8_t) );
00879 p_stream->p_vlc->pf_memcpy( id->p_frame->ref_index[i],
00880 id->ff_enc_c->coded_frame->ref_index[i],
00881 b8_stride * 2 * mb_height * sizeof(int8_t));
00882 }
00883 }
00884 }
00885 #endif
00886
00887 p_out = block_New( p_stream, i_out );
00888 p_stream->p_vlc->pf_memcpy( p_out->p_buffer, id->p_buffer_out, i_out );
00889 p_out->i_length = p_buffer->i_length;
00890 p_out->i_pts = p_buffer->i_dts;
00891 p_out->i_dts = p_buffer->i_dts;
00892 p_out->i_rate = p_buffer->i_rate;
00893
00894 switch ( id->ff_enc_c->coded_frame->pict_type )
00895 {
00896 case FF_I_TYPE:
00897 p_out->i_flags |= BLOCK_FLAG_TYPE_I;
00898 break;
00899 case FF_P_TYPE:
00900 p_out->i_flags |= BLOCK_FLAG_TYPE_P;
00901 break;
00902 case FF_B_TYPE:
00903 p_out->i_flags |= BLOCK_FLAG_TYPE_B;
00904 break;
00905 default:
00906 break;
00907 }
00908
00909 block_Release( p_buffer );
00910
00911 return p_out;
00912 }
00913
00914
00915
00916
00917 static block_t *AudioGetBuffer( sout_stream_t *p_stream, sout_stream_id_t *id,
00918 block_t *p_buffer )
00919 {
00920 int i_out;
00921 block_t *p_out;
00922
00923 i_out = avcodec_encode_audio( id->ff_enc_c, id->p_buffer_out,
00924 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
00925 id->p_samples );
00926
00927 if ( i_out <= 0 )
00928 return NULL;
00929
00930 p_out = block_New( p_stream, i_out );
00931 p_stream->p_vlc->pf_memcpy( p_out->p_buffer, id->p_buffer_out, i_out );
00932 p_out->i_length = p_buffer->i_length;
00933 p_out->i_pts = p_buffer->i_dts;
00934 p_out->i_dts = p_buffer->i_dts;
00935 p_out->i_rate = p_buffer->i_rate;
00936
00937 block_Release( p_buffer );
00938
00939 return p_out;
00940 }
00941