[FFmpeg-devel] [PATCH] VP8 de/encode via libvpx
David Conrad
lessen42
Wed May 19 20:56:15 CEST 2010
On May 19, 2010, at 2:28 PM, James Zern wrote:
> VP8 and associated WebM container made public today [1].
>
> The attached will enable decode and basic encode of VP8 through
> libvpx. I split the encode as some of the options mapping done will
> probably be questionable so I thought that would do with its own
> thread.
>
> Some notes and questions regarding the sources:
> - libvpx{enc,dec} currently have a BSD style license, if it doesn't
> make sense in this context we can go to LGPL
Doesn't much matter, but I think shorter license headers might be nice
> - the configure test might do to be split for encode/decode
Only if disabling the encoder or decoder in libvpx means the relevant headers aren't installed or linking fails.
> - also related to configure and the sources, currently the library
> does not install includes to vpx/, for example, so the check is done
> just in the current include path
Does the libvpx install target work? It only reruns configure for me and I had to install the headers and libs manually.
> - libvpx can be built with multi-thread support (libpthread). Is it up
> to the user to add --enable-pthreads in this case or should that be
> rolled into this specific test?
It's up to the user for the moment as with libx264, but this is another reason for pthreads autodetection.
I've already applied the CODEC_ID_VP8 and fourcc/V_VP8 patches
The rest of the patches should be combined into one, or at least split into no more than 1. new options+version bump, 2. decoder+version bump, 3. encoder+version bump
Also, ffmpeg's indentation policy is 4 spaces.
> --- /dev/null 2010-02-26 16:50:52.000000000 -0500
> +++ libavcodec/libvpxdec.c 2010-05-17 23:46:16.000000000 -0400
> @@ -0,0 +1,168 @@
>
> [...]
>
> +#include "avcodec.h"
> +
> +#ifndef HAVE_STDINT_H
> +# define HAVE_STDINT_H 1
> +#endif
> +#define VPX_CODEC_DISABLE_COMPAT 1
Is all that really needed?
> +#if (defined(CONFIG_LIBPOSTPROC) && CONFIG_LIBPOSTPROC) ||\
> + (defined(CONFIG_POSTPROC) && CONFIG_POSTPROC)
> + const vpx_codec_flags_t flags = 0;
> +#else
> + const vpx_codec_flags_t flags = VPX_CODEC_USE_POSTPROC;
> +#endif
> +
> + av_log(avctx,AV_LOG_INFO,"%s\n",vpx_codec_version_str());
> + av_log(avctx,AV_LOG_VERBOSE,"%s\n",vpx_codec_build_config());
> +
> + if(vpx_codec_dec_init(&ctx->decoder,iface,&deccfg,flags)!=VPX_CODEC_OK) {
> + const char* error = vpx_codec_error(&ctx->decoder);
> + av_log(avctx,AV_LOG_ERROR,"Failed to initialize decoder: %s\n",error);
> + return -1;
> + }
> +
> + /*FIXME set based on user parameters. for now we'll disable based on
> + libpostproc presence in mplayer/ffmpeg based builds*/
> + if(flags&VPX_CODEC_USE_POSTPROC) {
> + ppcfg.post_proc_flag = VP8_DEMACROBLOCK|VP8_DEBLOCK|VP8_ADDNOISE;
> + ppcfg.deblocking_level = 5;
> + ppcfg.noise_level = 1;
> + vpx_codec_control(&ctx->decoder,VP8_SET_POSTPROC,&ppcfg);
> + }
IMO, a decoder shouldn't do postprocessing not required by the standard (e.g. in-loop filtering only)
> + if( (img= vpx_codec_get_frame(&ctx->decoder,&iter)) ) {
> + assert(img->fmt==IMG_FMT_I420);
Return an error rather than assert()
> + picture->data[0] = img->planes[0];
> + picture->data[1] = img->planes[1];
> + picture->data[2] = img->planes[2];
> + picture->data[3] = img->planes[3];
> + picture->linesize[0] = img->stride[0];
> + picture->linesize[1] = img->stride[1];
> + picture->linesize[2] = img->stride[2];
> + picture->linesize[3] = img->stride[3];
No need to copy the 4th plane if it only supports yuv420p
> --- /dev/null 2010-02-26 16:50:52.000000000 -0500
> +++ libavcodec/libvpxenc.c 2010-05-18 21:54:12.000000000 -0400
> @@ -0,0 +1,446 @@
> [...]
> + void *buf; /**< compressed data buffer */
> + size_t sz; /**< length of compressed data */
> + vpx_codec_pts_t pts; /**< time stamp to show frame
> + (in timebase units) */
> + unsigned long duration; /**< duration to show frame
> + (in timebase units) */
> + vpx_codec_frame_flags_t flags; /**< flags for this frame */
> + struct FrameListData *next;
> +} coded_frame_t;
> +
> +typedef struct VP8EncoderContext {
> + vpx_codec_ctx_t encoder;
> + vpx_image_t rawimg;
> + vpx_fixed_buf_t twopass_stats;
> + unsigned long deadline; //i.e., RT/GOOD/BEST
> + coded_frame_t* coded_frame_list;
> +} vp8ctx_t;
Don't use the _t namespace, it's reserved by POSIX
> +static int vp8_free(AVCodecContext *avctx);
> +static void free_frame_list(coded_frame_t* list);
> +static void free_coded_frame(coded_frame_t* cx_frame);
> +static void coded_frame_add(void* list, coded_frame_t* cx_frame);
> +static void log_encoder_error(AVCodecContext *avctx, const char* desc);
> +static void dump_enc_cfg(AVCodecContext *avctx, const vpx_codec_enc_cfg_t* cfg);
Arrange functions so forward prototypes aren't needed
> + { vpx_codec_err_t res;
> + const vpx_codec_pts_t timestamp = frame?frame->pts:0;
> + const unsigned long framedur = avctx->ticks_per_frame;
> + const vpx_enc_frame_flags_t flags = 0; //VPX_EFLAG_FORCE_KF
> + const unsigned long deadline = ctx->deadline;
Random conditionless subblocks are ugly, and const on local non-pointer variables is unnecessary.
More information about the ffmpeg-devel
mailing list