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