[FFmpeg-devel] [PATCH] AVHWAccel infrastructure v2 (take 3)

Gwenole Beauchesne gbeauchesne
Fri Nov 13 16:38:42 CET 2009


Hi,

On Mon, 9 Nov 2009, Michael Niedermayer wrote:

> On Mon, Sep 28, 2009 at 03:19:47PM +0200, Gwenole Beauchesne wrote:
>> On Sat, 26 Sep 2009, Gwenole Beauchesne wrote:
>>
>>> Le 26 sept. 09 ? 09:28, Gwenole Beauchesne a ?crit :
>>>
>>>> This patch updates the AVHWAccel infrastructure to make it possible to:
>>>> - Get rid of the PixelFormat hacks
>>>> - Get pixels back from GPU memory when the user requested it
>>>> - Fallback implicitly to SW decoding
>>>> - Handle multiple hardware accelerators (e.g. different chips in a single
>>>> system)
>>>> - Enable user-applications very easily
>
> Can these be split into seperate patches?

I think this was the smallest bits and, as you noticed hereunder, some 
enums/structs looked incomplete because they were part of other patches.

Besides, the patch did not remove the HW accel pixfmts so that to maintain 
some compatibility for now, and because I don't know what was the usual 
procedure for that since this would remove pixfmt in the middle of others, 
thus being an API/ABI change.

> [...]
>> @@ -2526,6 +2527,14 @@ typedef struct AVCodecContext {
>>       * - decoding: Set by libavcodec
>>       */
>>       enum AVChromaLocation chroma_sample_location;
>> +
>> +    /**
>> +     * Hardware accelerator configuration attributes.
>> +     * The array is terminated by HWACCEL_ATTR_NONE.
>> +     * - encoding: unused
>> +     * - decoding: Set by user
>> +     */
>> +    const uintptr_t *hwaccel_attrs;
>>  } AVCodecContext;
>>
>>  /**
>
> uintptr_t is an optional type in C
> and i really have a bad feeling about using it in public API, i bet this
> will break several compilers

I wanted an uintptr_t so that it was as large as a pointer because a 
pointer may be needed for certain attributes.

> [...]
>> +/** Identifies the hardware accelerator */
>> +enum HWAccelID {
>> +    HWACCEL_ID_NONE,
>> +    HWACCEL_ID_NB
>> +};
>
> That doesnt look complete, and thus makes a review hard

Others were:
HWACCEL_ID_VAAPI,
HWACCEL_ID_VDPAU,

>> +
>> +/** Identifies the hardware accelerator entry-point */
>> +enum HWAccelEntrypoint {
>> +    HWACCEL_ENTRYPOINT_VLD = 1, ///< Variable-length decoding
>> +    HWACCEL_ENTRYPOINT_IZZ,     ///< Inverse zig-zag scan decoder
>> +    HWACCEL_ENTRYPOINT_IDCT,    ///< Inverse discrete cosine transform
>> +    HWACCEL_ENTRYPOINT_MOCO,    ///< Motion compensation
>> +    HWACCEL_ENTRYPOINT_NB
>> +};
>
> The documentation is too terse

/** Identifies the hardware accelerator entry-point. The entry-point 
defines the point where the hardware accelerator would actually handle the 
decoding operations */
?

> [...]
>> @@ -248,9 +249,29 @@ int avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){
>>          }
>>      }
>>
>> +    if (s->hwaccel &&
>> +        !ff_find_hwaccel_attribute(s, HWACCEL_ATTR_GET_PIXELS, &alloc_pixels))
>> +        alloc_pixels = 0; /* SW surfaces are not needed */
>> +
>
> We have an existing API to let the user application choose the output
> format (get_format())
> your patch does this instead without explaining why the existing API is
> not used  ...

get_format() deals with pixel formats. The aim was to get rid of HW accel 
pixel formats because some other HW accelerator will need the pixel format 
set to e.g. NV12 and we'd still need a way to identify this HW 
accelerator.

