[FFmpeg-devel] [PATCH] HWAccel infrastructure (take 6)
Michael Niedermayer
michaelni
Fri Feb 20 22:04:08 CET 2009
On Fri, Feb 20, 2009 at 05:25:49PM +0100, Gwenole Beauchesne wrote:
> Le 20 f?vr. 09 ? 15:36, Michael Niedermayer a ?crit :
>
>>>> i still think this is ugly implemented ...
>>>
>>> Well, I need at least two things: the slice size and mb_y. I preferred
>>> regrouping everything into the original mpeg_decode_slice(),
>>> otherwise, with a buf temporary, we would have to maintain at least 3
>>> locations where we (i) update mb_y, (ii) record current slice
>>> position, (iii) early on top do buf-prev_buf to get the size and call
>>> hwaccel->decode_slice() and even (iv) for the very last slice.
>>>
>>> What would you suggest?
>>
>> dunno, lets leave it for now if you dont see a way to improve it
>> little in the patch depends on how mpeg1/2 is dealt with ...
>
> Moving the code back into decode_chunks() and getting rid of the extra
> ff_find_start_code() would require either of the following solutions:
>
> (1) Perform one hwaccel->decode_slice() at the end of the frame (before
> slice_end() check) and another call down in the normal "slice" case + in
> both case, updating s->mb_{x,y} et al.
> -or-
> (2) Perform a single hwaccel->decode_slice() at the begining of the loop
> but maintain another variable (beyond the "old_buf_start"): an
> "old_start_code" one to actually know if the previous iteration dealt with
> a slice.
>
> I really think keeping the current code in the original mpeg_decode_slice()
> better, because it's a single (and natural, IMO) location to maintain.
>
> Here is a new patch. Is this OK now?
[...]
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 62e4e47..129e15d 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -2315,6 +2315,13 @@ typedef struct AVCodecContext {
> * - decoding: unused.
> */
> float rc_min_vbv_overflow_use;
> +
> + /**
> + * Hardware accelerator in use
> + * - encoding: unused.
> + * - decoding: Set by libavcodec
> + */
> + struct AVHWAccel *hwaccel;
> } AVCodecContext;
>
> /**
> @@ -2360,6 +2367,87 @@ typedef struct AVCodec {
> } AVCodec;
>
> /**
> + * AVHWAccel.
> + */
> +typedef struct AVHWAccel {
> + /**
> + * Name of the hardware accelerated codec.
> + * The name is globally unique among encoders and among decoders (but an
> + * encoder and a decoder can share the same name).
> + */
> + const char *name;
> +
> + /**
> + * Type of codec implemented by the hardware accelerator.
> + *
> + * See CODEC_TYPE_xxx
> + */
> + enum CodecType type;
> +
> + /**
> + * Codec implemented by the hardware accelerator.
> + *
> + * See CODEC_ID_xxx
> + */
> + enum CodecID id;
> +
> + /**
> + * Supported pixel format.
> + *
> + * Only hardware accelerated formats are supported here.
> + */
> + enum PixelFormat pix_fmt;
> +
> + /**
> + * Hardware accelerated codec capabilities.
> + * see FF_HWACCEL_CODEC_CAP_*
> + */
> + int capabilities;
> +
> + struct AVHWAccel *next;
> +
> + /**
> + * Called at the beginning of each frame or field picture.
> + *
> + * Meaningful frame information (codec specific) is guaranteed to
> + * be parsed at this point. This function is mandatory.
> + *
> + * Note that \p buf can be NULL along with \p buf_size set to 0.
> + * Otherwise, this means the whole frame is available at this point.
> + *
> + * @param avctx the codec context
> + * @param buf the frame data buffer base
> + * @param buf_size the size of the frame in bytes
> + * @return zero if successful, a negative value otherwise
> + */
> + int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
> +
> + /**
> + * Callback for each slice.
> + *
> + * Meaningful slice information (codec specific) is guaranteed to
> + * be parsed at this point. This function is mandatory.
> + *
> + * @param avctx the codec context
> + * @param buf the slice data buffer base
> + * @param buf_size the size of the slice in bytes
> + * @return zero if successful, a negative value otherwise
> + */
> + int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size);
> +
> + /**
> + * Called at the end of each frame or field picture.
> + *
> + * The whole picture is parsed at this point and can now be sent
> + * to the hardware accelerator. This function is mandatory.
> + *
> + * @param avctx the codec context
> + * @return zero if successful, a negative value otherwise
> + */
> + int (*end_frame)(AVCodecContext *avctx);
> +} AVHWAccel;
> +
> +/**
> * four components are given, that's all.
> * the last component is alpha
> */
> @@ -3166,4 +3254,16 @@ int av_parse_video_frame_rate(AVRational *frame_rate, const char *str);
> #define AVERROR_NOENT AVERROR(ENOENT) /**< No such file or directory. */
> #define AVERROR_PATCHWELCOME -MKTAG('P','A','W','E') /**< Not yet implemented in FFmpeg. Patches welcome. */
>
> +/**
> + * Registers the hardware accelerator \p hwaccel.
> + */
> +void av_register_hwaccel(AVHWAccel *hwaccel);
> +
> +/**
> + * If hwaccel is NULL, returns the first registered hardware accelerator,
> + * if hwaccel is non-NULL, returns the next registered hardware accelerator
> + * after hwaccel, or NULL if hwaccel is the last one.
> + */
> +AVHWAccel *av_hwaccel_next(AVHWAccel *hwaccel);
> +
> #endif /* AVCODEC_AVCODEC_H */
> diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c
> index a196326..c21bc70 100644
> --- a/libavcodec/error_resilience.c
> +++ b/libavcodec/error_resilience.c
> @@ -680,6 +680,7 @@ void ff_er_frame_end(MpegEncContext *s){
> Picture *pic= s->current_picture_ptr;
>
> if(!s->error_recognition || s->error_count==0 || s->avctx->lowres ||
> + s->avctx->hwaccel ||
> s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU ||
> s->error_count==3*s->mb_width*(s->avctx->skip_top + s->avctx->skip_bottom)) return;
>
> diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
> index 4cd2ce8..1eb7f9d 100644
> --- a/libavcodec/h263dec.c
> +++ b/libavcodec/h263dec.c
> @@ -25,6 +25,7 @@
> * H.263 decoder.
> */
>
> +#include "internal.h"
> #include "avcodec.h"
> #include "dsputil.h"
> #include "mpegvideo.h"
ok and i would appreciate it if someone could apply this so the patch becomes
smaller
> @@ -51,9 +52,14 @@ av_cold int ff_h263_decode_init(AVCodecContext *avctx)
> s->quant_precision=5;
> s->decode_mb= ff_h263_decode_mb;
> s->low_delay= 1;
> - avctx->pix_fmt= PIX_FMT_YUV420P;
> s->unrestricted_mv= 1;
>
> + avctx->hwaccel = ff_query_hwaccel_codec(avctx, avctx->codec->id);
> + if (avctx->hwaccel)
> + avctx->pix_fmt = avctx->hwaccel->pix_fmt;
> + else
> + avctx->pix_fmt = PIX_FMT_YUV420P;
> +
> /* select sub codec */
> switch(avctx->codec->id) {
> case CODEC_ID_H263:
avctx->pix_fmt = ff_query_pixfmt(avctx, avctx->codec->id);
avctx->hwaccel = ff_pixfmt_to_hwaccal(avctx->codec->id, avctx->pix_fmt);
seems simpler per codec, also it seems better split if one has several
sw pix_fmts
> @@ -133,6 +139,9 @@ av_cold int ff_h263_decode_end(AVCodecContext *avctx)
> static int get_consumed_bytes(MpegEncContext *s, int buf_size){
> int pos= (get_bits_count(&s->gb)+7)>>3;
>
> + if (s->avctx->hwaccel) {
> + return buf_size;
> + }
> if(s->divx_packed){
if(s->divx_packed || s->avctx->hwaccel)
> //we would have to scan through the whole buf to handle the weird reordering ...
and update the comment if you want
> return buf_size;
> @@ -159,6 +168,9 @@ static int decode_slice(MpegEncContext *s){
>
> ff_set_qscale(s, s->qscale);
>
> + if (s->avctx->hwaccel)
> + return 0;
> +
> if(s->partitioned_frame){
> const int qscale= s->qscale;
>
ok
[...]
> --- a/libavcodec/h264.c
> +++ b/libavcodec/h264.c
> @@ -25,6 +25,7 @@
> * @author Michael Niedermayer <michaelni at gmx.at>
> */
>
> +#include "internal.h"
> #include "dsputil.h"
> #include "avcodec.h"
> #include "mpegvideo.h"
ok
[...]
> diff --git a/libavcodec/imgconvert.c b/libavcodec/imgconvert.c
> index abc253e..5b19826 100644
> --- a/libavcodec/imgconvert.c
> +++ b/libavcodec/imgconvert.c
> @@ -57,6 +57,7 @@ typedef struct PixFmtInfo {
> uint8_t color_type; /**< color type (see FF_COLOR_xxx constants) */
> uint8_t pixel_type; /**< pixel storage type (see FF_PIXEL_xxx constants) */
> uint8_t is_alpha : 1; /**< true if alpha can be specified */
> + uint8_t is_hwaccel : 1; /**< true if this is an HW accelerated format */
> uint8_t x_chroma_shift; /**< X chroma subsampling factor is 2 ^ shift */
> uint8_t y_chroma_shift; /**< Y chroma subsampling factor is 2 ^ shift */
> uint8_t depth; /**< bit depth of the color components */
> @@ -263,24 +264,31 @@ static const PixFmtInfo pix_fmt_info[PIX_FMT_NB] = {
> },
> [PIX_FMT_XVMC_MPEG2_MC] = {
> .name = "xvmcmc",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_XVMC_MPEG2_IDCT] = {
> .name = "xvmcidct",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_VDPAU_MPEG1] = {
> .name = "vdpau_mpeg1",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_VDPAU_MPEG2] = {
> .name = "vdpau_mpeg2",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_VDPAU_H264] = {
> .name = "vdpau_h264",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_VDPAU_WMV3] = {
> .name = "vdpau_wmv3",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_VDPAU_VC1] = {
> .name = "vdpau_vc1",
> + .is_hwaccel = 1,
> },
> [PIX_FMT_UYYVYY411] = {
> .name = "uyyvyy411",
> @@ -443,6 +451,11 @@ void avcodec_pix_fmt_string (char *buf, int buf_size, int pix_fmt)
> }
> }
>
> +int ff_is_hwaccel_pix_fmt(enum PixelFormat pix_fmt)
> +{
> + return pix_fmt_info[pix_fmt].is_hwaccel;
> +}
> +
> int ff_set_systematic_pal(uint32_t pal[256], enum PixelFormat pix_fmt){
> int i;
>
> diff --git a/libavcodec/internal.h b/libavcodec/internal.h
> index a8bed35..e1b3b0d 100644
> --- a/libavcodec/internal.h
> +++ b/libavcodec/internal.h
> @@ -24,6 +24,9 @@
> #ifndef AVCODEC_INTERNAL_H
> #define AVCODEC_INTERNAL_H
>
> +#include <stdint.h>
> +#include "avcodec.h"
> +
> /**
> * Logs a generic warning message about a missing feature.
> * @param[in] avc a pointer to an arbitrary struct of which the first field is
ok
[...]
> diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c
> index 6cf0335..c14cd6e 100644
> --- a/libavcodec/mpeg12.c
> +++ b/libavcodec/mpeg12.c
> @@ -26,6 +26,7 @@
> */
>
> //#define DEBUG
> +#include "internal.h"
> #include "avcodec.h"
> #include "dsputil.h"
> #include "mpegvideo.h"
ok
[...]
> @@ -1303,6 +1308,7 @@ static int mpeg_decode_postinit(AVCodecContext *avctx){
> avctx->pix_fmt = mpeg_get_pixelformat(avctx);
> //until then pix_fmt may be changed right after codec init
> if( avctx->pix_fmt == PIX_FMT_XVMC_MPEG2_IDCT ||
> + avctx->hwaccel ||
> s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU )
> if( avctx->idct_algo == FF_IDCT_AUTO )
> avctx->idct_algo = FF_IDCT_SIMPLE;
ok
[...]
> diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
> index 2eec211..c213c82 100644
> --- a/libavcodec/mpegvideo.c
> +++ b/libavcodec/mpegvideo.c
> @@ -955,7 +955,8 @@ void MPV_frame_end(MpegEncContext *s)
> //just to make sure that all data is rendered.
> if(CONFIG_MPEG_XVMC_DECODER && s->avctx->xvmc_acceleration){
> ff_xvmc_field_end(s);
> - }else if(!(s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
> + }else if(!s->avctx->hwaccel
> + && !(s->avctx->codec->capabilities&CODEC_CAP_HWACCEL_VDPAU)
> && s->unrestricted_mv
> && s->current_picture.reference
> && !s->intra_only
> diff --git a/libavcodec/utils.c b/libavcodec/utils.c
> index 215029d..3229e9e 100644
> --- a/libavcodec/utils.c
> +++ b/libavcodec/utils.c
> @@ -391,7 +391,9 @@ int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, v
> return 0;
> }
>
> -enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat * fmt){
> +enum PixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum PixelFormat *fmt){
> + while (*fmt != PIX_FMT_NONE && ff_is_hwaccel_pix_fmt(*fmt))
> + ++fmt;
> return fmt[0];
> }
>
ok
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> ... defining _GNU_SOURCE...
For the love of all that is holy, and some that is not, don't do that.
-- Luca & Mans
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090220/d232e47a/attachment.pgp>
More information about the ffmpeg-devel
mailing list