FreeRDP
Loading...
Searching...
No Matches
dsp_ffmpeg.c
1
21#include <freerdp/config.h>
22
23#include <freerdp/log.h>
24
25#include <libavcodec/avcodec.h>
26#include <libavutil/avutil.h>
27#include <libavutil/opt.h>
28#if defined(SWRESAMPLE_FOUND)
29#include <libswresample/swresample.h>
30#elif defined(AVRESAMPLE_FOUND)
31#include <libavresample/avresample.h>
32#else
33#error "libswresample or libavresample required"
34#endif
35
36#include "dsp.h"
37#include "dsp_ffmpeg.h"
38
39#define TAG FREERDP_TAG("dsp.ffmpeg")
40
41struct S_FREERDP_DSP_CONTEXT
42{
44
45 BOOL isOpen;
46
47 UINT32 bufferedSamples;
48
49 enum AVCodecID id;
50 const AVCodec* codec;
51 AVCodecContext* context;
52 AVFrame* frame;
53 AVFrame* resampled;
54 AVFrame* buffered;
55 AVPacket* packet;
56#if defined(SWRESAMPLE_FOUND)
57 SwrContext* rcontext;
58#else
59 AVAudioResampleContext* rcontext;
60#endif
61};
62
63static BOOL ffmpeg_codec_is_filtered(enum AVCodecID id, WINPR_ATTR_UNUSED BOOL encoder)
64{
65 switch (id)
66 {
67#if !defined(WITH_DSP_EXPERIMENTAL)
68
69 case AV_CODEC_ID_ADPCM_IMA_OKI:
70 case AV_CODEC_ID_MP3:
71 case AV_CODEC_ID_ADPCM_MS:
72 case AV_CODEC_ID_G723_1:
73 case AV_CODEC_ID_GSM_MS:
74 case AV_CODEC_ID_PCM_ALAW:
75 case AV_CODEC_ID_PCM_MULAW:
76 return TRUE;
77#endif
78
79 case AV_CODEC_ID_NONE:
80 return TRUE;
81
82 case AV_CODEC_ID_AAC:
83 case AV_CODEC_ID_AAC_LATM:
84 return FALSE;
85
86 default:
87 return FALSE;
88 }
89}
90
91static enum AVCodecID ffmpeg_get_avcodec(const AUDIO_FORMAT* WINPR_RESTRICT format)
92{
93 if (!format)
94 return AV_CODEC_ID_NONE;
95
96 switch (format->wFormatTag)
97 {
98 case WAVE_FORMAT_UNKNOWN:
99 return AV_CODEC_ID_NONE;
100
101 case WAVE_FORMAT_PCM:
102 switch (format->wBitsPerSample)
103 {
104 case 16:
105 return AV_CODEC_ID_PCM_U16LE;
106
107 case 8:
108 return AV_CODEC_ID_PCM_U8;
109
110 default:
111 return AV_CODEC_ID_NONE;
112 }
113
114 case WAVE_FORMAT_DVI_ADPCM:
115 return AV_CODEC_ID_ADPCM_IMA_OKI;
116
117 case WAVE_FORMAT_ADPCM:
118 return AV_CODEC_ID_ADPCM_MS;
119
120 case WAVE_FORMAT_ALAW:
121 return AV_CODEC_ID_PCM_ALAW;
122
123 case WAVE_FORMAT_MULAW:
124 return AV_CODEC_ID_PCM_MULAW;
125
126 case WAVE_FORMAT_GSM610:
127 return AV_CODEC_ID_GSM_MS;
128
129 case WAVE_FORMAT_MSG723:
130 return AV_CODEC_ID_G723_1;
131
132 case WAVE_FORMAT_AAC_MS:
133 return AV_CODEC_ID_AAC;
134
135 case WAVE_FORMAT_OPUS:
136 return AV_CODEC_ID_OPUS;
137
138 default:
139 return AV_CODEC_ID_NONE;
140 }
141}
142
143static int ffmpeg_sample_format(const AUDIO_FORMAT* WINPR_RESTRICT format)
144{
145 switch (format->wFormatTag)
146 {
147 case WAVE_FORMAT_PCM:
148 switch (format->wBitsPerSample)
149 {
150 case 8:
151 return AV_SAMPLE_FMT_U8;
152
153 case 16:
154 return AV_SAMPLE_FMT_S16;
155
156 default:
157 return FALSE;
158 }
159
160 case WAVE_FORMAT_DVI_ADPCM:
161 case WAVE_FORMAT_ADPCM:
162 return AV_SAMPLE_FMT_S16P;
163
164 case WAVE_FORMAT_MPEGLAYER3:
165 case WAVE_FORMAT_AAC_MS:
166 return AV_SAMPLE_FMT_FLTP;
167
168 case WAVE_FORMAT_OPUS:
169 return AV_SAMPLE_FMT_S16;
170
171 case WAVE_FORMAT_MSG723:
172 case WAVE_FORMAT_GSM610:
173 return AV_SAMPLE_FMT_S16P;
174
175 case WAVE_FORMAT_ALAW:
176 return AV_SAMPLE_FMT_S16;
177
178 default:
179 return FALSE;
180 }
181}
182
183static void ffmpeg_close_context(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context)
184{
185 if (context)
186 {
187 if (context->context)
188 avcodec_free_context(&context->context);
189
190 if (context->frame)
191 av_frame_free(&context->frame);
192
193 if (context->resampled)
194 av_frame_free(&context->resampled);
195
196 if (context->buffered)
197 av_frame_free(&context->buffered);
198
199 if (context->packet)
200 av_packet_free(&context->packet);
201
202 if (context->rcontext)
203 {
204#if defined(SWRESAMPLE_FOUND)
205 swr_free(&context->rcontext);
206#else
207 avresample_free(&context->rcontext);
208#endif
209 }
210
211 context->id = AV_CODEC_ID_NONE;
212 context->codec = NULL;
213 context->isOpen = FALSE;
214 context->context = NULL;
215 context->frame = NULL;
216 context->resampled = NULL;
217 context->packet = NULL;
218 context->rcontext = NULL;
219 }
220}
221
222static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context)
223{
224 int ret = 0;
225
226 if (!context || context->isOpen)
227 return FALSE;
228
229 const AUDIO_FORMAT* format = &context->common.format;
230
231 if (!format)
232 return FALSE;
233 context->id = ffmpeg_get_avcodec(format);
234
235 if (ffmpeg_codec_is_filtered(context->id, context->common.encoder))
236 goto fail;
237
238 if (context->common.encoder)
239 context->codec = avcodec_find_encoder(context->id);
240 else
241 context->codec = avcodec_find_decoder(context->id);
242
243 if (!context->codec)
244 goto fail;
245
246 context->context = avcodec_alloc_context3(context->codec);
247
248 if (!context->context)
249 goto fail;
250
251 switch (context->id)
252 {
253 /* We need support for multichannel and sample rates != 8000 */
254 case AV_CODEC_ID_GSM_MS:
255 context->context->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
256 break;
257
258 case AV_CODEC_ID_AAC:
259#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(60, 31, 102)
260 context->context->profile = FF_PROFILE_AAC_MAIN;
261#else
262 context->context->profile = AV_PROFILE_AAC_MAIN;
263#endif
264 break;
265
266 default:
267 break;
268 }
269
270 context->context->max_b_frames = 1;
271 context->context->delay = 0;
272
273#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
274 av_channel_layout_default(&context->context->ch_layout, format->nChannels);
275#else
276 context->context->channels = format->nChannels;
277 const int64_t layout = av_get_default_channel_layout(format->nChannels);
278 context->context->channel_layout = layout;
279#endif
280 context->context->sample_rate = (int)format->nSamplesPerSec;
281 context->context->block_align = format->nBlockAlign;
282 context->context->bit_rate = format->nAvgBytesPerSec * 8LL;
283 context->context->sample_fmt = ffmpeg_sample_format(format);
284 context->context->time_base = av_make_q(1, context->context->sample_rate);
285
286 if ((ret = avcodec_open2(context->context, context->codec, NULL)) < 0)
287 {
288 const char* err = av_err2str(ret);
289 WLog_ERR(TAG, "Error avcodec_open2 %s [%d]", err, ret);
290 goto fail;
291 }
292
293 context->packet = av_packet_alloc();
294
295 if (!context->packet)
296 goto fail;
297
298 context->frame = av_frame_alloc();
299
300 if (!context->frame)
301 goto fail;
302
303 context->resampled = av_frame_alloc();
304
305 if (!context->resampled)
306 goto fail;
307
308 context->buffered = av_frame_alloc();
309
310 if (!context->buffered)
311 goto fail;
312
313#if defined(SWRESAMPLE_FOUND)
314 context->rcontext = swr_alloc();
315#else
316 context->rcontext = avresample_alloc_context();
317#endif
318
319 if (!context->rcontext)
320 goto fail;
321
322#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
323 av_channel_layout_default(&context->frame->ch_layout, format->nChannels);
324#else
325 context->frame->channel_layout = layout;
326 context->frame->channels = format->nChannels;
327#endif
328 WINPR_ASSERT(format->nSamplesPerSec <= INT_MAX);
329 context->frame->sample_rate = (int)format->nSamplesPerSec;
330 context->frame->format = AV_SAMPLE_FMT_S16;
331
332 if (context->common.encoder)
333 {
334 context->resampled->format = context->context->sample_fmt;
335 context->resampled->sample_rate = context->context->sample_rate;
336 }
337 else
338 {
339 context->resampled->format = AV_SAMPLE_FMT_S16;
340
341 WINPR_ASSERT(format->nSamplesPerSec <= INT_MAX);
342 context->resampled->sample_rate = (int)format->nSamplesPerSec;
343 }
344
345#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
346 av_channel_layout_default(&context->resampled->ch_layout, format->nChannels);
347#else
348 context->resampled->channel_layout = layout;
349 context->resampled->channels = format->nChannels;
350#endif
351
352 if (context->context->frame_size > 0)
353 {
354#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
355 ret = av_channel_layout_copy(&context->buffered->ch_layout, &context->resampled->ch_layout);
356 if (ret != 0)
357 goto fail;
358#else
359 context->buffered->channel_layout = context->resampled->channel_layout;
360 context->buffered->channels = context->resampled->channels;
361#endif
362 context->buffered->format = context->resampled->format;
363 context->buffered->nb_samples = context->context->frame_size;
364
365 ret = av_frame_get_buffer(context->buffered, 1);
366 if (ret < 0)
367 goto fail;
368 }
369
370 context->isOpen = TRUE;
371 return TRUE;
372fail:
373 ffmpeg_close_context(context);
374 return FALSE;
375}
376
377#if defined(SWRESAMPLE_FOUND)
378static BOOL ffmpeg_resample_frame(SwrContext* WINPR_RESTRICT context, AVFrame* WINPR_RESTRICT in,
379 AVFrame* WINPR_RESTRICT out)
380{
381 int ret = 0;
382
383 if (!swr_is_initialized(context))
384 {
385 if ((ret = swr_config_frame(context, out, in)) < 0)
386 {
387 const char* err = av_err2str(ret);
388 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
389 return FALSE;
390 }
391
392 if ((ret = (swr_init(context))) < 0)
393 {
394 const char* err = av_err2str(ret);
395 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
396 return FALSE;
397 }
398 }
399
400 if ((ret = swr_convert_frame(context, out, in)) < 0)
401 {
402 const char* err = av_err2str(ret);
403 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
404 return FALSE;
405 }
406
407 return TRUE;
408}
409#else
410static BOOL ffmpeg_resample_frame(AVAudioResampleContext* WINPR_RESTRICT context,
411 AVFrame* WINPR_RESTRICT in, AVFrame* WINPR_RESTRICT out)
412{
413 int ret;
414
415 if (!avresample_is_open(context))
416 {
417 if ((ret = avresample_config(context, out, in)) < 0)
418 {
419 const char* err = av_err2str(ret);
420 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
421 return FALSE;
422 }
423
424 if ((ret = (avresample_open(context))) < 0)
425 {
426 const char* err = av_err2str(ret);
427 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
428 return FALSE;
429 }
430 }
431
432 if ((ret = avresample_convert_frame(context, out, in)) < 0)
433 {
434 const char* err = av_err2str(ret);
435 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
436 return FALSE;
437 }
438
439 return TRUE;
440}
441#endif
442
443static BOOL ffmpeg_encode_frame(AVCodecContext* WINPR_RESTRICT context, AVFrame* WINPR_RESTRICT in,
444 AVPacket* WINPR_RESTRICT packet, wStream* WINPR_RESTRICT out)
445{
446 if (in->format == AV_SAMPLE_FMT_FLTP)
447 {
448 uint8_t** pp = in->extended_data;
449#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
450 const int nr_channels = in->channels;
451#else
452 const int nr_channels = in->ch_layout.nb_channels;
453#endif
454
455 for (int y = 0; y < nr_channels; y++)
456 {
457 float* data = (float*)pp[y];
458 for (int x = 0; x < in->nb_samples; x++)
459 {
460 const float val1 = data[x];
461 if (isnan(val1))
462 data[x] = 0.0f;
463 else if (isinf(val1))
464 {
465 if (val1 < 0.0f)
466 data[x] = -1.0f;
467 else
468 data[x] = 1.0f;
469 }
470 }
471 }
472 }
473 /* send the packet with the compressed data to the encoder */
474 int ret = avcodec_send_frame(context, in);
475
476 if (ret < 0)
477 {
478 const char* err = av_err2str(ret);
479 // Ignore errors: AAC encoder sometimes returns -22
480 // The log message from ffmpeg is '[aac @ 0x7f140db753c0] Input contains (near) NaN/+-Inf'
481 if (ret == AVERROR(EINVAL))
482 {
483 WLog_DBG(TAG, "Error submitting the packet to the encoder %s [%d], ignoring", err, ret);
484 return TRUE;
485 }
486
487 WLog_ERR(TAG, "Error submitting the packet to the encoder %s [%d]", err, ret);
488
489 return FALSE;
490 }
491
492 /* read all the output frames (in general there may be any number of them */
493 while (TRUE)
494 {
495 ret = avcodec_receive_packet(context, packet);
496
497 if ((ret == AVERROR(EAGAIN)) || (ret == AVERROR_EOF))
498 break;
499
500 if (ret < 0)
501 {
502 const char* err = av_err2str(ret);
503 WLog_ERR(TAG, "Error during encoding %s [%d]", err, ret);
504 return FALSE;
505 }
506
507 WINPR_ASSERT(packet->size >= 0);
508 if (!Stream_EnsureRemainingCapacity(out, (size_t)packet->size))
509 return FALSE;
510
511 Stream_Write(out, packet->data, (size_t)packet->size);
512 av_packet_unref(packet);
513 }
514
515 return TRUE;
516}
517
518static BOOL ffmpeg_fill_frame(AVFrame* WINPR_RESTRICT frame,
519 const AUDIO_FORMAT* WINPR_RESTRICT inputFormat,
520 const BYTE* WINPR_RESTRICT data, size_t size)
521{
522 int ret = 0;
523#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
524 frame->channels = inputFormat->nChannels;
525 frame->channel_layout = av_get_default_channel_layout(frame->channels);
526#else
527 av_channel_layout_default(&frame->ch_layout, inputFormat->nChannels);
528#endif
529 WINPR_ASSERT(inputFormat->nSamplesPerSec <= INT_MAX);
530 frame->sample_rate = (int)inputFormat->nSamplesPerSec;
531 frame->format = ffmpeg_sample_format(inputFormat);
532
533 const int bpp = av_get_bytes_per_sample(frame->format);
534 WINPR_ASSERT(bpp >= 0);
535 WINPR_ASSERT(size <= INT_MAX);
536 const size_t nb_samples = size / inputFormat->nChannels / (size_t)bpp;
537 frame->nb_samples = (int)nb_samples;
538
539 if ((ret = avcodec_fill_audio_frame(frame, inputFormat->nChannels, frame->format, data,
540 (int)size, 1)) < 0)
541 {
542 const char* err = av_err2str(ret);
543 WLog_ERR(TAG, "Error during audio frame fill %s [%d]", err, ret);
544 return FALSE;
545 }
546
547 return TRUE;
548}
549#if defined(SWRESAMPLE_FOUND)
550static BOOL ffmpeg_decode(AVCodecContext* WINPR_RESTRICT dec_ctx, AVPacket* WINPR_RESTRICT pkt,
551 AVFrame* WINPR_RESTRICT frame, SwrContext* WINPR_RESTRICT resampleContext,
552 AVFrame* WINPR_RESTRICT resampled, wStream* WINPR_RESTRICT out)
553#else
554static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame,
555 AVAudioResampleContext* resampleContext, AVFrame* resampled, wStream* out)
556#endif
557{
558 /* send the packet with the compressed data to the decoder */
559 int ret = avcodec_send_packet(dec_ctx, pkt);
560
561 if (ret < 0)
562 {
563 const char* err = av_err2str(ret);
564 WLog_ERR(TAG, "Error submitting the packet to the decoder %s [%d]", err, ret);
565 return FALSE;
566 }
567
568 /* read all the output frames (in general there may be any number of them */
569 while (ret >= 0)
570 {
571 ret = avcodec_receive_frame(dec_ctx, frame);
572
573 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
574 break;
575
576 if (ret < 0)
577 {
578 const char* err = av_err2str(ret);
579 WLog_ERR(TAG, "Error during decoding %s [%d]", err, ret);
580 return FALSE;
581 }
582
583#if defined(SWRESAMPLE_FOUND)
584 if (!swr_is_initialized(resampleContext))
585 {
586 if ((ret = swr_config_frame(resampleContext, resampled, frame)) < 0)
587 {
588#else
589 if (!avresample_is_open(resampleContext))
590 {
591 if ((ret = avresample_config(resampleContext, resampled, frame)) < 0)
592 {
593#endif
594 const char* err = av_err2str(ret);
595 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
596 return FALSE;
597 }
598
599#if defined(SWRESAMPLE_FOUND)
600 ret = (swr_init(resampleContext));
601#else
602 ret = (avresample_open(resampleContext));
603#endif
604 if (ret < 0)
605 {
606 const char* err = av_err2str(ret);
607 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
608 return FALSE;
609 }
610 }
611
612#if defined(SWRESAMPLE_FOUND)
613 ret = swr_convert_frame(resampleContext, resampled, frame);
614#else
615 ret = avresample_convert_frame(resampleContext, resampled, frame);
616#endif
617 if (ret < 0)
618 {
619 const char* err = av_err2str(ret);
620 WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
621 return FALSE;
622 }
623
624 {
625
626#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
627 WINPR_ASSERT(resampled->ch_layout.nb_channels >= 0);
628 const size_t nrchannels = (size_t)resampled->ch_layout.nb_channels;
629#else
630 const size_t nrchannels = resampled->channels;
631#endif
632 WINPR_ASSERT(resampled->nb_samples >= 0);
633 const size_t data_size = nrchannels * (size_t)resampled->nb_samples * 2ull;
634 if (!Stream_EnsureRemainingCapacity(out, data_size))
635 return FALSE;
636 Stream_Write(out, resampled->data[0], data_size);
637 }
638 }
639
640 return TRUE;
641}
642
643BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* WINPR_RESTRICT format, BOOL encode)
644{
645 enum AVCodecID id = ffmpeg_get_avcodec(format);
646
647 if (ffmpeg_codec_is_filtered(id, encode))
648 return FALSE;
649
650 if (encode)
651 return avcodec_find_encoder(id) != NULL;
652 else
653 return avcodec_find_decoder(id) != NULL;
654}
655
656FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode)
657{
658 FREERDP_DSP_CONTEXT* context = NULL;
659#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
660 avcodec_register_all();
661#endif
662 context = calloc(1, sizeof(FREERDP_DSP_CONTEXT));
663
664 if (!context)
665 goto fail;
666
667 if (!freerdp_dsp_common_context_init(&context->common, encode))
668 goto fail;
669
670 return context;
671
672fail:
673 WINPR_PRAGMA_DIAG_PUSH
674 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
675 freerdp_dsp_ffmpeg_context_free(context);
676 WINPR_PRAGMA_DIAG_POP
677 return NULL;
678}
679
680void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context)
681{
682 if (context)
683 {
684 ffmpeg_close_context(context);
685 freerdp_dsp_common_context_uninit(&context->common);
686 free(context);
687 }
688}
689
690BOOL freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
691 const AUDIO_FORMAT* WINPR_RESTRICT targetFormat)
692{
693 if (!context || !targetFormat)
694 return FALSE;
695
696 ffmpeg_close_context(context);
697 context->common.format = *targetFormat;
698 return ffmpeg_open_context(context);
699}
700
701static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
702 const BYTE* WINPR_RESTRICT src, size_t size,
703 const AUDIO_FORMAT* WINPR_RESTRICT srcFormat,
704 const BYTE** WINPR_RESTRICT data, size_t* WINPR_RESTRICT length,
705 AUDIO_FORMAT* WINPR_RESTRICT dstFormat)
706{
707 UINT32 bpp = 0;
708 size_t samples = 0;
709
710 if (!context || !data || !length || !dstFormat)
711 return FALSE;
712
713 if (srcFormat->wFormatTag != WAVE_FORMAT_PCM)
714 return FALSE;
715
716 bpp = srcFormat->wBitsPerSample > 8 ? 2 : 1;
717 samples = size / bpp / srcFormat->nChannels;
718
719 *dstFormat = *srcFormat;
720 if (context->common.format.nChannels == srcFormat->nChannels)
721 {
722 *data = src;
723 *length = size;
724 return TRUE;
725 }
726
727 Stream_SetPosition(context->common.channelmix, 0);
728
729 /* Destination has more channels than source */
730 if (context->common.format.nChannels > srcFormat->nChannels)
731 {
732 switch (srcFormat->nChannels)
733 {
734 case 1:
735 if (!Stream_EnsureCapacity(context->common.channelmix, size * 2))
736 return FALSE;
737
738 for (size_t x = 0; x < samples; x++)
739 {
740 for (size_t y = 0; y < bpp; y++)
741 Stream_Write_UINT8(context->common.channelmix, src[x * bpp + y]);
742
743 for (size_t y = 0; y < bpp; y++)
744 Stream_Write_UINT8(context->common.channelmix, src[x * bpp + y]);
745 }
746
747 Stream_SealLength(context->common.channelmix);
748 *data = Stream_Buffer(context->common.channelmix);
749 *length = Stream_Length(context->common.channelmix);
750 dstFormat->nChannels = 2;
751 return TRUE;
752
753 case 2: /* We only support stereo, so we can not handle this case. */
754 default: /* Unsupported number of channels */
755 WLog_WARN(TAG, "[%s] unsupported source channel count %" PRIu16, __func__,
756 srcFormat->nChannels);
757 return FALSE;
758 }
759 }
760
761 /* Destination has less channels than source */
762 switch (srcFormat->nChannels)
763 {
764 case 2:
765 if (!Stream_EnsureCapacity(context->common.channelmix, size / 2))
766 return FALSE;
767
768 /* Simply drop second channel.
769 * TODO: Calculate average */
770 for (size_t x = 0; x < samples; x++)
771 {
772 for (size_t y = 0; y < bpp; y++)
773 Stream_Write_UINT8(context->common.channelmix, src[2 * x * bpp + y]);
774 }
775
776 Stream_SealLength(context->common.channelmix);
777 *data = Stream_Buffer(context->common.channelmix);
778 *length = Stream_Length(context->common.channelmix);
779 dstFormat->nChannels = 1;
780 return TRUE;
781
782 case 1: /* Invalid, do we want to use a 0 channel sound? */
783 default: /* Unsupported number of channels */
784 WLog_WARN(TAG, "[%s] unsupported channel count %" PRIu16, __func__,
785 srcFormat->nChannels);
786 return FALSE;
787 }
788
789 return FALSE;
790}
791
792BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
793 const AUDIO_FORMAT* WINPR_RESTRICT format,
794 const BYTE* WINPR_RESTRICT sdata, size_t length,
795 wStream* WINPR_RESTRICT out)
796{
797 AUDIO_FORMAT fmt = { 0 };
798
799 if (!context || !format || !sdata || !out || !context->common.encoder)
800 return FALSE;
801
802 if (!context || !sdata || !out)
803 return FALSE;
804
805 /* https://github.com/FreeRDP/FreeRDP/issues/7607
806 *
807 * we get noisy data with channel transformation, so do it ourselves.
808 */
809 const BYTE* data = NULL;
810 if (!freerdp_dsp_channel_mix(context, sdata, length, format, &data, &length, &fmt))
811 return FALSE;
812
813 /* Create input frame */
814 if (!ffmpeg_fill_frame(context->frame, format, data, length))
815 return FALSE;
816
817 /* Resample to desired format. */
818 if (!ffmpeg_resample_frame(context->rcontext, context->frame, context->resampled))
819 return FALSE;
820
821 if (context->context->frame_size <= 0)
822 {
823 return ffmpeg_encode_frame(context->context, context->resampled, context->packet, out);
824 }
825 else
826 {
827 int copied = 0;
828 int rest = context->resampled->nb_samples;
829
830 do
831 {
832 int inSamples = rest;
833
834 if ((inSamples < 0) || (context->bufferedSamples > (UINT32)(INT_MAX - inSamples)))
835 return FALSE;
836
837 if (inSamples + (int)context->bufferedSamples > context->context->frame_size)
838 inSamples = context->context->frame_size - (int)context->bufferedSamples;
839
840#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
841 const int nrchannels = context->context->ch_layout.nb_channels;
842#else
843 const int nrchannels = context->context->channels;
844#endif
845 const int rc =
846 av_samples_copy(context->buffered->extended_data, context->resampled->extended_data,
847 (int)context->bufferedSamples, copied, inSamples, nrchannels,
848 context->context->sample_fmt);
849 if (rc < 0)
850 return FALSE;
851 rest -= inSamples;
852 copied += inSamples;
853 context->bufferedSamples += (UINT32)inSamples;
854
855 if (context->context->frame_size <= (int)context->bufferedSamples)
856 {
857 /* Encode in desired format. */
858 if (!ffmpeg_encode_frame(context->context, context->buffered, context->packet, out))
859 return FALSE;
860
861 context->bufferedSamples = 0;
862 }
863 } while (rest > 0);
864
865 return TRUE;
866 }
867}
868
869BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
870 const AUDIO_FORMAT* WINPR_RESTRICT srcFormat,
871 const BYTE* WINPR_RESTRICT data, size_t length,
872 wStream* WINPR_RESTRICT out)
873{
874 if (!context || !srcFormat || !data || !out || context->common.encoder)
875 return FALSE;
876
877#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
878 av_init_packet(context->packet);
879#endif
880 context->packet->data = WINPR_CAST_CONST_PTR_AWAY(data, uint8_t*);
881
882 WINPR_ASSERT(length <= INT_MAX);
883 context->packet->size = (int)length;
884 return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext,
885 context->resampled, out);
886}