Subversion Repositories Kolibri OS

Rev

Rev 6117 | Rev 6121 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6117 serge 1
#include 
2
#include 
3
#include 
4
#include 
5
#include 
6
#include 
7
#include 
8
#include 
9
#include 
10
#include 
11
#include 
12
#include 
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 "";
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 "";
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 "";
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
{
6118 serge 466
    vst_t *vst = (vst_t*)avctx->opaque;
467
    void *surface = (void *)(uintptr_t)v_surface_id[vst->dfx];
6117 serge 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
 
6118 serge 484
int fplay_init_context(vst_t *vst)
6117 serge 485
{
6118 serge 486
    AVCodecContext *vCtx = vst->vCtx;
6117 serge 487
 
6118 serge 488
    vCtx->opaque       = vst;
489
    vCtx->thread_count = 1;
490
    vCtx->get_format   = get_format;
491
    vCtx->get_buffer2  = get_buffer2;
6117 serge 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
 
6118 serge 510
void va_convert_picture(vst_t *vst, int width, int height, AVPicture *pic)
6117 serge 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
 
6118 serge 519
    vaSyncSurface(vaapi->display,v_surface_id[vst->dfx]);
6117 serge 520
 
6118 serge 521
    status = vaDeriveImage(vaapi->display,v_surface_id[vst->dfx],&vaimage);
6117 serge 522
    if (!vaapi_check_status(status, "vaDeriveImage()"))
523
    {
524
        FAIL();
525
        return;
526
    };
527
 
528
    static int once = 2;
529
 
6118 serge 530
    if(once && vst->dfx == 0)
6117 serge 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
}