Project

General

Profile

RE: Add new field to webui ยป vaapi.c

Stefan Dietzel, 2022-03-21 19:39

 
1
/*
2
 *  tvheadend - Codec Profiles
3
 *
4
 *  Copyright (C) 2016 Tvheadend
5
 *
6
 *  This program is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20

    
21
#include "transcoding/codec/internals.h"
22
#include <fcntl.h>
23
#include <sys/ioctl.h>
24

    
25

    
26
#define AV_DICT_SET_QP(d, v, a) \
27
    AV_DICT_SET_INT((d), "qp", (v) ? (v) : (a), AV_DICT_DONT_OVERWRITE)
28

    
29

    
30
/* vaapi ==================================================================== */
31

    
32
typedef struct {
33
    TVHVideoCodecProfile;
34
    int qp;
35
    int quality;
36
    double buff_factor;
37
    int rc_mode;
38
    int tier;
39
    int ignore_bframe;
40
} tvh_codec_profile_vaapi_t;
41

    
42
#if defined(__linux__)
43
#include <linux/types.h>
44
#include <asm/ioctl.h>
45
#else
46
#include <sys/ioccom.h>
47
#include <sys/types.h>
48
typedef size_t   __kernel_size_t;
49
#endif
50

    
51
typedef struct drm_version {
52
   int version_major;        /**< Major version */
53
   int version_minor;        /**< Minor version */
54
   int version_patchlevel;   /**< Patch level */
55
   __kernel_size_t name_len; /**< Length of name buffer */
56
   char *name;               /**< Name of driver */
57
   __kernel_size_t date_len; /**< Length of date buffer */
58
   char *date;               /**< User-space buffer to hold date */
59
   __kernel_size_t desc_len; /**< Length of desc buffer */
60
   char *desc;               /**< User-space buffer to hold desc */
61
} drm_version_t;
62

    
63
#define DRM_IOCTL_VERSION _IOWR('d', 0x00, struct drm_version)
64

    
65

    
66
static int
67
probe_vaapi_device(const char *device, char *name, size_t namelen)
68
{
69
    drm_version_t dv;
70
    char dname[128];
71
    int fd;
72

    
73
    if ((fd = open(device, O_RDWR)) < 0)
74
        return -1;
75
    memset(&dv, 0, sizeof(dv));
76
    memset(dname, 0, sizeof(dname));
77
    dv.name = dname;
78
    dv.name_len = sizeof(dname)-1;
79
    if (ioctl(fd, DRM_IOCTL_VERSION, &dv) < 0) {
80
        close(fd);
81
        return -1;
82
    }
83
    snprintf(name, namelen, "%s v%d.%d.%d (%s)",
84
             dv.name, dv.version_major, dv.version_minor,
85
             dv.version_patchlevel, device);
86
    close(fd);
87
    return 0;
88
}
89

    
90
static htsmsg_t *
91
tvh_codec_profile_vaapi_device_list(void *obj, const char *lang)
92
{
93
    static const char *renderD_fmt = "/dev/dri/renderD%d";
94
    static const char *card_fmt = "/dev/dri/card%d";
95
    htsmsg_t *result = htsmsg_create_list();
96
    char device[PATH_MAX];
97
    char name[128];
98
    int i, dev_num;
99

    
100
    for (i = 0; i < 32; i++) {
101
        dev_num = i + 128;
102
        snprintf(device, sizeof(device), renderD_fmt, dev_num);
103
        if (probe_vaapi_device(device, name, sizeof(name)) == 0)
104
            htsmsg_add_msg(result, NULL, htsmsg_create_key_val(device, name));
105
    }
106
    for (i = 0; i < 32; i++) {
107
        dev_num = i + 128;
108
        snprintf(device, sizeof(device), card_fmt, dev_num);
109
        if (probe_vaapi_device(device, name, sizeof(name)) == 0)
110
            htsmsg_add_msg(result, NULL, htsmsg_create_key_val(device, name));
111
    }
112
    return result;
113
}
114

    
115
static int
116
tvh_codec_profile_vaapi_open(tvh_codec_profile_vaapi_t *self,
117
                             AVDictionary **opts)
