ffmpeg 压缩摄像头采集的图片为*.H264文件

主要用opencv打开摄像头,采集到数据后,传输给ffmpeg ,压缩为h264数据,h264的文件可以直接拖到vcl播放器播放

MyEncoder.h

#pragma once
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include<libavfilter/avfilter.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}

class MyEncoder
{
public:
    MyEncoder();
public:
    AVFrame *m_pRGBFrame;   //帧对象  
    AVFrame *m_pYUVFrame;   //帧对象  
    AVCodec *pCodecH264;    //编码器  
    AVCodecContext *c;      //编码器数据结构对象  
    uint8_t *yuv_buff;      //yuv图像数据区  
    uint8_t *rgb_buff;      //rgb图像数据区  
    SwsContext *scxt;       //图像格式转换对象  
    uint8_t *outbuf;        //编码出来视频数据缓存  
    int outbuf_size;        //编码输出数据去大小  
    int nDataLen;           //rgb图像数据区长度  
    int width;              //输出视频宽度  
    int height;             //输出视频高度  
    AVPacket pkt;            //数据包结构体
public:
    void Ffmpeg_Encoder_Init();//初始化  
    void Ffmpeg_Encoder_Setpara(AVCodecID mycodeid, int vwidth, int vheight);//设置参数,第一个参数为编码器,第二个参数为压缩出来的视频的宽度,第三个视频则为其高度  
    void Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data);//编码并写入数据到文件  
    void Ffmpeg_Encoder_Close();//关闭 
};

MyEncoder.cpp

#include "MyEncoder.h"

MyEncoder::MyEncoder()
{
}

void MyEncoder::Ffmpeg_Encoder_Init()
{
    av_register_all();
    avcodec_register_all();

    m_pRGBFrame = new AVFrame[1];//RGB帧数据赋值    
    m_pYUVFrame = new AVFrame[1];//YUV帧数据赋值    

    c = NULL;//解码器指针对象赋初值  
}

void MyEncoder::Ffmpeg_Encoder_Setpara(AVCodecID mycodeid, int vwidth, int vheight)
{
    pCodecH264 = avcodec_find_encoder(mycodeid);//查找h264编码器  
    if (!pCodecH264)
    {
        fprintf(stderr, "h264 codec not found\n");
        exit(1);
    }
    width = vwidth;
    height = vheight;

    c = avcodec_alloc_context3(pCodecH264);//函数用于分配一个AVCodecContext并设置默认值,如果失败返回NULL,并可用av_free()进行释放  
    c->bit_rate = 400000; //设置采样参数,即比特率  
    c->width = vwidth;//设置编码视频宽度   
    c->height = vheight; //设置编码视频高度  
    c->time_base.den = 2;//设置帧率,num为分子和den为分母,如果是1/25则表示25帧/s  
    c->time_base.num = 1;
    c->gop_size = 10; //设置GOP大小,该值表示每10帧会插入一个I帧  
    c->max_b_frames = 1;//设置B帧最大数,该值表示在两个非B帧之间,所允许插入的B帧的最大帧数  
    c->pix_fmt = AV_PIX_FMT_YUV420P;//设置像素格式  

    av_opt_set(c->priv_data, "tune", "zerolatency", 0);//设置编码器的延时,解决前面的几十帧不出数据的情况  

    if (avcodec_open2(c, pCodecH264, NULL) < 0)return;//打开编码器  

    nDataLen = vwidth*vheight * 3;//计算图像rgb数据区长度  

    yuv_buff = new uint8_t[nDataLen / 2];//初始化数据区,为yuv图像帧准备填充缓存  
    rgb_buff = new uint8_t[nDataLen];//初始化数据区,为rgb图像帧准备填充缓存  
    outbuf_size = 100000;////初始化编码输出数据区  
    outbuf = new uint8_t[outbuf_size];

    scxt = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR24, c->width, c->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);//初始化格式转换函数  
}

void MyEncoder::Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data)
{
    av_init_packet(&pkt);
    memcpy(rgb_buff, data, nDataLen);//拷贝图像数据到rgb图像帧缓存中准备处理  
    avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, AV_PIX_FMT_RGB24, width, height);//将rgb_buff填充到m_pRGBFrame  
    //av_image_fill_arrays((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, AV_PIX_FMT_RGB24, width, height);
    avpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, AV_PIX_FMT_YUV420P, width, height);//将yuv_buff填充到m_pYUVFrame  
    sws_scale(scxt, m_pRGBFrame->data, m_pRGBFrame->linesize, 0, c->height, m_pYUVFrame->data, m_pYUVFrame->linesize);// 将RGB转化为YUV  
    int myoutputlen = 0;
    int returnvalue = avcodec_encode_video2(c, &pkt, m_pYUVFrame, &myoutputlen);
    if (returnvalue == 0)
    {
        fwrite(pkt.data, 1, pkt.size, file);
    }
    av_free_packet(&pkt);
}

void MyEncoder::Ffmpeg_Encoder_Close()
{
    delete[]m_pRGBFrame;
    delete[]m_pYUVFrame;
    delete[]rgb_buff;
    delete[]yuv_buff;
    delete[]outbuf;
    sws_freeContext(scxt);
    avcodec_close(c);//关闭编码器  
    av_free(c);
}

main.cpp

#include "opencv2/opencv.hpp"
#include "MyEncoder.h"
using namespace cv;

int main()
{
    cv::VideoCapture capture(0); // 打开摄像头
    cv::Mat imageTemp;
    capture >> imageTemp;

    MyEncoder myencoder;
    myencoder.Ffmpeg_Encoder_Init();//初始化编码器  
    myencoder.Ffmpeg_Encoder_Setpara(AV_CODEC_ID_H264, imageTemp.cols, imageTemp.rows);//设置编码器参数  
                                                             //图象编码  
    FILE *f = NULL;
    char * filename = "myData.h264";
    fopen_s(&f, filename, "wb");//打开文件存储编码完成数据  

    for (int i = 0; i < 500; i ++)
    {
        capture >> imageTemp;
        myencoder.Ffmpeg_Encoder_Encode(f, (uchar*)imageTemp.data);//编码  
        imshow("send", imageTemp);
        cv::waitKey(30);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/baidu_31872269/article/details/78312751