📄 encoder.c
字号:
/***************************************************************************** * encoder.c: video and audio encoder using the ffmpeg library ***************************************************************************** * Copyright (C) 1999-2004 the VideoLAN team * $Id: 9e115b226e5c241c5af54a4e85d19df8feeec163 $ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Gildas Bazin <gbazin@videolan.org> * Christophe Massiot <massiot@via.ecp.fr> * Part of the file Copyright (C) FFMPEG Project Developers * (mpeg4_default matrixes) * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_vout.h>#include <vlc_aout.h>#include <vlc_sout.h>#include <vlc_codec.h>#include <vlc_interface.h>/* ffmpeg header */#define HAVE_MMX 1#ifdef HAVE_LIBAVCODEC_AVCODEC_H# include <libavcodec/avcodec.h>#elif defined(HAVE_FFMPEG_AVCODEC_H)# include <ffmpeg/avcodec.h>#else# include <avcodec.h>#endif#include "avcodec.h"#include "chroma.h"#include "fourcc.h"#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 OpenEncoder ( vlc_object_t * );void 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 void* FfmpegThread( vlc_object_t *p_this );static int FfmpegExecute( AVCodecContext *s, int (*pf_func)(AVCodecContext *c2, void *arg2), void **arg, int *ret, int count );/***************************************************************************** * thread_context_t : for multithreaded encoding *****************************************************************************/struct 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; bool b_work, b_done;};/***************************************************************************** * encoder_sys_t : ffmpeg encoder descriptor *****************************************************************************/struct encoder_sys_t{ /* * Ffmpeg properties */ AVCodec *p_codec; AVCodecContext *p_context; /* * Common properties */ char *p_buffer; uint8_t *p_buffer_out; size_t i_buffer_out; /* * Video properties */ mtime_t i_last_ref_pts; mtime_t i_buggy_pts_detect; mtime_t i_last_pts; bool 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; int i_rc_buffer_size; float f_rc_buffer_aggressivity; bool b_pre_me; bool b_hurry_up; bool b_interlace, b_interlace_me; float f_i_quant_factor; int i_noise_reduction; bool b_mpeg4_matrix; bool b_trellis; int i_quality; /* for VBR */ float f_lumi_masking, f_dark_masking, f_p_masking, f_border_masking; int i_luma_elim, i_chroma_elim;#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(40<<8)+4) int i_aac_profile; /* AAC profile to use.*/#endif /* Used to work around stupid timestamping behaviour in libavcodec */ uint64_t i_framenum; mtime_t pi_delay_pts[MAX_FRAME_DELAY];};static const char *const ppsz_enc_options[] = { "keyint", "bframes", "vt", "qmin", "qmax", "hq", "rc-buffer-size", "rc-buffer-aggressivity", "pre-me", "hurry-up", "interlace", "i-quant-factor", "noise-reduction", "mpeg4-matrix", "trellis", "qscale", "strict", "lumi-masking", "dark-masking", "p-masking", "border-masking", "luma-elim-threshold", "chroma-elim-threshold",#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(40<<8)+4) "aac-profile",#endif NULL};static const uint16_t mpa_bitrate_tab[2][15] ={ {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}};static const uint16_t mpa_freq_tab[6] ={ 44100, 48000, 32000, 22050, 24000, 16000 };static const uint16_t mpeg4_default_intra_matrix[64] = { 8, 17, 18, 19, 21, 23, 25, 27, 17, 18, 19, 21, 23, 25, 27, 28, 20, 21, 22, 23, 24, 26, 28, 30, 21, 22, 23, 24, 26, 28, 30, 32, 22, 23, 24, 26, 28, 30, 32, 35, 23, 24, 26, 28, 30, 32, 35, 38, 25, 26, 28, 30, 32, 35, 38, 41, 27, 28, 30, 32, 35, 38, 41, 45,};static const uint16_t mpeg4_default_non_intra_matrix[64] = { 16, 17, 18, 19, 20, 21, 22, 23, 17, 18, 19, 20, 21, 22, 23, 24, 18, 19, 20, 21, 22, 23, 24, 25, 19, 20, 21, 22, 23, 24, 26, 27, 20, 21, 22, 23, 25, 26, 27, 28, 21, 22, 23, 24, 26, 27, 28, 30, 22, 23, 24, 26, 27, 28, 30, 31, 23, 24, 25, 27, 28, 30, 31, 33,};/***************************************************************************** * OpenEncoder: probe the encoder *****************************************************************************/int 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; const char *psz_namecodec; vlc_value_t val; if( !GetFfmpegCodec( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id, &psz_namecodec ) ) { if( TestFfmpegChroma( -1, p_enc->fmt_out.i_codec ) != VLC_SUCCESS ) { /* 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 ); intf_UserFatal( p_enc, false, _("Streaming / Transcoding failed"), _("\"%s\" is no 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 ); intf_UserFatal( p_enc, false, _("Streaming / Transcoding failed"), _("\"%s\" is no audio encoder."), psz_namecodec ); return VLC_EGENERIC; } /* Initialization must be done before avcodec_find_encoder() */ InitLibavcodec( p_this ); p_codec = avcodec_find_encoder( i_codec_id ); if( !p_codec ) { msg_Err( p_enc, "cannot find encoder %s", psz_namecodec ); intf_UserFatal( p_enc, false, _("Streaming / Transcoding failed"), _("VLC could not find encoder \"%s\"."), psz_namecodec ); return VLC_EGENERIC; } /* Allocate the memory needed to store the encoder's structure */ if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL ) return VLC_ENOMEM; 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 = NULL; p_sys->p_buffer_out = NULL; p_sys->i_buffer_out = 0; p_sys->p_context = p_context = avcodec_alloc_context(); p_context->debug = config_GetInt( p_enc, "ffmpeg-debug" ); p_context->opaque = (void *)p_this; /* Set CPU capabilities */ unsigned i_cpu = vlc_CPU(); p_context->dsp_mask = 0; if( !(i_cpu & CPU_CAPABILITY_MMX) ) { p_context->dsp_mask |= FF_MM_MMX; } if( !(i_cpu & CPU_CAPABILITY_MMXEXT) ) { p_context->dsp_mask |= FF_MM_MMXEXT; } if( !(i_cpu & CPU_CAPABILITY_3DNOW) ) { p_context->dsp_mask |= FF_MM_3DNOW; } if( !(i_cpu & CPU_CAPABILITY_SSE) ) { p_context->dsp_mask |= FF_MM_SSE; p_context->dsp_mask |= FF_MM_SSE2; } config_ChainParse( 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 * 1000; var_Get( p_enc, ENC_CFG_PREFIX "interlace", &val ); p_sys->b_interlace = val.b_bool; var_Get( p_enc, ENC_CFG_PREFIX "interlace-me", &val ); p_sys->b_interlace_me = 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 "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 ); p_sys->i_hq = FF_MB_DECISION_RD; 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; } else p_sys->i_hq = FF_MB_DECISION_RD; 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 ); if( val.i_int < - 1 || val.i_int > 1 ) val.i_int = 0; p_context->strict_std_compliance = val.i_int; var_Get( p_enc, ENC_CFG_PREFIX "lumi-masking", &val ); p_sys->f_lumi_masking = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "dark-masking", &val ); p_sys->f_dark_masking = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "p-masking", &val ); p_sys->f_p_masking = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "border-masking", &val ); p_sys->f_border_masking = val.f_float; var_Get( p_enc, ENC_CFG_PREFIX "luma-elim-threshold", &val );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -