派生自 development/c++

pansen
2019-03-09 d6496edbb01f7b24c01615b111595a08d0fb8487
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//
// Created by ps on 19-1-11.
//
 
//
// #TODO
// 可以把ffmpeg的操作抽成一个对象
//
 
#ifndef GB28181SDK_FFMPEGDECODERJPG_H
#define GB28181SDK_FFMPEGDECODERJPG_H
 
#include <iostream>
#include <unistd.h>
#include <MyQueue.h>
#include <atomic>
 
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include <list>
#include "GlobalSignalWaitLock.hpp"
#include "basic_struct_for_video_image.h"
 
extern "C"
{
#include <libavutil/frame.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavfilter/avfiltergraph.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
 
#include <mutex>
 
namespace BASICGB28181 {
 
#define TryCath(CODE)     try { \
CODE } catch (std::exception ex) { \
ERR(ex.what()); \
return false; \
}
 
    static void initFFmpeg();
 
    static cv::Mat avframe_to_cvmat(AVFrame *frame);
 
    typedef struct _buffInfo {
        uint8_t *buff;
        int buffLen;
        std::string camIdx;
    } frameBuffInfo;
 
    struct FrameIdPackage_s_t {
        int64_t m_frameId;
        AVPacket m_packet;
    };
 
    struct FrameRange_s_t {
        int64_t m_startFrameId;
        int64_t m_endFrameId;
        std::string m_videoName;
 
        FrameRange_s_t() {
            m_startFrameId = 0;
            m_endFrameId = 0;
            m_videoName.clear();
        }
 
        bool IsFrameIdInRange(int64_t frameId) {
            return m_startFrameId <= frameId && frameId <= m_endFrameId;
        }
    };
 
    enum RecordState_e_t {
        START_RECORD,
        RECORDING_VIDEO,
        STOP_RECORD,
    };
//    std::map<std::string, MyQueue<frameBuffInfo *> > MapMyQueue;
 
    static std::mutex g_mutex;
 
    class FFmpegDecoderJPG {
    public:
        FFmpegDecoderJPG();
 
        virtual ~FFmpegDecoderJPG();
 
        /***
         * 放入I帧或者P帧
         * #TODO如果第一帧不是I帧会不会有异常?
         * @param data 帧数据地址
         * @param datalen 数据长度
         * @param camIdx 摄像机id
         * @return
         */
        bool pushInfo(unsigned char *data, int datalen, const std::string &camIdx);
 
        /***
         * 开启解帧线程
         * @param camIdx 摄像机id
         * @param gpuIdx gpuId
         * @return
         */
        bool startThd(const std::string &camIdx, const int &fps, const int &gpuIdx = -1);
 
        /***
         * 停止解帧线程
         * @return
         */
        bool stopThd();
 
        //****************************
        std::string GetImageName();
 
        //保存imageName所在的视频到strPath的路径下
        bool SaveVideoByImageName(const std::string &strPath, const std::string &imageName);
 
 
        //设置录像保存的最短长度和最长长度
        bool SetMinMaxVideoSeconds(const int minSeconds, const int maxSecond);
 
 
    private:
        //检查保存,每次保存一帧到数组的时候调用
        bool CheckSave();
 
        //Function
        bool HandleSave();
 
        //录像的时候,在视频保存完以后,调用这个函数清空缓存
        bool CleanToFrameId(int64_t lastFrameId);
 
        //不录像的时候,如果保存了足够多的帧,调用此函数清除最前面的两个I帧之间的数据
        bool CleanOneKeyFrameOneRange();
 
    private:
        //记录最后一个I帧的位置
        int64_t m_last_I_FrameId = -1;
        //保存视频的路径
        std::string m_videoPath;
        //录像的两种状态,
        RecordState_e_t m_recordState = STOP_RECORD;
 
        //开始录像的帧ID
        int64_t m_startFrameId = 0;
 
        //最后一个需要录像的帧ID
        int64_t m_endFrameId = 0;
 
        //Variable
        // 录像视频的最短长度(帧数)
        int m_minVideoFrameCount = 10 * 25; // 10 seconds
 
        // 录像视频的最长长度(帧数)
        int m_maxVideoFrameCount = 20 * 25; // 20 seconds;
 
        int m_maxVectorFrameCount = m_maxVideoFrameCount * 2;
 
        //对收到的帧进行计数
        int64_t m_frameIndex = 0;
 
//*******************************************
        AVFormatContext *ic;
        unsigned char *iobuffer;
        AVIOContext *avio;
        AVStream *stream;
        AVCodecContext *ctx;
        AVCodec *codec;
        AVCodec *codec_cuvid;
        AVPacket pkt;
        AVFrame *frame;
 
        //*******************************************
        //将帧保存到帧数组
        void SaveToPacketVector(AVPacket &packet);
 
        //保存lastFrameId之前的视频保存到path表示的文件中
        bool SaveVideo(std::string path, int64_t lastFrameId);
 
 
    public:
        //第一帧必须是I帧
        std::vector<FrameIdPackage_s_t> m_packetsVec;
        //******************
 
        int64_t frame_number, first_frame_number;
 
        //打开文件写入文件头
        int startWrite(const char *filename);
 
        //关闭用startWrite打开的文件
        int stopWrite();
 
        //对packet做转换
        void conversion(void *packet, const long int &firstKeyPts, const long int &firstKeyDts, void *inVideoStream);
 
        bool m_bstartWrite = {false};
        bool m_bFirstKeyFrame = {false};
        long int m_nFirstKeyPts = 0;
        long int m_nFirstKeyDts = 0;
        AVFormatContext *m_pOutFmtCtx = {nullptr};
        AVStream *video_st{0};
        AVStream *m_pOutVideo_stream{nullptr};
 
        //****************************
    public:
        /***
         * 获取线程状态
         * @return
         */
        bool getRunning();
 
        cv::Mat getImage();
 
//        #todo send Image func ? thd?
 
    private:
        int m_buf_size; //32768;
        int m_gpuIdx;
        int m_fps;
        bool m_PackageState;
        std::string m_camIdx;
 
        MyQueue<frameBuffInfo *> m_rtpQueue;
 
        cv::Mat m_image;
 
        std::atomic<bool> m_running;
        bool m_readData;
    private:
 
        /***
         * ffmpeg读取内存数据回调函数
         * @param opaque
         * @param buf
         * @param bufsize
         * @return
         */
        static int read_data(void *opaque, uint8_t *buf, int bufsize);
 
        /***
         * 裸流解码函数
         * @param p_this 类指针
         */
        static void BareFlowDecoderThd(FFmpegDecoderJPG *p_this);
 
    };
}
 
 
#endif //GB28181SDK_FFMPEGDECODERJPG_H