FFMPEG缓存队列

at 5个月前  ca FFmpeg  pv 194  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文档

http://ffmpeg.org/doxygen/trunk/group__lavu__video.html

版权声明

本文仅代表作者观点,不代表码农殇立场。
本文系作者授权码农殇发表,未经许可,不得转载。

 

扫一扫在手机阅读、分享本文

已有0条评论