mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 20:54:10 +00:00
Handle floating point/fixed formats seamlessly.
This commit is contained in:
parent
dcf505f0ea
commit
64d3d2185c
102
record/ffemu.c
102
record/ffemu.c
@ -103,10 +103,17 @@ struct ff_audio_info
|
|||||||
bool use_float;
|
bool use_float;
|
||||||
unsigned sample_size;
|
unsigned sample_size;
|
||||||
|
|
||||||
|
enum AVSampleFormat fill_format;
|
||||||
|
|
||||||
float *float_conv;
|
float *float_conv;
|
||||||
size_t float_conv_frames;
|
size_t float_conv_frames;
|
||||||
|
|
||||||
float *resample_out;
|
float *resample_out;
|
||||||
size_t resample_out_frames;
|
size_t resample_out_frames;
|
||||||
|
|
||||||
|
int16_t *fixed_conv;
|
||||||
|
size_t fixed_conv_frames;
|
||||||
|
|
||||||
double ratio;
|
double ratio;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -159,6 +166,51 @@ struct ffemu
|
|||||||
volatile bool can_sleep;
|
volatile bool can_sleep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool ffemu_codec_has_sample_format(enum AVSampleFormat fmt, const enum AVSampleFormat *fmts)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++)
|
||||||
|
if (fmt == fmts[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffemu_audio_resolve_format(struct ff_audio_info *audio, AVCodec *codec)
|
||||||
|
{
|
||||||
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
|
||||||
|
audio->fill_format = AV_SAMPLE_FMT_NONE;
|
||||||
|
|
||||||
|
if (ffemu_codec_has_sample_format(AV_SAMPLE_FMT_FLTP, codec->sample_fmts))
|
||||||
|
{
|
||||||
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
|
||||||
|
audio->fill_format = AV_SAMPLE_FMT_FLTP;
|
||||||
|
audio->use_float = true;
|
||||||
|
RARCH_LOG("[FFmpeg]: Using sample format FLTP.\n");
|
||||||
|
}
|
||||||
|
else if (ffemu_codec_has_sample_format(AV_SAMPLE_FMT_FLT, codec->sample_fmts))
|
||||||
|
{
|
||||||
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
|
||||||
|
audio->fill_format = AV_SAMPLE_FMT_FLT;
|
||||||
|
audio->use_float = true;
|
||||||
|
RARCH_LOG("[FFmpeg]: Using sample format FLT.\n");
|
||||||
|
}
|
||||||
|
else if (ffemu_codec_has_sample_format(AV_SAMPLE_FMT_S16P, codec->sample_fmts))
|
||||||
|
{
|
||||||
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
audio->fill_format = AV_SAMPLE_FMT_S16P;
|
||||||
|
audio->use_float = false;
|
||||||
|
RARCH_LOG("[FFmpeg]: Using sample format S16P.\n");
|
||||||
|
}
|
||||||
|
else if (ffemu_codec_has_sample_format(AV_SAMPLE_FMT_S16, codec->sample_fmts))
|
||||||
|
{
|
||||||
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
|
audio->fill_format = AV_SAMPLE_FMT_S16;
|
||||||
|
audio->use_float = false;
|
||||||
|
RARCH_LOG("[FFmpeg]: Using sample format S16.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
audio->sample_size = audio->use_float ? sizeof(float) : sizeof(int16_t);
|
||||||
|
}
|
||||||
|
|
||||||
static bool ffemu_init_audio(ffemu_t *handle)
|
static bool ffemu_init_audio(ffemu_t *handle)
|
||||||
{
|
{
|
||||||
struct ff_config_param *params = &handle->config;
|
struct ff_config_param *params = &handle->config;
|
||||||
@ -176,23 +228,22 @@ static bool ffemu_init_audio(ffemu_t *handle)
|
|||||||
|
|
||||||
audio->codec = avcodec_alloc_context3(codec);
|
audio->codec = avcodec_alloc_context3(codec);
|
||||||
|
|
||||||
audio->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
audio->codec->codec_type = AVMEDIA_TYPE_AUDIO;
|
||||||
audio->codec->channels = param->channels;
|
audio->codec->channels = param->channels;
|
||||||
audio->codec->channel_layout = AV_CH_LAYOUT_STEREO;
|
audio->codec->channel_layout = AV_CH_LAYOUT_STEREO;
|
||||||
|
|
||||||
|
ffemu_audio_resolve_format(audio, codec);
|
||||||
|
|
||||||
if (params->sample_rate)
|
if (params->sample_rate)
|
||||||
{
|
{
|
||||||
RARCH_LOG("[FFmpeg]: Using FLT sampling format.\n");
|
|
||||||
audio->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
|
|
||||||
audio->ratio = (double)params->sample_rate / param->samplerate;
|
audio->ratio = (double)params->sample_rate / param->samplerate;
|
||||||
audio->codec->sample_rate = params->sample_rate;
|
audio->codec->sample_rate = params->sample_rate;
|
||||||
audio->codec->time_base = av_d2q(1.0 / params->sample_rate, 1000000);
|
audio->codec->time_base = av_d2q(1.0 / params->sample_rate, 1000000);
|
||||||
|
|
||||||
audio->resampler = resampler_new();
|
audio->resampler = resampler_new();
|
||||||
audio->use_float = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RARCH_LOG("[FFmpeg]: Using S16 sampling format.\n");
|
|
||||||
audio->codec->sample_fmt = AV_SAMPLE_FMT_S16;
|
audio->codec->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||||
audio->codec->sample_rate = (int)roundf(param->samplerate);
|
audio->codec->sample_rate = (int)roundf(param->samplerate);
|
||||||
audio->codec->time_base = av_d2q(1.0 / param->samplerate, 1000000);
|
audio->codec->time_base = av_d2q(1.0 / param->samplerate, 1000000);
|
||||||
@ -206,8 +257,6 @@ static bool ffemu_init_audio(ffemu_t *handle)
|
|||||||
else if (params->audio_bit_rate)
|
else if (params->audio_bit_rate)
|
||||||
audio->codec->bit_rate = params->audio_bit_rate;
|
audio->codec->bit_rate = params->audio_bit_rate;
|
||||||
|
|
||||||
audio->sample_size = audio->use_float ? sizeof(float) : sizeof(int16_t);
|
|
||||||
|
|
||||||
// Allow experimental codecs.
|
// Allow experimental codecs.
|
||||||
audio->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
|
audio->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
|
||||||
|
|
||||||
@ -574,8 +623,7 @@ void ffemu_free(ffemu_t *handle)
|
|||||||
av_free(handle->audio.codec);
|
av_free(handle->audio.codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle->audio.buffer)
|
av_free(handle->audio.buffer);
|
||||||
av_free(handle->audio.buffer);
|
|
||||||
|
|
||||||
if (handle->video.codec)
|
if (handle->video.codec)
|
||||||
{
|
{
|
||||||
@ -583,11 +631,8 @@ void ffemu_free(ffemu_t *handle)
|
|||||||
av_free(handle->video.codec);
|
av_free(handle->video.codec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle->video.conv_frame)
|
av_free(handle->video.conv_frame);
|
||||||
av_free(handle->video.conv_frame);
|
av_free(handle->video.conv_frame_buf);
|
||||||
|
|
||||||
if (handle->video.conv_frame_buf)
|
|
||||||
av_free(handle->video.conv_frame_buf);
|
|
||||||
|
|
||||||
scaler_ctx_gen_reset(&handle->video.scaler);
|
scaler_ctx_gen_reset(&handle->video.scaler);
|
||||||
|
|
||||||
@ -603,8 +648,10 @@ void ffemu_free(ffemu_t *handle)
|
|||||||
|
|
||||||
if (handle->audio.resampler)
|
if (handle->audio.resampler)
|
||||||
resampler_free(handle->audio.resampler);
|
resampler_free(handle->audio.resampler);
|
||||||
|
|
||||||
av_free(handle->audio.float_conv);
|
av_free(handle->audio.float_conv);
|
||||||
av_free(handle->audio.resample_out);
|
av_free(handle->audio.resample_out);
|
||||||
|
av_free(handle->audio.fixed_conv);
|
||||||
|
|
||||||
free(handle);
|
free(handle);
|
||||||
}
|
}
|
||||||
@ -807,7 +854,7 @@ static bool encode_audio(ffemu_t *handle, AVPacket *pkt, bool dry)
|
|||||||
handle->audio.sample_size;
|
handle->audio.sample_size;
|
||||||
|
|
||||||
avcodec_fill_audio_frame(frame, handle->audio.codec->channels,
|
avcodec_fill_audio_frame(frame, handle->audio.codec->channels,
|
||||||
handle->audio.use_float ? AV_SAMPLE_FMT_FLTP : AV_SAMPLE_FMT_S16,
|
handle->audio.fill_format,
|
||||||
handle->audio.buffer,
|
handle->audio.buffer,
|
||||||
samples_size, 1);
|
samples_size, 1);
|
||||||
|
|
||||||
@ -850,7 +897,7 @@ static bool encode_audio(ffemu_t *handle, AVPacket *pkt, bool dry)
|
|||||||
|
|
||||||
static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
||||||
{
|
{
|
||||||
if (!handle->audio.use_float)
|
if (!handle->audio.use_float && !handle->audio.resampler)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (data->frames > handle->audio.float_conv_frames)
|
if (data->frames > handle->audio.float_conv_frames)
|
||||||
@ -869,11 +916,21 @@ static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
|||||||
handle->audio.resample_out_frames * handle->params.channels * sizeof(float));
|
handle->audio.resample_out_frames * handle->params.channels * sizeof(float));
|
||||||
if (!handle->audio.resample_out)
|
if (!handle->audio.resample_out)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
handle->audio.fixed_conv_frames = max(handle->audio.resample_out_frames, handle->audio.float_conv_frames);
|
||||||
|
handle->audio.fixed_conv = (int16_t*)av_realloc(handle->audio.fixed_conv,
|
||||||
|
handle->audio.fixed_conv_frames * handle->params.channels * sizeof(int16_t));
|
||||||
|
if (!handle->audio.fixed_conv)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_convert_s16_to_float(handle->audio.float_conv, (const int16_t*)data->data, data->frames * handle->params.channels, 1.0);
|
if (handle->audio.use_float || handle->audio.resampler)
|
||||||
|
{
|
||||||
|
audio_convert_s16_to_float(handle->audio.float_conv,
|
||||||
|
(const int16_t*)data->data, data->frames * handle->params.channels, 1.0);
|
||||||
|
data->data = handle->audio.float_conv;
|
||||||
|
}
|
||||||
|
|
||||||
data->data = handle->audio.float_conv;
|
|
||||||
if (handle->audio.resampler)
|
if (handle->audio.resampler)
|
||||||
{
|
{
|
||||||
// It's always two channels ...
|
// It's always two channels ...
|
||||||
@ -886,6 +943,13 @@ static void ffemu_audio_resample(ffemu_t *handle, struct ffemu_audio_data *data)
|
|||||||
resampler_process(handle->audio.resampler, &info);
|
resampler_process(handle->audio.resampler, &info);
|
||||||
data->data = handle->audio.resample_out;
|
data->data = handle->audio.resample_out;
|
||||||
data->frames = info.output_frames;
|
data->frames = info.output_frames;
|
||||||
|
|
||||||
|
if (!handle->audio.use_float)
|
||||||
|
{
|
||||||
|
audio_convert_float_to_s16(handle->audio.fixed_conv, handle->audio.resample_out,
|
||||||
|
data->frames * handle->params.channels);
|
||||||
|
data->data = handle->audio.fixed_conv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user