diff options
Diffstat (limited to 'libavcodec/libxvid.c')
-rw-r--r-- | libavcodec/libxvid.c | 162 |
1 files changed, 89 insertions, 73 deletions
diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index eab61be..88d748e 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -2,20 +2,20 @@ * Interface to xvidcore for mpeg4 encoding * Copyright (c) 2004 Adam Thayer <krevnik@comcast.net> * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg 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.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -28,6 +28,8 @@ #include <xvid.h> #include <unistd.h> #include "avcodec.h" +#include "internal.h" +#include "libavutil/file.h" #include "libavutil/cpu.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" @@ -46,7 +48,7 @@ * This stores all the private context for the codec. */ struct xvid_context { - AVClass *class; /**< Handle for Xvid encoder */ + AVClass *class; void *encoder_handle; /**< Handle for Xvid encoder */ int xsize; /**< Frame x size */ int ysize; /**< Frame y size */ @@ -58,6 +60,7 @@ struct xvid_context { char *twopassbuffer; /**< Character buffer for two-pass */ char *old_twopassbuffer; /**< Old character buffer (two-pass) */ char *twopassfile; /**< second pass temp file name */ + int twopassfd; unsigned char *intra_matrix; /**< P-Frame Quant Matrix */ unsigned char *inter_matrix; /**< I-Frame Quant Matrix */ int lumi_aq; /**< Lumi masking as an aq method */ @@ -75,6 +78,8 @@ struct xvid_ff_pass1 { struct xvid_context *context; /**< Pointer to private context */ }; +static int xvid_encode_close(AVCodecContext *avctx); + /* * Xvid 2-Pass Kludge Section * @@ -105,7 +110,7 @@ static int xvid_ff_2pass_create(xvid_plg_create_t * param, /* This is because we can safely prevent a buffer overflow */ log[0] = 0; snprintf(log, BUFFER_REMAINING(log), - "# avconv 2-pass log file, using xvid codec\n"); + "# ffmpeg 2-pass log file, using xvid codec\n"); snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log), "# Do not modify. libxvidcore version: %d.%d.%d\n\n", XVID_VERSION_MAJOR(XVID_VERSION), @@ -352,46 +357,47 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { uint16_t *intra, *inter; int fd; - xvid_plugin_single_t single = { 0 }; - struct xvid_ff_pass1 rc2pass1 = { 0 }; - xvid_plugin_2pass2_t rc2pass2 = { 0 }; - xvid_plugin_lumimasking_t masking_l = { 0 }; /* For lumi masking */ - xvid_plugin_lumimasking_t masking_v = { 0 }; /* For variance AQ */ - xvid_plugin_ssim_t ssim = { 0 }; - xvid_gbl_init_t xvid_gbl_init = { 0 }; - xvid_enc_create_t xvid_enc_create = { 0 }; - xvid_enc_plugin_t plugins[7]; - - /* Bring in VOP flags from avconv command-line */ - x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */ + xvid_plugin_single_t single = { 0 }; + struct xvid_ff_pass1 rc2pass1 = { 0 }; + xvid_plugin_2pass2_t rc2pass2 = { 0 }; + xvid_plugin_lumimasking_t masking_l = { 0 }; /* For lumi masking */ + xvid_plugin_lumimasking_t masking_v = { 0 }; /* For variance AQ */ + xvid_plugin_ssim_t ssim = { 0 }; + xvid_gbl_init_t xvid_gbl_init = { 0 }; + xvid_enc_create_t xvid_enc_create = { 0 }; + xvid_enc_plugin_t plugins[4]; + + x->twopassfd = -1; + + /* 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( avctx->trellis - ) - x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */ + x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */ + if( avctx->trellis) + x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */ if( xvid_flags & CODEC_FLAG_AC_PRED ) - x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */ + x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */ if( xvid_flags & CODEC_FLAG_GRAY ) - x->vop_flags |= XVID_VOP_GREYSCALE; + 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; + 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; + 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; + x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 + | XVID_ME_HALFPELREFINE16; case ME_ZERO: /* Quality 0 */ default: @@ -402,21 +408,21 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { 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; + 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; + x->me_flags |= XVID_ME_HALFPELREFINE16_RD + | XVID_ME_QUARTERPELREFINE16_RD; default: break; } - /* Bring in VOL flags from avconv command-line */ + /* Bring in VOL flags from ffmpeg command-line */ #if FF_API_GMC if (avctx->flags & CODEC_FLAG_GMC) x->gmc = 1; @@ -424,12 +430,12 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { x->vol_flags = 0; if (x->gmc) { - x->vol_flags |= XVID_VOL_GMC; - x->me_flags |= XVID_ME_GME_REFINE; + 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; + 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; } @@ -485,7 +491,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { if( x->twopassbuffer == NULL || x->old_twopassbuffer == NULL ) { av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot allocate 2-pass log buffers\n"); - return -1; + goto fail; } x->twopassbuffer[0] = x->old_twopassbuffer[0] = 0; @@ -496,28 +502,27 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { rc2pass2.version = XVID_VERSION; rc2pass2.bitrate = avctx->bit_rate; - fd = ff_tempfile("xvidff.", &x->twopassfile); + fd = av_tempfile("xvidff.", &x->twopassfile, 0, avctx); if( fd == -1 ) { av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write 2-pass pipe\n"); - return -1; + goto fail; } + x->twopassfd = fd; if( avctx->stats_in == NULL ) { av_log(avctx, AV_LOG_ERROR, "Xvid: No 2-pass information loaded for second pass\n"); - return -1; + goto fail; } 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; + goto fail; } - close(fd); rc2pass2.filename = x->twopassfile; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; plugins[xvid_enc_create.num_plugins].param = &rc2pass2; @@ -535,12 +540,6 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { if (avctx->lumi_masking != 0.0) x->lumi_aq = 1; - if (x->lumi_aq && x->variance_aq) { - x->variance_aq = 0; - av_log(avctx, AV_LOG_WARNING, - "variance_aq is ignored when lumi_aq is set.\n"); - } - /* Luminance Masking */ if (x->lumi_aq) { masking_l.method = 0; @@ -561,6 +560,11 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { xvid_enc_create.num_plugins++; } + if( x->lumi_aq && x->variance_aq ) + av_log(avctx, AV_LOG_INFO, + "Both lumi_aq and variance_aq are enabled. The resulting quality" + "will be the worse one of the two effects made by the AQ.\n"); + /* SSIM */ if (x->ssim) { plugins[xvid_enc_create.num_plugins].func = xvid_plugin_ssim; @@ -644,11 +648,13 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { 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; + av_assert0(xvid_enc_create.num_plugins + (!!x->ssim) + (!!x->variance_aq) + (!!x->lumi_aq) <= FF_ARRAY_ELEMS(plugins)); + /* 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; + goto fail; } x->encoder_handle = xvid_enc_create.handle; @@ -657,6 +663,9 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) { return AVERROR(ENOMEM); return 0; +fail: + xvid_encode_close(avctx); + return -1; } static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, @@ -672,11 +681,8 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, xvid_enc_frame_t xvid_enc_frame = { 0 }; xvid_enc_stats_t xvid_enc_stats = { 0 }; - if (!user_packet && - (ret = av_new_packet(pkt, mb_width*mb_height*MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0) { - av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + if ((ret = ff_alloc_packet2(avctx, pkt, mb_width*mb_height*MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0) return ret; - } /* Start setting up the frame */ xvid_enc_frame.version = XVID_VERSION; @@ -689,7 +695,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, /* Initialize input image fields */ if( avctx->pix_fmt != AV_PIX_FMT_YUV420P ) { av_log(avctx, AV_LOG_ERROR, "Xvid: Color spaces other than 420p not supported\n"); - return -1; + return AVERROR(EINVAL); } xvid_enc_frame.input.csp = XVID_CSP_PLANAR; /* YUV420P */ @@ -710,11 +716,13 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, XVID_TYPE_AUTO; /* Pixel aspect ratio setting */ - if (avctx->sample_aspect_ratio.num < 1 || avctx->sample_aspect_ratio.num > 255 || - avctx->sample_aspect_ratio.den < 1 || avctx->sample_aspect_ratio.den > 255) { - av_log(avctx, AV_LOG_ERROR, "Invalid pixel aspect ratio %i/%i\n", + if (avctx->sample_aspect_ratio.num < 0 || avctx->sample_aspect_ratio.num > 255 || + avctx->sample_aspect_ratio.den < 0 || avctx->sample_aspect_ratio.den > 255) { + av_log(avctx, AV_LOG_WARNING, + "Invalid pixel aspect ratio %i/%i, limit is 255/255 reducing\n", avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); - return -1; + av_reduce(&avctx->sample_aspect_ratio.num, &avctx->sample_aspect_ratio.den, + avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 255); } xvid_enc_frame.par = XVID_PAR_EXT; xvid_enc_frame.par_width = avctx->sample_aspect_ratio.num; @@ -774,23 +782,31 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if (!xerr) return 0; av_log(avctx, AV_LOG_ERROR, "Xvid: Encoding Error Occurred: %i\n", xerr); - return -1; + return AVERROR_EXTERNAL; } } static av_cold int xvid_encode_close(AVCodecContext *avctx) { struct xvid_context *x = avctx->priv_data; - xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL); + if(x->encoder_handle) + xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL); + x->encoder_handle = NULL; av_freep(&avctx->extradata); if( x->twopassbuffer != NULL ) { - av_free(x->twopassbuffer); - av_free(x->old_twopassbuffer); + av_freep(&x->twopassbuffer); + av_freep(&x->old_twopassbuffer); + avctx->stats_out = NULL; + } + if (x->twopassfd>=0) { + unlink(x->twopassfile); + close(x->twopassfd); + x->twopassfd = -1; } - av_free(x->twopassfile); - av_free(x->intra_matrix); - av_free(x->inter_matrix); + av_freep(&x->twopassfile); + av_freep(&x->intra_matrix); + av_freep(&x->inter_matrix); return 0; } |