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