[2/9] hwcontext_dxva2: add support for the P8 format

Message ID 1476214475-20187-2-git-send-email-anton@khirnov.net
State Committed
Commit 10065d9324c2e35ce7040b6a2b9ebf6079bcbf42
Headers show

Commit Message

Anton Khirnov Oct. 11, 2016, 7:34 p.m.
This format is used internally by the QSV encoder to store the encoded
bitstream.
---
 libavutil/hwcontext_dxva2.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

Comments

Hendrik Leppkes Oct. 11, 2016, 8:33 p.m. | #1
On Tue, Oct 11, 2016 at 9:34 PM, Anton Khirnov <anton@khirnov.net> wrote:
> This format is used internally by the QSV encoder to store the encoded
> bitstream.

What does that even mean?
It smells like some evil hackery going into the nice clean hwcontext.

- Hendrik
Anton Khirnov Oct. 12, 2016, 7:58 a.m. | #2
Quoting Hendrik Leppkes (2016-10-11 22:33:43)
> On Tue, Oct 11, 2016 at 9:34 PM, Anton Khirnov <anton@khirnov.net> wrote:
> > This format is used internally by the QSV encoder to store the encoded
> > bitstream.
> 
> What does that even mean?
> It smells like some evil hackery going into the nice clean hwcontext.

Moderately evil.
If you want to use gpu surfaces with QSV, you need to supply a frame
allocator, which will be invoked to pass surface pools to it. For
encoding, this allocator gets invoked not only for the pool of input
frames, but also for a separate pool of (I assume) reconstructed frames
and another pool of MFX_FOURCC_P8, which on Windows needs to return
D3DFMT_P8 d3d surfaces. I think those are used to store the encoded
bitstream on the GPU.

In any case, while using P8 surfaces for this purpose is indeed rather
strange, there's nothing especially wrong about supporting them in the
DXVA2 hwcontext, it's just another surface format. The only hacky part
is the actual palette itself -- I didn't find a way to retrieve the
palette from a surface, so it's "emulated" by a dummy zero-filled
buffer. The actual contents are irrelevant for my specific use case (and
I don't expect it will be used for anything else).
Vittorio Giovara Oct. 12, 2016, 2:51 p.m. | #3
On Wed, Oct 12, 2016 at 3:58 AM, Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Hendrik Leppkes (2016-10-11 22:33:43)
>> On Tue, Oct 11, 2016 at 9:34 PM, Anton Khirnov <anton@khirnov.net> wrote:
>> > This format is used internally by the QSV encoder to store the encoded
>> > bitstream.
>>
>> What does that even mean?
>> It smells like some evil hackery going into the nice clean hwcontext.
>
> Moderately evil.
> If you want to use gpu surfaces with QSV, you need to supply a frame
> allocator, which will be invoked to pass surface pools to it. For
> encoding, this allocator gets invoked not only for the pool of input
> frames, but also for a separate pool of (I assume) reconstructed frames
> and another pool of MFX_FOURCC_P8, which on Windows needs to return
> D3DFMT_P8 d3d surfaces. I think those are used to store the encoded
> bitstream on the GPU.
>
> In any case, while using P8 surfaces for this purpose is indeed rather
> strange, there's nothing especially wrong about supporting them in the
> DXVA2 hwcontext, it's just another surface format. The only hacky part
> is the actual palette itself -- I didn't find a way to retrieve the
> palette from a surface, so it's "emulated" by a dummy zero-filled
> buffer. The actual contents are irrelevant for my specific use case (and
> I don't expect it will be used for anything else).
>
> --

Can we have this detailed explanation in the commit log please?

Patch

diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c
index 3159792..da24c6f 100644
--- a/libavutil/hwcontext_dxva2.c
+++ b/libavutil/hwcontext_dxva2.c
@@ -40,6 +40,10 @@ 
 typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
 typedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);
 
+typedef struct DXVA2Mapping {
+    uint32_t palette_dummy[256];
+} DXVA2Mapping;
+
 typedef struct DXVA2FramesContext {
     IDirect3DSurface9 **surfaces_internal;
     int              nb_surfaces_used;
@@ -66,6 +70,7 @@  static const struct {
 } supported_formats[] = {
     { MKTAG('N', 'V', '1', '2'), AV_PIX_FMT_NV12 },
     { MKTAG('P', '0', '1', '0'), AV_PIX_FMT_P010 },
+    { D3DFMT_P8,                 AV_PIX_FMT_PAL8 },
 };
 
 DEFINE_GUID(video_decoder_service,   0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02);
@@ -245,12 +250,14 @@  static void dxva2_unmap_frame(AVHWFramesContext *ctx, FFHWMapDescriptor *hwmap)
 {
     IDirect3DSurface9 *surface = (IDirect3DSurface9*)hwmap->source->data[3];
     IDirect3DSurface9_UnlockRect(surface);
+    av_freep(&hwmap->priv);
 }
 
 static int dxva2_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src,
                            int flags)
 {
     IDirect3DSurface9 *surface = (IDirect3DSurface9*)src->data[3];
+    DXVA2Mapping      *map;
     D3DSURFACE_DESC    surfaceDesc;
     D3DLOCKED_RECT     LockedRect;
     HRESULT            hr;
@@ -271,10 +278,16 @@  static int dxva2_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *
         return AVERROR_UNKNOWN;
     }
 
+    map = av_mallocz(sizeof(*map));
+    if (!map)
+        goto fail;
+
     err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
-                                dxva2_unmap_frame, NULL);
-    if (err < 0)
+                                dxva2_unmap_frame, map);
+    if (err < 0) {
+        av_freep(&map);
         goto fail;
+    }
 
     for (i = 0; i < nb_planes; i++)
         dst->linesize[i] = LockedRect.Pitch;
@@ -282,6 +295,9 @@  static int dxva2_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *
     av_image_fill_pointers(dst->data, dst->format, surfaceDesc.Height,
                            (uint8_t*)LockedRect.pBits, dst->linesize);
 
+    if (dst->format == AV_PIX_FMT_PAL8)
+        dst->data[1] = (uint8_t*)map->palette_dummy;
+
     return 0;
 fail:
     IDirect3DSurface9_UnlockRect(surface);