📄 encoder.c
字号:
/***************************************************************************** * encoder.c: video and audio encoder using the ffmpeg library ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN * $Id: encoder.c 11321 2005-06-06 17:11:25Z gbazin $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Gildas Bazin <gbazin@videolan.org> * Christophe Massiot <massiot@via.ecp.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <vlc/vlc.h>#include <vlc/vout.h>#include <vlc/aout.h>#include <vlc/sout.h>#include <vlc/decoder.h>/* ffmpeg header */#define HAVE_MMX#ifdef HAVE_FFMPEG_AVCODEC_H# include <ffmpeg/avcodec.h>#else# include <avcodec.h>#endif#if LIBAVCODEC_BUILD < 4704# define AV_NOPTS_VALUE 0#endif#if LIBAVCODEC_BUILD < 4684# define FF_QP2LAMBDA 118#endif#include "ffmpeg.h"#define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)#define HURRY_UP_GUARD1 (450000)#define HURRY_UP_GUARD2 (300000)#define HURRY_UP_GUARD3 (100000)#define MAX_FRAME_DELAY (FF_MAX_B_FRAMES + 2)/***************************************************************************** * Local prototypes *****************************************************************************/int E_(OpenEncoder) ( vlc_object_t * );void E_(CloseEncoder)( vlc_object_t * );static block_t *EncodeVideo( encoder_t *, picture_t * );static block_t *EncodeAudio( encoder_t *, aout_buffer_t * );struct thread_context_t;static int FfmpegThread( struct thread_context_t *p_context );static int FfmpegExecute( AVCodecContext *s, int (*pf_func)(AVCodecContext *c2, void *arg2), void **arg, int *ret, int count );/***************************************************************************** * thread_context_t : for multithreaded encoding *****************************************************************************/#if LIBAVCODEC_BUILD >= 4702struct thread_context_t{ VLC_COMMON_MEMBERS AVCodecContext *p_context; int (* pf_func)(AVCodecContext *c, void *arg); void *arg; int i_ret; vlc_mutex_t lock; vlc_cond_t cond; vlc_bool_t b_work, b_done;};#endif/***************************************************************************** * encoder_sys_t : ffmpeg encoder descriptor *****************************************************************************/struct encoder_sys_t{ /* * Ffmpeg properties */ AVCodec *p_codec; AVCodecContext *p_context; /* * Common properties */ char *p_buffer; char *p_buffer_out; /* * Video properties */ mtime_t i_last_ref_pts; mtime_t i_buggy_pts_detect; mtime_t i_last_pts; vlc_bool_t b_inited; /* * Audio properties */ int i_frame_size; int i_samples_delay; mtime_t i_pts; /* Encoding settings */ int i_key_int; int i_b_frames; int i_vtolerance; int i_qmin; int i_qmax; int i_hq; vlc_bool_t b_strict_rc; int i_rc_buffer_size; float f_rc_buffer_aggressivity; vlc_bool_t b_pre_me; vlc_bool_t b_hurry_up; vlc_bool_t b_interlace; float f_i_quant_factor; int i_noise_reduction; vlc_bool_t b_mpeg4_matrix; vlc_bool_t b_trellis; int i_quality; /* for VBR */ /* Used to work around stupid timestamping behaviour in libavcodec */ uint64_t i_framenum; mtime_t pi_delay_pts[MAX_FRAME_DELAY];};static const char *ppsz_enc_options[] = { "keyint", "bframes", "vt", "qmin", "qmax", "hq", "strict-rc", "rc-buffer-size", "rc-buffer-aggressivity", "pre-me", "hurry-up", "interlace", "i-quant-factor", "noise-reduction", "mpeg4-matrix", "trellis", "qscale", "strict", NULL};/***************************************************************************** * OpenEncoder: probe the encoder *****************************************************************************/extern int16_t IMPORT_SYMBOL ff_mpeg4_default_intra_matrix[];extern int16_t IMPORT_SYMBOL ff_mpeg4_default_non_intra_matrix[];int E_(OpenEncoder)( vlc_object_t *p_this ){ encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys = p_enc->p_sys; AVCodecContext *p_context; AVCodec *p_codec; int i_codec_id, i_cat; char *psz_namecodec; vlc_value_t val; if( !E_(GetFfmpegCodec)( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id, &psz_namecodec ) ) { if( E_(GetFfmpegChroma)( p_enc->fmt_out.i_codec ) < 0 ) { /* handed chroma output */ return VLC_EGENERIC; } i_cat = VIDEO_ES; i_codec_id = CODEC_ID_RAWVIDEO; psz_namecodec = "Raw video"; } if( p_enc->fmt_out.i_cat == VIDEO_ES && i_cat != VIDEO_ES ) { msg_Err( p_enc, "\"%s\" is not a video encoder", psz_namecodec ); return VLC_EGENERIC; } if( p_enc->fmt_out.i_cat == AUDIO_ES && i_cat != AUDIO_ES ) { msg_Err( p_enc, "\"%s\" is not an audio encoder", psz_namecodec ); return VLC_EGENERIC; } /* Initialization must be done before avcodec_find_decoder() */ E_(InitLibavcodec)(p_this); p_codec = avcodec_find_encoder( i_codec_id ); if( !p_codec ) { msg_Err( p_enc, "cannot find encoder %s", psz_namecodec ); return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL ) { msg_Err( p_enc, "out of memory" ); return VLC_EGENERIC; } memset( p_sys, 0, sizeof(encoder_sys_t) ); p_enc->p_sys = p_sys; p_sys->p_codec = p_codec; p_enc->pf_encode_video = EncodeVideo; p_enc->pf_encode_audio = EncodeAudio; p_sys->p_buffer_out = NULL; p_sys->p_buffer = NULL; p_sys->p_context = p_context = avcodec_alloc_context(); /* Set CPU capabilities */ p_context->dsp_mask = 0; if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) ) { p_context->dsp_mask |= FF_MM_MMX; } if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) ) { p_context->dsp_mask |= FF_MM_MMXEXT; } if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) ) { p_context->dsp_mask |= FF_MM_3DNOW; } if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) ) { p_context->dsp_mask |= FF_MM_SSE; p_context->dsp_mask |= FF_MM_SSE2; } sout_CfgParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); var_Get( p_enc, ENC_CFG_PREFIX "keyint", &val ); p_sys->i_key_int = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "bframes", &val ); p_sys->i_b_frames = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "vt", &val ); p_sys->i_vtolerance = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "interlace", &val ); p_sys->b_interlace = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "pre-me", &val ); p_sys->b_pre_me = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "hurry-up", &val ); p_sys->b_hurry_up = val.b_bool; if( p_sys->b_hurry_up ) { /* hurry up mode needs noise reduction, even small */ p_sys->i_noise_reduction = 1; } var_Get( p_enc, ENC_CFG_PREFIX "strict-rc", &val ); p_sys->b_strict_rc = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-size", &val ); p_sys->i_rc_buffer_size = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-aggressivity", &val ); p_sys->f_rc_buffer_aggressivity = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "i-quant-factor", &val ); p_sys->f_i_quant_factor = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "noise-reduction", &val ); p_sys->i_noise_reduction = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "mpeg4-matrix", &val ); p_sys->b_mpeg4_matrix = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "qscale", &val ); if( val.f_float < 0.01 || val.f_float > 255.0 ) val.f_float = 0; p_sys->i_quality = (int)(FF_QP2LAMBDA * val.f_float + 0.5); var_Get( p_enc, ENC_CFG_PREFIX "hq", &val ); if( val.psz_string && *val.psz_string ) { if( !strcmp( val.psz_string, "rd" ) ) p_sys->i_hq = FF_MB_DECISION_RD; else if( !strcmp( val.psz_string, "bits" ) ) p_sys->i_hq = FF_MB_DECISION_BITS; else if( !strcmp( val.psz_string, "simple" ) ) p_sys->i_hq = FF_MB_DECISION_SIMPLE; else p_sys->i_hq = FF_MB_DECISION_RD; } if( val.psz_string ) free( val.psz_string ); var_Get( p_enc, ENC_CFG_PREFIX "qmin", &val ); p_sys->i_qmin = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "qmax", &val ); p_sys->i_qmax = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "trellis", &val ); p_sys->b_trellis = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "strict", &val );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -