Merge commit '8ad9f9d675eab139aa2208722009eeed981460dd'
authorClément Bœsch <cboesch@gopro.com>
Thu, 30 Mar 2017 08:55:32 +0000 (10:55 +0200)
committerClément Bœsch <cboesch@gopro.com>
Thu, 30 Mar 2017 08:55:32 +0000 (10:55 +0200)
* commit '8ad9f9d675eab139aa2208722009eeed981460dd':
  hwcontext_vaapi: Frame mapping support

Merged-by: Clément Bœsch <cboesch@gopro.com>
1  2 
libavutil/hwcontext_vaapi.c

@@@ -1,18 -1,18 +1,18 @@@
  /*
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -70,20 -70,12 +70,12 @@@ typedef struct VAAPIFramesContext 
      int derive_works;
  } VAAPIFramesContext;
  
- enum {
-     VAAPI_MAP_READ   = 0x01,
-     VAAPI_MAP_WRITE  = 0x02,
-     VAAPI_MAP_DIRECT = 0x04,
- };
- typedef struct VAAPISurfaceMap {
-     // The source hardware frame of this mapping (with hw_frames_ctx set).
-     const AVFrame *source;
-     // VAAPI_MAP_* flags which apply to this mapping.
-     int flags;
+ typedef struct VAAPIMapping {
      // Handle to the derived or copied image which is mapped.
      VAImage image;
- } VAAPISurfaceMap;
+     // The mapping flags actually used.
+     int flags;
+ } VAAPIMapping;
  
  #define MAP(va, rt, av) { \
          VA_FOURCC_ ## va, \
@@@ -112,15 -104,13 +104,15 @@@ static struct 
      MAP(P010, YUV420_10BPP, P010),
  #endif
      MAP(BGRA, RGB32,   BGRA),
 -  //MAP(BGRX, RGB32,   BGR0),
 +    MAP(BGRX, RGB32,   BGR0),
      MAP(RGBA, RGB32,   RGBA),
 -  //MAP(RGBX, RGB32,   RGB0),
 +    MAP(RGBX, RGB32,   RGB0),
 +#ifdef VA_FOURCC_ABGR
      MAP(ABGR, RGB32,   ABGR),
 -  //MAP(XBGR, RGB32,   0BGR),
 +    MAP(XBGR, RGB32,   0BGR),
 +#endif
      MAP(ARGB, RGB32,   ARGB),
 -  //MAP(XRGB, RGB32,   0RGB),
 +    MAP(XRGB, RGB32,   0RGB),
  };
  #undef MAP
  
@@@ -142,7 -132,8 +134,8 @@@ static int vaapi_get_image_format(AVHWD
  
      for (i = 0; i < ctx->nb_formats; i++) {
          if (ctx->formats[i].pix_fmt == pix_fmt) {
-             *image_format = &ctx->formats[i].image_format;
+             if (image_format)
+                 *image_format = &ctx->formats[i].image_format;
              return 0;
          }
      }
@@@ -397,10 -388,6 +390,10 @@@ static AVBufferRef *vaapi_pool_alloc(vo
      VAStatus vas;
      AVBufferRef *ref;
  
 +    if (hwfc->initial_pool_size > 0 &&
 +        avfc->nb_surfaces >= hwfc->initial_pool_size)
 +        return NULL;
 +
      vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
                             hwfc->width, hwfc->height,
                             &surface_id, 1,
@@@ -636,17 -623,15 +629,15 @@@ static int vaapi_transfer_get_formats(A
      return 0;
  }
  
- static void vaapi_unmap_frame(void *opaque, uint8_t *data)
+ static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
+                               HWMapDescriptor *hwmap)
  {
-     AVHWFramesContext *hwfc = opaque;
      AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
-     VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
-     const AVFrame *src;
+     VAAPIMapping           *map = hwmap->priv;
      VASurfaceID surface_id;
      VAStatus vas;
  
-     src = map->source;
-     surface_id = (VASurfaceID)(uintptr_t)src->data[3];
+     surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
      av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  
      vas = vaUnmapBuffer(hwctx->display, map->image.buf);
                 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
      }
  
-     if ((map->flags & VAAPI_MAP_WRITE) &&
-         !(map->flags & VAAPI_MAP_DIRECT)) {
+     if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
+         !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
          vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
                           0, 0, hwfc->width, hwfc->height,
                           0, 0, hwfc->width, hwfc->height);
@@@ -682,7 -667,7 +673,7 @@@ static int vaapi_map_frame(AVHWFramesCo
      VAAPIFramesContext *ctx = hwfc->internal->priv;
      VASurfaceID surface_id;
      VAImageFormat *image_format;
-     VAAPISurfaceMap *map;
+     VAAPIMapping *map;
      VAStatus vas;
      void *address = NULL;
      int err, i;
      surface_id = (VASurfaceID)(uintptr_t)src->data[3];
      av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  
-     if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
+     if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
          // Requested direct mapping but it is not possible.
          return AVERROR(EINVAL);
      }
      if (dst->format == AV_PIX_FMT_NONE)
          dst->format = hwfc->sw_format;
-     if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
+     if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
          // Requested direct mapping but the formats do not match.
          return AVERROR(EINVAL);
      }
          return AVERROR(EINVAL);
      }
  
-     map = av_malloc(sizeof(VAAPISurfaceMap));
+     map = av_malloc(sizeof(*map));
      if (!map)
          return AVERROR(ENOMEM);
-     map->source         = src;
-     map->flags          = flags;
+     map->flags = flags;
      map->image.image_id = VA_INVALID_ID;
  
      vas = vaSyncSurface(hwctx->display, surface_id);
      // faster with a copy routine which is aware of the limitation, but we
      // assume for now that the user is not aware of that and would therefore
      // prefer not to be given direct-mapped memory if they request read access.
-     if (ctx->derive_works &&
-         ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
+     if (ctx->derive_works && dst->format == hwfc->sw_format &&
+         ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
          vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
          if (vas != VA_STATUS_SUCCESS) {
              av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
              err = AVERROR(EIO);
              goto fail;
          }
-         map->flags |= VAAPI_MAP_DIRECT;
+         map->flags |= AV_HWFRAME_MAP_DIRECT;
      } else {
          vas = vaCreateImage(hwctx->display, image_format,
                              hwfc->width, hwfc->height, &map->image);
              err = AVERROR(EIO);
              goto fail;
          }
-         if (flags & VAAPI_MAP_READ) {
+         if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
              vas = vaGetImage(hwctx->display, surface_id, 0, 0,
                               hwfc->width, hwfc->height, map->image.image_id);
              if (vas != VA_STATUS_SUCCESS) {
          goto fail;
      }
  
+     err = ff_hwframe_map_create(src->hw_frames_ctx,
+                                 dst, src, &vaapi_unmap_frame, map);
+     if (err < 0)
+         goto fail;
      dst->width  = src->width;
      dst->height = src->height;
  
          FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
      }
  
-     dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
-                                    &vaapi_unmap_frame, hwfc, 0);
-     if (!dst->buf[0]) {
-         err = AVERROR(ENOMEM);
-         goto fail;
-     }
      return 0;
  
  fail:
@@@ -829,7 -810,7 +816,7 @@@ static int vaapi_transfer_data_from(AVH
          return AVERROR(ENOMEM);
      map->format = dst->format;
  
-     err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
+     err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
      if (err)
          goto fail;
  
@@@ -860,7 -841,7 +847,7 @@@ static int vaapi_transfer_data_to(AVHWF
          return AVERROR(ENOMEM);
      map->format = src->format;
  
-     err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
+     err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
      if (err)
          goto fail;
  
@@@ -877,6 -858,28 +864,28 @@@ fail
      return err;
  }
  
+ static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
+                           const AVFrame *src, int flags)
+ {
+     int err;
+     if (dst->format != AV_PIX_FMT_NONE) {
+         err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
+         if (err < 0)
+             return AVERROR(ENOSYS);
+     }
+     err = vaapi_map_frame(hwfc, dst, src, flags);
+     if (err)
+         return err;
+     err = av_frame_copy_props(dst, src);
+     if (err)
+         return err;
+     return 0;
+ }
  static void vaapi_device_free(AVHWDeviceContext *ctx)
  {
      AVVAAPIDeviceContext *hwctx = ctx->hwctx;
@@@ -999,6 -1002,8 +1008,8 @@@ const HWContextType ff_hwcontext_type_v
      .transfer_get_formats   = &vaapi_transfer_get_formats,
      .transfer_data_to       = &vaapi_transfer_data_to,
      .transfer_data_from     = &vaapi_transfer_data_from,
+     .map_to                 = NULL,
+     .map_from               = &vaapi_map_from,
  
      .pix_fmts = (const enum AVPixelFormat[]) {
          AV_PIX_FMT_VAAPI,