FFMPEG缓存队列
2022-12-18 本文已影响0人
何亮hook_8285
缓存队列
视频缓存队列
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>
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();
}
//heliang
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();
}
//heliang
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;
}