diff options
Diffstat (limited to 'libavcodec/libxvid.c')
-rw-r--r-- | libavcodec/libxvid.c | 142 |
1 files changed, 88 insertions, 54 deletions
diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index 5282ea7..4574f38 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 */ @@ -25,10 +25,10 @@ * @author Adam Thayer (krevnik@comcast.net) */ -#include <unistd.h> #include <xvid.h> #include "libavutil/cpu.h" +#include "libavutil/file.h" #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" @@ -37,6 +37,14 @@ #include "libxvid.h" #include "mpegvideo.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if HAVE_IO_H +#include <io.h> +#endif + /** * Buffer management macros. */ @@ -49,7 +57,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 */ @@ -61,6 +69,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 */ @@ -78,6 +87,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 * @@ -108,7 +119,7 @@ static int xvid_ff_2pass_create(xvid_plg_create_t *param, void **handle) /* 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), @@ -350,32 +361,34 @@ static void xvid_correct_framerate(AVCodecContext *avctx) static av_cold int xvid_encode_init(AVCodecContext *avctx) { - int xerr, i; + int xerr, i, ret = -1; int xvid_flags = avctx->flags; struct xvid_context *x = avctx->priv_data; 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 */ + x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */ if (avctx->trellis) - x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */ + 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; @@ -418,7 +431,7 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) 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; @@ -460,6 +473,18 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) xvid_enc_create.num_zones = 0; xvid_enc_create.num_threads = avctx->thread_count; +#if (XVID_VERSION <= 0x010303) && (XVID_VERSION >= 0x010300) + /* workaround for a bug in libxvidcore */ + if (avctx->height <= 16) { + if (avctx->thread_count < 2) { + xvid_enc_create.num_threads = 0; + } else { + av_log(avctx, AV_LOG_ERROR, + "Too small height for threads > 1."); + return AVERROR(EINVAL); + } + } +#endif xvid_enc_create.plugins = plugins; xvid_enc_create.num_plugins = 0; @@ -489,26 +514,29 @@ 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 < 0) { av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write 2-pass pipe\n"); return fd; } + x->twopassfd = fd; if (!avctx->stats_in) { av_log(avctx, AV_LOG_ERROR, "Xvid: No 2-pass information loaded for second pass\n"); - return AVERROR_INVALIDDATA; + return AVERROR(EINVAL); } - if (strlen(avctx->stats_in) > - write(fd, avctx->stats_in, strlen(avctx->stats_in))) { - close(fd); + ret = write(fd, avctx->stats_in, strlen(avctx->stats_in)); + if (ret == -1) + ret = AVERROR(errno); + else if (strlen(avctx->stats_in) > ret) { av_log(avctx, AV_LOG_ERROR, "Xvid: Cannot write to 2-pass pipe\n"); - return AVERROR(EIO); + ret = AVERROR(EIO); } + if (ret < 0) + return ret; - close(fd); rc2pass2.filename = x->twopassfile; plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; plugins[xvid_enc_create.num_plugins].param = &rc2pass2; @@ -526,12 +554,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; @@ -552,6 +574,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; @@ -643,11 +670,13 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) 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; + return AVERROR_EXTERNAL; } x->encoder_handle = xvid_enc_create.handle; @@ -667,11 +696,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*(int64_t)mb_height*MAX_MB_BYTES + FF_MIN_BUFFER_SIZE)) < 0) return ret; - } /* Start setting up the frame */ xvid_enc_frame.version = XVID_VERSION; @@ -685,7 +711,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 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 */ @@ -706,11 +732,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,7 +802,7 @@ static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return 0; av_log(avctx, AV_LOG_ERROR, "Xvid: Encoding Error Occurred: %i\n", xerr); - return xerr; + return AVERROR_EXTERNAL; } } @@ -789,12 +817,18 @@ static av_cold int xvid_encode_close(AVCodecContext *avctx) av_freep(&avctx->extradata); if (x->twopassbuffer) { - 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; } |