From 132d822b795bb4df3bf90a9ed13d625f63565647 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Thu, 4 Apr 2013 10:08:51 +0200 Subject: [PATCH] Lavc: avoid posterization with H.264 Enable AQ mode to avoid posterization with H.264. --- configure.ac | 5 +- src/video_compress/libavcodec.c | 122 +++++++++++++++++------------- src/video_decompress/libavcodec.c | 29 +++---- 3 files changed, 88 insertions(+), 68 deletions(-) diff --git a/configure.ac b/configure.ac index 92b2e9265..61f5dd61e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/video_compress/libavcodec.c b/src/video_compress/libavcodec.c index 0d94c7c93..bc4342151 100644 --- a/src/video_compress/libavcodec.c +++ b/src/video_compress/libavcodec.c @@ -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=][:bitrate=]" - "[:subsampling=]\n"); + "[:subsampling=][:preset=]\n"); printf("\t\t may be " " one of \"H.264\", \"VP8\" or " "\"MJPEG\" (default)\n"); printf("\t\t specifies requested bitrate\n"); printf("\t\t may be one of 422 or 420, default 420 for progresive, 422 for interlaced\n"); + printf("\t\t 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); } diff --git a/src/video_decompress/libavcodec.c b/src/video_decompress/libavcodec.c index c04bbc077..88c10eb15 100644 --- a/src/video_decompress/libavcodec.c +++ b/src/video_decompress/libavcodec.c @@ -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 {