Besides, with this iteration of hwaccel, the pixel format for HW will have 
the same meaning as for SW: what pixel format the user actually wants for 
real. e.g. if he wants to get the HW decoded pixels back, pixfmt will 
identify this format, which will be the "standard" meaning, i.e. the same 
as in SW mode.

>>      if(buf->base[0]){
>>          pic->age= *picture_number - buf->last_pic_num;
>>          buf->last_pic_num= *picture_number;
>> +    }else if(s->hwaccel && !alloc_pixels){
>> +        pic->age= 256*256*256*64;
>> +        buf->last_pic_num= -256*256*256*64;
>> +        memset(buf->linesize, 0, sizeof(buf->linesize));
>> +        memset(buf->base, 0, sizeof(buf->base));
>> +        memset(buf->data, 0, sizeof(buf->data));
>> +        /*
>> +         * Allocate a dummy buffer so that we don't have to worry
>> +         * about hwaccel checks afterwards in this get_buffer() /
>> +         * release_buffer() machinery.
>> +         */
>> +        buf->base[0] = av_malloc(16);
>> +        buf->data[0] = buf->base[0];
>> +        buf->width   = s->width;
>> +        buf->height  = s->height;
>> +        buf->pix_fmt = s->pix_fmt;
>
> i would say base/data either contain pixels or could contain some struct
> representing a surface of the hwaccelerator
> why is neither of these the case?

data[3] does contain that struct for the HW accelerator (vaapi_context, 
vdpau_render_state). However, for the default mode of operations, that is 
user wants to use hwaccel for decode+display, we don't have to allocate 
data[0-2] pixels. This saves memory in that case. However, making it NULL 
is possible but would require further checks in 
get_buffer()/release_buffer().

alloc_pixels is set if the user requested so through 
HWACCEL_ATTR_GET_PIXELS. We could keep FFmpeg allocating the pixels but 
doing so for several MBs won't be useful for the common case 
(decode+display), i.e. IMHO this would be a waste.

> [...]
>> +/** Returns a hardware accelerator for the specified codec */
>> +static AVHWAccel *find_hwaccel(AVCodecContext *avctx, enum CodecID codec_id)
>> +{
>> +    AVHWAccel *hwaccel = NULL, *best = NULL;
>> +    uintptr_t hwaccel_id, get_pixels;
>> +
>> +    static const int score[] = {
>> +        [HWACCEL_ENTRYPOINT_MOCO] = 1,
>> +        [HWACCEL_ENTRYPOINT_IDCT] = 2,
>> +        [HWACCEL_ENTRYPOINT_IZZ]  = 3,
>> +        [HWACCEL_ENTRYPOINT_VLD]  = 4
>> +    };
>> +
>> +    if (!ff_find_hwaccel_attribute(avctx, HWACCEL_ATTR_FORCE_ID, &hwaccel_id))
>> +        hwaccel_id = HWACCEL_ID_NONE;
>> +
>> +    if (!ff_find_hwaccel_attribute(avctx, HWACCEL_ATTR_GET_PIXELS, &get_pixels))
>> +        get_pixels = 0;
>> +
>> +    while ((hwaccel = av_hwaccel_next(hwaccel))) {
>> +        if (hwaccel_id != HWACCEL_ID_NONE && hwaccel->hwaccel_id != hwaccel_id)
>> +            continue;
>> +        if (get_pixels && !(hwaccel->capabilities & HWACCEL_CAP_GET_PIXELS))
>> +            continue;
>> +        if (hwaccel->id == codec_id &&
>> +            (!best || score[best->entrypoint] < score[hwaccel->entrypoint]))
>> +            best = hwaccel;
>> +    }
>> +    return best;
>> +}
>
> the formats given to the user app in get_format() are ordered per preferance
> this again bypasses existing API without comment
> why?

Because get_format() deals with pixel format which we (well, I) don't want 
in order to implement the following:
- Get pixels back from GPU memory when the user requested it => pixfmt 
will be used for the actual format chosen by the user
- Implement another HW accelerator that is a pure decoder: it returns NV12 
pixels.

Thanks,
Gwenole



More information about the ffmpeg-devel mailing list