Lavc: avoid posterization with H.264

Enable AQ mode to avoid posterization with H.264.
This commit is contained in:
Martin Pulec
2013-04-04 10:08:51 +02:00
parent 33849e055e
commit 132d822b79
3 changed files with 88 additions and 68 deletions

View File

@@ -2386,7 +2386,7 @@ AS_HELP_STRING([--disable-libavcodec], [disable libavcodec support(default is au
[libavcodec_req=auto]
)
#PKG_CHECK_MODULES([LIBAVCODEC], [libavcodec], [found_libavcodec=yes], [found_libavcodec=no])
if test $system = Windows; then
AC_CHECK_HEADERS([libavcodec/avcodec.h libavutil/imgutils.h libavutil/opt.h])
AC_CHECK_LIB(avcodec, avcodec_open2)
AC_CHECK_LIB(avutil, av_free)
@@ -2401,6 +2401,9 @@ then
else
found_libavcodec=no
fi
else # Linux, OS X
PKG_CHECK_MODULES([LIBAVCODEC], [libavcodec], [found_libavcodec=yes], [found_libavcodec=no])
fi
if test $libavcodec_req != no -a $found_libavcodec = yes
then

View File

@@ -67,6 +67,16 @@
#define DEFAULT_CODEC MJPG
#ifndef HAVE_AVCODEC_ENCODE_VIDEO2
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
#define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P
#define AV_CODEC_ID_H264 CODEC_ID_H264
#define AV_CODEC_ID_MJPEG CODEC_ID_MJPEG
#define AV_CODEC_ID_VP8 CODEC_ID_VP8
#endif
struct libav_video_compress {
pthread_mutex_t *lavcd_global_lock;
@@ -91,6 +101,7 @@ struct libav_video_compress {
int subsampling;
codec_t out_codec;
char *preset;
};
static void to_yuv420(AVFrame *out_frame, unsigned char *in_data, int width, int height);
@@ -101,12 +112,13 @@ static void cleanup(struct libav_video_compress *s);
static void usage() {
printf("Libavcodec encoder usage:\n");
printf("\t-c libavcodec[:codec=<codec_name>][:bitrate=<bits_per_sec>]"
"[:subsampling=<subsampling>]\n");
"[:subsampling=<subsampling>][:preset=<preset>]\n");
printf("\t\t<codec_name> may be "
" one of \"H.264\", \"VP8\" or "
"\"MJPEG\" (default)\n");
printf("\t\t<bits_per_sec> specifies requested bitrate\n");
printf("\t\t<subsampling> may be one of 422 or 420, default 420 for progresive, 422 for interlaced\n");
printf("\t\t<preset> codec preset options, eg. ultrafast, superfast, medium etc. for H.264\n");
printf("\t\t\t0 means codec default (same as when parameter omitted)\n");
}
@@ -125,6 +137,7 @@ void * libavcodec_compress_init(char * fmt)
s->in_frame = NULL;
s->selected_codec_id = DEFAULT_CODEC;
s->subsampling = s->requested_subsampling = 0;
s->preset = NULL;
s->requested_bitrate = -1;
@@ -178,6 +191,9 @@ void * libavcodec_compress_init(char * fmt)
free(s);
return NULL;
}
} else if(strncasecmp("preset=", item, strlen("preset=")) == 0) {
char *preset = item + strlen("preset=");
s->preset = strdup(preset);
} else {
fprintf(stderr, "[lavc] Error: unknown option %s.\n",
item);
@@ -212,18 +228,12 @@ static bool configure_with(struct libav_video_compress *s, struct video_desc des
double avg_bpp; // average bite per pixel
struct video_desc compressed_desc;
enum {
YUV420P,
YUV422P,
YUVJ420P,
YUVJ422P
} tmp_pixfmt;
compressed_desc = desc;
switch(s->selected_codec_id) {
case H264:
#ifdef HAVE_GPL
codec_id = CODEC_ID_H264;
tmp_pixfmt = YUV420P;
codec_id = AV_CODEC_ID_H264;
pix_fmt = AV_PIX_FMT_YUV420P;
compressed_desc.color_spec = H264;
// from H.264 Primer
avg_bpp =
@@ -238,14 +248,14 @@ static bool configure_with(struct libav_video_compress *s, struct video_desc des
return false;
#endif
case MJPG:
codec_id = CODEC_ID_MJPEG;
tmp_pixfmt = YUVJ420P;
codec_id = AV_CODEC_ID_MJPEG;
pix_fmt = AV_PIX_FMT_YUVJ420P;
compressed_desc.color_spec = MJPG;
avg_bpp = 0.7;
break;
case VP8:
codec_id = CODEC_ID_VP8;
tmp_pixfmt = YUV420P;
codec_id = AV_CODEC_ID_VP8;
pix_fmt = AV_PIX_FMT_YUV420P;
compressed_desc.color_spec = VP8;
avg_bpp = 0.5;
break;
@@ -262,47 +272,16 @@ static bool configure_with(struct libav_video_compress *s, struct video_desc des
(desc.interlacing == INTERLACED_MERGED &&
s->requested_subsampling != 420)) {
s->subsampling = 422;
if(tmp_pixfmt == YUV420P) {
tmp_pixfmt = YUV422P;
if(pix_fmt == AV_PIX_FMT_YUV420P) {
pix_fmt = AV_PIX_FMT_YUV422P;
}
if(tmp_pixfmt == YUVJ420P) {
tmp_pixfmt = YUVJ422P;
if(pix_fmt == AV_PIX_FMT_YUVJ420P) {
pix_fmt = AV_PIX_FMT_YUVJ422P;
}
} else {
s->subsampling = 420;
}
switch(tmp_pixfmt) {
case YUV420P:
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
pix_fmt = AV_PIX_FMT_YUV420P;
#else
pix_fmt = PIX_FMT_YUV420P;
#endif
break;
case YUV422P:
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
pix_fmt = AV_PIX_FMT_YUV422P;
#else
pix_fmt = PIX_FMT_YUV422P;
#endif
break;
case YUVJ420P:
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
pix_fmt = AV_PIX_FMT_YUVJ420P;
#else
pix_fmt = PIX_FMT_YUVJ420P;
#endif
break;
case YUVJ422P:
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
pix_fmt = AV_PIX_FMT_YUVJ422P;
#else
pix_fmt = PIX_FMT_YUVJ422P;
#endif
break;
}
for(int i = 0; i < 2; ++i) {
s->out[i] = tile_alloc_desc(compressed_desc);
#ifndef HAVE_AVCODEC_ENCODE_VIDEO2
@@ -373,15 +352,51 @@ static bool configure_with(struct libav_video_compress *s, struct video_desc des
s->decoded = malloc(desc.width * desc.height * 4);
if(codec_id == CODEC_ID_H264) {
av_opt_set(s->codec_ctx->priv_data, "preset", "ultrafast", 0);
if(s->preset) {
if(av_opt_set(s->codec_ctx->priv_data, "preset", s->preset, 0) != 0) {
fprintf(stderr, "[Lavc] Error: Unable to set preset.\n");
return false;
}
}
if(codec_id == AV_CODEC_ID_H264) {
#ifdef HAVE_GPL
if(!s->preset) {
// ultrafast - --aq-mode 0
// This option causes posterization. Enabling it requires some 20% additional
// percent of CPU.
char params[] = "no-8x8dct=1:aq-mode=1:b-adapt=0:bframes=0:no-cabac=1:"
"no-deblock=1:no-mbtree=1:me=dia:no-mixed-refs=1:partitions=none:"
"rc-lookahead=0:ref=1:scenecut=0:subme=0:trellis=0:";
int ret;
// newer LibAV
ret = av_opt_set(s->codec_ctx->priv_data, "x264-params", params, 0);
if(ret != 0) {
// newer FFMPEG
ret = av_opt_set(s->codec_ctx->priv_data, "x264opts", params, 0);
}
if(ret != 0) {
// older version of both
// or superfast?? requires + some 70 % CPU but does not cause posterization
ret = av_opt_set(s->codec_ctx->priv_data, "preset", "ultrafast", 0);
fprintf(stderr, "[Lavc] Warning: Old FFMPEG/LibAV detected."
"Try supplying 'preset=superfast' argument to "
"avoid posterization!\n");
}
if(ret != 0) {
fprintf(stderr, "[Lavc] Warning: Unable to set preset.\n");
}
}
//av_opt_set(s->codec_ctx->priv_data, "tune", "fastdecode", 0);
av_opt_set(s->codec_ctx->priv_data, "tune", "zerolatency", 0);
#ifndef DISABLE_H264_INTRA_REFRESH
s->codec_ctx->refs = 1;
av_opt_set(s->codec_ctx->priv_data, "intra-refresh", "1", 0);
#endif
} else if(codec_id == CODEC_ID_VP8) {
#endif // defined DISABLE_H264_INTRA_REFRESH
#endif // defined HAVE_GPL
} else if(codec_id == AV_CODEC_ID_VP8) {
s->codec_ctx->thread_count = 8;
s->codec_ctx->profile = 3;
s->codec_ctx->slices = 4;
@@ -581,7 +596,7 @@ static void cleanup(struct libav_video_compress *s)
{
for(int i = 0; i < 2; ++i) {
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
vf_free(s->out[i]);
tile_free(s->out[i]);
s->out[i] = 0;
av_free_packet(&s->pkt[i]);
#else
@@ -613,6 +628,7 @@ void libavcodec_compress_done(void *arg)
cleanup(s);
rm_release_shared_lock(LAVCD_LOCK_NAME);
free(s->preset);
free(s);
}

View File

@@ -63,6 +63,17 @@
#include "video_compress/libavcodec.h" // LAVCD_LOCK_NAME
#include "video_decompress.h"
#ifndef HAVE_AVCODEC_ENCODE_VIDEO2
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
#define AV_PIX_FMT_YUVJ422P PIX_FMT_YUVJ422P
#define AV_PIX_FMT_NONE PIX_FMT_NONE
#define AV_CODEC_ID_H264 CODEC_ID_H264
#define AV_CODEC_ID_MJPEG CODEC_ID_MJPEG
#define AV_CODEC_ID_VP8 CODEC_ID_VP8
#endif
struct state_libavcodec_decompress {
pthread_mutex_t *global_lavcd_lock;
AVCodec *codec;
@@ -109,16 +120,16 @@ static bool configure_with(struct state_libavcodec_decompress *s,
int codec_id;
switch(desc.color_spec) {
case H264:
codec_id = CODEC_ID_H264;
codec_id = AV_CODEC_ID_H264;
break;
case MJPG:
case JPEG:
codec_id = CODEC_ID_MJPEG;
codec_id = AV_CODEC_ID_MJPEG;
fprintf(stderr, "[lavd] Warning: JPEG decoder "
"will use full-scale YUV.\n");
break;
case VP8:
codec_id = CODEC_ID_VP8;
codec_id = AV_CODEC_ID_VP8;
break;
default:
fprintf(stderr, "[lavd] Unsupported codec!!!\n");
@@ -154,7 +165,7 @@ static bool configure_with(struct state_libavcodec_decompress *s,
#endif
// set by decoder
s->codec_ctx->pix_fmt = PIX_FMT_NONE;
s->codec_ctx->pix_fmt = AV_PIX_FMT_NONE;
pthread_mutex_lock(s->global_lavcd_lock);
if(avcodec_open2(s->codec_ctx, s->codec, NULL) < 0) {
@@ -373,26 +384,16 @@ static int change_pixfmt(AVFrame *frame, unsigned char *dst, int av_codec,
assert(out_codec == UYVY || out_codec == RGB);
switch(av_codec) {
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
case AV_PIX_FMT_YUV422P:
case AV_PIX_FMT_YUVJ422P:
#else
case PIX_FMT_YUV422P:
case PIX_FMT_YUVJ422P:
#endif
if(out_codec == UYVY) {
yuv422p_to_yuv422((char *) dst, frame, width, height, pitch);
} else {
yuv422p_to_rgb24((char *) dst, frame, width, height, pitch);
}
break;
#ifdef HAVE_AVCODEC_ENCODE_VIDEO2
case AV_PIX_FMT_YUV420P:
case AV_PIX_FMT_YUVJ420P:
#else
case PIX_FMT_YUV420P:
case PIX_FMT_YUVJ420P:
#endif
if(out_codec == UYVY) {
yuv420p_to_yuv422((char *) dst, frame, width, height, pitch);
} else {