1、从解码数组获取到解码后的数据
static int audio_decode_frame(VideoState *is)
{int data_size, resampled_data_size;av_unused double audio_clock0;int wanted_nb_samples;Frame *af;if (is->paused)return -1;//音频数组队列获取数据do {
#if defined(_WIN32)while (frame_queue_nb_remaining(&is->sampq) == 0) {if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_tgt.bytes_per_sec / 2)return -1;av_usleep (1000);}
#endifif (!(af = frame_queue_peek_readable(&is->sampq)))return -1;frame_queue_next(&is->sampq);} while (af->serial != is->audioq.serial);// 获取音频数据data_size = av_samples_get_buffer_size(NULL, af->frame->ch_layout.nb_channels, af->frame->nb_samples, af->frame->format, 1);// 同步视频的转换wanted_nb_samples = synchronize_audio(is, af->frame->nb_samples);// 格式是否与SDL输出格式一样if (af->frame->format != is->audio_src.fmt ||av_channel_layout_compare(&af->frame->ch_layout, &is->audio_src.ch_layout) ||af->frame->sample_rate != is->audio_src.freq ||(wanted_nb_samples != af->frame->nb_samples && !is->swr_ctx)) {swr_free(&is->swr_ctx);// 重采样上下文swr_alloc_set_opts2(&is->swr_ctx,&is->audio_tgt.ch_layout, is->audio_tgt.fmt, is->audio_tgt.freq,&af->frame->ch_layout, af->frame->format, af->frame->sample_rate,0, NULL);if (!is->swr_ctx || swr_init(is->swr_ctx) < 0) {av_log(NULL, AV_LOG_ERROR,"Cannot create sample rate converter for conversion of %d Hz %s %d channels to %d Hz %s %d channels!\n",af->frame->sample_rate, av_get_sample_fmt_name(af->frame->format), af->frame->ch_layout.nb_channels,is->audio_tgt.freq, av_get_sample_fmt_name(is->audio_tgt.fmt), is->audio_tgt.ch_layout.nb_channels);swr_free(&is->swr_ctx);return -1;}if (av_channel_layout_copy(&is->audio_src.ch_layout, &af->frame->ch_layout) < 0)return -1;is->audio_src.freq = af->frame->sample_rate;is->audio_src.fmt = af->frame->format;}if (is->swr_ctx) {// 格式不同需要转换//分配空间const uint8_t **in = (const uint8_t **)af->frame->extended_data;uint8_t **out = &is->audio_buf1;int out_count = (int64_t)wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate + 256;int out_size = av_samples_get_buffer_size(NULL, is->audio_tgt.ch_layout.nb_channels, out_count, is->audio_tgt.fmt, 0);int len2;if (out_size < 0) {av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size() failed\n");return -1;}if (wanted_nb_samples != af->frame->nb_samples) {if (swr_set_compensation(is->swr_ctx, (wanted_nb_samples - af->frame->nb_samples) * is->audio_tgt.freq / af->frame->sample_rate,wanted_nb_samples * is->audio_tgt.freq / af->frame->sample_rate) < 0) {av_log(NULL, AV_LOG_ERROR, "swr_set_compensation() failed\n");return -1;}}av_fast_malloc(&is->audio_buf1, &is->audio_buf1_size, out_size);if (!is->audio_buf1)return AVERROR(ENOMEM);// 转换len2 = swr_convert(is->swr_ctx, out, out_count, in, af->frame->nb_samples);if (len2 < 0) {av_log(NULL, AV_LOG_ERROR, "swr_convert() failed\n");return -1;}if (len2 == out_count) {av_log(NULL, AV_LOG_WARNING, "audio buffer is probably too small\n");if (swr_init(is->swr_ctx) < 0)swr_free(&is->swr_ctx);}is->audio_buf = is->audio_buf1;resampled_data_size = len2 * is->audio_tgt.ch_layout.nb_channels * av_get_bytes_per_sample(is->audio_tgt.fmt);} else {// 格式相同直接传递is->audio_buf = af->frame->data[0];resampled_data_size = data_size;}audio_clock0 = is->audio_clock;// af->pts不是无效值时,更新VideoState音频的PTS,让video同步用if (!isnan(af->pts))is->audio_clock = af->pts + (double) af->frame->nb_samples / af->frame->sample_rate;elseis->audio_clock = NAN;is->audio_clock_serial = af->serial;
#ifdef DEBUG{static double last_clock;printf("audio: delay=%0.3f clock=%0.3f clock0=%0.3f\n", is->audio_clock - last_clock, is->audio_clock, audio_clock0);last_clock = is->audio_clock;}
#endifreturn resampled_data_size;
}
2、放到sdl缓存播放回调函数
static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
{VideoState *is = opaque;int audio_size, len1;audio_callback_time = av_gettime_relative();// 缓存区需要数据填充while (len > 0) {// audio_buf的播放数据已经消耗完了,需要重新获取数据if (is->audio_buf_index >= is->audio_buf_size) {audio_size = audio_decode_frame(is);if (audio_size < 0) {/* if error, just output silence */is->audio_buf = NULL;is->audio_buf_size = SDL_AUDIO_MIN_BUFFER_SIZE / is->audio_tgt.frame_size * is->audio_tgt.frame_size;} else {if (is->show_mode != SHOW_MODE_VIDEO)update_sample_display(is, (int16_t *)is->audio_buf, audio_size);is->audio_buf_size = audio_size;}is->audio_buf_index = 0;}// 可播放数据长度len1 = is->audio_buf_size - is->audio_buf_index;if (len1 > len)len1 = len;//拷贝数据if (!is->muted && is->audio_buf && is->audio_volume == SDL_MIX_MAXVOLUME) //音量最大时直接拷贝memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);else { //清空streammemset(stream, 0, len1);//不是静音时混音处理if (!is->muted && is->audio_buf)SDL_MixAudioFormat(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, is->audio_volume);}// 移动位置len -= len1;stream += len1;is->audio_buf_index += len1;}// 音频播放数据is->audio_write_buf_size = is->audio_buf_size - is->audio_buf_index;// 当audio时钟无效时,通过计算采样点获取,我们假设 SDL 使用的音频驱动程序有两个周期。if (!isnan(is->audio_clock)) {set_clock_at(&is->audclk, is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / is->audio_tgt.bytes_per_sec, is->audio_clock_serial, audio_callback_time / 1000000.0);sync_clock_to_slave(&is->extclk, &is->audclk);}
}
3、sdl音频播放初始化,在stream_component_open打开音频时打开
static int audio_open(void *opaque, AVChannelLayout *wanted_channel_layout, int wanted_sample_rate, struct AudioParams *audio_hw_params)
{SDL_AudioSpec wanted_spec, spec;const char *env;static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;int wanted_nb_channels = wanted_channel_layout->nb_channels;// 获取SDL通道数env = SDL_getenv("SDL_AUDIO_CHANNELS");if (env) {wanted_nb_channels = atoi(env);av_channel_layout_uninit(wanted_channel_layout);av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);}// 声道布局变声道数if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {av_channel_layout_uninit(wanted_channel_layout);av_channel_layout_default(wanted_channel_layout, wanted_nb_channels);}wanted_nb_channels = wanted_channel_layout->nb_channels;// 初始化SDL播放参数wanted_spec.channels = wanted_nb_channels;wanted_spec.freq = wanted_sample_rate;if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");return -1;}while (next_sample_rate_idx && next_sample_rates[next_sample_rate_idx] >= wanted_spec.freq)next_sample_rate_idx--;wanted_spec.format = AUDIO_S16SYS;wanted_spec.silence = 0;wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC));wanted_spec.callback = sdl_audio_callback;wanted_spec.userdata = opaque;// 打开SDL音频播放器while (!(audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n", wanted_spec.channels, wanted_spec.freq, SDL_GetError());wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];if (!wanted_spec.channels) {wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];wanted_spec.channels = wanted_nb_channels;if (!wanted_spec.freq) {av_log(NULL, AV_LOG_ERROR, "No more combinations to try, audio open failed\n");return -1;}}av_channel_layout_default(wanted_channel_layout, wanted_spec.channels);}// 检测打开的格式是否正确if (spec.format != AUDIO_S16SYS) {av_log(NULL, AV_LOG_ERROR, "SDL advised audio format %d is not supported!\n", spec.format);return -1;}// 检测打开的通道数是否正确if (spec.channels != wanted_spec.channels) {av_channel_layout_uninit(wanted_channel_layout);av_channel_layout_default(wanted_channel_layout, spec.channels);if (wanted_channel_layout->order != AV_CHANNEL_ORDER_NATIVE) {av_log(NULL, AV_LOG_ERROR, "SDL advised channel count %d is not supported!\n", spec.channels);return -1;}}// 返回播放的音频参数,播放时是否需要转换audio_hw_params->fmt = AV_SAMPLE_FMT_S16;audio_hw_params->freq = spec.freq;if (av_channel_layout_copy(&audio_hw_params->ch_layout, wanted_channel_layout) < 0)return -1;audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, 1, audio_hw_params->fmt, 1);audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, audio_hw_params->ch_layout.nb_channels, audio_hw_params->freq, audio_hw_params->fmt, 1);if (audio_hw_params->bytes_per_sec <= 0 || audio_hw_params->frame_size <= 0) {av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");return -1;}return spec.size;
}