WYY
2025-02-27 aeea0feedc9e25294962be52c5e1dc7e34fdb006
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#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);
    }
}
 
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;
    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;
 
    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()<<"打开解码器失败";
        sws_freeContext(pSwsContext);
        avformat_close_input(&pAVFormatContext);
        return false;
    }
 
    qDebug()<<"初始化视频流成功";
    return true;
}
 
void QFFmpeg::Play()
{
    AVPacket packet;
    int frameFinished;
    int videoStreamIndex = -1;
 
    // 打开视频文件
    if (avformat_open_input(&pAVFormatContext, url.toStdString().c_str(), NULL, NULL) != 0)
        return;
 
    // 获取流信息
    avformat_find_stream_info(pAVFormatContext, NULL);
 
    // 找到视频流索引
    for (uint i = 0; i < pAVFormatContext->nb_streams; i++) {
        if (pAVFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStreamIndex = i;
            break;
        }
    }
 
    // 获取解码器
    AVCodec *codec = avcodec_find_decoder(pAVFormatContext->streams[videoStreamIndex]->codec->codec_id);
    if (!codec) {
        qDebug() << "未找到解码器";
        return;
    }
 
    if (avcodec_open2(pAVCodecContext, codec, NULL) < 0) {
        qDebug() << "打开解码器失败";
        return;
    }
 
    // 初始化帧
    pAVFrame = av_frame_alloc();
    AVFrame *pFrameRGB = av_frame_alloc();
    uint8_t *buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB24, pAVCodecContext->width, pAVCodecContext->height));
    avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pAVCodecContext->width, pAVCodecContext->height);
 
    // 初始化缩放上下文
    struct SwsContext *sws_ctx = sws_getContext(pAVCodecContext->width,
                                                pAVCodecContext->height,
                                                pAVCodecContext->pix_fmt,
                                                pAVCodecContext->width,
                                                pAVCodecContext->height,
                                                AV_PIX_FMT_RGB24,
                                                SWS_BILINEAR,
                                                NULL,
                                                NULL,
                                                NULL);
 
    while (av_read_frame(pAVFormatContext, &packet) >= 0) {
        if (packet.stream_index == videoStreamIndex) {
            avcodec_send_packet(pAVCodecContext, &packet);
 
            while (avcodec_receive_frame(pAVCodecContext, pAVFrame) == 0) {
                sws_scale(sws_ctx,
                        (const uint8_t **)pAVFrame->data,
                        pAVFrame->linesize,
                        0,
                        pAVCodecContext->height,
                        pFrameRGB->data,
                        pFrameRGB->linesize);
 
                QImage img(pFrameRGB->data[0],
                        pAVCodecContext->width,
                        pAVCodecContext->height,
                        QImage::Format_RGB888);
 
                emit GetImage(img, 0);
            }
        }
        av_packet_unref(&packet);
    }
 
    avformat_close_input(&pAVFormatContext);
    av_frame_free(&pAVFrame);
    av_frame_free(&pFrameRGB);
    av_free(buffer);
    sws_freeContext(sws_ctx);
}