118
{
119
    // pix_fmt
120
    AV_DICT_SET_PIX_FMT(opts, self->pix_fmt, AV_PIX_FMT_VAAPI);
121
    return 0;
122
}
123

    
124
static const codec_profile_class_t codec_profile_vaapi_class = {
125
    {
126
        .ic_super      = (idclass_t *)&codec_profile_video_class,
127
        .ic_class      = "codec_profile_vaapi",
128
        .ic_caption    = N_("vaapi"),
129
        .ic_properties = (const property_t[]){
130
            {
131
                .type     = PT_STR,
132
                .id       = "device",
133
                .name     = N_("Device name"),
134
                .desc     = N_("Device name (e.g. /dev/dri/renderD129)."),
135
                .group    = 3,
136
                .off      = offsetof(tvh_codec_profile_vaapi_t, device),
137
                .list     = tvh_codec_profile_vaapi_device_list,
138
            },
139
            {
140
                .type     = PT_DBL,
141
                .id       = "bit_rate",
142
                .name     = N_("Bitrate (kb/s) (0=auto)"),
143
                .desc     = N_("Target bitrate."),
144
                .group    = 3,
145
                .get_opts = codec_profile_class_get_opts,
146
                .off      = offsetof(TVHCodecProfile, bit_rate),
147
                .def.d    = 0,
148
            },
149
            {
150
                .type     = PT_DBL,
151
                .id       = "buff_factor",
152
                .name     = N_("Buffer factor"),
153
                .desc     = N_("Size of transcoding buffer (buffer=bitrate*1000*factor). Good factor is 3."),
154
                .group    = 3,
155
                .get_opts = codec_profile_class_get_opts,
156
                .off      = offsetof(tvh_codec_profile_vaapi_t, buff_factor),
157
                .def.d    = 3,
158
            },
159
            {
160
                .type     = PT_INT,
161
                .id       = "rc_mode",
162
                .name     = N_("Rate control mode"),
163
                .desc     = N_("Set rate control mode (from 0 to 6).[0=auto 1=CQP 2=CBR 3=VBR 4=ICQ 5=QVBR 6=AVBR]"),
164
                .group    = 3,
165
                .get_opts = codec_profile_class_get_opts,
166
                .off      = offsetof(tvh_codec_profile_vaapi_t, rc_mode),
167
                .intextra = INTEXTRA_RANGE(0, 6, 0),
168
                .def.d    = 0,
169
            },
170
            {
171
                .type     = PT_INT,
172
                .id       = "qp",
173
                .name     = N_("Constant QP (0=auto)"),
174
                .group    = 3,
175
                .desc     = N_("Fixed QP of P frames [0-52]."),
176
                .get_opts = codec_profile_class_get_opts,
177
                .off      = offsetof(tvh_codec_profile_vaapi_t, qp),
178
                .intextra = INTEXTRA_RANGE(0, 52, 1),
179
                .def.i    = 0,
180
            },
181
            {
182
                .type     = PT_INT,
183
                .id       = "ignore_bframe",
184
                .name     = N_("Ignore B-Frames"),
185
                .group    = 3,
186
                .desc     = N_("Some VAAPI drivers cannot handle b-frames (like AMD). [0=use b-frames (default) 1=ignore b-frames]"),
187
                .get_opts = codec_profile_class_get_opts,
188
                .off      = offsetof(tvh_codec_profile_vaapi_t, ignore_bframe),
189
                .intextra = INTEXTRA_RANGE(0, 1, 0),
190
                .def.i    = 0,
191
            },
192
            {}
193
        }
194
    },
195
    .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_open,
196
};
197

    
198

    
199
/* h264_vaapi =============================================================== */
200

    
201
static const AVProfile vaapi_h264_profiles[] = {
202
    { FF_PROFILE_H264_CONSTRAINED_BASELINE, "Constrained Baseline" },
203
    { FF_PROFILE_H264_MAIN,                 "Main" },
204
    { FF_PROFILE_H264_HIGH,                 "High" },
205
    { FF_PROFILE_UNKNOWN },
206
};
207

    
208
static int
209
tvh_codec_profile_vaapi_h264_open(tvh_codec_profile_vaapi_t *self,
210
                                  AVDictionary **opts)
