static bool ffmpeg_init_audio(ffmpeg_t *handle) { settings_t *settings = config_get_ptr(); struct ff_config_param *params = &handle->config; struct ff_audio_info *audio = &handle->audio; struct ffemu_params *param = &handle->params; AVCodec *codec = avcodec_find_encoder_by_name( *params->acodec ? params->acodec : "flac"); if (!codec) { RARCH_ERR("[FFmpeg]: Cannot find acodec %s.\n", *params->acodec ? params->acodec : "flac"); return false; } audio->encoder = codec; audio->codec = avcodec_alloc_context3(codec); audio->codec->codec_type = AVMEDIA_TYPE_AUDIO; audio->codec->channels = param->channels; audio->codec->channel_layout = (param->channels > 1) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; ffmpeg_audio_resolve_format(audio, codec); ffmpeg_audio_resolve_sample_rate(handle, codec); if (params->sample_rate) { audio->ratio = (double)params->sample_rate / param->samplerate; audio->codec->sample_rate = params->sample_rate; audio->codec->time_base = av_d2q(1.0 / params->sample_rate, 1000000); rarch_resampler_realloc(&audio->resampler_data, &audio->resampler, settings->audio.resampler, audio->ratio); } else { audio->codec->sample_fmt = AV_SAMPLE_FMT_S16; audio->codec->sample_rate = (int)roundf(param->samplerate); audio->codec->time_base = av_d2q(1.0 / param->samplerate, 1000000); } if (params->audio_qscale) { audio->codec->flags |= CODEC_FLAG_QSCALE; audio->codec->global_quality = params->audio_global_quality; } else if (params->audio_bit_rate) audio->codec->bit_rate = params->audio_bit_rate; /* Allow experimental codecs. */ audio->codec->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; if (handle->muxer.ctx->oformat->flags & AVFMT_GLOBALHEADER) audio->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if (avcodec_open2(audio->codec, codec, params->audio_opts ? ¶ms->audio_opts : NULL) != 0) return false; if (!audio->codec->frame_size) /* If not set (PCM), just set something. */ audio->codec->frame_size = 1024; audio->buffer = (uint8_t*)av_malloc( audio->codec->frame_size * audio->codec->channels * audio->sample_size); #if 0 RARCH_LOG("[FFmpeg]: Audio frame size: %d.\n", audio->codec->frame_size); #endif if (!audio->buffer) return false; audio->outbuf_size = FF_MIN_BUFFER_SIZE; audio->outbuf = (uint8_t*)av_malloc(audio->outbuf_size); if (!audio->outbuf) return false; return true; }
void init_audio(void) { audio_convert_init_simd(); // Resource leaks will follow if audio is initialized twice. if (driver.audio_data) return; // Accomodate rewind since at some point we might have two full buffers. size_t max_bufsamples = AUDIO_CHUNK_SIZE_NONBLOCKING * 2; size_t outsamples_max = max_bufsamples * AUDIO_MAX_RATIO * g_settings.slowmotion_ratio; // Used for recording even if audio isn't enabled. rarch_assert(g_extern.audio_data.conv_outsamples = (int16_t*)malloc(outsamples_max * sizeof(int16_t))); g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING; g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING; g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size; // Needs to be able to hold full content of a full max_bufsamples in addition to its own. rarch_assert(g_extern.audio_data.rewind_buf = (int16_t*)malloc(max_bufsamples * sizeof(int16_t))); g_extern.audio_data.rewind_size = max_bufsamples; if (!g_settings.audio.enable) { g_extern.audio_active = false; return; } find_audio_driver(); #ifdef HAVE_THREADS if (g_extern.system.audio_callback.callback) { RARCH_LOG("Starting threaded audio driver ...\n"); if (!rarch_threaded_audio_init(&driver.audio, &driver.audio_data, *g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency, driver.audio)) { RARCH_ERR("Cannot open threaded audio driver ... Exiting ...\n"); rarch_fail(1, "init_audio()"); } } else #endif { driver.audio_data = driver.audio->init(*g_settings.audio.device ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency); } if (!driver.audio_data) { RARCH_ERR("Failed to initialize audio driver. Will continue without audio.\n"); g_extern.audio_active = false; } g_extern.audio_data.use_float = false; if (g_extern.audio_active && driver.audio->use_float && driver.audio->use_float(driver.audio_data)) g_extern.audio_data.use_float = true; if (!g_settings.audio.sync && g_extern.audio_active) { driver.audio->set_nonblock_state(driver.audio_data, true); g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size; } // Should never happen. if (g_extern.audio_data.in_rate <= 0.0f) { RARCH_WARN("Input rate is invalid (%.3f Hz). Using output rate (%u Hz).\n", g_extern.audio_data.in_rate, g_settings.audio.out_rate); g_extern.audio_data.in_rate = g_settings.audio.out_rate; } g_extern.audio_data.orig_src_ratio = g_extern.audio_data.src_ratio = (double)g_settings.audio.out_rate / g_extern.audio_data.in_rate; if (!rarch_resampler_realloc(&g_extern.audio_data.resampler_data, &g_extern.audio_data.resampler, g_settings.audio.resampler, g_extern.audio_data.orig_src_ratio)) { RARCH_ERR("Failed to initialize resampler \"%s\".\n", g_settings.audio.resampler); g_extern.audio_active = false; } rarch_assert(g_extern.audio_data.data = (float*)malloc(max_bufsamples * sizeof(float))); g_extern.audio_data.data_ptr = 0; rarch_assert(g_settings.audio.out_rate < g_extern.audio_data.in_rate * AUDIO_MAX_RATIO); rarch_assert(g_extern.audio_data.outsamples = (float*)malloc(outsamples_max * sizeof(float))); g_extern.audio_data.rate_control = false; if (!g_extern.system.audio_callback.callback && g_extern.audio_active && g_settings.audio.rate_control) { if (driver.audio->buffer_size && driver.audio->write_avail) { g_extern.audio_data.driver_buffer_size = driver.audio->buffer_size(driver.audio_data); g_extern.audio_data.rate_control = true; } else RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n"); } rarch_main_command(RARCH_CMD_DSP_FILTER_DEINIT); g_extern.measure_data.buffer_free_samples_count = 0; if (g_extern.audio_active && !g_extern.audio_data.mute && g_extern.system.audio_callback.callback) // Threaded driver is initially stopped. driver.audio->start(driver.audio_data); }