// // Created by ps on 19-1-11. // // // #TODO // 可以把ffmpeg的操作抽成一个对象 // #ifndef GB28181SDK_FFMPEGDECODERJPG_H #define GB28181SDK_FFMPEGDECODERJPG_H #include #include #include #include #include "opencv2/core.hpp" #include "opencv2/highgui.hpp" #include #include "GlobalSignalWaitLock.hpp" #include "basic_struct_for_video_image.h" extern "C" { #include #include #include #include #include #include #include #include #include #include #include } #include 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 > 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 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, unsigned long int frame_index = 0); 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; bool m_SnapshotNotSaveRet{true}; std::string m_camIdx; MyQueue m_rtpQueue; cv::Mat m_image; std::atomic 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