[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