FFMPEG缓存队列
at 1年前 ca FFmpeg pv 611 by touch
缓存队列
视频缓存队列
AVFifoBuffer是FFmpeg提供的一个先入先出的缓冲队列。 #include <libavutil/fifo.h> AVFifoBuffer 缓存结构体 av_fifo_alloc 初始化缓存队列 av_fifo_generic_write 写到缓存队列中 av_fifo_size 获取缓存队列大小 av_fifo_generic_read 读取缓存队列中的数据 av_fifo_free 销毁存储队列 av_fifo_space 返回缓存队列剩余空间大小
#include <iostream> #include <string> #include <fstream> #include <thread> #include <functional> using namespace std; extern "C"{ #include <libavformat/avformat.h> #include <libavutil/pixdesc.h> #include <libavutil/opt.h> #include <libavutil/fifo.h> #include <libavutil/imgutils.h> }; AVFifoBuffer *videoFiFoBuf; //宽度 int width=1920; //高度 int height=818; //裸流格式 AVPixelFormat pfmt=AV_PIX_FMT_YUV420P; //一帧的数据 int frameSize=0; //读取 void proccessYuvData(function<void()> completeCallBack) { ifstream ifs("d:\\test.yuv",ios::binary); AVFrame *frame=av_frame_alloc(); frame->width=width; frame->height=height; frame->format=pfmt; //初始化frame中buffer av_frame_get_buffer(frame,0); while (!ifs.eof()) { ifs.read((char*)frame->data[0],frame->linesize[0]*height); ifs.read((char*)frame->data[1],frame->linesize[1]*height/2); ifs.read((char*)frame->data[2],frame->linesize[2]*height/2); //返回AVFifoBuffer中以字节为单位的空间量 if (av_fifo_space(videoFiFoBuf) >= frameSize) { //写到队列中的buffer中 av_fifo_generic_write(videoFiFoBuf,frame->data[0],frame->linesize[0]*height,NULL); av_fifo_generic_write(videoFiFoBuf,frame->data[1],frame->linesize[1]*height/2,NULL); av_fifo_generic_write(videoFiFoBuf,frame->data[2],frame->linesize#include <iostream> #include <string> #include <fstream> #include <thread> #include <functional> extern "C"{ #include <libavformat/avformat.h> #include <libavutil/pixdesc.h> #include <libavutil/opt.h> #include <libavutil/fifo.h> #include <libavutil/imgutils.h> }; AVFifoBuffer *videoFiFoBuf; //宽度 int width=1920; //高度 int height=818; //裸流格式 AVPixelFormat pfmt=AV_PIX_FMT_YUV420P; //一帧的数据 int frameSize=0; //读取 void proccessYuvData(std::function<void()> completeCallBack) { std::ifstream ifs("d:\\test.yuv",std::ios::binary); AVFrame *frame=av_frame_alloc(); frame->width=width; frame->height=height; frame->format=pfmt; //初始化frame中buffer av_frame_get_buffer(frame,0); while (!ifs.eof()) { ifs.read((char*)frame->data[0],frame->linesize[0]*height); ifs.read((char*)frame->data[1],frame->linesize[1]*height/2); ifs.read((char*)frame->data[2],frame->linesize[2]*height/2); //返回AVFifoBuffer中以字节为单位的空间量 if (av_fifo_space(videoFiFoBuf) >= frameSize) { //写到队列中的buffer中 av_fifo_generic_write(videoFiFoBuf,frame->data[0],frame->linesize[0]*height,NULL); av_fifo_generic_write(videoFiFoBuf,frame->data[1],frame->linesize[1]*height/2,NULL); av_fifo_generic_write(videoFiFoBuf,frame->data[2],frame->linesize[2]*height/2,NULL); } } av_frame_free(&frame); completeCallBack(); } int main() { bool mainFlag=true; //在缓存队列中申请60秒的存储空间 frameSize=av_image_get_buffer_size(pfmt, width, height,1); videoFiFoBuf=av_fifo_alloc(60 *frameSize ); std::function<void()> completeCallBack=std::bind([&]()->void{ std::cout << "complete" <<std::endl; mainFlag= false; }); //第一线程用于生产yuv数据 std::thread t1(proccessYuvData,completeCallBack); t1.detach(); //消费缓存队列中的yuv数据 uint8_t *yuvData=new uint8_t[frameSize]; AVFrame *frame=av_frame_alloc(); std::ofstream ofs("d:\\fifo.yuv",std::ios::binary); while(mainFlag) { //返回AVFifoBuffer中数量 int bufSize=av_fifo_size(videoFiFoBuf); //如果缓存队列没有数据则休眠等待 if(bufSize<=0) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); continue; } av_fifo_generic_read(videoFiFoBuf,yuvData,frameSize,NULL); //填充到frame中 av_image_fill_arrays(frame->data,frame->linesize,yuvData,pfmt,width,height,1); ofs.write((char*)frame->data[0],frame->linesize[0]*height); ofs.write((char*)frame->data[1],frame->linesize[1]*height/2); ofs.write((char*)frame->data[2],frame->linesize[2]*height/2); } ofs.close(); av_frame_free(&frame); av_fifo_free(videoFiFoBuf); delete yuvData; return 0; }
音频缓存队列
AVAudioFifo是FFmpeg提供的一个先入先出的音频缓冲队列。主要要以下几个特点: 操作在样本级别而不是字节级别。 支持多通道的格式,不管是planar还是packed类型。 当写入一个已满的buffer时会自动重新分配内存。 #include <libavutil/audio_fifo.h> AVAudioFifo av_audio_fifo_alloc 根据采样格式、通道数和样本个数创建一个AVAudioFifo av_audio_fifo_read 从AVAudioFifo读取数据 av_audio_fifo_size 获取当前AVAudioFifo中可供读取的样本数量 av_audio_fifo_realloc 根据新的样本个数为AVAudioFifo重新分配空间 av_audio_fifo_write 将数据写入AVAudioFifo av_audio_fifo_free 销毁
#include <iostream> #include <string> #include <fstream> #include <thread> #include <functional> extern "C"{ #include <libavformat/avformat.h> #include <libavutil/pixdesc.h> #include <libavutil/opt.h> #include <libavutil/audio_fifo.h> }; AVAudioFifo *audioFifo; int frameSize=0; AVFrame *frame; //处理音频 void proccessAudio(std::function<void()> completeCallBack) { std::ifstream ifs("d:\\test.pcm",std::ios::binary); uint8_t **converted_samples; converted_samples = (uint8_t **)calloc(frame->channels, sizeof(converted_samples)); uint8_t *pcmData=new uint8_t[frameSize]; while(!ifs.eof()) { ifs.read((char*)pcmData,frameSize); converted_samples[0]=pcmData; av_audio_fifo_write(audioFifo, (void **)converted_samples,frame->nb_samples); } completeCallBack(); } int main() { bool mainFlag=true; //裸流格式 AVSampleFormat pfmt=AV_SAMPLE_FMT_S16; //设置音频帧参数 frame=av_frame_alloc(); //每帧单个通道的采样点数 frame->nb_samples=1024; //采样点格式 frame->format=pfmt; frame->sample_rate=48000; //通道布局情况 frame->channel_layout=AV_CH_LAYOUT_STEREO; //通道数 frame->channels=av_get_channel_layout_nb_channels(frame->channel_layout); av_frame_get_buffer(frame,0); //初始化音频队列,初始化30帧队列 audioFifo=av_audio_fifo_alloc(pfmt,frame->channels,30*frame->nb_samples); //获取一帧的大小 frameSize=frame->nb_samples*av_get_bytes_per_sample(pfmt)*frame->channels; std::function<void()> completeCallBack=std::bind([&]()->void{ std::cout << "complete" <<std::endl; mainFlag= false; }); std::thread t1(proccessAudio,completeCallBack); t1.detach(); std::ofstream ofs("d:\\fifo.pcm",std::ios::binary); int re=1; while(re>0 || mainFlag) { int size=av_audio_fifo_size(audioFifo); std::cout << size << std::endl; if(size<=0) { re=0; continue; } re=av_audio_fifo_read(audioFifo, (void **)frame->data,frame->nb_samples); ofs.write((char*)frame->data[0],frame->linesize[0]); } ofs.close(); av_audio_fifo_free(audioFifo); av_frame_free(&frame); return 0; }
FFMPEG API文档
版权声明
本文仅代表作者观点,不代表码农殇立场。
本文系作者授权码农殇发表,未经许可,不得转载。
已有0条评论