211
{
212
    // bit_rate or qp
213
    if (self->bit_rate) {
214
        if (self->buff_factor <= 0) {
215
            self->buff_factor = 3;
216
        }
217
        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
218
        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
219
        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
220
        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
221
        AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
222
        if (self->ignore_bframe) {
223
            AV_DICT_SET_INT(opts, "bf", 0, 0);
224
        }
225
    }
226
    else {
227
        AV_DICT_SET_QP(opts, self->qp, 20);
228
    }
229
    AV_DICT_SET_INT(opts, "quality", self->quality, 0);
230
    return 0;
231
}
232

    
233

    
234
static const codec_profile_class_t codec_profile_vaapi_h264_class = {
235
    {
236
        .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
237
        .ic_class      = "codec_profile_vaapi_h264",
238
        .ic_caption    = N_("vaapi_h264"),
239
        .ic_properties = (const property_t[]){
240
            {
241
                .type     = PT_INT,
242
                .id       = "quality",
243
                .name     = N_("Quality (0=auto)"),
244
                .desc     = N_("Set encode quality (trades off against speed, "
245
                               "higher is faster) [0-8]."),
246
                .group    = 5,
247
                .opts     = PO_EXPERT,
248
                .get_opts = codec_profile_class_get_opts,
249
                .off      = offsetof(tvh_codec_profile_vaapi_t, quality),
250
                .intextra = INTEXTRA_RANGE(0, 8, 1),
251
                .def.i    = 0,
252
            },
253
            {}
254
        }
255
    },
256
    .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_h264_open,
257
};
258

    
259

    
260
TVHVideoCodec tvh_codec_vaapi_h264 = {
261
    .name     = "h264_vaapi",
262
    .size     = sizeof(tvh_codec_profile_vaapi_t),
263
    .idclass  = &codec_profile_vaapi_h264_class,
264
    .profiles = vaapi_h264_profiles,
265
    .profile_init = tvh_codec_profile_video_init,
266
    .profile_destroy = tvh_codec_profile_video_destroy,
267
};
268

    
269

    
270
/* hevc_vaapi =============================================================== */
271

    
272
static const AVProfile vaapi_hevc_profiles[] = {
273
    { FF_PROFILE_HEVC_MAIN, "Main" },
274
    { FF_PROFILE_HEVC_MAIN_10, "Main 10" },
275
    { FF_PROFILE_HEVC_REXT, "Rext" },
276
    { FF_PROFILE_UNKNOWN },
277
};
278

    
279
static int
280
tvh_codec_profile_vaapi_hevc_open(tvh_codec_profile_vaapi_t *self,
281
                                  AVDictionary **opts)
282
{
283
    // bit_rate or qp
284
    if (self->bit_rate) {
285
        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
286
        if (self->buff_factor <= 0) {
287
            self->buff_factor = 3;
288
        }
289
        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
290
        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
291
        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
292
        AV_DICT_SET_INT(opts, "rc_mode", self->rc_mode, AV_DICT_DONT_OVERWRITE);
293
        AV_DICT_SET_INT(opts, "tier", self->tier, AV_DICT_DONT_OVERWRITE);
294
        if (self->ignore_bframe) {
295
            AV_DICT_SET_INT(opts, "bf", 0, 0);
296
        }
297
    }
298
    else {
299
        AV_DICT_SET_QP(opts, self->qp, 25);
300
    }
301
    return 0;
302
}
303

    
304

    
305
static const codec_profile_class_t codec_profile_vaapi_hevc_class = {
306
    {
307
        .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
308
        .ic_class      = "codec_profile_vaapi_hevc",
309
        .ic_caption    = N_("vaapi_hevc"),
310
        .ic_properties = (const property_t[]){
311
            {
312
                .type     = PT_INT,
313
                .id       = "tier",
314
                .name     = N_("Tier"),
315
                .desc     = N_("Set tier (general_tier_flag) [0=main 1=high]"),
316
                .group    = 5,
317
                .opts     = PO_EXPERT,
318
                .get_opts = codec_profile_class_get_opts,
319
                .off      = offsetof(tvh_codec_profile_vaapi_t, tier),
320
                .intextra = INTEXTRA_RANGE(0, 1, 0),
321
                .def.i    = 0,
322
            },
323
            {}
324
        }
325
    },
326
    .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_hevc_open,
327
};
328

    
329

    
330
TVHVideoCodec tvh_codec_vaapi_hevc = {
331
    .name     = "hevc_vaapi",
332
    .size     = sizeof(tvh_codec_profile_vaapi_t),
333
    .idclass  = &codec_profile_vaapi_hevc_class,
334
    .profiles = vaapi_hevc_profiles,
335
    .profile_init = tvh_codec_profile_video_init,
336
    .profile_destroy = tvh_codec_profile_video_destroy,
337
};
338

    
339

    
340
/* vp8_vaapi =============================================================== */
341

    
342
static const AVProfile vaapi_vp8_profiles[] = {
343
    { FF_PROFILE_UNKNOWN },
344
};
345

    
346
static int
347
tvh_codec_profile_vaapi_vp8_open(tvh_codec_profile_vaapi_t *self,
348
                                  AVDictionary **opts)
349
{
350
    // bit_rate or qp
351
    if (self->bit_rate) {
352
        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
353
        if (self->buff_factor <= 0) {
354
            self->buff_factor = 3;
355
        }
356
        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
357
        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
358
        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
359
    }
360
    else {
361
        AV_DICT_SET_QP(opts, self->qp, 25);
362
    }
363
    if (self->ignore_bframe) {
364
        AV_DICT_SET_INT(opts, "bf", 0, 0);
365
    }
366
    return 0;
367
}
368

    
369

    
370
static const codec_profile_class_t codec_profile_vaapi_vp8_class = {
371
    {
372
        .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
373
        .ic_class      = "codec_profile_vaapi_vp8",
374
        .ic_caption    = N_("vaapi_vp8")
375
    },
376
    .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_vp8_open,
377
};
378

    
379

    
380
TVHVideoCodec tvh_codec_vaapi_vp8 = {
381
    .name     = "vp8_vaapi",
382
    .size     = sizeof(tvh_codec_profile_vaapi_t),
383
    .idclass  = &codec_profile_vaapi_vp8_class,
384
    .profiles = vaapi_vp8_profiles,
385
    .profile_init = tvh_codec_profile_video_init,
386
    .profile_destroy = tvh_codec_profile_video_destroy,
387
};
388

    
389
/* vp9_vaapi =============================================================== */
390

    
391
static const AVProfile vaapi_vp9_profiles[] = {
392
    { FF_PROFILE_UNKNOWN },
393
};
394

    
395
static int
396
tvh_codec_profile_vaapi_vp9_open(tvh_codec_profile_vaapi_t *self,
397
                                  AVDictionary **opts)
398
{
399
    // bit_rate or qp
400
    if (self->bit_rate) {
401
        AV_DICT_SET_BIT_RATE(opts, self->bit_rate);
402
        if (self->buff_factor <= 0) {
403
            self->buff_factor = 3;
404
        }
405
        AV_DICT_SET_INT(opts, "maxrate", (self->bit_rate) * 1000, AV_DICT_DONT_OVERWRITE);
406
        AV_DICT_SET_INT(opts, "bufsize", ((self->bit_rate) * 1000) * self->buff_factor, AV_DICT_DONT_OVERWRITE);
407
        AV_DICT_SET(opts, "force_key_frames", "expr:gte(t,n_forced*3)", AV_DICT_DONT_OVERWRITE);
408
    }
409
    else {
410
        AV_DICT_SET_QP(opts, self->qp, 25);
411
    }
412
    if (self->ignore_bframe) {
413
        AV_DICT_SET_INT(opts, "bf", 0, 0);
414
    }
415
    return 0;
416
}
417

    
418

    
419
static const codec_profile_class_t codec_profile_vaapi_vp9_class = {
420
    {
421
        .ic_super      = (idclass_t *)&codec_profile_vaapi_class,
422
        .ic_class      = "codec_profile_vaapi_vp9",
423
        .ic_caption    = N_("vaapi_vp9")
424
    },
425
    .open = (codec_profile_open_meth)tvh_codec_profile_vaapi_vp9_open,
426
};
427

    
428

    
429
TVHVideoCodec tvh_codec_vaapi_vp9 = {
430
    .name     = "vp9_vaapi",
431
    .size     = sizeof(tvh_codec_profile_vaapi_t),
432
    .idclass  = &codec_profile_vaapi_vp9_class,
433
    .profiles = vaapi_vp9_profiles,
434
    .profile_init = tvh_codec_profile_video_init,
435
    .profile_destroy = tvh_codec_profile_video_destroy,
436
};
437

    
    (1-1/1)