//
|
// 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, 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;
|
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
|