Blame libfreerdp/codec/dsp_ffmpeg.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Digital Sound Processing - FFMPEG backend
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2018 Armin Novak <armin.novak@thincast.com>
Packit Service fa4841
 * Copyright 2018 Thincast Technologies GmbH
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
Packit Service fa4841
#include <libavcodec/avcodec.h>
Packit Service fa4841
#include <libavutil/avutil.h>
Packit Service fa4841
#include <libavutil/opt.h>
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
#include <libswresample/swresample.h>
Packit Service fa4841
#elif defined(AVRESAMPLE_FOUND)
Packit Service fa4841
#include <libavresample/avresample.h>
Packit Service fa4841
#else
Packit Service fa4841
#error "libswresample or libavresample required"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include "dsp.h"
Packit Service fa4841
#include "dsp_ffmpeg.h"
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("dsp.ffmpeg")
Packit Service fa4841
Packit Service fa4841
struct _FREERDP_DSP_CONTEXT
Packit Service fa4841
{
Packit Service fa4841
	AUDIO_FORMAT format;
Packit Service fa4841
Packit Service fa4841
	BOOL isOpen;
Packit Service fa4841
	BOOL encoder;
Packit Service fa4841
Packit Service fa4841
	UINT32 bufferedSamples;
Packit Service fa4841
Packit Service fa4841
	enum AVCodecID id;
Packit Service fa4841
	AVCodec* codec;
Packit Service fa4841
	AVCodecContext* context;
Packit Service fa4841
	AVFrame* frame;
Packit Service fa4841
	AVFrame* resampled;
Packit Service fa4841
	AVFrame* buffered;
Packit Service fa4841
	AVPacket* packet;
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
	SwrContext* rcontext;
Packit Service fa4841
#else
Packit Service fa4841
	AVAudioResampleContext* rcontext;
Packit Service fa4841
#endif
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
static BOOL ffmpeg_codec_is_filtered(enum AVCodecID id, BOOL encoder)
Packit Service fa4841
{
Packit Service fa4841
	switch (id)
Packit Service fa4841
	{
Packit Service fa4841
#if !defined(WITH_DSP_EXPERIMENTAL)
Packit Service fa4841
Packit Service fa4841
		case AV_CODEC_ID_ADPCM_IMA_OKI:
Packit Service fa4841
		case AV_CODEC_ID_MP3:
Packit Service fa4841
		case AV_CODEC_ID_ADPCM_MS:
Packit Service fa4841
		case AV_CODEC_ID_G723_1:
Packit Service fa4841
			return TRUE;
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
		case AV_CODEC_ID_NONE:
Packit Service fa4841
			return TRUE;
Packit Service fa4841
Packit Service b1ea74
		case AV_CODEC_ID_GSM_MS:
Packit Service b1ea74
		case AV_CODEC_ID_AAC:
Packit Service b1ea74
		case AV_CODEC_ID_AAC_LATM:
Packit Service b1ea74
#if !defined(WITH_DSP_EXPERIMENTAL)
Packit Service b1ea74
			if (encoder)
Packit Service b1ea74
				return TRUE;
Packit Service b1ea74
#endif
Packit Service b1ea74
			return FALSE;
Packit Service b1ea74
Packit Service fa4841
		default:
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static enum AVCodecID ffmpeg_get_avcodec(const AUDIO_FORMAT* format)
Packit Service fa4841
{
Packit Service fa4841
	const char* id;
Packit Service fa4841
Packit Service fa4841
	if (!format)
Packit Service fa4841
		return AV_CODEC_ID_NONE;
Packit Service fa4841
Packit Service fa4841
	id = audio_format_get_tag_string(format->wFormatTag);
Packit Service fa4841
Packit Service fa4841
	switch (format->wFormatTag)
Packit Service fa4841
	{
Packit Service fa4841
		case WAVE_FORMAT_UNKNOWN:
Packit Service fa4841
			return AV_CODEC_ID_NONE;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_PCM:
Packit Service fa4841
			switch (format->wBitsPerSample)
Packit Service fa4841
			{
Packit Service fa4841
				case 16:
Packit Service fa4841
					return AV_CODEC_ID_PCM_U16LE;
Packit Service fa4841
Packit Service fa4841
				case 8:
Packit Service fa4841
					return AV_CODEC_ID_PCM_U8;
Packit Service fa4841
Packit Service fa4841
				default:
Packit Service fa4841
					return AV_CODEC_ID_NONE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_DVI_ADPCM:
Packit Service fa4841
			return AV_CODEC_ID_ADPCM_IMA_OKI;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_ADPCM:
Packit Service fa4841
			return AV_CODEC_ID_ADPCM_MS;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_ALAW:
Packit Service fa4841
			return AV_CODEC_ID_PCM_ALAW;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_MULAW:
Packit Service fa4841
			return AV_CODEC_ID_PCM_MULAW;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_GSM610:
Packit Service fa4841
			return AV_CODEC_ID_GSM_MS;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_MSG723:
Packit Service fa4841
			return AV_CODEC_ID_G723_1;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_AAC_MS:
Packit Service fa4841
			return AV_CODEC_ID_AAC;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			return AV_CODEC_ID_NONE;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int ffmpeg_sample_format(const AUDIO_FORMAT* format)
Packit Service fa4841
{
Packit Service fa4841
	switch (format->wFormatTag)
Packit Service fa4841
	{
Packit Service fa4841
		case WAVE_FORMAT_PCM:
Packit Service fa4841
			switch (format->wBitsPerSample)
Packit Service fa4841
			{
Packit Service fa4841
				case 8:
Packit Service fa4841
					return AV_SAMPLE_FMT_U8;
Packit Service fa4841
Packit Service fa4841
				case 16:
Packit Service fa4841
					return AV_SAMPLE_FMT_S16;
Packit Service fa4841
Packit Service fa4841
				default:
Packit Service fa4841
					return FALSE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_DVI_ADPCM:
Packit Service fa4841
		case WAVE_FORMAT_ADPCM:
Packit Service fa4841
			return AV_SAMPLE_FMT_S16P;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_MPEGLAYER3:
Packit Service fa4841
		case WAVE_FORMAT_AAC_MS:
Packit Service fa4841
			return AV_SAMPLE_FMT_FLTP;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_MSG723:
Packit Service fa4841
		case WAVE_FORMAT_GSM610:
Packit Service fa4841
			return AV_SAMPLE_FMT_S16P;
Packit Service fa4841
Packit Service fa4841
		case WAVE_FORMAT_ALAW:
Packit Service fa4841
			return AV_SAMPLE_FMT_S16;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void ffmpeg_close_context(FREERDP_DSP_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	if (context)
Packit Service fa4841
	{
Packit Service fa4841
		if (context->context)
Packit Service fa4841
			avcodec_free_context(&context->context);
Packit Service fa4841
Packit Service fa4841
		if (context->frame)
Packit Service fa4841
			av_frame_free(&context->frame);
Packit Service fa4841
Packit Service fa4841
		if (context->resampled)
Packit Service fa4841
			av_frame_free(&context->resampled);
Packit Service fa4841
Packit Service fa4841
		if (context->buffered)
Packit Service fa4841
			av_frame_free(&context->buffered);
Packit Service fa4841
Packit Service fa4841
		if (context->packet)
Packit Service fa4841
			av_packet_free(&context->packet);
Packit Service fa4841
Packit Service fa4841
		if (context->rcontext)
Packit Service fa4841
		{
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
			swr_free(&context->rcontext);
Packit Service fa4841
#else
Packit Service fa4841
			avresample_free(&context->rcontext);
Packit Service fa4841
#endif
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		context->id = AV_CODEC_ID_NONE;
Packit Service fa4841
		context->codec = NULL;
Packit Service fa4841
		context->isOpen = FALSE;
Packit Service fa4841
		context->context = NULL;
Packit Service fa4841
		context->frame = NULL;
Packit Service fa4841
		context->resampled = NULL;
Packit Service fa4841
		context->packet = NULL;
Packit Service fa4841
		context->rcontext = NULL;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
	int layout;
Packit Service fa4841
	const AUDIO_FORMAT* format;
Packit Service fa4841
Packit Service fa4841
	if (!context || context->isOpen)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	format = &context->format;
Packit Service fa4841
Packit Service fa4841
	if (!format)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	layout = av_get_default_channel_layout(format->nChannels);
Packit Service fa4841
	context->id = ffmpeg_get_avcodec(format);
Packit Service fa4841
Packit Service fa4841
	if (ffmpeg_codec_is_filtered(context->id, context->encoder))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (context->encoder)
Packit Service fa4841
		context->codec = avcodec_find_encoder(context->id);
Packit Service fa4841
	else
Packit Service fa4841
		context->codec = avcodec_find_decoder(context->id);
Packit Service fa4841
Packit Service fa4841
	if (!context->codec)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	context->context = avcodec_alloc_context3(context->codec);
Packit Service fa4841
Packit Service fa4841
	if (!context->context)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	switch (context->id)
Packit Service fa4841
	{
Packit Service fa4841
		/* We need support for multichannel and sample rates != 8000 */
Packit Service fa4841
		case AV_CODEC_ID_GSM_MS:
Packit Service fa4841
			context->context->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case AV_CODEC_ID_AAC:
Packit Service fa4841
			context->context->profile = FF_PROFILE_AAC_MAIN;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			break;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	context->context->channels = format->nChannels;
Packit Service fa4841
	context->context->channel_layout = layout;
Packit Service fa4841
	context->context->sample_rate = format->nSamplesPerSec;
Packit Service fa4841
	context->context->block_align = format->nBlockAlign;
Packit Service fa4841
	context->context->bit_rate = format->nAvgBytesPerSec * 8;
Packit Service fa4841
	context->context->sample_fmt = ffmpeg_sample_format(format);
Packit Service fa4841
	context->context->time_base = av_make_q(1, context->context->sample_rate);
Packit Service fa4841
Packit Service fa4841
	if ((ret = avcodec_open2(context->context, context->codec, NULL)) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service fa4841
		WLog_ERR(TAG, "Error avcodec_open2 %s [%d]", err, ret);
Packit Service fa4841
		goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	context->packet = av_packet_alloc();
Packit Service fa4841
Packit Service fa4841
	if (!context->packet)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	context->frame = av_frame_alloc();
Packit Service fa4841
Packit Service fa4841
	if (!context->frame)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	context->resampled = av_frame_alloc();
Packit Service fa4841
Packit Service fa4841
	if (!context->resampled)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	context->buffered = av_frame_alloc();
Packit Service fa4841
Packit Service fa4841
	if (!context->buffered)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
	context->rcontext = swr_alloc();
Packit Service fa4841
#else
Packit Service fa4841
	context->rcontext = avresample_alloc_context();
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (!context->rcontext)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	context->frame->channel_layout = layout;
Packit Service fa4841
	context->frame->channels = format->nChannels;
Packit Service fa4841
	context->frame->sample_rate = format->nSamplesPerSec;
Packit Service fa4841
	context->frame->format = AV_SAMPLE_FMT_S16;
Packit Service fa4841
Packit Service fa4841
	if (context->encoder)
Packit Service fa4841
	{
Packit Service fa4841
		context->resampled->format = context->context->sample_fmt;
Packit Service fa4841
		context->resampled->sample_rate = context->context->sample_rate;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		context->resampled->format = AV_SAMPLE_FMT_S16;
Packit Service fa4841
		context->resampled->sample_rate = format->nSamplesPerSec;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	context->resampled->channel_layout = layout;
Packit Service fa4841
	context->resampled->channels = format->nChannels;
Packit Service fa4841
Packit Service fa4841
	if (context->context->frame_size > 0)
Packit Service fa4841
	{
Packit Service fa4841
		context->buffered->channel_layout = context->resampled->channel_layout;
Packit Service fa4841
		context->buffered->channels = context->resampled->channels;
Packit Service fa4841
		context->buffered->format = context->resampled->format;
Packit Service fa4841
		context->buffered->nb_samples = context->context->frame_size;
Packit Service fa4841
Packit Service fa4841
		if ((ret = av_frame_get_buffer(context->buffered, 1)) < 0)
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	context->isOpen = TRUE;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	ffmpeg_close_context(context);
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service b1ea74
static BOOL ffmpeg_resample_frame(SwrContext* context, AVFrame* in, AVFrame* out)
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
Packit Service fa4841
	if (!swr_is_initialized(context))
Packit Service fa4841
	{
Packit Service fa4841
		if ((ret = swr_config_frame(context, out, in)) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if ((ret = (swr_init(context))) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((ret = swr_convert_frame(context, out, in)) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service fa4841
		WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
#else
Packit Service b1ea74
static BOOL ffmpeg_resample_frame(AVAudioResampleContext* context, AVFrame* in, AVFrame* out)
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
Packit Service fa4841
	if (!avresample_is_open(context))
Packit Service fa4841
	{
Packit Service fa4841
		if ((ret = avresample_config(context, out, in)) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if ((ret = (avresample_open(context))) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((ret = avresample_convert_frame(context, out, in)) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service fa4841
		WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service b1ea74
static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, AVPacket* packet,
Packit Service b1ea74
                                wStream* out)
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
	/* send the packet with the compressed data to the encoder */
Packit Service fa4841
	ret = avcodec_send_frame(context, in);
Packit Service fa4841
Packit Service fa4841
	if (ret < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service b1ea74
		WLog_ERR(TAG, "Error submitting the packet to the encoder %s [%d]", err, ret);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* read all the output frames (in general there may be any number of them */
Packit Service fa4841
	while (ret >= 0)
Packit Service fa4841
	{
Packit Service fa4841
		ret = avcodec_receive_packet(context, packet);
Packit Service fa4841
Packit Service fa4841
		if ((ret == AVERROR(EAGAIN)) || (ret == AVERROR_EOF))
Packit Service fa4841
			return TRUE;
Packit Service fa4841
		else if (ret < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during encoding %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (!Stream_EnsureRemainingCapacity(out, packet->size))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service fa4841
		Stream_Write(out, packet->data, packet->size);
Packit Service fa4841
		av_packet_unref(packet);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL ffmpeg_fill_frame(AVFrame* frame, const AUDIO_FORMAT* inputFormat, const BYTE* data,
Packit Service b1ea74
                              size_t size)
Packit Service fa4841
{
Packit Service fa4841
	int ret, bpp;
Packit Service fa4841
	frame->channels = inputFormat->nChannels;
Packit Service fa4841
	frame->sample_rate = inputFormat->nSamplesPerSec;
Packit Service fa4841
	frame->format = ffmpeg_sample_format(inputFormat);
Packit Service fa4841
	frame->channel_layout = av_get_default_channel_layout(frame->channels);
Packit Service fa4841
	bpp = av_get_bytes_per_sample(frame->format);
Packit Service fa4841
	frame->nb_samples = size / inputFormat->nChannels / bpp;
Packit Service fa4841
Packit Service b1ea74
	if ((ret = avcodec_fill_audio_frame(frame, frame->channels, frame->format, data, size, 1)) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service fa4841
		WLog_ERR(TAG, "Error during audio frame fill %s [%d]", err, ret);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service b1ea74
static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame,
Packit Service b1ea74
                          SwrContext* resampleContext, AVFrame* resampled, wStream* out)
Packit Service fa4841
#else
Packit Service b1ea74
static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame,
Packit Service b1ea74
                          AVAudioResampleContext* resampleContext, AVFrame* resampled, wStream* out)
Packit Service fa4841
#endif
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
	/* send the packet with the compressed data to the decoder */
Packit Service fa4841
	ret = avcodec_send_packet(dec_ctx, pkt);
Packit Service fa4841
Packit Service fa4841
	if (ret < 0)
Packit Service fa4841
	{
Packit Service fa4841
		const char* err = av_err2str(ret);
Packit Service b1ea74
		WLog_ERR(TAG, "Error submitting the packet to the decoder %s [%d]", err, ret);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* read all the output frames (in general there may be any number of them */
Packit Service fa4841
	while (ret >= 0)
Packit Service fa4841
	{
Packit Service fa4841
		ret = avcodec_receive_frame(dec_ctx, frame);
Packit Service fa4841
Packit Service fa4841
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
Packit Service fa4841
			return TRUE;
Packit Service fa4841
		else if (ret < 0)
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during decoding %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
		if (!swr_is_initialized(resampleContext))
Packit Service fa4841
		{
Packit Service fa4841
			if ((ret = swr_config_frame(resampleContext, resampled, frame)) < 0)
Packit Service fa4841
			{
Packit Service fa4841
#else
Packit Service fa4841
		if (!avresample_is_open(resampleContext))
Packit Service fa4841
		{
Packit Service fa4841
			if ((ret = avresample_config(resampleContext, resampled, frame)) < 0)
Packit Service fa4841
			{
Packit Service fa4841
#endif
Packit Service fa4841
				const char* err = av_err2str(ret);
Packit Service fa4841
				WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
				return FALSE;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
			if ((ret = (swr_init(resampleContext))) < 0)
Packit Service fa4841
#else
Packit Service fa4841
			if ((ret = (avresample_open(resampleContext))) < 0)
Packit Service fa4841
#endif
Packit Service fa4841
			{
Packit Service fa4841
				const char* err = av_err2str(ret);
Packit Service fa4841
				WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
				return FALSE;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
#if defined(SWRESAMPLE_FOUND)
Packit Service fa4841
		if ((ret = swr_convert_frame(resampleContext, resampled, frame)) < 0)
Packit Service fa4841
#else
Packit Service fa4841
		if ((ret = avresample_convert_frame(resampleContext, resampled, frame)) < 0)
Packit Service fa4841
#endif
Packit Service fa4841
		{
Packit Service fa4841
			const char* err = av_err2str(ret);
Packit Service fa4841
			WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		{
Packit Service fa4841
			const size_t data_size = resampled->channels * resampled->nb_samples * 2;
Packit Service fa4841
			Stream_EnsureRemainingCapacity(out, data_size);
Packit Service fa4841
			Stream_Write(out, resampled->data[0], data_size);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode)
Packit Service fa4841
{
Packit Service fa4841
	enum AVCodecID id = ffmpeg_get_avcodec(format);
Packit Service fa4841
Packit Service fa4841
	if (ffmpeg_codec_is_filtered(id, encode))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (encode)
Packit Service fa4841
		return avcodec_find_encoder(id) != NULL;
Packit Service fa4841
	else
Packit Service fa4841
		return avcodec_find_decoder(id) != NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode)
Packit Service fa4841
{
Packit Service fa4841
	FREERDP_DSP_CONTEXT* context;
Packit Service fa4841
	avcodec_register_all();
Packit Service fa4841
	context = calloc(1, sizeof(FREERDP_DSP_CONTEXT));
Packit Service fa4841
Packit Service fa4841
	if (!context)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	context->encoder = encode;
Packit Service fa4841
	return context;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context)
Packit Service fa4841
{
Packit Service fa4841
	if (context)
Packit Service fa4841
	{
Packit Service fa4841
		ffmpeg_close_context(context);
Packit Service fa4841
		free(context);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* context,
Packit Service fa4841
                                      const AUDIO_FORMAT* targetFormat)
Packit Service fa4841
{
Packit Service fa4841
	if (!context || !targetFormat)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	ffmpeg_close_context(context);
Packit Service fa4841
	context->format = *targetFormat;
Packit Service fa4841
	return ffmpeg_open_context(context);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* format,
Packit Service fa4841
                               const BYTE* data, size_t length, wStream* out)
Packit Service fa4841
{
Packit Service fa4841
	int rc;
Packit Service fa4841
Packit Service fa4841
	if (!context || !format || !data || !out || !context->encoder)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!context || !data || !out)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* Create input frame */
Packit Service fa4841
	if (!ffmpeg_fill_frame(context->frame, format, data, length))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* Resample to desired format. */
Packit Service b1ea74
	if (!ffmpeg_resample_frame(context->rcontext, context->frame, context->resampled))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (context->context->frame_size <= 0)
Packit Service fa4841
	{
Packit Service b1ea74
		return ffmpeg_encode_frame(context->context, context->resampled, context->packet, out);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		int copied = 0;
Packit Service fa4841
		int rest = context->resampled->nb_samples;
Packit Service fa4841
Packit Service fa4841
		do
Packit Service fa4841
		{
Packit Service fa4841
			int inSamples = rest;
Packit Service fa4841
Packit Service b1ea74
			if ((inSamples < 0) || (context->bufferedSamples > (UINT32)(INT_MAX - inSamples)))
Packit Service b1ea74
				return FALSE;
Packit Service fa4841
Packit Service b1ea74
			if (inSamples + (int)context->bufferedSamples > context->context->frame_size)
Packit Service b1ea74
				inSamples = context->context->frame_size - (int)context->bufferedSamples;
Packit Service b1ea74
Packit Service b1ea74
			rc =
Packit Service b1ea74
			    av_samples_copy(context->buffered->extended_data, context->resampled->extended_data,
Packit Service b1ea74
			                    (int)context->bufferedSamples, copied, inSamples,
Packit Service b1ea74
			                    context->context->channels, context->context->sample_fmt);
Packit Service fa4841
			rest -= inSamples;
Packit Service fa4841
			copied += inSamples;
Packit Service b1ea74
			context->bufferedSamples += (UINT32)inSamples;
Packit Service fa4841
Packit Service b1ea74
			if (context->context->frame_size <= (int)context->bufferedSamples)
Packit Service fa4841
			{
Packit Service fa4841
				/* Encode in desired format. */
Packit Service b1ea74
				if (!ffmpeg_encode_frame(context->context, context->buffered, context->packet, out))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				context->bufferedSamples = 0;
Packit Service fa4841
			}
Packit Service b1ea74
		} while (rest > 0);
Packit Service fa4841
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat,
Packit Service fa4841
                               const BYTE* data, size_t length, wStream* out)
Packit Service fa4841
{
Packit Service fa4841
	if (!context || !srcFormat || !data || !out || context->encoder)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	av_init_packet(context->packet);
Packit Service fa4841
	context->packet->data = (uint8_t*)data;
Packit Service fa4841
	context->packet->size = length;
Packit Service b1ea74
	return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext,
Packit Service b1ea74
	                     context->resampled, out);
Packit Service fa4841
}