seo網(wǎng)站關(guān)鍵詞優(yōu)化軟件邁步者seo
1.簡(jiǎn)介
這里引入FFmpeg庫(kù),獲取音頻流數(shù)據(jù),然后通過(guò)FFmpeg將視頻流解碼成pcm原始數(shù)據(jù),再將pcm數(shù)據(jù)送入到SDL庫(kù)中實(shí)現(xiàn)音頻播放。
2.FFmpeg的操作流程
- 注冊(cè)API:av_register_all()
- 構(gòu)建輸入AVFormatContext上下文:avformat_open_input()
- 查找音視頻流信息:avformat_find_stream_info()
- 查找解碼器:avcodec_find_decoder()
- 打開(kāi)解碼器:avcodec_open2()
- 然后通過(guò)while循環(huán),不停的讀取數(shù)據(jù):av_read_frame()
- 幀解碼:avcodec_send_packet()和avcodec_receive_frame()
- 重采樣:swr_convert()
3.SDL音頻播放流程
SDL播放音頻的流程如下:
- 初始化音頻子系統(tǒng):SDL_Init()。
- 設(shè)置音頻參數(shù):SDL_AudioSpec。
- 設(shè)置回調(diào)函數(shù):SDL_AudioCallback。
- 打開(kāi)音頻設(shè)備:SDL_OpenAudio()。
- 打開(kāi)pcm文件,讀取數(shù)據(jù)。
- 開(kāi)始播放:SDL_PauseAudio()。
4.示例
#include <stdio.h>
#include <SDL.h>
#include <memory>extern "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";///打開(kāi)輸入的流int ret = avformat_open_input(&pFormatCtx, inputUrl, NULL, NULL);if (ret != 0){printf("Couldn't open input stream.\n");return -1;}//查找流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0){printf("Couldn't 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;}//申請(qǐng)AVCodecContextAVCodecContext* pCodecCtx = avcodec_alloc_context3(codec);if (!pCodecCtx){return -1;}avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[audio_index]->codecpar);//打開(kāi)解碼器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("can't open audio.\n");return -1;}//PlaySDL_PauseAudio(0);// 分配輸出音頻數(shù)據(jù)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;//輸入的樣本數(shù)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);//輸出的樣本數(shù)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);//返回每個(gè)通道輸出的樣本數(shù),錯(cuò)誤時(shí)為負(fù)值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.相關(guān)推薦
[總結(jié)]FFMPEG視音頻編解碼零基礎(chǔ)學(xué)習(xí)方法_零基礎(chǔ)ffmpeg 雷霄驊-CSDN博客?
FFmpeg 音頻解碼(秒懂)-CSDN博客
SDL2 播放音頻數(shù)據(jù)(PCM)-CSDN博客
SDL2 消息循環(huán)和事件響應(yīng)-CSDN博客?
SDL2 播放視頻文件(MP4)-CSDN博客?