📄 xvidff.c
字号:
/* * Interface to xvidcore for mpeg4 encoding * Copyright (c) 2004 Adam Thayer <krevnik@comcast.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * @file xvidmpeg4.c * Interface to xvidcore for MPEG-4 compliant encoding. * @author Adam Thayer (krevnik@comcast.net) */ #include <xvid.h>#include <unistd.h>#include "common.h"#include "avcodec.h"#ifdef CONFIG_WIN32#include <fcntl.h>#endif/** * Buffer management macros. */#define BUFFER_SIZE 1024#define BUFFER_REMAINING(x) (BUFFER_SIZE - strlen(x))#define BUFFER_CAT(x) (&((x)[strlen(x)]))/* For PPC Use */#if HAVE_ALTIVEC==1extern int has_altivec(void);#endif/** * Structure for the private XviD context. * This stores all the private context for the codec. */typedef struct xvid_context { void *encoder_handle; /** Handle for XviD Encoder */ int xsize, ysize; /** Frame size */ int vop_flags; /** VOP flags for XviD Encoder */ int vol_flags; /** VOL flags for XviD Encoder */ int me_flags; /** Motion Estimation flags */ int qscale; /** Do we use constant scale? */ int quicktime_format; /** Are we in a QT-based format? */ AVFrame encoded_picture; /** Encoded frame information */ char *twopassbuffer; /** Character buffer for two-pass */ char *old_twopassbuffer; /** Old character buffer (two-pass) */ char *twopassfile; /** second pass temp file name */ unsigned char *intra_matrix; /** P-Frame Quant Matrix */ unsigned char *inter_matrix; /** I-Frame Quant Matrix */} xvid_context_t; /** * Structure for the private first-pass plugin. */typedef struct xvid_ff_pass1 { int version; /** XviD version */ xvid_context_t *context; /** Pointer to private context */} xvid_ff_pass1_t;/* Prototypes - See function implementation for details */int xvid_strip_vol_header(AVCodecContext *avctx, unsigned char *frame, unsigned int header_len, unsigned int frame_len);int xvid_ff_2pass(void *ref, int opt, void *p1, void *p2);void xvid_correct_framerate(AVCodecContext *avctx); /** * Creates the private context for the encoder. * All buffers are allocated, settings are loaded from the user, * and the encoder context created. * * @param avctx AVCodecContext pointer to context * @return Returns 0 on success, -1 on failure */ int ff_xvid_encode_init(AVCodecContext *avctx) { int xerr, i; int xvid_flags = avctx->flags; xvid_context_t *x = avctx->priv_data; uint16_t *intra, *inter; int fd; xvid_plugin_single_t single; xvid_ff_pass1_t rc2pass1; xvid_plugin_2pass2_t rc2pass2; xvid_gbl_init_t xvid_gbl_init; xvid_enc_create_t xvid_enc_create; xvid_enc_plugin_t plugins[7]; /* Bring in VOP flags from ffmpeg command-line */ x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */ if( xvid_flags & CODEC_FLAG_4MV ) x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */ if( xvid_flags & CODEC_FLAG_TRELLIS_QUANT) x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */ if( xvid_flags & CODEC_FLAG_AC_PRED ) x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */ if( xvid_flags & CODEC_FLAG_GRAY ) x->vop_flags |= XVID_VOP_GREYSCALE; /* Decide which ME quality setting to use */ x->me_flags = 0; switch( avctx->me_method ) { case ME_FULL: /* Quality 6 */ x->me_flags |= XVID_ME_EXTSEARCH16 | XVID_ME_EXTSEARCH8; case ME_EPZS: /* Quality 4 */ x->me_flags |= XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP; case ME_LOG: /* Quality 2 */ case ME_PHODS: case ME_X1: x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16; case ME_ZERO: /* Quality 0 */ default: break; } /* Decide how we should decide blocks */ switch( avctx->mb_decision ) { case 2: x->vop_flags |= XVID_VOP_MODEDECISION_RD; x->me_flags |= XVID_ME_HALFPELREFINE8_RD | XVID_ME_QUARTERPELREFINE8_RD | XVID_ME_EXTSEARCH_RD | XVID_ME_CHECKPREDICTION_RD; case 1: if( !(x->vop_flags & XVID_VOP_MODEDECISION_RD) ) x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD; x->me_flags |= XVID_ME_HALFPELREFINE16_RD | XVID_ME_QUARTERPELREFINE16_RD; default: break; } /* Bring in VOL flags from ffmpeg command-line */ x->vol_flags = 0; if( xvid_flags & CODEC_FLAG_GMC ) { x->vol_flags |= XVID_VOL_GMC; x->me_flags |= XVID_ME_GME_REFINE; } if( xvid_flags & CODEC_FLAG_QPEL ) { x->vol_flags |= XVID_VOL_QUARTERPEL; x->me_flags |= XVID_ME_QUARTERPELREFINE16; if( x->vop_flags & XVID_VOP_INTER4V ) x->me_flags |= XVID_ME_QUARTERPELREFINE8; } memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init)); xvid_gbl_init.version = XVID_VERSION; xvid_gbl_init.debug = 0; #ifdef ARCH_POWERPC /* XviD's PPC support is borked, use libavcodec to detect */#if HAVE_ALTIVEC==1 if( has_altivec() ) { xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ALTIVEC; } else#endif xvid_gbl_init.cpu_flags = XVID_CPU_FORCE; #else /* XviD can detect on x86 */ xvid_gbl_init.cpu_flags = 0;#endif /* Initialize */ xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL); /* Create the encoder reference */ memset(&xvid_enc_create, 0, sizeof(xvid_enc_create)); xvid_enc_create.version = XVID_VERSION; /* Store the desired frame size */ xvid_enc_create.width = x->xsize = avctx->width; xvid_enc_create.height = x->ysize = avctx->height; /* XviD can determine the proper profile to use */ /* xvid_enc_create.profile = XVID_PROFILE_S_L3; */ /* We don't use zones or threads */ xvid_enc_create.zones = NULL; xvid_enc_create.num_zones = 0; xvid_enc_create.num_threads = 0; xvid_enc_create.plugins = plugins; xvid_enc_create.num_plugins = 0; /* Initialize Buffers */ x->twopassbuffer = NULL; x->old_twopassbuffer = NULL; x->twopassfile = NULL; if( xvid_flags & CODEC_FLAG_PASS1 ) { memset(&rc2pass1, 0, sizeof(xvid_ff_pass1_t)); rc2pass1.version = XVID_VERSION; rc2pass1.context = x; x->twopassbuffer = av_malloc(BUFFER_SIZE); x->old_twopassbuffer = av_malloc(BUFFER_SIZE); if( x->twopassbuffer == NULL || x->old_twopassbuffer == NULL ) { av_log(avctx, AV_LOG_ERROR, "XviD: Cannot allocate 2-pass log buffers\n"); return -1; } x->twopassbuffer[0] = x->old_twopassbuffer[0] = 0; plugins[xvid_enc_create.num_plugins].func = xvid_ff_2pass; plugins[xvid_enc_create.num_plugins].param = &rc2pass1; xvid_enc_create.num_plugins++; } else if( xvid_flags & CODEC_FLAG_PASS2 ) { memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t)); rc2pass2.version = XVID_VERSION; rc2pass2.bitrate = avctx->bit_rate; #ifdef CONFIG_WIN32 /* Ugly work around */ { char *tempname; tempname = tempnam(".", "xvidff"); fd = -1; if( tempname && (fd = open(tempname, _O_RDWR | _O_BINARY)) != -1 ) { x->twopassfile = av_strdup(tempname);#undef free free(tempname);#define free please_use_av_free if( x->twopassfile == NULL ) { av_log(avctx, AV_LOG_ERROR, "XviD: Cannot allocate 2-pass buffer\n"); return -1; } } }#else x->twopassfile = av_malloc(BUFFER_SIZE); if( x->twopassfile == NULL ) { av_log(avctx, AV_LOG_ERROR, "XviD: Cannot allocate 2-pass buffer\n"); return -1; } strcpy(x->twopassfile, "/tmp/xvidff.XXXXXX"); fd = mkstemp(x->twopassfile); if(fd < 0){ strcpy(x->twopassfile, "./xvidff.XXXXXX"); fd = mkstemp(x->twopassfile); }#endif if( fd == -1 ) { av_log(avctx, AV_LOG_ERROR, "XviD: Cannot write 2-pass pipe\n"); return -1; } if( avctx->stats_in == NULL ) { av_log(avctx, AV_LOG_ERROR, "XviD: No 2-pass information loaded for second pass\n"); return -1; } if( strlen(avctx->stats_in) > write(fd, avctx->stats_in, strlen(avctx->stats_in)) ) { close(fd); av_log(avctx, AV_LOG_ERROR, "XviD: Cannot write to 2-pass pipe\n"); return -1; } close(fd); rc2pass2.filename = x->twopassfile; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; plugins[xvid_enc_create.num_plugins].param = &rc2pass2; xvid_enc_create.num_plugins++; } else if( !(xvid_flags & CODEC_FLAG_QSCALE) ) { /* Single Pass Bitrate Control! */ memset(&single, 0, sizeof(xvid_plugin_single_t)); single.version = XVID_VERSION; single.bitrate = avctx->bit_rate; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single; plugins[xvid_enc_create.num_plugins].param = &single; xvid_enc_create.num_plugins++; } /* Luminance Masking */ if( 0.0 != avctx->lumi_masking ) { plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking; plugins[xvid_enc_create.num_plugins].param = NULL; xvid_enc_create.num_plugins++; } /* Frame Rate and Key Frames */ xvid_correct_framerate(avctx); xvid_enc_create.fincr = avctx->time_base.num; xvid_enc_create.fbase = avctx->time_base.den; if( avctx->gop_size > 0 ) xvid_enc_create.max_key_interval = avctx->gop_size; else xvid_enc_create.max_key_interval = 240; /* XviD's best default */ /* Quants */ if( xvid_flags & CODEC_FLAG_QSCALE ) x->qscale = 1; else x->qscale = 0; xvid_enc_create.min_quant[0] = avctx->qmin; xvid_enc_create.min_quant[1] = avctx->qmin; xvid_enc_create.min_quant[2] = avctx->qmin; xvid_enc_create.max_quant[0] = avctx->qmax; xvid_enc_create.max_quant[1] = avctx->qmax; xvid_enc_create.max_quant[2] = avctx->qmax; /* Quant Matrices */ x->intra_matrix = x->inter_matrix = NULL; if( avctx->mpeg_quant ) x->vol_flags |= XVID_VOL_MPEGQUANT; if( (avctx->intra_matrix || avctx->inter_matrix) ) { x->vol_flags |= XVID_VOL_MPEGQUANT; if( avctx->intra_matrix ) { intra = avctx->intra_matrix; x->intra_matrix = av_malloc(sizeof(unsigned char) * 64); } else intra = NULL; if( avctx->inter_matrix ) { inter = avctx->inter_matrix; x->inter_matrix = av_malloc(sizeof(unsigned char) * 64); } else inter = NULL; for( i = 0; i < 64; i++ ) { if( intra ) x->intra_matrix[i] = (unsigned char)intra[i]; if( inter ) x->inter_matrix[i] = (unsigned char)inter[i]; } } /* Misc Settings */ xvid_enc_create.frame_drop_ratio = 0; xvid_enc_create.global = 0; if( xvid_flags & CODEC_FLAG_CLOSED_GOP ) xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP; /* Determines which codec mode we are operating in */ avctx->extradata = NULL; avctx->extradata_size = 0; if( xvid_flags & CODEC_FLAG_GLOBAL_HEADER ) { /* In this case, we are claiming to be MPEG4 */ x->quicktime_format = 1; avctx->codec_id = CODEC_ID_MPEG4; } else { /* We are claiming to be XviD */ x->quicktime_format = 0; avctx->codec_tag = ff_get_fourcc("xvid"); } /* Bframes */ xvid_enc_create.max_bframes = avctx->max_b_frames; xvid_enc_create.bquant_offset = avctx->b_quant_offset; xvid_enc_create.bquant_ratio = 100 * avctx->b_quant_factor; if( avctx->max_b_frames > 0 && !x->quicktime_format ) xvid_enc_create.global |= XVID_GLOBAL_PACKED; /* Create encoder context */ xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL); if( xerr ) { av_log(avctx, AV_LOG_ERROR, "XviD: Could not create encoder reference\n"); return -1; } x->encoder_handle = xvid_enc_create.handle; avctx->coded_frame = &x->encoded_picture; return 0;}/** * Encodes a single frame. * * @param avctx AVCodecContext pointer to context * @param frame Pointer to encoded frame buffer * @param buf_size Size of encoded frame buffer * @param data Pointer to AVFrame of unencoded frame * @return Returns 0 on success, -1 on failure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -