Project

General

Profile

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

Stefan Dietzel, 2022-03-17 21:27

 
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
};
266

    
267

    
268
/* hevc_vaapi =============================================================== */
269

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

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

    
302

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

    
327

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

    
337

    
338
/* vp8_vaapi =============================================================== */
339

    
340
static const AVProfile vaapi_vp8_profiles[] = {
341
    { FF_PROFILE_UNKNOWN },
342
};
343

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

    
367

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

    
377

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

    
387
/* vp9_vaapi =============================================================== */
388

    
389
static const AVProfile vaapi_vp9_profiles[] = {
390
    { FF_PROFILE_UNKNOWN },
391
};
392

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

    
416

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

    
426

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

    
    (1-1/1)