视频安防平台-MP4文件存储和读取的封装

视频安防平台-MP4文件存储和读取的封装

一般客户端存储录像文件会采用mp4的格式进行封装,下面针对mp4文件封装了一层,支持语音流的写入、语音流的读出、支持视频流的写入、支持视频流的读出,支持按帧读、按时间读取、支持倒放、随机读取等各种历史视频控制功能,支持文件加密等功能。
下面粘贴一下mp4文件的封装头文件:
#ifndef __LIBMP4_H_
#define __LIBMP4_H_

#ifndef _MP4V2_H_
#define _MP4V2_H_
#include "mp4v2/mp4v2.h"
#include <vector>
#endif
using namespace std;

typedef struct sps_pps_header
{
	unsigned char start_code_prefix[5];
}sps_pps_header_t;

#define MP4ENCODER_ERROR(err) ((MP4EncoderResult)(-(err)))
#define DEFAULT_RECORD_TIME 0U
#define MAX_FRAME_LEN		2*1024*1024UL
#define MAX_AUDIO_SIZE		100*1024UL

//#define AUDIO_STEP_SIZE		160
#define AUDIO_STEP_SIZE			160 * 2	//双声道数据加倍

#define H264_VIDEO_TYPE		"H264"
#define MPEG4_VIDEO_TYPE	"MPEG4"
#define MPEG2_VIDEO_TYPE	"MPEG2"
#define PRIVATE_VIDEO_TYPE	"PRIVATE"
#define ALAW_AUDIO_TYPE		"ALAW"

typedef enum
{
	MP4ENCODER_ENONE = 0,
	MP4ENCODER_E_CREATE_FAIL,
	MP4ENCODER_E_ADD_VIDEO_TRACK,
	MP4ENCODER_E_ADD_AUDIO_TRACK,
	MP4ENCODER_WARN_RECORD_OVER,
	MP4ENCODER_E_WRITE_VIDEO_DATA,
	MP4ENCODER_E_WRITE_AUDIO_DATA,
	MP4ENCODER_E_ALLOC_MEMORY_FAILED,
	MP4ENCODER_E_UNKONOWN
}MP4EncoderResult;

enum StreamTypes
{
	E_STREAM_UNKNOWN = -1,
	E_STREAM_PRAVITE,
	E_STREAM_H264,
	E_STREAM_MPEG4,
	E_STREAM_MPEG2,
	E_STREAM_ALAW
};

class MP4Encoder
{
public:
	MP4Encoder(void);
	~MP4Encoder(void);
	MP4EncoderResult MP4CreateFile(const char *sFileName,unsigned uRecordTime = DEFAULT_RECORD_TIME,bool bEnc = false);
	MP4EncoderResult MP4AddH264Track(const uint8_t *sData, int nSize,int nWidth, int nHeight, int nFrameRate = 25);
	MP4EncoderResult MP4AddAACTrack(const uint8_t *sData, int nSize);
	MP4EncoderResult MP4AddALAWTrack(const uint8_t *sData, int nSize);
	MP4EncoderResult MP4AddMPEGTrack(int nWidth, int nHeight, int nFrameRate = 25,uint8_t nVdeoType = MP4_MPEG4_VIDEO_TYPE);
	MP4EncoderResult MP4WriteH264Data(uint8_t *sData, int nSize, uint64_t u64PTS);
	MP4EncoderResult MP4WriteAACData(const uint8_t *sData, int nSize,uint64_t u64PTS);
	MP4EncoderResult MP4WriteALAWData(uint8_t *sData, int nSize,uint64_t u64PTS);
	MP4EncoderResult MP4WriteMPEGData(uint8_t *sData, int nSize, uint64_t u64PTS);
    MP4EncoderResult MP4ModifyFile(const char *sFileName);
    MP4EncoderResult MP4OptimizeFile(const char *sFileName);
	void MP4ReleaseFile();
private:
	unsigned m_uSecond;
	MP4FileHandle m_hFile;
	bool m_bFirstVideo,m_bFirstAudio;
	MP4TrackId m_videoTrack, m_audioTrack;
	uint64_t m_u64VideoPTS,m_u64AudioPTS, m_u64FirstPTS, m_u64LastPTS;
	bool m_IsPrivateStream;
	char*			m_pAudioBuf;
	int				m_AudioSize;
	bool			m_bEnc;
};

struct MP4SampleData
{
	MP4SampleData(void)
	{
		pData = NULL;
		nLen = 0;
		nPts = 0;
		IsKeyFrame = false;
	}
	uint8_t *pData;
	uint32_t nLen;
	uint64_t nPts;
	bool IsKeyFrame;
};

typedef vector<MP4SampleData>  MP4SampleVector;

