/***************************************************************************** * VideoCommand: Create/Delete a video encoder *****************************************************************************/ static mtime_t VideoCommand( sout_stream_t *p_stream, sout_stream_id_t *id ) { sout_stream_sys_t *p_sys = p_stream->p_sys; if ( p_sys->i_cmd == 0 && !(id->p_queued->i_flags & BLOCK_FLAG_TYPE_I) ) { mtime_t i_dts = id->p_queued->i_dts; block_t *p_block = id->p_queued->p_next; while ( p_block != NULL ) { if ( p_block->i_flags & BLOCK_FLAG_TYPE_I ) return i_dts; i_dts = p_block->i_dts; p_block = p_block->p_next; } return 0; } p_sys->i_old_cmd = p_sys->i_cmd; if ( id->ff_enc ) { vlc_avcodec_lock(); avcodec_close( id->ff_enc_c ); vlc_avcodec_unlock(); av_free( id->ff_enc_c ); av_free( id->p_frame ); free( id->p_buffer_out ); id->ff_enc = NULL; } if ( p_sys->i_cmd > 0 ) { /* Create a new encoder. */ int i_ff_codec = CODEC_ID_MPEG2VIDEO; int i_aspect_num, i_aspect_den; if( i_ff_codec == 0 ) { msg_Err( p_stream, "cannot find encoder" ); return 0; } id->ff_enc = avcodec_find_encoder( i_ff_codec ); if( !id->ff_enc ) { msg_Err( p_stream, "cannot find encoder (avcodec)" ); return 0; } #if LIBAVCODEC_VERSION_MAJOR < 54 id->ff_enc_c = avcodec_alloc_context(); #else id->ff_enc_c = avcodec_alloc_context3( id->ff_enc ); #endif id->ff_enc_c->dsp_mask = GetVlcDspMask(); id->ff_enc_c->width = p_sys->p_pictures[p_sys->i_cmd-1].format.i_width; id->ff_enc_c->height = p_sys->p_pictures[p_sys->i_cmd-1].format.i_height; av_reduce( &i_aspect_num, &i_aspect_den, p_sys->i_aspect, VOUT_ASPECT_FACTOR, 1 << 30 /* something big */ ); av_reduce( &id->ff_enc_c->sample_aspect_ratio.num, &id->ff_enc_c->sample_aspect_ratio.den, i_aspect_num * (int64_t)id->ff_enc_c->height, i_aspect_den * (int64_t)id->ff_enc_c->width, 1 << 30 ); #if LIBAVCODEC_BUILD >= 4754 id->ff_enc_c->time_base.num = 1; id->ff_enc_c->time_base.den = 25; /* FIXME */ #else id->ff_enc_c->frame_rate = 25; /* FIXME */ id->ff_enc_c->frame_rate_base = 1; #endif id->ff_enc_c->gop_size = 200; id->ff_enc_c->max_b_frames = 0; id->ff_enc_c->flags |= CODEC_FLAG_QSCALE | CODEC_FLAG_INPUT_PRESERVED | CODEC_FLAG_LOW_DELAY; id->ff_enc_c->mb_decision = FF_MB_DECISION_SIMPLE; id->ff_enc_c->pix_fmt = PIX_FMT_YUV420P; vlc_avcodec_lock(); int ret; #if LIBAVCODEC_VERSION_MAJOR >= 54 AVDictionary *options = NULL; if (p_sys->options) av_dict_copy(&options, p_sys->options, 0); ret = avcodec_open2( id->ff_enc_c, id->ff_enc, options ? &options : NULL ); #else ret = avcodec_open( id->ff_enc_c, id->ff_enc ); #endif vlc_avcodec_unlock(); #if LIBAVCODEC_VERSION_MAJOR >= 54 AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_stream, "Unknown option \"%s\"", t->key ); } av_dict_free(&options); #endif if (ret) { msg_Err( p_stream, "cannot open encoder" ); return 0; } id->p_buffer_out = malloc( id->ff_enc_c->width * id->ff_enc_c->height * 3 ); id->p_frame = avcodec_alloc_frame(); id->p_frame->linesize[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].i_pitch; id->p_frame->linesize[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].i_pitch; id->p_frame->linesize[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].i_pitch; id->p_frame->data[0] = p_sys->p_pictures[p_sys->i_cmd-1].p[0].p_pixels; id->p_frame->data[1] = p_sys->p_pictures[p_sys->i_cmd-1].p[1].p_pixels; id->p_frame->data[2] = p_sys->p_pictures[p_sys->i_cmd-1].p[2].p_pixels; id->i_nb_pred = p_sys->i_gop; } return 0; }
/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*) p_this; unsigned i_codec_id; int i_cat, i_result; const char *psz_namecodec; AVCodecContext *p_context = NULL; AVCodec *p_codec = NULL; /* *** determine codec type *** */ if( !GetFfmpegCodec( p_dec->fmt_in.i_codec, &i_cat, &i_codec_id, &psz_namecodec ) ) { return VLC_EGENERIC; } /* Initialization must be done before avcodec_find_decoder() */ vlc_init_avcodec(); /* *** ask ffmpeg for a decoder *** */ char *psz_decoder = var_CreateGetString( p_this, "avcodec-codec" ); if( psz_decoder && *psz_decoder ) { p_codec = avcodec_find_decoder_by_name( psz_decoder ); if( !p_codec ) msg_Err( p_this, "Decoder `%s' not found", psz_decoder ); else if( p_codec->id != i_codec_id ) { msg_Err( p_this, "Decoder `%s' can't handle %4.4s", psz_decoder, (char*)&p_dec->fmt_in.i_codec ); p_codec = NULL; } } free( psz_decoder ); if( !p_codec ) p_codec = avcodec_find_decoder( i_codec_id ); if( !p_codec ) { msg_Dbg( p_dec, "codec not found (%s)", psz_namecodec ); return VLC_EGENERIC; } /* *** get a p_context *** */ p_context = avcodec_alloc_context3(p_codec); if( !p_context ) return VLC_ENOMEM; p_context->debug = var_InheritInteger( p_dec, "avcodec-debug" ); p_context->opaque = (void *)p_this; /* set CPU capabilities */ #if LIBAVUTIL_VERSION_CHECK(51, 25, 0, 42, 100) av_set_cpu_flags_mask( INT_MAX & ~GetVlcDspMask() ); #else p_context->dsp_mask = GetVlcDspMask(); #endif p_dec->b_need_packetized = true; switch( i_cat ) { case VIDEO_ES: p_dec->pf_decode_video = DecodeVideo; i_result = InitVideoDec ( p_dec, p_context, p_codec, i_codec_id, psz_namecodec ); break; case AUDIO_ES: p_dec->pf_decode_audio = DecodeAudio; i_result = InitAudioDec ( p_dec, p_context, p_codec, i_codec_id, psz_namecodec ); break; case SPU_ES: p_dec->pf_decode_sub = DecodeSubtitle; i_result = InitSubtitleDec( p_dec, p_context, p_codec, i_codec_id, psz_namecodec ); break; default: i_result = VLC_EGENERIC; } if( i_result == VLC_SUCCESS ) { p_dec->p_sys->i_cat = i_cat; if( p_context->profile != FF_PROFILE_UNKNOWN) p_dec->fmt_in.i_profile = p_context->profile; if( p_context->level != FF_LEVEL_UNKNOWN) p_dec->fmt_in.i_level = p_context->level; } return i_result; }
/***************************************************************************** * Add: Add an input elementary stream *****************************************************************************/ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt ) { sout_stream_sys_t *p_sys = p_stream->p_sys; sout_stream_id_t *id; id = calloc( 1, sizeof( sout_stream_id_t ) ); if( !id ) return NULL; if( p_fmt->i_cat == VIDEO_ES && p_fmt->i_codec == VLC_CODEC_MPGV ) { id->b_switcher_video = true; p_fmt->i_codec = VLC_CODEC_MPGV; msg_Dbg( p_stream, "creating video switcher for fcc=`%4.4s' cmd:%d", (char*)&p_fmt->i_codec, p_sys->i_cmd ); } else if ( p_fmt->i_cat == AUDIO_ES && p_fmt->i_codec == VLC_CODEC_MPGA && p_sys->b_audio ) { int i_ff_codec = CODEC_ID_MP2; int i; id->b_switcher_audio = true; msg_Dbg( p_stream, "creating audio switcher for fcc=`%4.4s' cmd:%d", (char*)&p_fmt->i_codec, p_sys->i_cmd ); /* Allocate the encoder right now. */ if( i_ff_codec == 0 ) { msg_Err( p_stream, "cannot find encoder" ); free( id ); return NULL; } id->ff_enc = avcodec_find_encoder( i_ff_codec ); if( !id->ff_enc ) { msg_Err( p_stream, "cannot find encoder (avcodec)" ); free( id ); return NULL; } #if LIBAVCODEC_VERSION_MAJOR < 54 id->ff_enc_c = avcodec_alloc_context(); #else id->ff_enc_c = avcodec_alloc_context3( id->ff_enc ); #endif id->ff_enc_c->dsp_mask = GetVlcDspMask(); id->ff_enc_c->sample_rate = p_fmt->audio.i_rate; id->ff_enc_c->time_base.num = 1; id->ff_enc_c->time_base.den = p_fmt->audio.i_rate; id->ff_enc_c->channels = p_fmt->audio.i_channels; id->ff_enc_c->bit_rate = p_fmt->i_bitrate; int ret; #if LIBAVCODEC_VERSION_MAJOR >= 54 AVDictionary *options = NULL; if (p_sys->options) av_dict_copy(&options, p_sys->options, 0); vlc_avcodec_lock(); ret = avcodec_open2( id->ff_enc_c, id->ff_enc, options ? &options : NULL ); vlc_avcodec_unlock(); AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options, "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_stream, "Unknown option \"%s\"", t->key ); } av_dict_free(&options); #else vlc_avcodec_lock(); ret = avcodec_open( id->ff_enc_c, id->ff_enc ); vlc_avcodec_unlock(); #endif if (ret) { msg_Err( p_stream, "cannot open encoder" ); av_free( id->ff_enc_c ); free( id ); return NULL; } id->p_buffer_out = malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * 2 ); id->p_samples = calloc( id->ff_enc_c->frame_size * p_fmt->audio.i_channels, sizeof(int16_t) ); if( !id->p_buffer_out || !id->p_samples ) goto error; for( i = 0; i < MAX_AUDIO; i++ ) { if( p_sys->pp_audio_ids[i] == NULL ) { p_sys->pp_audio_ids[i] = id; break; } } if( i == MAX_AUDIO ) { msg_Err( p_stream, "too many audio streams!" ); goto error; } } else { msg_Dbg( p_stream, "do not know what to do when switching (fcc=`%4.4s')", (char*)&p_fmt->i_codec ); } /* src format */ memcpy( &id->f_src, p_fmt, sizeof( es_format_t ) ); /* open output stream */ id->id = p_stream->p_next->pf_add( p_stream->p_next, p_fmt ); if( id->id != NULL ) return id; error: vlc_avcodec_lock(); avcodec_close( id->ff_enc_c ); vlc_avcodec_unlock(); free( id->p_samples ); free( id->p_buffer_out ); av_free( id->ff_enc_c ); free( id ); return NULL; }