Subversion Repositories Kolibri OS

Rev

Rev 6117 | Rev 6121 | Go to most recent revision | 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 <kos32sys.h>
  13. #include "winlib/winlib.h"
  14. #include "fplay.h"
  15.  
  16. struct hw_profile
  17. {
  18.     enum AVCodecID av_codec;
  19.     int ff_profile;
  20.     uint64_t va_profile;
  21. };
  22.  
  23.  
  24. #define ENTER()   printf("enter %s\n",__FUNCTION__)
  25. #define LEAVE()   printf("leave %s\n",__FUNCTION__)
  26. #define FAIL()    printf("fail %s\n",__FUNCTION__)
  27.  
  28.  
  29. #if DEBUG
  30. # define D(x) x
  31. # define bug printf
  32. #else
  33. # define D(x)
  34. #endif
  35.  
  36. #undef  ARRAY_ELEMS
  37. #define ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
  38.  
  39. static int drm_fd = 0;
  40. static struct vaapi_context *v_context;
  41.  
  42. static VASurfaceID v_surface_id[4];
  43.  
  44. #define HAS_HEVC VA_CHECK_VERSION(0, 38, 0)
  45. #define HAS_VP9 (VA_CHECK_VERSION(0, 38, 1) && defined(FF_PROFILE_VP9_0))
  46.  
  47. #define PE(av_codec_id, ff_profile, vdp_profile)                \
  48.     {AV_CODEC_ID_ ## av_codec_id, FF_PROFILE_ ## ff_profile,    \
  49.      VAProfile ## vdp_profile}
  50.  
  51. static const struct hw_profile profiles[] = {
  52.     PE(MPEG2VIDEO,  MPEG2_MAIN,         MPEG2Main),
  53.     PE(MPEG2VIDEO,  MPEG2_SIMPLE,       MPEG2Simple),
  54.     PE(MPEG4,       MPEG4_ADVANCED_SIMPLE, MPEG4AdvancedSimple),
  55.     PE(MPEG4,       MPEG4_MAIN,         MPEG4Main),
  56.     PE(MPEG4,       MPEG4_SIMPLE,       MPEG4Simple),
  57.     PE(H264,        H264_HIGH,          H264High),
  58.     PE(H264,        H264_MAIN,          H264Main),
  59.     PE(H264,        H264_BASELINE,      H264Baseline),
  60.     PE(VC1,         VC1_ADVANCED,       VC1Advanced),
  61.     PE(VC1,         VC1_MAIN,           VC1Main),
  62.     PE(VC1,         VC1_SIMPLE,         VC1Simple),
  63.     PE(WMV3,        VC1_ADVANCED,       VC1Advanced),
  64.     PE(WMV3,        VC1_MAIN,           VC1Main),
  65.     PE(WMV3,        VC1_SIMPLE,         VC1Simple),
  66. #if HAS_HEVC
  67.     PE(HEVC,        HEVC_MAIN,          HEVCMain),
  68.     PE(HEVC,        HEVC_MAIN_10,       HEVCMain10),
  69. #endif
  70. #if HAS_VP9
  71.     PE(VP9,         VP9_0,              VP9Profile0),
  72. #endif
  73.     {0}
  74. };
  75.  
  76. int va_check_codec_support(enum AVCodecID id)
  77. {
  78.     for (int n = 0; profiles[n].av_codec; n++) {
  79.         if (profiles[n].av_codec == id)
  80.             return 1;
  81.     }
  82.     return 0;
  83. }
  84.  
  85. static int vaapi_check_status(VAStatus status, const char *msg)
  86. {
  87.     if (status != VA_STATUS_SUCCESS) {
  88.         fprintf(stderr, "[%s] %s: %s\n", PACKAGE_NAME, msg, vaErrorStr(status));
  89.         return 0;
  90.     }
  91.     return 1;
  92. };
  93.  
  94. static const char *string_of_VADisplayAttribType(VADisplayAttribType type)
  95. {
  96.     switch (type) {
  97. #define TYPE(type) \
  98.         case VADisplayAttrib##type: return "VADisplayAttrib" #type
  99.         TYPE(Brightness);
  100.         TYPE(Contrast);
  101.         TYPE(Hue);
  102.         TYPE(Saturation);
  103.         TYPE(BackgroundColor);
  104. #if !VA_CHECK_VERSION(0,34,0)
  105.         TYPE(DirectSurface);
  106. #endif
  107. #if VA_CHECK_VERSION(0,32,0)
  108.         TYPE(Rotation);
  109. #endif
  110. #undef TYPE
  111.     default: break;
  112.     }
  113.     return "<unknown>";
  114. }
  115.  
  116. static const char *string_of_VAProfile(VAProfile profile)
  117. {
  118.     switch (profile) {
  119. #define PROFILE(profile) \
  120.         case VAProfile##profile: return "VAProfile" #profile
  121.         PROFILE(MPEG2Simple);
  122.         PROFILE(MPEG2Main);
  123.         PROFILE(MPEG4Simple);
  124.         PROFILE(MPEG4AdvancedSimple);
  125.         PROFILE(MPEG4Main);
  126. #if VA_CHECK_VERSION(0,32,0)
  127.         PROFILE(JPEGBaseline);
  128.         PROFILE(H263Baseline);
  129.         PROFILE(H264ConstrainedBaseline);
  130. #endif
  131.         PROFILE(H264Baseline);
  132.         PROFILE(H264Main);
  133.         PROFILE(H264High);
  134.         PROFILE(VC1Simple);
  135.         PROFILE(VC1Main);
  136.         PROFILE(VC1Advanced);
  137. #undef PROFILE
  138.     default: break;
  139.     }
  140.     return "<unknown>";
  141. }
  142.  
  143. static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
  144. {
  145.     switch (entrypoint) {
  146. #define ENTRYPOINT(entrypoint) \
  147.         case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
  148.         ENTRYPOINT(VLD);
  149.         ENTRYPOINT(IZZ);
  150.         ENTRYPOINT(IDCT);
  151.         ENTRYPOINT(MoComp);
  152.         ENTRYPOINT(Deblocking);
  153. #if VA_CHECK_VERSION(0,32,0)
  154.         ENTRYPOINT(EncSlice);
  155.         ENTRYPOINT(EncPicture);
  156. #endif
  157. #undef ENTRYPOINT
  158.     default: break;
  159.     }
  160.     return "<unknown>";
  161. }
  162.  
  163. VADisplay va_open_display(void)
  164. {
  165.     VADisplay va_dpy;
  166.  
  167.     drm_fd = get_service("DISPLAY");
  168.     if (drm_fd == 0)
  169.         return NULL;
  170.  
  171.     va_dpy = vaGetDisplayDRM(drm_fd);
  172.     if (va_dpy)
  173.         return va_dpy;
  174.  
  175.     drm_fd = 0;
  176.     return NULL;
  177. };
  178.  
  179. int vaapi_init(VADisplay display)
  180. {
  181.     struct vaapi_context *vaapi;
  182.     int major_version, minor_version;
  183.     int i, num_display_attrs, max_display_attrs;
  184.     VADisplayAttribute *display_attrs = NULL;
  185.     VAStatus status;
  186.  
  187.     if (v_context)
  188.         return 0;
  189.  
  190.     if (!display)
  191.         goto error;
  192.     D(bug("VA display %p\n", display));
  193.  
  194.     status = vaInitialize(display, &major_version, &minor_version);
  195.     if (!vaapi_check_status(status, "vaInitialize()"))
  196.         goto error;
  197.     D(bug("VA API version %d.%d\n", major_version, minor_version));
  198.  
  199.     max_display_attrs = vaMaxNumDisplayAttributes(display);
  200.     display_attrs = malloc(max_display_attrs * sizeof(display_attrs[0]));
  201.     if (!display_attrs)
  202.         goto error;
  203.  
  204.     num_display_attrs = 0; /* XXX: workaround old GMA500 bug */
  205.     status = vaQueryDisplayAttributes(display, display_attrs, &num_display_attrs);
  206.     if (!vaapi_check_status(status, "vaQueryDisplayAttributes()"))
  207.         goto error;
  208.     D(bug("%d display attributes available\n", num_display_attrs));
  209.     for (i = 0; i < num_display_attrs; i++) {
  210.         VADisplayAttribute * const display_attr = &display_attrs[i];
  211.         D(bug("  %-32s (%s/%s) min %d max %d value 0x%x\n",
  212.               string_of_VADisplayAttribType(display_attr->type),
  213.               (display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---",
  214.               (display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---",
  215.               display_attr->min_value,
  216.               display_attr->max_value,
  217.               display_attr->value));
  218.     }
  219.  
  220.     if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL)
  221.         goto error;
  222.     vaapi->display               = display;
  223.     vaapi->config_id             = VA_INVALID_ID;
  224.     vaapi->context_id            = VA_INVALID_ID;
  225.  
  226.     v_context = vaapi;
  227.  
  228.     return 0;
  229.  
  230. error:
  231.     free(display_attrs);
  232.     return -1;
  233. }
  234.  
  235.  
  236. static int has_profile(struct vaapi_context *vaapi, VAProfile profile)
  237. {
  238.     VAProfile *profiles;
  239.     int        n_profiles;
  240.     VAStatus   status;
  241.     int i;
  242.  
  243.     profiles = calloc(vaMaxNumProfiles(vaapi->display), sizeof(profiles[0]));
  244.  
  245.     status = vaQueryConfigProfiles(vaapi->display,profiles,&n_profiles);
  246.  
  247.     if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
  248.         return 0;
  249.  
  250.     D(bug("%d profiles available\n", n_profiles));
  251.  
  252.     for (i = 0; i < n_profiles; i++)
  253.     {
  254.         if (profiles[i] == profile)
  255.             return 1;
  256.     }
  257.     return 0;
  258. }
  259.  
  260. static int has_entrypoint(struct vaapi_context *vaapi, VAProfile profile, VAEntrypoint entrypoint)
  261. {
  262.     VAEntrypoint *entrypoints;
  263.     int           n_entrypoints;
  264.     VAStatus      status;
  265.     int i;
  266.  
  267.     entrypoints = calloc(vaMaxNumEntrypoints(vaapi->display), sizeof(entrypoints[0]));
  268.  
  269.     status = vaQueryConfigEntrypoints(vaapi->display, profile,
  270.                                       entrypoints, &n_entrypoints);
  271.     if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
  272.         return 0;
  273.  
  274.     D(bug("%d entrypoints available for %s\n", n_entrypoints,
  275.           string_of_VAProfile(profile)));
  276.  
  277.     for (i = 0; i < n_entrypoints; i++)
  278.     {
  279.         if (entrypoints[i] == entrypoint)
  280.             return 1;
  281.     }
  282.     return 0;
  283. }
  284.  
  285. static int vaapi_init_decoder(VAProfile    profile,
  286.                        VAEntrypoint entrypoint,
  287.                        unsigned int picture_width,
  288.                        unsigned int picture_height)
  289. {
  290.     struct vaapi_context* const vaapi = v_context;
  291.     VAConfigAttrib attrib;
  292.     VAConfigID  config_id = VA_INVALID_ID;
  293.     VAContextID context_id = VA_INVALID_ID;
  294.     VAStatus status;
  295.  
  296. ENTER();
  297.     if (!vaapi)
  298.     {
  299.         FAIL();
  300.         return -1;
  301.     };
  302.  
  303.     if (!has_profile(vaapi, profile))
  304.     {
  305.         FAIL();
  306.         return -1;
  307.     };
  308.  
  309.     if (!has_entrypoint(vaapi, profile, entrypoint))
  310.     {
  311.         FAIL();
  312.         return -1;
  313.     };
  314.  
  315.     if (vaapi->config_id != VA_INVALID_ID)
  316.         vaDestroyConfig(vaapi->display, vaapi->config_id);
  317.  
  318.     attrib.type = VAConfigAttribRTFormat;
  319.  
  320.     printf("vaGetConfigAttributes\n");
  321.     status = vaGetConfigAttributes(vaapi->display, profile, entrypoint,
  322.                                    &attrib, 1);
  323.     if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
  324.     {
  325.         FAIL();
  326.         return -1;
  327.     }
  328.  
  329.     if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
  330.     {
  331.         printf("Chroma format not supported.\n");
  332.         FAIL();
  333.         return -1;
  334.     };
  335.  
  336.     printf("vaCreateConfig\n");
  337.     status = vaCreateConfig(vaapi->display, profile, entrypoint,
  338.                             &attrib, 1, &config_id);
  339.     if (!vaapi_check_status(status, "vaCreateConfig()"))
  340.     {
  341.         FAIL();
  342.         return -1;
  343.     }
  344.  
  345.     printf("vaCreateSurfaces %dx%d\n",picture_width,picture_height);
  346.     status = vaCreateSurfaces(vaapi->display, VA_RT_FORMAT_YUV420, picture_width, picture_height,
  347.                               v_surface_id,4,NULL,0);
  348.     printf("v_surface_id_3 %x\n", v_surface_id[3]);
  349.     if (!vaapi_check_status(status, "vaCreateSurfaces()"))
  350.     {
  351.         FAIL();
  352.         return -1;
  353.     };
  354.     {
  355.         VAImage vaimage;
  356.         VABufferInfo info = {0};
  357.  
  358.         vaDeriveImage(vaapi->display,v_surface_id[0],&vaimage);
  359.         printf("vaDeriveImage: %x  fourcc: %x\n"
  360.                "offset0: %d pitch0: %d\n"
  361.                "offset1: %d pitch1: %d\n"
  362.                "offset2: %d pitch2: %d\n",
  363.                 vaimage.buf, vaimage.format.fourcc,
  364.                 vaimage.offsets[0],vaimage.pitches[0],
  365.                 vaimage.offsets[1],vaimage.pitches[1],
  366.                 vaimage.offsets[2],vaimage.pitches[2]);
  367.  
  368.         info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
  369.         vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info);
  370.         printf("vaAcquireBufferHandle: %x type: %x\n"
  371.                 "mem type: %x mem size: %x\n",
  372.                 info.handle, info.type, info.mem_type, info.mem_size);
  373.  
  374.         vaReleaseBufferHandle(vaapi->display, vaimage.buf);
  375.  
  376.         vaDestroyImage(vaapi->display,vaimage.image_id);
  377.     };
  378.  
  379.     printf("vaCreateContext %dx%d\n",picture_width,picture_height);
  380.     status = vaCreateContext(vaapi->display, config_id,
  381.                              picture_width, picture_height,
  382.                              VA_PROGRESSIVE,
  383.                              v_surface_id, 4,
  384.                              &context_id);
  385.     if (!vaapi_check_status(status, "vaCreateContext()"))
  386.     {
  387.         FAIL();
  388.         return -1;
  389.     };
  390.  
  391.     vaapi->config_id      = config_id;
  392.     vaapi->context_id     = context_id;
  393.     LEAVE();
  394.     return 0;
  395. }
  396.  
  397.  
  398. static enum PixelFormat get_format(struct AVCodecContext *avctx,
  399.                                    const enum AVPixelFormat *fmt)
  400. {
  401.     int i, profile;
  402.  
  403.     ENTER();
  404.  
  405. //    for (int i = 0; fmt[i] != AV_PIX_FMT_NONE; i++)
  406. //        printf(" %s", av_get_pix_fmt_name(fmt[i]));
  407.  
  408.     for (i = 0; fmt[i] != PIX_FMT_NONE; i++) {
  409.         printf("pixformat %x\n", fmt[i]);
  410.         if (fmt[i] != AV_PIX_FMT_VAAPI_VLD)
  411.             continue;
  412.  
  413.         switch (avctx->codec_id)
  414.         {
  415.         case CODEC_ID_MPEG2VIDEO:
  416.             profile = VAProfileMPEG2Main;
  417.             break;
  418.         case CODEC_ID_MPEG4:
  419.         case CODEC_ID_H263:
  420.             profile = VAProfileMPEG4AdvancedSimple;
  421.             break;
  422.         case CODEC_ID_H264:
  423.             profile = VAProfileH264High;
  424.             break;
  425.         case CODEC_ID_WMV3:
  426.             profile = VAProfileVC1Main;
  427.             break;
  428.         case CODEC_ID_VC1:
  429.             profile = VAProfileVC1Advanced;
  430.             break;
  431.         default:
  432.             profile = -1;
  433.             break;
  434.         }
  435.         if (profile >= 0) {
  436.             if (vaapi_init_decoder(profile, VAEntrypointVLD, avctx->width, avctx->height) == 0)
  437.             {
  438.                 avctx->hwaccel_context = v_context;
  439.                 LEAVE();
  440.                 return fmt[i]; ;
  441.             }
  442.         }
  443.     }
  444.     FAIL();
  445.     return PIX_FMT_NONE;
  446. }
  447.  
  448. struct av_surface
  449. {
  450.     int         w;
  451.     int         h;
  452.     VASurfaceID id;
  453. };
  454.  
  455. static void av_release_buffer(void *opaque, uint8_t *data)
  456. {
  457.     struct av_surface surface = *(struct av_surface*)data;
  458. //    VDPAUContext *ctx = opaque;
  459.  
  460. //    ctx->video_surface_destroy(surface);
  461.     av_freep(&data);
  462. }
  463.  
  464. static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flags)
  465. {
  466.     vst_t *vst = (vst_t*)avctx->opaque;
  467.     void *surface = (void *)(uintptr_t)v_surface_id[vst->dfx];
  468.  
  469.     pic->data[3] = surface;
  470.  
  471.     struct av_surface *avsurface;
  472.     surface = av_malloc(sizeof(*avsurface));
  473.     if (!surface)
  474.         return AVERROR(ENOMEM);
  475.  
  476.     pic->buf[0] = av_buffer_create((uint8_t*)avsurface, sizeof(*avsurface),
  477.                                      av_release_buffer, avctx,
  478.                                      AV_BUFFER_FLAG_READONLY);
  479.     return 0;
  480. }
  481.  
  482. struct vaapi_context va_context_storage;
  483.  
  484. int fplay_init_context(vst_t *vst)
  485. {
  486.     AVCodecContext *vCtx = vst->vCtx;
  487.  
  488.     vCtx->opaque       = vst;
  489.     vCtx->thread_count = 1;
  490.     vCtx->get_format   = get_format;
  491.     vCtx->get_buffer2  = get_buffer2;
  492.  
  493.     return 0;
  494. }
  495.  
  496. int fplay_vaapi_init(void)
  497. {
  498.     VADisplay dpy;
  499.  
  500.     dpy = va_open_display();
  501.  
  502.     if (vaapi_init(dpy) < 0)
  503.         return -1;
  504.  
  505.     return 0;
  506. }
  507.  
  508. struct SwsContext *vacvt_ctx;
  509.  
  510. void va_convert_picture(vst_t *vst, int width, int height, AVPicture *pic)
  511. {
  512.     uint8_t  *src_data[4];
  513.     int       src_linesize[4];
  514.     VAImage vaimage;
  515.     VAStatus status;
  516.     uint8_t *vdata;
  517.     struct vaapi_context* const vaapi = v_context;
  518.  
  519.     vaSyncSurface(vaapi->display,v_surface_id[vst->dfx]);
  520.  
  521.     status = vaDeriveImage(vaapi->display,v_surface_id[vst->dfx],&vaimage);
  522.     if (!vaapi_check_status(status, "vaDeriveImage()"))
  523.     {
  524.         FAIL();
  525.         return;
  526.     };
  527.  
  528.     static int once = 2;
  529.  
  530.     if(once && vst->dfx == 0)
  531.     {
  532.         VABufferInfo info = {0};
  533.  
  534.         printf("vaDeriveImage: %x  fourcc: %x\n"
  535.                "offset0: %d pitch0: %d\n"
  536.                "offset1: %d pitch1: %d\n"
  537.                "offset2: %d pitch2: %d\n",
  538.                 vaimage.buf, vaimage.format.fourcc,
  539.                 vaimage.offsets[0],vaimage.pitches[0],
  540.                 vaimage.offsets[1],vaimage.pitches[1],
  541.                 vaimage.offsets[2],vaimage.pitches[2]);
  542.  
  543.         info.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
  544.         status = vaAcquireBufferHandle(vaapi->display, vaimage.buf, &info);
  545.         if (vaapi_check_status(status, "vaAcquireBufferHandle()"))
  546.         {
  547.             printf("vaAcquireBufferHandle: %x type: %x\n"
  548.                     "mem type: %x mem size: %d\n",
  549.                     info.handle, info.type, info.mem_type, info.mem_size);
  550.  
  551.             vaReleaseBufferHandle(vaapi->display, vaimage.buf);
  552.         }
  553.         once--;
  554.     };
  555.  
  556.     src_linesize[0] = vaimage.pitches[0];
  557.     src_linesize[1] = vaimage.pitches[1];
  558.     src_linesize[2] = vaimage.pitches[2];
  559.     src_linesize[3] = 0;
  560.  
  561.     status = vaMapBuffer(vaapi->display,vaimage.buf,(void **)&vdata);
  562.     if (!vaapi_check_status(status, "vaMapBuffer()"))
  563.     {
  564.         FAIL();
  565.         return;
  566.     };
  567.  
  568. //    printf("vdata: %x offset0: %d offset1: %d offset2: %d\n", vdata,
  569. //            vaimage.offsets[0],
  570. //            vaimage.offsets[1],
  571. //            vaimage.offsets[2]);
  572.  
  573.     src_data[0] = vdata + vaimage.offsets[0];
  574.     src_data[1] = vdata + vaimage.offsets[1];
  575.     src_data[2] = vdata + vaimage.offsets[2];
  576.     src_data[3] = 0;
  577.  
  578.     vacvt_ctx = sws_getCachedContext(vacvt_ctx, width, height, AV_PIX_FMT_NV12,
  579.               width, height, AV_PIX_FMT_BGRA,
  580.               SWS_FAST_BILINEAR, NULL, NULL, NULL);
  581.     if(vacvt_ctx == NULL)
  582.     {
  583.         printf("Cannot initialize the conversion context!\n");
  584.         return ;
  585.     };
  586.  
  587.  
  588. //    __asm__ volatile ("int3");
  589.  
  590.     sws_scale(vacvt_ctx, (const uint8_t* const *)src_data, src_linesize, 0, height, pic->data, pic->linesize);
  591.  
  592.     vaUnmapBuffer (vaapi->display, vaimage.buf);
  593.     vaDestroyImage(vaapi->display, vaimage.image_id);
  594. }
  595.