2021-08-22

ffmpeg+qt尝试1

#include <iostream>
#include <opencv2/highgui.hpp>
#include <QException>

extern "C"
{
#include "libavformat/avformat.h"
#include "libavutil/time.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
}


#pragma comment(lib,"opencv_world320.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"swscale.lib")

using namespace std;
using namespace cv;

/*
*1,opencv获取视频,open分为两部,grab()解码,然后retrieve()把yuv转换为rgb
*2,将得到的BRG24转换为yuv;
*3,H264编码,
*4,封装推流
*/


int main()
{

    char* inurl="C:/Users/hhhheyijia/Desktop/a.mp4";//可以换成rtsp流地址
    char* outurl="rtmp://139.224.104.177/live";

    avcodec_register_all();
    avformat_network_init();

    VideoCapture cam;
    Mat frame;
    //namedWindow("test");

    //创建转换上下文
    SwsContext* sws=NULL;
    //frame
    AVFrame *yuv=NULL;
    //编码器上下文
    AVCodecContext* vc=NULL;
    //输出上下文
    AVFormatContext* oct=NULL;


    try
    {
        cam.open(inurl);

        //输入宽高
        int inWidth=cam.get(CAP_PROP_FRAME_WIDTH);
        int inHeight=cam.get(CAP_PROP_FRAME_HEIGHT);
        int fps=cam.get(CAP_PROP_FPS);
        //转换上下文
        sws=sws_getCachedContext(sws,
                                 inWidth,inHeight,AV_PIX_FMT_BGR24,
                                 inWidth,inHeight,AV_PIX_FMT_YUV420P,
                                 SWS_BICUBIC,
                                 0,0,0);


        //输出yuv
        yuv=av_frame_alloc();
        yuv->width=inWidth;
        yuv->height=inHeight;
        yuv->format=AV_PIX_FMT_YUV420P;
        yuv->pts=0;

        int ret=av_frame_get_buffer(yuv,32);
        if(ret<0)
        {
            char buf[1024]={0};
            av_strerror(ret,buf,sizeof(buf)-1);
        }

        //查找编码器
        AVCodec* codec=avcodec_find_encoder(AV_CODEC_ID_H264);
        //创建上下文
        vc=avcodec_alloc_context3(codec);
        //配置编码器
        vc->flags|=AV_CODEC_FLAG_GLOBAL_HEADER; //全局参数
        vc->codec_id=codec->id; //编码ID
        vc->thread_count=4;  //编码线程数

        vc->pix_fmt=AV_PIX_FMT_YUV420P;  //编码格式
        vc->bit_rate=100*1024*8;  //50KB
        vc->time_base={1,fps};
        vc->framerate={fps,1};
        vc->width=inWidth;
        vc->height=inHeight;

        vc->gop_size=50;
        vc->max_b_frames=10;
        //打开编码器
        ret=avcodec_open2(vc,codec,NULL);
        if(ret<0)
        {
            char buf[1024]={0};
            av_strerror(ret,buf,sizeof(buf)-1);
        }
        //创建输出上下文
        ret=avformat_alloc_output_context2(&oct,0,"flv",outurl);
        if(!oct)
        {
            char buf[1024]={0};
            av_strerror(ret,buf,sizeof(buf)-1);
        }
        //创建输出视频流
        AVStream* vs=avformat_new_stream(oct,NULL);
        vs->codec->codec_tag=0;
        //复制编码信息
        avcodec_parameters_from_context(vs->codecpar,vc);
        av_dump_format(oct,0,outurl,1);

        //打开IO
        ret=avio_open(&oct->pb,outurl,AVIO_FLAG_READ_WRITE);
        if(ret!=0)
        {
            char buf[1024]={0};
            av_strerror(ret,buf,sizeof(buf)-1);
        }
        //写入头文件
        ret=avformat_write_header(oct,NULL);
        if(ret<0)
        {
            char buf[1024]={0};
            av_strerror(ret,buf,sizeof(buf)-1);
        }


        AVPacket pack;
        memset(&pack,0,sizeof(pack));
        int vpts=0;
        for(;;)
        {
            ///读取rtsp视频帧,解码视频帧
            if(!cam.grab())
            {
                continue;
            }
            ///yuv转换为rgb
            if(!cam.retrieve(frame))
            {
                continue;
            }

            //imshow("video",frame);
            //waitKey(1);

            //输入数据
            uint8_t* indata[AV_NUM_DATA_POINTERS]={0};
            indata[0]=frame.data;
            int linesize[AV_NUM_DATA_POINTERS]={0};
            linesize[0]=frame.elemSize()*frame.cols;

            //转换yuv
            int h=sws_scale(sws,indata,linesize,0,inHeight,
                      yuv->data,yuv->linesize);
            //cout<<h<<" "<<flush;

            //编码一帧
            yuv->pts=vpts;
            vpts++;
            ret=avcodec_send_frame(vc,yuv);
            if(ret!=0)
                continue;

            ret=avcodec_receive_packet(vc,&pack);
            if(ret!=0)
                continue;

            //推流
            pack.pts=av_rescale_q(pack.pts,vc->time_base,vs->time_base);
            pack.dts=av_rescale_q(pack.dts,vc->time_base,vs->time_base);
            pack.duration=av_rescale_q(pack.duration,vc->time_base,vs->time_base);
            ret=av_interleaved_write_frame(oct,&pack);
            if(ret==0)
            {
                cout<<"#"<<flush;
            }


        }
    }
    catch(exception& ex)
    {
        if(cam.isOpened())
            cam.release();

        if(sws)
        {
            sws_freeContext(sws);
            sws=NULL;
        }

        if(vc)
        {
            avcodec_close(vc);
            avcodec_free_context(&vc);
        }


        cerr<<ex.what()<<endl;
    }

    getchar();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值