1/***
2  This file is part of PulseAudio.
3
4  Copyright 2020 Sanchayan Maity <sanchayan@asymptotic.io>
5
6  PulseAudio is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  PulseAudio is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  General Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public
17  License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
18***/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <pulsecore/log.h>
25#include <pulsecore/macro.h>
26#include <pulsecore/once.h>
27#include <pulse/sample.h>
28
29#include <arpa/inet.h>
30
31#include "a2dp-codecs.h"
32#include "a2dp-codec-api.h"
33#include "a2dp-codec-gst.h"
34#include "rtp.h"
35
36static bool can_be_supported(bool for_encoding) {
37    GstElementFactory *element_factory;
38
39    if (for_encoding) {
40        element_factory = gst_element_factory_find("openaptxenc");
41        if (element_factory == NULL) {
42            pa_log_info("aptX encoder element `openaptxenc` not found");
43            return false;
44        }
45
46        gst_object_unref(element_factory);
47    } else {
48        element_factory = gst_element_factory_find("openaptxdec");
49        if (element_factory == NULL) {
50            pa_log_info("aptX decoder element `openaptxdec` not found");
51            return false;
52        }
53
54        gst_object_unref(element_factory);
55    }
56
57    return true;
58}
59
60static bool can_accept_capabilities_common(const a2dp_aptx_t *capabilities, uint32_t vendor_id, uint16_t codec_id) {
61    if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id)
62        return false;
63
64    if (!(capabilities->frequency & (APTX_SAMPLING_FREQ_16000 | APTX_SAMPLING_FREQ_32000 |
65                                     APTX_SAMPLING_FREQ_44100 | APTX_SAMPLING_FREQ_48000)))
66        return false;
67
68    if (!(capabilities->channel_mode & APTX_CHANNEL_MODE_STEREO))
69        return false;
70
71    return true;
72}
73
74static bool can_accept_capabilities(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) {
75    const a2dp_aptx_t *capabilities = (const a2dp_aptx_t *) capabilities_buffer;
76
77    if (capabilities_size != sizeof(*capabilities))
78        return false;
79
80    return can_accept_capabilities_common(capabilities, APTX_VENDOR_ID, APTX_CODEC_ID);
81}
82
83static bool can_accept_capabilities_hd(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) {
84    const a2dp_aptx_hd_t *capabilities = (const a2dp_aptx_hd_t *) capabilities_buffer;
85
86    if (capabilities_size != sizeof(*capabilities))
87        return false;
88
89    return can_accept_capabilities_common(&capabilities->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID);
90}
91
92static const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) {
93    const pa_a2dp_codec_capabilities *a2dp_capabilities;
94    const char *key;
95    void *state;
96
97    /* There is no preference, just choose random valid entry */
98    PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) {
99        if (can_accept_capabilities(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding))
100            return key;
101    }
102
103    return NULL;
104}
105
106static const char *choose_remote_endpoint_hd(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) {
107    const pa_a2dp_codec_capabilities *a2dp_capabilities;
108    const char *key;
109    void *state;
110
111    /* There is no preference, just choose random valid entry */
112    PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) {
113        if (can_accept_capabilities_hd(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding))
114            return key;
115    }
116
117    return NULL;
118}
119
120static void fill_capabilities_common(a2dp_aptx_t *capabilities, uint32_t vendor_id, uint16_t codec_id) {
121    capabilities->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id);
122    capabilities->channel_mode = APTX_CHANNEL_MODE_STEREO;
123    capabilities->frequency = APTX_SAMPLING_FREQ_16000 | APTX_SAMPLING_FREQ_32000 |
124                              APTX_SAMPLING_FREQ_44100 | APTX_SAMPLING_FREQ_48000;
125}
126
127static uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) {
128    a2dp_aptx_t *capabilities = (a2dp_aptx_t *) capabilities_buffer;
129
130    pa_zero(*capabilities);
131    fill_capabilities_common(capabilities, APTX_VENDOR_ID, APTX_CODEC_ID);
132    return sizeof(*capabilities);
133}
134
135static uint8_t fill_capabilities_hd(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) {
136    a2dp_aptx_hd_t *capabilities = (a2dp_aptx_hd_t *) capabilities_buffer;
137
138    pa_zero(*capabilities);
139    fill_capabilities_common(&capabilities->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID);
140    return sizeof(*capabilities);
141}
142
143static bool is_configuration_valid_common(const a2dp_aptx_t *config, uint32_t vendor_id, uint16_t codec_id) {
144    if (A2DP_GET_VENDOR_ID(config->info) != vendor_id || A2DP_GET_CODEC_ID(config->info) != codec_id) {
145        pa_log_error("Invalid vendor codec information in configuration");
146        return false;
147    }
148
149    if (config->frequency != APTX_SAMPLING_FREQ_16000 && config->frequency != APTX_SAMPLING_FREQ_32000 &&
150        config->frequency != APTX_SAMPLING_FREQ_44100 && config->frequency != APTX_SAMPLING_FREQ_48000) {
151        pa_log_error("Invalid sampling frequency in configuration");
152        return false;
153    }
154
155    if (config->channel_mode != APTX_CHANNEL_MODE_STEREO) {
156        pa_log_error("Invalid channel mode in configuration");
157        return false;
158    }
159
160    return true;
161}
162
163static bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) {
164    const a2dp_aptx_t *config = (const a2dp_aptx_t *) config_buffer;
165
166    if (config_size != sizeof(*config)) {
167        pa_log_error("Invalid size of config buffer");
168        return false;
169    }
170
171    return is_configuration_valid_common(config, APTX_VENDOR_ID, APTX_CODEC_ID);
172}
173
174static bool is_configuration_valid_hd(const uint8_t *config_buffer, uint8_t config_size) {
175    const a2dp_aptx_hd_t *config = (const a2dp_aptx_hd_t *) config_buffer;
176
177    if (config_size != sizeof(*config)) {
178        pa_log_error("Invalid size of config buffer");
179        return false;
180    }
181
182    return is_configuration_valid_common(&config->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID);
183}
184
185static int fill_preferred_configuration_common(const pa_sample_spec *default_sample_spec, const a2dp_aptx_t *capabilities, a2dp_aptx_t *config, uint32_t vendor_id, uint16_t codec_id) {
186    int i;
187
188    static const struct {
189        uint32_t rate;
190        uint8_t cap;
191    } freq_table[] = {
192        { 16000U, APTX_SAMPLING_FREQ_16000 },
193        { 32000U, APTX_SAMPLING_FREQ_32000 },
194        { 44100U, APTX_SAMPLING_FREQ_44100 },
195        { 48000U, APTX_SAMPLING_FREQ_48000 }
196    };
197
198    if (A2DP_GET_VENDOR_ID(capabilities->info) != vendor_id || A2DP_GET_CODEC_ID(capabilities->info) != codec_id) {
199        pa_log_error("No supported vendor codec information");
200        return -1;
201    }
202
203    config->info = A2DP_SET_VENDOR_ID_CODEC_ID(vendor_id, codec_id);
204
205    if (!(capabilities->channel_mode & APTX_CHANNEL_MODE_STEREO)) {
206        pa_log_error("No supported channel modes");
207        return -1;
208    }
209
210    config->channel_mode = APTX_CHANNEL_MODE_STEREO;
211
212    /* Find the lowest freq that is at least as high as the requested sampling rate */
213    for (i = 0; (unsigned) i < PA_ELEMENTSOF(freq_table); i++) {
214        if (freq_table[i].rate >= default_sample_spec->rate && (capabilities->frequency & freq_table[i].cap)) {
215            config->frequency = freq_table[i].cap;
216            break;
217        }
218    }
219
220    if ((unsigned) i == PA_ELEMENTSOF(freq_table)) {
221        for (--i; i >= 0; i--) {
222            if (capabilities->frequency & freq_table[i].cap) {
223                config->frequency = freq_table[i].cap;
224                break;
225            }
226        }
227
228        if (i < 0) {
229            pa_log_error("Not suitable sample rate");
230            return false;
231        }
232    }
233
234    return 0;
235}
236
237static uint8_t fill_preferred_configuration(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) {
238    a2dp_aptx_t *config = (a2dp_aptx_t *) config_buffer;
239    const a2dp_aptx_t *capabilities = (const a2dp_aptx_t *) capabilities_buffer;
240
241    if (capabilities_size != sizeof(*capabilities)) {
242        pa_log_error("Invalid size of capabilities buffer");
243        return 0;
244    }
245
246    pa_zero(*config);
247
248    if (fill_preferred_configuration_common(default_sample_spec, capabilities, config, APTX_VENDOR_ID, APTX_CODEC_ID) < 0)
249        return 0;
250
251    return sizeof(*config);
252}
253
254static uint8_t fill_preferred_configuration_hd(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) {
255    a2dp_aptx_hd_t *config = (a2dp_aptx_hd_t *) config_buffer;
256    const a2dp_aptx_hd_t *capabilities = (const a2dp_aptx_hd_t *) capabilities_buffer;
257
258    if (capabilities_size != sizeof(*capabilities)) {
259        pa_log_error("Invalid size of capabilities buffer");
260        return 0;
261    }
262
263    pa_zero(*config);
264
265    if (fill_preferred_configuration_common(default_sample_spec, &capabilities->aptx, &config->aptx, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID) < 0)
266        return 0;
267
268    return sizeof(*config);
269}
270
271GstElement *gst_init_aptx(struct gst_info *info, pa_sample_spec *ss, bool for_encoding) {
272    GstElement *bin, *sink, *src, *capsf;
273    GstCaps *caps;
274    GstPad *pad;
275    const char *aptx_codec_media_type;
276
277    ss->format = PA_SAMPLE_S24LE;
278
279    if (info->codec_type == APTX_HD) {
280        switch (info->a2dp_codec_t.aptx_hd_config->aptx.frequency) {
281            case APTX_SAMPLING_FREQ_16000:
282                ss->rate = 16000u;
283                break;
284            case APTX_SAMPLING_FREQ_32000:
285                ss->rate = 32000u;
286                break;
287            case APTX_SAMPLING_FREQ_44100:
288                ss->rate = 44100u;
289                break;
290            case APTX_SAMPLING_FREQ_48000:
291                ss->rate = 48000u;
292                break;
293            default:
294                pa_log_error("aptX HD invalid frequency %d", info->a2dp_codec_t.aptx_hd_config->aptx.frequency);
295                goto fail;
296        }
297
298        switch (info->a2dp_codec_t.aptx_hd_config->aptx.channel_mode) {
299            case APTX_CHANNEL_MODE_STEREO:
300                ss->channels = 2;
301                break;
302            default:
303                pa_log_error("aptX HD invalid channel mode %d", info->a2dp_codec_t.aptx_hd_config->aptx.frequency);
304                goto fail;
305        }
306    } else {
307        switch (info->a2dp_codec_t.aptx_config->frequency) {
308            case APTX_SAMPLING_FREQ_16000:
309                ss->rate = 16000u;
310                break;
311            case APTX_SAMPLING_FREQ_32000:
312                ss->rate = 32000u;
313                break;
314            case APTX_SAMPLING_FREQ_44100:
315                ss->rate = 44100u;
316                break;
317            case APTX_SAMPLING_FREQ_48000:
318                ss->rate = 48000u;
319                break;
320            default:
321                pa_log_error("aptX invalid frequency %d", info->a2dp_codec_t.aptx_config->frequency);
322                goto fail;
323        }
324
325        switch (info->a2dp_codec_t.aptx_config->channel_mode) {
326            case APTX_CHANNEL_MODE_STEREO:
327                ss->channels = 2;
328                break;
329            default:
330                pa_log_error("aptX invalid channel mode %d", info->a2dp_codec_t.aptx_config->frequency);
331                goto fail;
332        }
333    }
334
335    aptx_codec_media_type = info->codec_type == APTX_HD ? "audio/aptx-hd" : "audio/aptx";
336
337    capsf = gst_element_factory_make("capsfilter", "aptx_capsfilter");
338    if (!capsf) {
339        pa_log_error("Could not create aptX capsfilter element");
340        goto fail;
341    }
342
343    caps = gst_caps_new_simple(aptx_codec_media_type,
344            "rate", G_TYPE_INT, (int) ss->rate,
345            "channels", G_TYPE_INT, (int) ss->channels,
346            NULL);
347    g_object_set(capsf, "caps", caps, NULL);
348    gst_caps_unref(caps);
349
350    if (for_encoding) {
351        sink = gst_element_factory_make("openaptxenc", "aptx_encoder");
352        src = capsf;
353
354        if (sink == NULL) {
355            pa_log_error("Could not create aptX encoder element");
356            goto fail_enc_dec;
357        }
358
359        bin = gst_bin_new("aptx_enc_bin");
360    } else {
361        sink = capsf;
362        src = gst_element_factory_make("openaptxdec", "aptx_decoder");
363
364        if (src == NULL) {
365            pa_log_error("Could not create aptX decoder element");
366            goto fail_enc_dec;
367        }
368
369        bin = gst_bin_new("aptx_dec_bin");
370    }
371
372    pa_assert(bin);
373
374    gst_bin_add_many(GST_BIN(bin), sink, src, NULL);
375    pa_assert_se(gst_element_link_many(sink, src, NULL));
376
377    pad = gst_element_get_static_pad(sink, "sink");
378    pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad)));
379    gst_object_unref(GST_OBJECT(pad));
380
381    pad = gst_element_get_static_pad(src, "src");
382    pa_assert_se(gst_element_add_pad(bin, gst_ghost_pad_new("src", pad)));
383    gst_object_unref(GST_OBJECT(pad));
384
385    return bin;
386
387fail_enc_dec:
388    gst_object_unref(GST_OBJECT(capsf));
389
390fail:
391    pa_log_error("aptX initialisation failed");
392    return NULL;
393}
394
395static void *init_common(enum a2dp_codec_type codec_type, bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
396    GstElement *bin;
397    struct gst_info *info = NULL;
398
399    info = pa_xnew0(struct gst_info, 1);
400    pa_assert(info);
401
402    info->core = core;
403    info->ss = sample_spec;
404
405    if (codec_type == APTX) {
406        info->codec_type = APTX;
407        info->a2dp_codec_t.aptx_config = (const a2dp_aptx_t *) config_buffer;
408        pa_assert(config_size == sizeof(*(info->a2dp_codec_t.aptx_config)));
409    } else if (codec_type == APTX_HD) {
410        info->codec_type = APTX_HD;
411        info->a2dp_codec_t.aptx_hd_config = (const a2dp_aptx_hd_t *) config_buffer;
412        pa_assert(config_size == sizeof(*(info->a2dp_codec_t.aptx_hd_config)));
413    } else
414        pa_assert_not_reached();
415
416    if (!(bin = gst_init_aptx(info, sample_spec, for_encoding)))
417        goto fail;
418
419    if (!gst_codec_init(info, for_encoding, bin))
420        goto fail;
421
422    return info;
423
424fail:
425    if (info)
426        pa_xfree(info);
427
428    return NULL;
429}
430
431static void *init(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
432    return init_common(APTX, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core);
433}
434
435static void *init_hd(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) {
436    return init_common(APTX_HD, for_encoding, for_backchannel, config_buffer, config_size, sample_spec, core);
437}
438
439static void deinit(void *codec_info) {
440    return gst_codec_deinit(codec_info);
441}
442
443static int reset(void *codec_info) {
444    return 0;
445}
446
447static int reset_hd(void *codec_info) {
448    struct gst_info *info = (struct gst_info *) codec_info;
449
450    info->seq_num = 0;
451
452    return 0;
453}
454
455static size_t get_block_size(void *codec_info, size_t link_mtu) {
456    /* aptX compression ratio is 6:1 and we need to process one aptX frame (4 bytes) at once */
457    size_t frame_count = (link_mtu / 4);
458
459    return frame_count * 4 * 6;
460}
461
462static size_t get_encoded_block_size(void *codec_info, size_t input_size) {
463    /* input size should be aligned to codec input block size */
464    pa_assert_fp(input_size % (4 * 6) == 0);
465
466    return (input_size / (4 * 6)) * 4;
467}
468
469static size_t get_block_size_hd(void *codec_info, size_t link_mtu) {
470    /* aptX HD compression ratio is 4:1 and we need to process one aptX HD frame (6 bytes) at once, plus aptX HD frames are encapsulated in RTP */
471    size_t rtp_size = sizeof(struct rtp_header);
472    size_t frame_count = (link_mtu - rtp_size) / 6;
473
474    return frame_count * 6 * 4;
475}
476
477static size_t get_encoded_block_size_hd(void *codec_info, size_t input_size) {
478    size_t rtp_size = sizeof(struct rtp_header);
479
480    /* input size should be aligned to codec input block size */
481    pa_assert_fp(input_size % (4 * 6) == 0);
482
483    return (input_size / (4 * 6)) * 6 + rtp_size;
484}
485
486static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
487    return 0;
488}
489
490static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
491    size_t written;
492
493    written = gst_transcode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer, output_size, processed);
494    if (PA_UNLIKELY(*processed == 0 || *processed != input_size))
495        pa_log_error("aptX encoding error");
496
497    return written;
498}
499
500static size_t encode_buffer_hd(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
501    struct gst_info *info = (struct gst_info *) codec_info;
502    struct rtp_header *header;
503    size_t written;
504
505    if (PA_UNLIKELY(output_size < sizeof(*header))) {
506        *processed = 0;
507        return 0;
508    }
509
510    written = encode_buffer(codec_info, timestamp, input_buffer, input_size, output_buffer + sizeof(*header), output_size - sizeof(*header), processed);
511
512    if (PA_LIKELY(written > 0)) {
513        header = (struct rtp_header *) output_buffer;
514        pa_zero(*header);
515        header->v = 2;
516        header->pt = 96;
517        header->sequence_number = htons(info->seq_num++);
518        header->timestamp = htonl(timestamp);
519        header->ssrc = htonl(1);
520        written += sizeof(*header);
521    }
522
523    return written;
524}
525
526static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
527    size_t written;
528
529    written = gst_transcode_buffer(codec_info, -1, input_buffer, input_size, output_buffer, output_size, processed);
530
531    /* Due to aptX latency, aptx_decode starts filling output buffer after 90 input samples.
532     * If input buffer contains less than 90 samples, aptx_decode returns zero (=no output)
533     * but set *processed to non zero as input samples were processed. So do not check for
534     * return value of aptx_decode, zero is valid. Decoding error is indicating by fact that
535     * not all input samples were processed. */
536    if (PA_UNLIKELY(*processed != input_size))
537        pa_log_error("aptX decoding error");
538
539    return written;
540}
541
542static size_t decode_buffer_hd(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
543    struct rtp_header *header;
544    size_t written;
545
546    if (PA_UNLIKELY(input_size < sizeof(*header))) {
547        *processed = 0;
548        return 0;
549    }
550
551    header = (struct rtp_header *) input_buffer;
552    written = decode_buffer(codec_info, input_buffer + sizeof(*header), input_size - sizeof(*header), output_buffer, output_size, processed);
553    *processed += sizeof(*header);
554    return written;
555}
556
557const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx = {
558    .id = { A2DP_CODEC_VENDOR, APTX_VENDOR_ID, APTX_CODEC_ID },
559    .support_backchannel = false,
560    .can_be_supported = can_be_supported,
561    .can_accept_capabilities = can_accept_capabilities,
562    .choose_remote_endpoint = choose_remote_endpoint,
563    .fill_capabilities = fill_capabilities,
564    .is_configuration_valid = is_configuration_valid,
565    .fill_preferred_configuration = fill_preferred_configuration,
566    .bt_codec = {
567        .name = "aptx",
568        .description = "aptX",
569        .init = init,
570        .deinit = deinit,
571        .reset = reset,
572        .get_read_block_size = get_block_size,
573        .get_write_block_size = get_block_size,
574        .get_encoded_block_size = get_encoded_block_size,
575        .reduce_encoder_bitrate = reduce_encoder_bitrate,
576        .encode_buffer = encode_buffer,
577        .decode_buffer = decode_buffer,
578    },
579};
580
581const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx_hd = {
582    .id = { A2DP_CODEC_VENDOR, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID },
583    .support_backchannel = false,
584    .can_be_supported = can_be_supported,
585    .can_accept_capabilities = can_accept_capabilities_hd,
586    .choose_remote_endpoint = choose_remote_endpoint_hd,
587    .fill_capabilities = fill_capabilities_hd,
588    .is_configuration_valid = is_configuration_valid_hd,
589    .fill_preferred_configuration = fill_preferred_configuration_hd,
590    .bt_codec = {
591        .name = "aptx_hd",
592        .description = "aptX HD",
593        .init = init_hd,
594        .deinit = deinit,
595        .reset = reset_hd,
596        .get_read_block_size = get_block_size_hd,
597        .get_write_block_size = get_block_size_hd,
598        .get_encoded_block_size = get_encoded_block_size_hd,
599        .reduce_encoder_bitrate = reduce_encoder_bitrate,
600        .encode_buffer = encode_buffer_hd,
601        .decode_buffer = decode_buffer_hd,
602    },
603};
604