国外最好的免费建站,免费图文模板,图书馆网站制作,推广方法和技巧1.简介
这里引入FFmpeg库#xff0c;获取音频流数据#xff0c;然后通过FFmpeg将视频流解码成pcm原始数据#xff0c;再将pcm数据送入到SDL库中实现音频播放。
2.FFmpeg的操作流程
注册API#xff1a;av_register_all()构建输入AVFormatContext上下文#xff1a;avform…1.简介
这里引入FFmpeg库获取音频流数据然后通过FFmpeg将视频流解码成pcm原始数据再将pcm数据送入到SDL库中实现音频播放。
2.FFmpeg的操作流程
注册APIav_register_all()构建输入AVFormatContext上下文avformat_open_input()查找音视频流信息avformat_find_stream_info()查找解码器avcodec_find_decoder()打开解码器avcodec_open2()然后通过while循环不停的读取数据av_read_frame()帧解码avcodec_send_packet()和avcodec_receive_frame()重采样swr_convert() 3.SDL音频播放流程
SDL播放音频的流程如下
初始化音频子系统SDL_Init()。设置音频参数SDL_AudioSpec。设置回调函数SDL_AudioCallback。打开音频设备SDL_OpenAudio()。打开pcm文件读取数据。开始播放SDL_PauseAudio()。
4.示例
#include stdio.h
#include SDL.h
#include memoryextern C
{
#include libavcodec/avcodec.h
#include libavformat/avformat.h
#include libswscale/swscale.h
#include libavutil/imgutils.h
#include libswresample/swresample.h
};static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;void fill_audio(void *udata, Uint8 *stream, int len)
{//SDL 2.0SDL_memset(stream, 0, len);if (audio_len 0) /* Only play if we have data left */return;len (len audio_len ? audio_len : len); /* Mix as much data as possible */SDL_MixAudio(stream, audio_pos, len, SDL_MIX_MAXVOLUME/2);audio_pos len;audio_len - len;
}AVFrame *recv(AVCodecContext *codecCtx)
{if (!codecCtx){return NULL;}AVFrame *frame av_frame_alloc();int ret avcodec_receive_frame(codecCtx, frame);if (ret AVERROR(EAGAIN) || ret AVERROR_EOF){av_frame_free(frame);return NULL;}else if (ret 0){av_frame_free(frame);return NULL;}return frame;
}#undef main
int main(int argc, char* argv[])
{av_register_all();///ffmpegavformat_network_init();AVFormatContext* pFormatCtx NULL;const char* inputUrl ./2.mp4;///打开输入的流int ret avformat_open_input(pFormatCtx, inputUrl, NULL, NULL);if (ret ! 0){printf(Couldnt open input stream.\n);return -1;}//查找流信息if (avformat_find_stream_info(pFormatCtx, NULL) 0){printf(Couldnt find stream information.\n);return -1;}//找到音频流索引int audio_index av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);AVStream* st pFormatCtx-streams[audio_index];AVCodec* codec nullptr;//找到解码器codec avcodec_find_decoder(st-codecpar-codec_id);if (!codec){fprintf(stderr, Codec not found\n);return -1;}//申请AVCodecContextAVCodecContext* pCodecCtx avcodec_alloc_context3(codec);if (!pCodecCtx){return -1;}avcodec_parameters_to_context(pCodecCtx, pFormatCtx-streams[audio_index]-codecpar);//打开解码器if ((ret avcodec_open2(pCodecCtx, codec, NULL) 0)){return -1;}AVPacket* pkt av_packet_alloc();//------------SDL----------------//Output Info-----------------------------printf(---------------- File Information ---------------\n);av_dump_format(pFormatCtx, 0, inputUrl, 0);printf(-------------------------------------------------\n);SwrContext *swrContext swr_alloc();if (!swrContext){return -1;}swrContext swr_alloc_set_opts(NULL, //ctxAV_CH_LAYOUT_STEREO, //输出channel布局AV_SAMPLE_FMT_S16, //输出的采样格式44100, //采样率av_get_default_channel_layout(pCodecCtx-channels), //输入channel布局pCodecCtx-sample_fmt, //输入的采样格式pCodecCtx-sample_rate, //输入的采样率0, NULL);// 初始化重采样上下文if (swr_init(swrContext) 0){swr_free(swrContext);return -1;}if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)){printf(Could not initialize SDL - %s\n, SDL_GetError());return -1;}//SDL_AudioSpecSDL_AudioSpec wanted_spec;wanted_spec.freq 44100;wanted_spec.format AUDIO_S16SYS;wanted_spec.channels 2;wanted_spec.silence 0;wanted_spec.samples 1024;wanted_spec.callback fill_audio;wanted_spec.userdata pCodecCtx;if (SDL_OpenAudio(wanted_spec, NULL) 0){printf(cant open audio.\n);return -1;}//PlaySDL_PauseAudio(0);// 分配输出音频数据uint8_t *out_buffer nullptr;while (av_read_frame(pFormatCtx, pkt) 0){if (pkt-stream_index audio_index){//一次send 多次recvint ret avcodec_send_packet(pCodecCtx, pkt);if (ret 0)continue;//释放资源av_packet_unref(pkt);while (1){AVFrame *frame recv(pCodecCtx);if (!frame)break;//输入的样本数int in_nb_samples frame-nb_samples;//1024int out_linesize;int dst_nb_samples av_rescale_rnd(in_nb_samples, 44100, frame-sample_rate, AV_ROUND_UP);//输出的样本数int out_buffer_size av_samples_get_buffer_size(NULL, 2, dst_nb_samples, AV_SAMPLE_FMT_S16, 0);if(!out_buffer)out_buffer (uint8_t *)av_malloc(out_buffer_size);//返回每个通道输出的样本数错误时为负值int sampleCount swr_convert(swrContext, out_buffer, dst_nb_samples,(const uint8_t**)frame-data, in_nb_samples);if (sampleCount 0){av_frame_free(frame);break;}int outSize sampleCount * 2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);while (audio_len 0)//Wait until finishSDL_Delay(1);//Set audio buffer (PCM data)audio_chunk (Uint8 *)out_buffer;//Audio buffer lengthaudio_len outSize;audio_pos audio_chunk;av_frame_free(frame);}}else{//释放资源av_packet_unref(pkt);}}//--------------av_free(out_buffer);av_packet_free(pkt);swr_close(swrContext);swr_free(swrContext);avcodec_close(pCodecCtx);avcodec_free_context(pCodecCtx);avformat_close_input(pFormatCtx);SDL_CloseAudio();SDL_Quit();
}5.相关推荐
[总结]FFMPEG视音频编解码零基础学习方法_零基础ffmpeg 雷霄骅-CSDN博客
FFmpeg 音频解码秒懂-CSDN博客
SDL2 播放音频数据(PCM)-CSDN博客
SDL2 消息循环和事件响应-CSDN博客
SDL2 播放视频文件(MP4)-CSDN博客