//回调接口
class IMP4Notify
{
public:
	virtual void OnReadVideoData(uint8_t *pData,uint32_t nLen,uint64_t nPts,bool IsKeyFrame) = 0; 
};

struct MP4_FRAME
{
    unsigned short Sn;                    //
    int bVideo;                           //
	int PayLoadType;                      //payload type
	int Manuf;                            //视频厂家
	StreamTypes eType;
	
	MP4SampleVector vmp4buf;      //存放多帧数据
};

class MP4Decoder
{
public:
	MP4Decoder();
	MP4Decoder(IMP4Notify* pNotify);
	~MP4Decoder(void);

	int MP4ReadFileExt(const char *sFileName,uint64_t *msFileDuration,uint64_t msStartTime = 0,uint64_t msEndTime = 0,bool FirstKeyFrame = false,bool bInitDirection = false);//读取时需要给定一个初始方向,默认0正向
	int MP4ReadSampleByFrame(uint64_t *CurSampleID,MP4_FRAME &mp4frame,bool wantKeyFrame = false,bool bDirection = false);//首次调用时,方向必须与打开文件时设置的初始方向一致
	int MP4ReadSampleByDuration(uint64_t msDuration,MP4_FRAME &mp4frame,bool wantKeyFrame = false,bool bDirection = false);//首次调用时,方向必须与打开文件时设置的初始方向一致
	int MP4ReadSampleByTime(uint64_t msStartTime,uint64_t msEndTime,MP4_FRAME &mp4frame);

	int MP4ReadAudioByFrame(uint64_t *CurSampleID,MP4_FRAME &mp4audio);
	int MP4ReadAudioByDuration(uint64_t msDuration,MP4_FRAME &mp4audio);
	int MP4ReadAudioByTime(uint64_t msStartTime,uint64_t msEndTime,MP4_FRAME &mp4audio);

	void MP4ReleaseFile();

	uint64_t MP4GetTotalSampleNum()
	{
		return m_TotalSample;
	}

	uint64_t MP4GetCurSampleID()
	{
		if(m_bDirection == false)
		{
			return m_ReadIndex;
		}
		else
		{
			return m_ReverseReadIndex;
		}
	}

	float MP4GetPos()
	{
		float nPos = 0;

		if(m_bDirection == false)
		{
			nPos = (float)m_ReadIndex * 100.00 / (float)m_FileAllSample;
		}
		else
		{
			nPos = (float)m_ReverseReadIndex * 100.00 / (float)m_FileAllSample;
		}

		return nPos;
	}

	void MP4SetPos(uint64_t msStartTime)
	{
		MP4SampleId StartSampleID;

		MP4Timestamp StartStamp =  MP4ConvertToTrackTimestamp(m_hFile,m_videoTrack,msStartTime,MP4_MSECS_TIME_SCALE);

		StartSampleID = MP4GetSampleIdFromTime(m_hFile,m_videoTrack,StartStamp,false);
		if(StartSampleID == MP4_INVALID_SAMPLE_ID)
		{
			return ;
		}

		if(StartSampleID > m_FinalSample)
		{
			return;
		}

		m_ReadIndex = StartSampleID;

	}

	//通知接口
	IMP4Notify* m_pMP4Notify;

private:
	
	MP4FileHandle m_hFile;
	MP4TrackId m_videoTrack, m_audioTrack;
	uint64_t m_u64VideoPTS,m_u64AudioPTS;
	uint64_t	m_msTotalDuration;//单位ms
	StreamTypes eStreamType;

	uint8_t m_video_data[MAX_FRAME_LEN];
	unsigned int m_video_len;

	uint8_t m_audio_data[MAX_AUDIO_SIZE];
	unsigned int m_audio_len;

	uint64_t m_msStartTime;
	uint64_t m_msEndTime;
	uint32_t m_ReadIndex;
	int32_t m_ReverseReadIndex;
	uint64_t m_FileAllSample;
	uint64_t m_TotalSample;
	uint64_t m_StartSample;
	uint64_t m_FinalSample;
	bool m_bDirection;//false 正向 true反向

	int MP4ReadSampleByFrameForward(uint64_t *CurSampleID,MP4_FRAME &mp4frame,bool wantKeyFrame = false);
	int MP4ReadSampleByDurationForward(uint64_t msDuration,MP4_FRAME &mp4frame,bool wantKeyFrame = false);
	int MP4ReadSampleByFrameReverse(uint64_t *CurSampleID,MP4_FRAME &mp4frame);
	int MP4ReadSampleByDurationReverse(uint64_t msDuration,MP4_FRAME &mp4frame);
	int MP4ReadChangeDirection(void);

	void MP4FreeSample(uint8_t** pSample);

	bool			m_bEnc;
	
};

#endif




  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值