Subversion Repositories Kolibri OS

Rev

Rev 6438 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <libavcodec/avcodec.h>
  6. #include <libavformat/avformat.h>
  7. #include <libswscale/swscale.h>
  8. #include <libavcodec/vaapi.h>
  9. #include <va/va.h>
  10. #include <va/va_drmcommon.h>
  11. #include <va/drm/va_drm.h>
  12. #include <alloca.h>
  13. #include <kos32sys.h>
  14. #include "winlib/winlib.h"
  15. #include "fplay.h"
  16.  
  17. struct hw_profile
  18. {
  19.     enum AVCodecID av_codec;
  20.     int ff_profile;
  21.     VAProfile va_profile;
  22. };
  23.  
  24.  
  25. #define ENTER()   printf("enter %s\n",__FUNCTION__)
  26. #define LEAVE()   printf("leave %s\n",__FUNCTION__)
  27. #define FAIL()    printf("fail %s\n",__FUNCTION__)
  28.  
  29.  
  30. #if DEBUG
  31. # define D(x) x
  32. # define bug printf
  33. #else
  34. # define D(x)
  35. #endif
  36.  
  37. #undef  ARRAY_ELEMS
  38. #define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
  39.  
  40. struct va_decoder
  41. {
  42.     struct decoder decoder;
  43.     VADisplay      dpy;
  44.     void          *hwctx;
  45.     VASurfaceID    v_surface_id[16];
  46. };
  47.  
  48. static struct va_decoder va_decoder;
  49.  
  50. static int drm_fd = 0;
  51. static struct vaapi_context *v_context;
  52.  
  53. #define HAS_HEVC VA_CHECK_VERSION(0, 38, 0)
  54. #define HAS_VP9 (VA_CHECK_VERSION(0, 38, 1) && defined(FF_PROFILE_VP9_0))
  55.  
  56. #define PE(av_codec_id, ff_profile, vdp_profile)                \
  57.     {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile,    \
  58.      VAProfile ## vdp_profile}
  59.  
  60. static const struct hw_profile hw_profiles[] = {
  61.     PE(MPEG2VIDEO,  MPEG2_MAIN,         MPEG2Main),
  62.     PE(MPEG2VIDEO,  MPEG2_SIMPLE,       MPEG2Simple),
  63.     PE(MPEG4,       MPEG4_ADVANCED_SIMPLE, MPEG4AdvancedSimple),
  64.     PE(MPEG4,       MPEG4_MAIN,         MPEG4Main),
  65.     PE(MPEG4,       MPEG4_SIMPLE,       MPEG4Simple),
  66.     PE(H264,        H264_HIGH,          H264High),
  67.     PE(H264,        H264_MAIN,          H264Main),
  68.     PE(H264,        H264_CONSTRAINED_BASELINE, H264ConstrainedBaseline),
  69.     PE(VC1,         VC1_ADVANCED,       VC1Advanced),
  70.     PE(VC1,         VC1_MAIN,           VC1Main),
  71.     PE(VC1,         VC1_SIMPLE,         VC1Simple),
  72.     PE(WMV3,        VC1_ADVANCED,       VC1Advanced),
  73.     PE(WMV3,        VC1_MAIN,           VC1Main),
  74.     PE(WMV3,        VC1_SIMPLE,         VC1Simple),
  75. #if HAS_HEVC
  76.     PE(HEVC,        HEVC_MAIN,          HEVCMain),
  77.     PE(HEVC,        HEVC_MAIN_10,       HEVCMain10),
  78. #endif
  79. #if HAS_VP9
  80.     PE(VP9,         VP9_0,              VP9Profile0),
  81. #endif
  82.     {0}
  83. };
  84.  
  85. int va_check_codec_support(enum AVCodecID id)
  86. {
  87.     for (int n = 0; hw_profiles[n].av_codec; n++) {
  88.         if (hw_profiles[n].av_codec == id)
  89.             return 1;
  90.     }
  91.     return 0;
  92. }
  93.  
  94. static int vaapi_check_status(VAStatus status, const char *msg)
  95. {
  96.     if (status != VA_STATUS_SUCCESS) {
  97.         fprintf(stderr, "[%s] %s: %s\n", PACKAGE_NAME, msg, vaErrorStr(status));
  98.         return 0;
  99.     }
  100.     return 1;
  101. };
  102.  
  103. static const char *string_of_VADisplayAttribType(VADisplayAttribType type)
  104. {
  105.     switch (type) {
  106. #define TYPE(type) \
  107.         case VADisplayAttrib##type: return "VADisplayAttrib" #type
  108.         TYPE(Brightness);
  109.         TYPE(Contrast);
  110.         TYPE(Hue);
  111.         TYPE(Saturation);
  112.         TYPE(BackgroundColor);
  113. #if !VA_CHECK_VERSION(0,34,0)
  114.         TYPE(DirectSurface);
  115. #endif
  116. #if VA_CHECK_VERSION(0,32,0)
  117.         TYPE(Rotation);
  118. #endif
  119. #undef TYPE
  120.     default: break;
  121.     }
  122.     return "<unknown>";
  123. }
  124.  
  125. static const char *string_of_VAProfile(VAProfile profile)
  126. {
  127.     switch (profile) {
  128. #define PROFILE(profile) \
  129.         case VAProfile##profile: return "VAProfile" #profile
  130.         PROFILE(MPEG2Simple);
  131.         PROFILE(MPEG2Main);
  132.         PROFILE(MPEG4Simple);
  133.         PROFILE(MPEG4AdvancedSimple);
  134.         PROFILE(MPEG4Main);
  135. #if VA_CHECK_VERSION(0,32,0)
  136.         PROFILE(JPEGBaseline);
  137.         PROFILE(H263Baseline);
  138.         PROFILE(H264ConstrainedBaseline);
  139. #endif
  140.         PROFILE(H264Baseline);
  141.         PROFILE(H264Main);
  142.         PROFILE(H264High);
  143.         PROFILE(VC1Simple);
  144.         PROFILE(VC1Main);
  145.         PROFILE(VC1Advanced);
  146. #undef PROFILE
  147.     default: break;
  148.     }
  149.     return "<unknown>";
  150. }
  151.  
  152. static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
  153. {
  154.     switch (entrypoint) {
  155. #define ENTRYPOINT(entrypoint) \
  156.         case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
  157.         ENTRYPOINT(VLD);
  158.         ENTRYPOINT(IZZ);
  159.         ENTRYPOINT(IDCT);
  160.         ENTRYPOINT(MoComp);
  161.         ENTRYPOINT(Deblocking);
  162. #if VA_CHECK_VERSION(0,32,0)
  163.         ENTRYPOINT(EncSlice);
  164.         ENTRYPOINT(EncPicture);
  165. #endif
  166. #undef ENTRYPOINT
  167.     default: break;
  168.     }
  169.     return "<unknown>";
  170. }
  171.  
  172.  
  173. void *vaapi_init(VADisplay display)
  174. {
  175.     struct vaapi_context *vaapi;
  176.     int major_version, minor_version;
  177.     int i, num_display_attrs, max_display_attrs;
  178.     VADisplayAttribute *display_attrs = NULL;
  179.     VAStatus status;
  180.  
  181.     if (v_context)
  182.         return 0;
  183.  
  184.     if (!display)
  185.         goto error;
  186.     D(bug("VA display %p\n", display));
  187.  
  188.     status = vaInitialize(display, &major_version, &minor_version);
  189.     if (!vaapi_check_status(status, "vaInitialize()"))
  190.         goto error;
  191.     D(bug("VA API version %d.%d\n", major_version, minor_version));
  192.  
  193.     max_display_attrs = vaMaxNumDisplayAttributes(display);
  194.     display_attrs = malloc(max_display_attrs * sizeof(display_attrs[0]));
  195.     if (!display_attrs)
  196.         goto error;
  197.  
  198.     num_display_attrs = 0; /* XXX: workaround old GMA500 bug */
  199.     status = vaQueryDisplayAttributes(display, display_attrs, &num_display_attrs);
  200.     if (!vaapi_check_status(status, "vaQueryDisplayAttributes()"))
  201.         goto error;
  202.     D(bug("%d display attributes available\n", num_display_attrs));
  203.     for (i = 0; i < num_display_attrs; i++) {
  204.         VADisplayAttribute * const display_attr = &display_attrs[i];
  205.         D(bug("  %-32s (%s/%s) min %d max %d value 0x%x\n",
  206.               string_of_VADisplayAttribType(display_attr->type),
  207.               (display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---",
  208.               (display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---",
  209.               display_attr->min_value,
  210.               display_attr->max_value,
  211.               display_attr->value));
  212.     }
  213.  
  214.     if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL)
  215.         goto error;
  216.     vaapi->display    = display;
  217.     vaapi->config_id  = VA_INVALID_ID;
  218.     vaapi->context_id = VA_INVALID_ID;
  219.  
  220.     v_context = vaapi;
  221.  
  222.     return vaapi;
  223.  
  224. error:
  225.     free(display_attrs);
  226.     return NULL;
  227. }
  228.  
  229. static int has_profile(struct vaapi_context *vaapi, VAProfile profile)
  230. {
  231.     VAProfile *profiles;
  232.     int        n_profiles;
  233.     size_t size;
  234.     VAStatus   status;
  235.     int i;
  236.  
  237.     size = vaMaxNumProfiles(vaapi->display) * sizeof(VAProfile);
  238.  
  239.     profiles = alloca(size);
  240.     memset(profiles, 0, size);
  241.  
  242.     status = vaQueryConfigProfiles(vaapi->display,profiles,&n_profiles);
  243.  
  244.     if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
  245.         return 0;
  246.  
  247.     D(bug("%d profiles available\n", n_profiles));
  248.  
  249.     for (i = 0; i < n_profiles; i++)
  250.     {
  251.         if (profiles[i] == profile)
  252.             return 1;
  253.     }
  254.     return 0;
  255. }
  256.  
  257. static int has_entrypoint(struct vaapi_context *vaapi, VAProfile profile, VAEntrypoint entrypoint)
  258. {
  259.     VAEntrypoint *entrypoints;
  260.     int           n_entrypoints;
  261.     size_t size;
  262.     VAStatus      status;
  263.     int i;
  264.  
  265.     size = vaMaxNumEntrypoints(vaapi->display) * sizeof(VAEntrypoint);
  266.  
  267.     entrypoints = alloca(size);
  268.     memset(entrypoints, 0, size);
  269.  
  270.     status = vaQueryConfigEntrypoints(vaapi->display, profile,
  271.                                       entrypoints, &n_entrypoints);
  272.     if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
  273.         return 0;
  274.  
  275.     D(bug("%d entrypoints available for %s\n", n_entrypoints,
  276.           string_of_VAProfile(profile)));
  277.  
  278.     for (i = 0; i < n_entrypoints; i++)
  279.     {
  280.         if (entrypoints[i] == entrypoint)
  281.             return 1;
  282.     }
  283.     return 0;
  284. }
  285.  
  286. static int vaapi_init_decoder(vst_t *vst,VAProfile profile,
  287.                               VAEntrypoint entrypoint,
  288.                               unsigned int picture_width,
  289.                               unsigned int picture_height)
  290. {
  291.     struct vaapi_context* const vaapi = v_context;
  292.     struct va_decoder *hw_decoder = (struct va_decoder*)vst->decoder;
  293.     VAConfigAttrib attrib;
  294.     VAConfigID  config_id = VA_INVALID_ID;
  295.     VAContextID context_id = VA_INVALID_ID;
  296.     VAStatus status;
  297.  
  298. ENTER();
  299.  
  300.     printf("%s profile %x width:%d height:%d\n",
  301.             __FUNCTION__, profile, picture_width, picture_height);
  302.  
  303.     if (!vaapi)
  304.     {
  305.         FAIL();
  306.         return -1;
  307.     };
  308.  
  309.     if (!has_profile(vaapi, profile))
  310.     {
  311.         FAIL();
  312.         return -1;
  313.     };
  314.  
  315.     if (!has_entrypoint(vaapi, profile, entrypoint))
  316.     {
  317.         FAIL();
  318.         return -1;
  319.     };
  320.  
  321.     if (vaapi->context_id != VA_INVALID_ID)
  322.         vaDestroyContext(vaapi->display, vaapi->context_id);
  323.  
  324.     if (hw_decoder->decoder.has_surfaces)
  325.     {
  326.         vaDestroySurfaces(vaapi->display,hw_decoder->v_surface_id,hw_decoder->decoder.nframes);
  327.         hw_decoder->decoder.has_surfaces = 0;
  328.     }
  329.  
  330.     if (vaapi->config_id != VA_INVALID_ID)
  331.         vaDestroyConfig(vaapi->display, vaapi->config_id);
  332.  
  333.  
  334.     attrib.type = VAConfigAttribRTFormat;
  335.  
  336.     printf("vaGetConfigAttributes\n");
  337.     status = vaGetConfigAttributes(vaapi->display, profile, entrypoint,
  338.                                    &attrib, 1);
  339.     if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
  340.     {
  341.         FAIL();
  342.         return -1;
  343.     }
  344.  
  345.     if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
  346.     {
  347.         printf("Chroma format not supported.\n");
  348.         FAIL();
  349.         return -1;
  350.     };
  351.  
  352.     printf("vaCreateConfig\n");
  353.     status = vaCreateConfig(vaapi->display, profile, entrypoint,
  354.                             &attrib, 1, &config_id);
  355.     if (!vaapi_check_status(status, "vaCreateConfig()"))
  356.     {
  357.         FAIL();
  358.         return -1;
  359.     }
  360.  
  361.     printf("vaCreateSurfaces %dx%d\n",picture_width,picture_height);
  362.     status = vaCreateSurfaces(vaapi->display, VA_RT_FORMAT_YUV420, picture_width, picture_height,
  363.                               hw_decoder->v_surface_id,hw_decoder->decoder.nframes,NULL,0);
  364.     if (!vaapi_check_status(status, "vaCreateSurfaces()"))
  365.     {
  366.         FAIL();
  367.         return -1;
  368.     };
  369.  
  370.     hw_decoder->decoder.has_surfaces = 1;
  371.  
  372.     {
  373.         VAImage vaimage;
  374.         VABufferInfo info = {0};
  375.  
  376.         vaDeriveImage(vaapi->display,hw_decoder->v_surface_id[0],&vaimage);
  377.         printf("vaDeriveImage: %x  fourcc: %x\n"
  378.                "offset0: %d pitch0: %d\n"
  379.                "offset1: %d pitch1: %d\n"
  380.                "offset2: %d pitch2: %d\n",
  381.                 vaimage.buf, vaimage.format.fourcc,
  382.                 vaimage.offsets[0],vaimage.pitches[0],
  383.                 vaimage.offsets[1],vaimage.pitches[1],
  384.                 vaimage.offsets[2],vaimage.pitches[2]);
  385.  
  386.         info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
  387.         vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info);
  388.         printf("vaAcquireBufferHandle: %x type: %x\n"
  389.                 "mem type: %x mem size: %x\n",
  390.                 info.handle, info.type, info.mem_type, info.mem_size);
  391.  
  392.         vaReleaseBufferHandle(vaapi->display, vaimage.buf);
  393.  
  394.         vaDestroyImage(vaapi->display,vaimage.image_id);
  395.     };
  396.  
  397.     printf("vaCreateContext %dx%d\n",picture_width,picture_height);
  398.     status = vaCreateContext(vaapi->display, config_id,
  399.                              picture_width, picture_height,
  400.                              VA_PROGRESSIVE,
  401.                              hw_decoder->v_surface_id, vst->decoder->nframes,
  402.                              &context_id);
  403.     if (!vaapi_check_status(status, "vaCreateContext()"))
  404.     {
  405.         FAIL();
  406.         return -1;
  407.     };
  408.  
  409.     vaapi->config_id  = config_id;
  410.     vaapi->context_id = context_id;
  411.     LEAVE();
  412.     return 0;
  413. }
  414.  
  415.  
  416. static enum PixelFormat get_format(struct AVCodecContext *avctx,
  417.                                    const enum AVPixelFormat *fmt)
  418. {
  419.     vst_t *vst = (vst_t*)avctx->opaque;
  420.     struct va_decoder* hw_decoder = (struct va_decoder*)vst->decoder;
  421.     struct decoder* decoder = &hw_decoder->decoder;
  422.     VAProfile profile = avctx->profile;
  423.     enum AVCodecID codec = avctx->codec_id;
  424.  
  425.     if(avctx->hwaccel_context != NULL)
  426.     {
  427.         if(decoder->codec_id != avctx->codec_id ||
  428.            decoder->profile  != avctx->profile)
  429.     {
  430.         printf("\n%s codec changed!!!\n"
  431.                "old id %d profile %x new id %d profile %x\n",
  432.                     __FUNCTION__, decoder->codec_id, decoder->profile,
  433.                 codec, profile);
  434.  
  435.         for(int i = 0; i < decoder->nframes; i++)
  436.         {
  437.             vframe_t *vframe = &decoder->vframes[i];
  438.             vframe->format   = AV_PIX_FMT_NONE;
  439.         };
  440.     }
  441.         else
  442.             return AV_PIX_FMT_VAAPI_VLD;
  443.     }
  444.  
  445.     if (codec == AV_CODEC_ID_H264)
  446.     {
  447.         if(profile == FF_PROFILE_H264_BASELINE)
  448.             profile = FF_PROFILE_H264_CONSTRAINED_BASELINE;
  449.     };
  450.  
  451.     printf("\n%s codec %d profile %x\n", __FUNCTION__,avctx->codec_id, avctx->profile);
  452.  
  453.     for (int i = 0; fmt[i] != PIX_FMT_NONE; i++)
  454.     {
  455.         if (fmt[i] != AV_PIX_FMT_VAAPI_VLD)
  456.             continue;
  457.  
  458.         for (int n = 0; hw_profiles[n].av_codec; n++)
  459.         {
  460.             if (hw_profiles[n].av_codec   == codec &&
  461.                 hw_profiles[n].ff_profile == profile)
  462.             {
  463.                 profile = hw_profiles[n].va_profile;
  464.                 if (vaapi_init_decoder(vst, profile, VAEntrypointVLD, avctx->width, avctx->height) == 0)
  465.                 {
  466.                     avctx->hwaccel_context = v_context;
  467.                     printf("%s format: %x\n",__FUNCTION__, fmt[i]);
  468.                     return fmt[i];
  469.                 }
  470.             }
  471.         }
  472.  
  473.     }
  474.     printf("%s format PIX_FMT_NONE\n",__FUNCTION__);
  475.     return PIX_FMT_NONE;
  476. }
  477.  
  478. struct av_surface
  479. {
  480.     int         w;
  481.     int         h;
  482.     VASurfaceID id;
  483. };
  484.  
  485. static void av_release_buffer(void *opaque, uint8_t *data)
  486. {
  487. }
  488.  
  489. static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags)
  490. {
  491.     static struct av_surface avsurface;
  492.     vst_t *vst = (vst_t*)avctx->opaque;
  493.     struct va_decoder* hw_decoder = (struct va_decoder*)vst->decoder;
  494.     void *surface;
  495.  
  496.     surface = (void *)(uintptr_t)hw_decoder->v_surface_id[vst->decoder->active_frame->index];
  497.  
  498.     pic->data[3] = surface;
  499.  
  500.     pic->buf[0] = av_buffer_create((uint8_t*)&avsurface, sizeof(avsurface),
  501.                                     av_release_buffer, avctx,
  502.                                     AV_BUFFER_FLAG_READONLY);
  503.     return 0;
  504. }
  505.  
  506.  
  507. #define EGL_TEXTURE_Y_U_V_WL            0x31D7
  508. #define EGL_TEXTURE_Y_UV_WL             0x31D8
  509. #define EGL_TEXTURE_Y_XUXV_WL           0x31D9
  510.  
  511. enum wl_drm_format {
  512.     WL_DRM_FORMAT_C8 = 0x20203843,
  513.     WL_DRM_FORMAT_RGB332 = 0x38424752,
  514.     WL_DRM_FORMAT_BGR233 = 0x38524742,
  515.     WL_DRM_FORMAT_XRGB4444 = 0x32315258,
  516.     WL_DRM_FORMAT_XBGR4444 = 0x32314258,
  517.     WL_DRM_FORMAT_RGBX4444 = 0x32315852,
  518.     WL_DRM_FORMAT_BGRX4444 = 0x32315842,
  519.     WL_DRM_FORMAT_ARGB4444 = 0x32315241,
  520.     WL_DRM_FORMAT_ABGR4444 = 0x32314241,
  521.     WL_DRM_FORMAT_RGBA4444 = 0x32314152,
  522.     WL_DRM_FORMAT_BGRA4444 = 0x32314142,
  523.     WL_DRM_FORMAT_XRGB1555 = 0x35315258,
  524.     WL_DRM_FORMAT_XBGR1555 = 0x35314258,
  525.     WL_DRM_FORMAT_RGBX5551 = 0x35315852,
  526.     WL_DRM_FORMAT_BGRX5551 = 0x35315842,
  527.     WL_DRM_FORMAT_ARGB1555 = 0x35315241,
  528.     WL_DRM_FORMAT_ABGR1555 = 0x35314241,
  529.     WL_DRM_FORMAT_RGBA5551 = 0x35314152,
  530.     WL_DRM_FORMAT_BGRA5551 = 0x35314142,
  531.     WL_DRM_FORMAT_RGB565 = 0x36314752,
  532.     WL_DRM_FORMAT_BGR565 = 0x36314742,
  533.     WL_DRM_FORMAT_RGB888 = 0x34324752,
  534.     WL_DRM_FORMAT_BGR888 = 0x34324742,
  535.     WL_DRM_FORMAT_XRGB8888 = 0x34325258,
  536.     WL_DRM_FORMAT_XBGR8888 = 0x34324258,
  537.     WL_DRM_FORMAT_RGBX8888 = 0x34325852,
  538.     WL_DRM_FORMAT_BGRX8888 = 0x34325842,
  539.     WL_DRM_FORMAT_ARGB8888 = 0x34325241,
  540.     WL_DRM_FORMAT_ABGR8888 = 0x34324241,
  541.     WL_DRM_FORMAT_RGBA8888 = 0x34324152,
  542.     WL_DRM_FORMAT_BGRA8888 = 0x34324142,
  543.     WL_DRM_FORMAT_XRGB2101010 = 0x30335258,
  544.     WL_DRM_FORMAT_XBGR2101010 = 0x30334258,
  545.     WL_DRM_FORMAT_RGBX1010102 = 0x30335852,
  546.     WL_DRM_FORMAT_BGRX1010102 = 0x30335842,
  547.     WL_DRM_FORMAT_ARGB2101010 = 0x30335241,
  548.     WL_DRM_FORMAT_ABGR2101010 = 0x30334241,
  549.     WL_DRM_FORMAT_RGBA1010102 = 0x30334152,
  550.     WL_DRM_FORMAT_BGRA1010102 = 0x30334142,
  551.     WL_DRM_FORMAT_YUYV = 0x56595559,
  552.     WL_DRM_FORMAT_YVYU = 0x55595659,
  553.     WL_DRM_FORMAT_UYVY = 0x59565955,
  554.     WL_DRM_FORMAT_VYUY = 0x59555956,
  555.     WL_DRM_FORMAT_AYUV = 0x56555941,
  556.     WL_DRM_FORMAT_NV12 = 0x3231564e,
  557.     WL_DRM_FORMAT_NV21 = 0x3132564e,
  558.     WL_DRM_FORMAT_NV16 = 0x3631564e,
  559.     WL_DRM_FORMAT_NV61 = 0x3136564e,
  560.     WL_DRM_FORMAT_YUV410 = 0x39565559,
  561.     WL_DRM_FORMAT_YVU410 = 0x39555659,
  562.     WL_DRM_FORMAT_YUV411 = 0x31315559,
  563.     WL_DRM_FORMAT_YVU411 = 0x31315659,
  564.     WL_DRM_FORMAT_YUV420 = 0x32315559,
  565.     WL_DRM_FORMAT_YVU420 = 0x32315659,
  566.     WL_DRM_FORMAT_YUV422 = 0x36315559,
  567.     WL_DRM_FORMAT_YVU422 = 0x36315659,
  568.     WL_DRM_FORMAT_YUV444 = 0x34325559,
  569.     WL_DRM_FORMAT_YVU444 = 0x34325659,
  570. };
  571.  
  572. void va_create_planar(vst_t *vst, vframe_t *vframe)
  573. {
  574.     struct vaapi_context* const vaapi = v_context;
  575.     struct va_decoder* hw_decoder = (struct va_decoder*)vst->decoder;
  576.     VABufferInfo info = {0};
  577.  
  578.     VAImage vaimage;
  579.     VAStatus status;
  580.     planar_t *planar;
  581.  
  582.     vaSyncSurface(vaapi->display,hw_decoder->v_surface_id[vframe->index]);
  583.  
  584.     if(vframe->format != AV_PIX_FMT_NONE)
  585.         return;
  586.  
  587.     if(vframe->planar != NULL)
  588.     {
  589.         pxDestroyPlanar(vframe->planar);
  590.         vframe->planar = NULL;
  591.     };
  592.  
  593.     status = vaDeriveImage(vaapi->display,hw_decoder->v_surface_id[vframe->index],&vaimage);
  594.     if (!vaapi_check_status(status, "vaDeriveImage()"))
  595.     {
  596.         FAIL();
  597.         return;
  598.     };
  599. /*
  600.     printf("vaDeriveImage: %x  fourcc: %x\n"
  601.            "offset0: %d pitch0: %d\n"
  602.            "offset1: %d pitch1: %d\n"
  603.            "offset2: %d pitch2: %d\n",
  604.             vaimage.buf, vaimage.format.fourcc,
  605.             vaimage.offsets[0],vaimage.pitches[0],
  606.             vaimage.offsets[1],vaimage.pitches[1],
  607.             vaimage.offsets[2],vaimage.pitches[2]);
  608. */
  609.     info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
  610.     status = vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info);
  611.     if (!vaapi_check_status(status, "vaAcquireBufferHandle()"))
  612.     {
  613.         vaDestroyImage(vaapi->display, vaimage.image_id);
  614.         FAIL();
  615.         return;
  616.     };
  617. /*
  618.     printf("vaAcquireBufferHandle: %x type: %x\n"
  619.             "mem type: %x mem size: %d\n",
  620.             info.handle, info.type, info.mem_type, info.mem_size);
  621. */
  622.     planar = pxCreatePlanar(info.handle, WL_DRM_FORMAT_NV12,
  623.                             vaimage.width, vaimage.height,
  624.                             vaimage.offsets[0],vaimage.pitches[0],
  625.                             vaimage.offsets[1],vaimage.pitches[1],
  626.                             vaimage.offsets[2],vaimage.pitches[2]);
  627.     if(planar != NULL)
  628.     {
  629.         vframe->planar = planar;
  630.         vframe->format = AV_PIX_FMT_NV12;
  631.     };
  632.  
  633.     vaReleaseBufferHandle(vaapi->display, vaimage.buf);
  634.     vaDestroyImage(vaapi->display, vaimage.image_id);
  635.  
  636. }
  637.  
  638. static enum AVCodecID profile_to_codec(VAProfile profile)
  639. {
  640.     enum AVCodecID id;
  641.  
  642.     switch(profile)
  643.     {
  644.         case VAProfileMPEG2Simple:
  645.         case VAProfileMPEG2Main:
  646.             id = AV_CODEC_ID_MPEG2VIDEO;
  647.             break;
  648.  
  649.         case VAProfileMPEG4Simple:
  650.         case VAProfileMPEG4AdvancedSimple:
  651.         case VAProfileMPEG4Main:
  652.             id = AV_CODEC_ID_MPEG4;
  653.             break;
  654.  
  655.         case VAProfileH264Baseline:
  656.         case VAProfileH264Main:
  657.         case VAProfileH264High:
  658.         case VAProfileH264ConstrainedBaseline:
  659.         case VAProfileH264MultiviewHigh:
  660.         case VAProfileH264StereoHigh:
  661.             id = AV_CODEC_ID_H264;
  662.             break;
  663.  
  664.         case VAProfileVC1Simple:
  665.         case VAProfileVC1Main:
  666.         case VAProfileVC1Advanced:
  667.             id = AV_CODEC_ID_VC1;
  668.             break;
  669.  
  670.         case VAProfileHEVCMain:
  671.         case VAProfileHEVCMain10:
  672.             id = AV_CODEC_ID_HEVC;
  673.             break;
  674.  
  675.         default:
  676.             id = AV_CODEC_ID_NONE;
  677.     };
  678.     return id;
  679. };
  680.  
  681. static VAProfile get_profile(VADisplay dpy, enum AVCodecID codec_id)
  682. {
  683.     VAProfile profile = VAProfileNone, *profile_list = NULL;
  684.     int num_profiles, max_num_profiles;
  685.     enum AVCodecID ff_id;
  686.     VAStatus va_status;
  687.     int i;
  688.  
  689.     max_num_profiles = vaMaxNumProfiles(dpy);
  690.  
  691.     profile_list = alloca(max_num_profiles * sizeof(VAProfile));
  692.     if (!profile_list)
  693.     {
  694.         printf("Failed to allocate memory for profile list\n");
  695.         goto err_0;
  696.     }
  697.  
  698.     va_status = vaQueryConfigProfiles(dpy, profile_list, &num_profiles);
  699.     if(!vaapi_check_status(va_status, "vaQueryConfigProfiles()"))
  700.         goto err_0;
  701.  
  702.     if(codec_id == AV_CODEC_ID_H263)
  703.         ff_id = AV_CODEC_ID_H264;
  704.     else if(codec_id == AV_CODEC_ID_WMV3)
  705.         ff_id = AV_CODEC_ID_VC1;
  706.     else
  707.         ff_id = codec_id;
  708.  
  709.     for (i = 0; i < num_profiles; i++)
  710.     {
  711.         if(ff_id == profile_to_codec(profile_list[i]))
  712.         {
  713.             profile = profile_list[i];
  714.             break;
  715.         }
  716.     };
  717.  
  718. err_0:
  719.     return profile;
  720. }
  721.  
  722. static void fini_va_decoder(vst_t *vst)
  723. {
  724.     struct vaapi_context* const vaapi = v_context;
  725.     struct va_decoder *hw_decoder = (struct va_decoder*)vst->decoder;
  726. ENTER();
  727.     for(int i = 0; i < hw_decoder->decoder.nframes; i++)
  728.     {
  729.         vframe_t *vframe = &hw_decoder->decoder.vframes[i];
  730.         if(vframe->planar != NULL)
  731.         {
  732.             printf("destroy planar %d\n", i);
  733.             pxDestroyPlanar(vframe->planar);
  734.             vframe->planar = NULL;
  735.         };
  736.     };
  737.  
  738.     av_frame_free(&hw_decoder->decoder.Frame);
  739.  
  740.     if (vaapi->context_id != VA_INVALID_ID)
  741.         vaDestroyContext(vaapi->display, vaapi->context_id);
  742.  
  743.     if (hw_decoder->decoder.has_surfaces)
  744.         vaDestroySurfaces(vaapi->display,hw_decoder->v_surface_id,hw_decoder->decoder.nframes);
  745.  
  746.     if (vaapi->config_id != VA_INVALID_ID)
  747.         vaDestroyConfig(vaapi->display, vaapi->config_id);
  748.  
  749.     vaTerminate(hw_decoder->dpy);
  750. LEAVE();
  751. };
  752.  
  753.  
  754. struct decoder* init_va_decoder(vst_t *vst)
  755. {
  756.     AVCodecContext *vCtx = vst->vCtx;
  757.     struct va_decoder *hw_decoder = &va_decoder;
  758.     struct decoder *decoder = &hw_decoder->decoder;
  759.  
  760.     drm_fd = get_service("DISPLAY");
  761.     if (drm_fd == 0)
  762.         return NULL;
  763.  
  764.     hw_decoder->dpy = vaGetDisplayDRM(drm_fd);
  765.     if (hw_decoder->dpy == NULL)
  766.         goto err_0;
  767.  
  768.     hw_decoder->hwctx = vaapi_init(hw_decoder->dpy);
  769.     if(hw_decoder->hwctx == NULL)
  770.         goto err_1;
  771.  
  772.     if(get_profile(hw_decoder->dpy, vCtx->codec_id) == VAProfileNone)
  773.         goto err_1;
  774.  
  775.     decoder->Frame = av_frame_alloc();
  776.     if(decoder->Frame == NULL)
  777.         goto err_1;
  778.  
  779.     if(vCtx->codec_id == AV_CODEC_ID_H264)
  780.         decoder->nframes = 16;
  781.     else
  782.         decoder->nframes = 4;
  783.  
  784.     for(int i = 0; i < decoder->nframes; i++)
  785.     {
  786.         vframe_t *vframe = &decoder->vframes[i];
  787.  
  788.         vframe->format    = AV_PIX_FMT_NONE;
  789.         vframe->is_hw_pic = 1;
  790.         vframe->index     = i;
  791.         list_add_tail(&vframe->list, &vst->input_list);
  792.     };
  793.  
  794.     vCtx->opaque       = vst;
  795.     vCtx->thread_count = 1;
  796.     vCtx->get_format   = get_format;
  797.     vCtx->get_buffer2  = get_buffer2;
  798.  
  799.     if(avcodec_open2(vst->vCtx, vst->vCodec, NULL) < 0)
  800.     {
  801.         printf("Error while opening codec for input stream %d\n",
  802.                 vst->vStream);
  803.         goto err_2;
  804.     };
  805.  
  806.     decoder->name     = vst->vCodec->name;
  807.     decoder->codec_id = vCtx->codec_id;
  808.     decoder->profile  = vCtx->profile;
  809.     decoder->pix_fmt  = vCtx->pix_fmt;
  810.     decoder->width    = vCtx->width;
  811.     decoder->height   = vCtx->height;
  812.     decoder->is_hw    = 1;
  813.     decoder->frame_reorder = 1;
  814.     decoder->fini     = fini_va_decoder;
  815.  
  816.     return (struct decoder*)decoder;
  817.  
  818. err_2:
  819.     av_frame_free(&decoder->Frame);
  820. err_1:
  821.     vaTerminate(hw_decoder->dpy);
  822. err_0:
  823.     drm_fd = 0;
  824.     return NULL;
  825. }
  826.