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