Subversion Repositories Kolibri OS

Rev

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