lm
2025-02-21 40b7e441c164ff611fe4f55b60d2157e4f0b948a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "qffmpeg.h"
#include <QDateTime>
#include <QDebug>
 
QFFmpeg::QFFmpeg(QObject *parent) :
    QObject(parent)
{
    videoStreamIndex=-1;
    av_register_all();//注册库中所有可用的文件格式和解码器
    avformat_network_init();//初始化网络流格式,使用RTSP网络流时必须先执行
    pAVFormatContext = avformat_alloc_context();//申请一个AVFormatContext结构的内存,并进行简单初始化
    pAVFrame=av_frame_alloc();
}
 
QFFmpeg::~QFFmpeg()
{
    if (pAVFormatContext) {
        avformat_close_input(&pAVFormatContext);
        avformat_free_context(pAVFormatContext);
    }
    if (pAVFrame) {
        av_frame_free(&pAVFrame);
    }
    if (pSwsContext) {
        sws_freeContext(pSwsContext);
    }
    avpicture_free(&pAVPicture);
}
 
bool QFFmpeg::Init()
{
    //打开视频流
    int result=avformat_open_input(&pAVFormatContext, url.toStdString().c_str(),NULL,NULL);
    if (result<0){
        qDebug()<<"打开视频流失败";
        return false;
    }
 
    //获取视频流信息
    result=avformat_find_stream_info(pAVFormatContext,NULL);
    if (result<0){
        qDebug()<<"获取视频流信息失败";
        avformat_close_input(&pAVFormatContext);
        return false;
    }
 
    //获取视频流索引
    videoStreamIndex = -1;
//    qDebug()<<"nb:"<<pAVFormatContext->nb_streams;
//    qDebug()<<"type:"<<pAVFormatContext->streams[0]->codec->codec_type;
//    qDebug()<<"AVMEDIA_TYPE_VIDEO:"<<AVMEDIA_TYPE_VIDEO;
    for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
        if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }
 
    if (videoStreamIndex==-1){
        qDebug()<<"获取视频流索引失败";
        avformat_close_input(&pAVFormatContext);
        return false;
    }
 
    //获取视频流的分辨率大小
    pAVCodecContext = pAVFormatContext->streams[videoStreamIndex]->codec;
    videoWidth=pAVCodecContext->width;
    videoHeight=pAVCodecContext->height;
 
    avpicture_alloc(&pAVPicture,AV_PIX_FMT_RGB24,videoWidth,videoHeight);
 
    AVCodec *pAVCodec;
 
    //获取视频流解码器
    pAVCodec = avcodec_find_decoder(pAVCodecContext->codec_id);
    pSwsContext = sws_getContext(videoWidth,videoHeight,AV_PIX_FMT_YUV420P,videoWidth,videoHeight,AV_PIX_FMT_RGB24,SWS_BICUBIC,0,0,0);
 
    //打开对应解码器
    result=avcodec_open2(pAVCodecContext,pAVCodec,NULL);
    if (result<0){
        qDebug()<<"打开解码器失败";
        avpicture_free(&pAVPicture);
        sws_freeContext(pSwsContext);
        avformat_close_input(&pAVFormatContext);
        return false;
    }
 
    qDebug()<<"初始化视频流成功";
    return true;
}
 
void QFFmpeg::Play()
{
    //一帧一帧读取视频
    int frameFinished = 0;
    while (av_read_frame(pAVFormatContext, &pAVPacket) >= 0) {
        if (pAVPacket.stream_index == videoStreamIndex) {
            qDebug() << "开始解码" << QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
            avcodec_decode_video2(pAVCodecContext, pAVFrame, &frameFinished, &pAVPacket);
            if (frameFinished) {
                mutex.lock();
                sws_scale(pSwsContext, (const uint8_t* const *)pAVFrame->data, pAVFrame->linesize, 0, videoHeight, pAVPicture.data, pAVPicture.linesize);
                QImage image(pAVPicture.data[0], videoWidth, videoHeight, QImage::Format_RGB888);
                QImage copyImage = image.copy(); // 深拷贝
                emit GetImage(copyImage, this->index);
                qDebug() << "解码成功,发送图像信号";
                mutex.unlock();
            }
        }
        av_packet_unref(&pAVPacket);
    }
    avformat_close_input(&pAVFormatContext);
}