summaryrefslogtreecommitdiff
path: root/libavcodec/libxvid.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/libxvid.c')
-rw-r--r--libavcodec/libxvid.c175
1 files changed, 116 insertions, 59 deletions
diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c
index 6486ad1855..b6840ee358 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,17 +25,26 @@
* @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"
#include "avcodec.h"
+#include "internal.h"
#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.
*/
@@ -48,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 */
@@ -60,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 */
@@ -77,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
*
@@ -107,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),
@@ -275,6 +287,8 @@ static int xvid_strip_vol_header(AVCodecContext *avctx, AVPacket *pkt,
/* We need to store the header, so extract it */
if (!avctx->extradata) {
avctx->extradata = av_malloc(vo_len);
+ if (!avctx->extradata)
+ return AVERROR(ENOMEM);
memcpy(avctx->extradata, pkt->data, vo_len);
avctx->extradata_size = vo_len;
}
@@ -347,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;
@@ -415,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;
@@ -457,6 +473,19 @@ 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.");
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ }
+#endif
xvid_enc_create.plugins = plugins;
xvid_enc_create.num_plugins = 0;
@@ -474,7 +503,8 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (!x->twopassbuffer || !x->old_twopassbuffer) {
av_log(avctx, AV_LOG_ERROR,
"Xvid: Cannot allocate 2-pass log buffers\n");
- return AVERROR(ENOMEM);
+ ret = AVERROR(ENOMEM);
+ goto fail;
}
x->twopassbuffer[0] =
x->old_twopassbuffer[0] = 0;
@@ -486,26 +516,31 @@ 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;
+ ret = fd;
+ goto fail;
}
+ 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;
+ ret = AVERROR(EINVAL);
+ goto fail;
}
- 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)
+ 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;
@@ -523,12 +558,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;
@@ -549,6 +578,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;
@@ -593,11 +627,19 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx)
if (avctx->intra_matrix) {
intra = avctx->intra_matrix;
x->intra_matrix = av_malloc(sizeof(unsigned char) * 64);
+ if (!x->intra_matrix) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
} else
intra = NULL;
if (avctx->inter_matrix) {
inter = avctx->inter_matrix;
x->inter_matrix = av_malloc(sizeof(unsigned char) * 64);
+ if (!x->inter_matrix) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
} else
inter = NULL;
@@ -636,19 +678,26 @@ 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;
+ goto fail;
}
x->encoder_handle = xvid_enc_create.handle;
avctx->coded_frame = av_frame_alloc();
- if (!avctx->coded_frame)
- return AVERROR(ENOMEM);
+ if (!avctx->coded_frame) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
return 0;
+fail:
+ xvid_encode_close(avctx);
+ return ret;
}
static int xvid_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
@@ -664,11 +713,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;
@@ -682,7 +728,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 */
@@ -703,11 +749,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;
@@ -770,7 +818,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;
}
}
@@ -778,16 +826,25 @@ 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) {
- 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);
+ av_frame_free(&avctx->coded_frame);
return 0;
}