美文网首页
FFMPEG缓存队列

FFMPEG缓存队列

作者: 何亮hook_8285 | 来源:发表于2022-12-18 01:31 被阅读0次

缓存队列

视频缓存队列

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;
}

FFMPEG API文档

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

相关文章

  • 音视频开发视频和视频帧:ffmpeg的RTMP推流

    推荐视频:RTSP/RTMP推流分析 推流架构分析/推流缓存队列的设计 /FFmpeg函数阻塞问题分析https:...

  • C++队列缓存的实现

    C++队列缓存的实现 为什么使用队列缓存 c++的队列缓存主要用于解决大数据量并发时的数据存储问题,可以将并发时的...

  • 直播(一)(视音频流缓存)

    @TOC 缓存队列实现 源码下载 视频音频缓存队列实现源码demo 1.原理 初始化固定数量的结点装入空闲队列,当...

  • 线程池

    线程池操作过程 线程池会一直存在核心线程,从缓存队列中拿Runnable任务执行。如果加入缓存队列的任务大于缓存队...

  • 消息队列的使用场景

    消息队列,本质上是一种分布式的阻塞队列。消息队列,也可以理解成一种缓存,对任务的缓存,所以,redis也可以作为一...

  • Vue2的一些原理

    keep-alive keep-alive - 多看源码,方知原理,才能优化 作用:缓存 怎么缓存:用队列缓存到内...

  • kxmovie源码分析

    KxMovieDecoder FFmpeg 编解码 解码后的数据放入一个队列里面 然后KxMovieGLView ...

  • 线程池--完整使用示例

    执行结果: 从执行结果可以看出,当线程池中线程的数目大于5时,便将任务放入任务缓存队列里面,当任务缓存队列满了之后...

  • Volley源码分析笔记

    Volley的介绍 线程管理 缓存管理 发送网络请求过程在主线程把请求加入请求队列缓存线程查询请求是否有缓存,如果...

  • Executors线程池

    newCacheThreadPool(缓存线程池):阻塞队列为SynchronousQueue,核心线程数0,最大...

网友评论

      本文标题:FFMPEG缓存队列

      本文链接:https://www.haomeiwen.com/subject/ldosqdtx.html