asf文件转成mp4

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/byxdaz/article/details/83184563

//asfToMp4.h

#pragma once

#include <windows.h>
#include "Audio/AudioFrameBuffer.h"
#include "AsfFile.h"								
#include "audio/G726EnDecoder.h"
#include "mp4v2/mp4v2.h"
#include "libfaac/include/faac.h"

#ifdef _DEBUG
#pragma  comment(lib,"libmp4v2/lib/Debug/libmp4v2.lib")
#pragma  comment(lib,"libfaac/lib/libfaacD.lib")
#else
#pragma  comment(lib,"libmp4v2/lib/Release/libmp4v2.lib")
#pragma  comment(lib,"libfaac/lib/libfaac.lib")
#endif

//文件转换进度类型
enum Mp4FileConvertProcessType
{
	Mp4FileConvertProcessType_None		=	0,			//none
	Mp4FileConvertProcessType_Running	=	1,			//转换中
	Mp4FileConvertProcessType_Finish	=	2,			//转换完成
	Mp4FileConvertProcessType_Exception	=	3,			//转换异常
	Mp4FileConvertProcessType_Cancel	=	4,			//取消
};
//文件转换进度回调函数
typedef void (CALLBACK* Mp4FileConvertProcessCallback)(int nType, unsigned int nCurrentSeconds, unsigned int nTotalSenconds, void* pUsr);

// NALU单元    
struct AsfToMp4_NaluUnit
{
	short alltype;//0x67,0x68,0x65 分别表示sps,pps,i
	short type;
	int size;
	unsigned char *data;
};

class AsfToMp4
{
public:
	AsfToMp4();
	virtual ~AsfToMp4();

	//设置文件路径
	void SetFilePathName(char *pSrc, char *pDest);

	void SetFrameRate(int nFrameRate);

	BOOL StartConvert(BOOL bIsAudio, BOOL bIsBlock, Mp4FileConvertProcessCallback funFileConvert,void *pUserData);
	BOOL StopConvert();

	static unsigned __stdcall ConvertThreadFun(LPVOID pParam);
	unsigned int ConvertThreadFun_Inner();

	//---------------------------------------------------------------------
	//说明:从文件中读取数据
	//参数:无
	//返回:成功返回TRUE,失败返回FALSE
	//---------------------------------------------------------------------
	BOOL	ReadFileData(char *pOutData,int & nOutDataSize, int & FrameType);

	//---------------------------------------------------------------------
	//说明:取得I帧的偏移长度,I帧中可能存在一定的无效数据,因此需要删除
	//参数:[in]stream:帧数据
	//		[in]iLen:数据长度
	//返回:返回I帧的偏移长度
	//调用:ChangeFile()中调用
	//---------------------------------------------------------------------
	int		GetPFrameOffset(unsigned char *stream, int iLen);

	//---------------------------------------------------------------------
	//说明:取得I帧的偏移长度,I帧中可能存在一定的无效数据,因此需要删除
	//参数:[in]stream:帧数据
	//		[in]iLen:数据长度
	//返回:返回I帧的偏移长度
	//调用:ChangeFile()中调用
	//---------------------------------------------------------------------
	int		GetAFrameOffset(unsigned char *stream, int iLen);

private:
	// 获取Asf文件头信息结构体。
	BOOL		GetAsfFileInfo(ASF_INFO_S *struAsfInfo);

	// read one nalu from H264 data buffer        
	int ReadOneNaluFromBuf(const unsigned char *buffer, unsigned int nBufferSize, unsigned int offSet, AsfToMp4_NaluUnit &nalu);

private:
	char m_szSrcFilePathName[MAX_PATH];
	char m_szDestFilePathName[MAX_PATH];
	CG726EnDecoder		m_G726EnDecoder;
	CAsfFile		m_AsfFile;					//asf文件读取类
	BOOL				m_bFileOver;				//是否文件结束
	ASF_INFO_S			m_AsfFileHead;	// asf文件头信息
	int					m_width;		// 画面宽度
	int					m_height;		// 画面高度
	int					m_nFrameRate;
	int					m_nTimeScale;

	BOOL				m_bIsAudio;						// 是否存在音频
	char *				m_pPcmDataBuffer;
	int					m_nPcmDataBufferSize;
	char *				m_pAacDataBuffer;
	int					m_nAacDataBufferSize;
	int					m_nAacMaxInputBytes;			//aac编码输入字节数(一帧数据)
	int					m_nAacMaxOutputBytes;			//aac编码输出字节数(一帧数据)
	char *				m_pTempDataBuffer;
	int					m_nTempDataBufferSize;
	int					m_nTempDataStartPos;
	faacEncHandle		m_faacEncHandle;
	BOOL				m_bInitFaac;

	BOOL				m_bIsAddH264VideoTrack;
	BOOL				m_bIsAddH264PictureParameterSet;
	BOOL				m_bIsAddAudioTrack;
	MP4FileHandle m_fileMp4;
	MP4TrackId m_videoTrack;
	MP4TrackId m_audioTrack;

protected:
	Mp4FileConvertProcessCallback m_funFileConvert;
	void *m_pUserData;
	BOOL				m_bIsStopConvert;
	HANDLE				m_hConvertThread;
};

//asfToMp4.cpp

#include "stdafx.h"
#include "AsfToMp4.h"
#include <process.h>

AsfToMp4::AsfToMp4()
{
	m_bIsAudio = FALSE;
	m_nFrameRate = 25;
	m_nTimeScale = 90000;
	memset(m_szSrcFilePathName, 0, sizeof(m_szSrcFilePathName));
	memset(m_szDestFilePathName, 0, sizeof(m_szDestFilePathName));
	m_bIsAddH264VideoTrack = FALSE;
	m_bIsAddH264PictureParameterSet = FALSE;
	m_bIsAddAudioTrack = FALSE;
	m_fileMp4 = NULL;
	m_videoTrack = 0;
	m_audioTrack = 0;
	m_nPcmDataBufferSize = 0;
	m_pPcmDataBuffer = NULL;
	m_nAacDataBufferSize = 0;
	m_pAacDataBuffer = NULL;
	m_nAacMaxInputBytes = 0;
	m_nAacMaxOutputBytes = 0;
	m_nTempDataBufferSize = 0;
	m_pTempDataBuffer = NULL;
	m_nTempDataStartPos = 0;
	m_faacEncHandle = NULL;
	m_bInitFaac = FALSE;

	m_funFileConvert = NULL;
	m_pUserData = NULL;
	m_bIsStopConvert = TRUE;
	m_hConvertThread = NULL;
}

AsfToMp4::~AsfToMp4()
{
	if (m_pPcmDataBuffer != NULL)
	{
		delete[]m_pPcmDataBuffer;
		m_pPcmDataBuffer = NULL;
	}
	if (m_pAacDataBuffer != NULL)
	{
		delete[]m_pAacDataBuffer;
		m_pAacDataBuffer = NULL;
	}
	if (m_pTempDataBuffer != NULL)
	{
		delete[]m_pTempDataBuffer;
		m_pTempDataBuffer = NULL;
	}
}

//设置文件路径
void AsfToMp4::SetFilePathName(char *pSrc, char *pDest)
{
	strcpy_s(m_szSrcFilePathName, pSrc);
	strcpy_s(m_szDestFilePathName, pDest);
}

void AsfToMp4::SetFrameRate(int nFrameRate)
{
	if (nFrameRate > 0)
	{
		m_nFrameRate = nFrameRate;
	}
}

unsigned __stdcall AsfToMp4::ConvertThreadFun(LPVOID pParam)
{
	AsfToMp4 *pAsfToMp4 = (AsfToMp4 *)pParam;
	return pAsfToMp4->ConvertThreadFun_Inner();
}
unsigned int AsfToMp4::ConvertThreadFun_Inner()
{
	BOOL bRet = TRUE;
	std::string strUtf8FileName = AsciiToUtf8(m_szDestFilePathName);
	m_fileMp4 = MP4CreateEx(strUtf8FileName.c_str(), 0, 1, 1, 0, 0, 0, 0);
	if (m_fileMp4 == MP4_INVALID_FILE_HANDLE)
	{
		printf("open file fialed.\n");
		if (m_funFileConvert != NULL)
		{
			m_funFileConvert(Mp4FileConvertProcessType_Exception, 0, 0, m_pUserData);
		}
		return 0;
	}
	unsigned int uiTotalSeconds = 0;
	unsigned int uiCurrentSeconds = 0;
	unsigned long long ullBeginTimestamp = 0;
	unsigned long inputSamples = 0;
	int nAudioChannelNum = 1;
	int nMP4AudioDuration = 1024;			//音频时间刻度
	if (m_bIsAudio)
	{
		if (!m_bInitFaac)
		{
			//init faac
			int nBitsPerSample = 16;
			inputSamples = 0;
			m_faacEncHandle = faacEncOpen(8000, nAudioChannelNum, &inputSamples, (unsigned long *)&m_nAacMaxOutputBytes);
			m_nAacMaxInputBytes = inputSamples*nBitsPerSample / 8;
			m_nPcmDataBufferSize = m_nAacMaxInputBytes;
			nMP4AudioDuration = inputSamples / nAudioChannelNum;

			m_pPcmDataBuffer = new char[m_nPcmDataBufferSize + 1];
			m_nAacDataBufferSize = m_nAacMaxOutputBytes;
			m_pAacDataBuffer = new char[m_nAacMaxOutputBytes + 1];
			m_nTempDataBufferSize = 1024 * 8;
			m_pTempDataBuffer = new char[m_nTempDataBufferSize + 1];
			m_nTempDataStartPos = 0;
			// Get current encoding configuration
			faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_faacEncHandle);
			if (!pConfiguration)
			{
				printf("GetCurrentConfiguration error!\n");
				if (m_funFileConvert != NULL)
				{
					m_funFileConvert(Mp4FileConvertProcessType_Exception, 0, 0, m_pUserData);
				}
				return 0;
			}
			//设置版本,录制MP4文件时要用MPEG4
			pConfiguration->version = MPEG4;
			pConfiguration->aacObjectType = LOW; //LC编码
												 //输入数据类型
			pConfiguration->inputFormat = FAAC_INPUT_16BIT;
			// outputFormat (0 = Raw; 1 = ADTS)
			// 录制MP4文件时,要用raw流。检验编码是否正确时可设置为 adts传输流,
			pConfiguration->outputFormat = 1;
			//瞬时噪声定形(temporal noise shaping,TNS)滤波器
			pConfiguration->shortctl = SHORTCTL_NORMAL;
			pConfiguration->useTns = true;
			//pConfiguration->useLfe=false;
			pConfiguration->quantqual = 100;
			pConfiguration->bandWidth = 0;
			pConfiguration->bitRate = 0;
			//  Set encoding configuration
			faacEncSetConfiguration(m_faacEncHandle, pConfiguration);

			m_bInitFaac = TRUE;
		}
	}
	MP4SetTimeScale(m_fileMp4, m_nTimeScale);
	int nDataBufferSize = 1920 * 1080 * 3;
	int nWriteSampleDataSize = 1920 * 1080 * 2;
	char * pWriteSampleData = new char[nWriteSampleDataSize + 1];
	int nFrameType = 0;
	int nTempDataBufferSize = nDataBufferSize;
	char *pDataBuffer = new char[nDataBufferSize + 1];
	unsigned long long ullTimeStamp = 0;
	unsigned int uiProcessIndex = 0;
	while (true)
	{
		nTempDataBufferSize = nDataBufferSize;
		bRet = ReadFileData(pDataBuffer, nTempDataBufferSize, nFrameType);
		if (!bRet)
		{
			break;
		}
		REPAIRFILEFRAMEINFO *pFrameInfo = (REPAIRFILEFRAMEINFO *)pDataBuffer;
		if (pFrameInfo->FrameType == 0x63643030 || pFrameInfo->FrameType == 0x63643130)
		{
			//I或P帧
			AsfToMp4_NaluUnit nalu;
			int pos = 0, len = 0;
			pos = 0;
			nalu.data = NULL;
			nalu.size = 0;
			nalu.type = 0;
			while (len = ReadOneNaluFromBuf((unsigned char *)pDataBuffer + sizeof(REPAIRFILEFRAMEINFO), nTempDataBufferSize - sizeof(REPAIRFILEFRAMEINFO), pos, nalu))
			{
				if (nalu.type == 0x07) // sps          
				{
					if (!m_bIsAddH264VideoTrack)
					{
						//获取视频分辨率
						ASF_INFO_S aiAsfInfo = m_AsfFile.GetAsfFileInfo();
						uiTotalSeconds = aiAsfInfo.struDuration.s32Hours * 3600 + aiAsfInfo.struDuration.s32Mins * 60 + aiAsfInfo.struDuration.s32Secs;
						ullBeginTimestamp = pFrameInfo->FrameStamp;
						if (aiAsfInfo.struVStream.u32samplePerSec == 0)
						{
							m_nFrameRate = m_AsfFile.GetFrameRateInVBR();
						}
						else
						{
							m_nFrameRate = aiAsfInfo.struAStream.u32SamplesPerSec;
						}
						//添加h264 track
						m_videoTrack = MP4AddH264VideoTrack(m_fileMp4,
							m_nTimeScale,
							m_nTimeScale / m_nFrameRate,
							aiAsfInfo.struVStream.u32BiWidth,
							aiAsfInfo.struVStream.u32BiHeight,
							nalu.data[1], // sps[1] AVCProfileIndication                   
							nalu.data[2], // sps[2] profile_compat                    
							nalu.data[3], // sps[3] AVCLevelIndication                    
							3);
						// 4 bytes length before each NAL unit                
						if (m_videoTrack == MP4_INVALID_TRACK_ID)
						{
							printf("add video track failed.\n");
							MP4Close(m_fileMp4);
							m_fileMp4 = NULL;
							if (pWriteSampleData != NULL)
							{
								delete[]pWriteSampleData;
								pWriteSampleData = NULL;
							}
							if (pDataBuffer != NULL)
							{
								delete[]pDataBuffer;
								pDataBuffer = NULL;
							}
							return FALSE;
						}
						MP4SetVideoProfileLevel(m_fileMp4, 1);
						//  Simple Profile @ Level 3                    
						MP4AddH264SequenceParameterSet(m_fileMp4, m_videoTrack, nalu.data, nalu.size);

						m_bIsAddH264VideoTrack = TRUE;
					}
					else
					{
						int jjj = 0;
					}
				}
				else if (nalu.type == 0x08) // pps            
				{
					if (!m_bIsAddH264PictureParameterSet)
					{
						if (m_bIsAddH264VideoTrack)
						{
							MP4AddH264PictureParameterSet(m_fileMp4, m_videoTrack, nalu.data, nalu.size);
							m_bIsAddH264PictureParameterSet = TRUE;
						}
					}
				}
				else
				{
					int datalen = nalu.size + 4;
					if (datalen > nWriteSampleDataSize)
					{
						delete[]pWriteSampleData;
						nWriteSampleDataSize = datalen;
						pWriteSampleData = new char[nWriteSampleDataSize + 1];
					}
					if (pWriteSampleData != NULL)
					{
						unsigned char *data = (unsigned char *)pWriteSampleData;
						// MP4 Nalu前四个字节表示Nalu长度                
						data[0] = nalu.size >> 24;
						data[1] = nalu.size >> 16;
						data[2] = nalu.size >> 8;
						data[3] = nalu.size & 0xff;
						memcpy(data + 4, nalu.data, nalu.size);
						if (!MP4WriteSample(m_fileMp4, m_videoTrack, data, datalen, MP4_INVALID_DURATION, 0, 1))
						{
							MP4Close(m_fileMp4);
							m_fileMp4 = NULL;
							if (pWriteSampleData != NULL)
							{
								delete[]pWriteSampleData;
								pWriteSampleData = NULL;
							}
							if (pDataBuffer != NULL)
							{
								delete[]pDataBuffer;
								pDataBuffer = NULL;
							}
							if (m_funFileConvert != NULL)
							{
								m_funFileConvert(Mp4FileConvertProcessType_Exception, 0, 0, m_pUserData);
							}
							return 0;
						}
					}
				}
				pos += len;
			}
		}
		else if (pFrameInfo->FrameType == 0x62773130)
		{
			//音频
			if (m_bIsAudio)
			{
				if (!m_bIsAddAudioTrack)
				{
					//添加aac音频
					m_audioTrack = MP4AddAudioTrack(m_fileMp4, 8000, nMP4AudioDuration, MP4_MPEG4_AUDIO_TYPE);
					if (m_audioTrack == MP4_INVALID_TRACK_ID)
					{
						printf("add audio track failed.\n");
						MP4Close(m_fileMp4);
						m_fileMp4 = NULL;
						if (m_funFileConvert != NULL)
						{
							m_funFileConvert(Mp4FileConvertProcessType_Exception, 0, 0, m_pUserData);
						}
						return 0;
					}
					MP4SetAudioProfileLevel(m_fileMp4, 0x2);
					unsigned long uLen = 0;
					unsigned char *apInfo = NULL;
					faacEncGetDecoderSpecificInfo(m_faacEncHandle, &apInfo, &uLen);
					MP4SetTrackESConfiguration(m_fileMp4, m_audioTrack, (unsigned char*)apInfo, uLen);
					if (apInfo != NULL)
					{
						delete apInfo;
					}
					m_bIsAddAudioTrack = TRUE;
				}
				if (m_bIsAddAudioTrack)
				{
					if (m_bInitFaac)
					{
						//转换g726转换aac
						char szPcmBuffer[2048] = { 0 };
						int nPcmBufferSize = 2048;
						BOOL bAudioFrameDecodeRet = m_G726EnDecoder.Decoder_DecodeFrame(pDataBuffer + sizeof(REPAIRFILEFRAMEINFO), nTempDataBufferSize - sizeof(REPAIRFILEFRAMEINFO), szPcmBuffer, &nPcmBufferSize);
						if (bAudioFrameDecodeRet)
						{
							memcpy(m_pTempDataBuffer + m_nTempDataStartPos, szPcmBuffer, nPcmBufferSize);
							m_nTempDataStartPos += nPcmBufferSize;
							if (m_nTempDataStartPos >= m_nAacMaxInputBytes)
							{
								memcpy(m_pPcmDataBuffer, m_pTempDataBuffer, m_nAacMaxInputBytes);
								//move data
								int nRemainSize = m_nTempDataStartPos - m_nAacMaxInputBytes;
								int j = 0;
								for (j = 0; j < nRemainSize; j++)
								{
									m_pTempDataBuffer[j] = m_pTempDataBuffer[m_nAacMaxInputBytes + j];
								}
								m_nTempDataStartPos -= m_nAacMaxInputBytes;
								int nRetFaacEncode = faacEncEncode(m_faacEncHandle, (int *)m_pPcmDataBuffer, inputSamples, (unsigned char *)m_pAacDataBuffer, m_nAacMaxOutputBytes);
								if (nRetFaacEncode > 0)
								{
									bool bMP4WriteSample = MP4WriteSample(m_fileMp4, m_audioTrack, (BYTE*)&m_pAacDataBuffer[7], nRetFaacEncode - 7, MP4_INVALID_DURATION, 0, true);
								}
								else if (nRetFaacEncode == 0)
								{
									//缓存处理,非错误
								}
								else
								{
									//编码失败,错误
								}
							}
						}
					}
				}
			}
		}
		else if (pFrameInfo->FrameType == 0x63643939)
		{
			//Binary
		}
		else
		{
			continue;
		}
		uiProcessIndex++;
		if (m_bIsStopConvert)
		{
			break;
		}
		else
		{
			if (m_funFileConvert != NULL)
			{
				if (ullBeginTimestamp != 0)
				{
					uiCurrentSeconds = ((pFrameInfo->FrameStamp - ullBeginTimestamp) / 1000000);
				}
				if (uiProcessIndex == 1 || uiProcessIndex % 25 == 0)
				{
					m_funFileConvert(Mp4FileConvertProcessType_Running, uiCurrentSeconds, uiTotalSeconds, m_pUserData);
				}
			}
		}
	}
	if (m_faacEncHandle != NULL)
	{
		faacEncClose(m_faacEncHandle);
		m_faacEncHandle = NULL;
	}
	MP4Close(m_fileMp4);
	m_fileMp4 = NULL;
	if (pWriteSampleData != NULL)
	{
		delete[]pWriteSampleData;
		pWriteSampleData = NULL;
	}
	if (pDataBuffer != NULL)
	{
		delete[]pDataBuffer;
		pDataBuffer = NULL;
	}
	if (!m_bIsStopConvert)
	{
		if (m_funFileConvert != NULL)
		{
			m_funFileConvert(Mp4FileConvertProcessType_Finish, uiTotalSeconds, uiTotalSeconds, m_pUserData);
		}
	}

	return 0;
}

BOOL AsfToMp4::StartConvert(BOOL bIsAudio, BOOL bIsBlock, Mp4FileConvertProcessCallback funFileConvert, void *pUserData)
{
	m_funFileConvert = funFileConvert;
	m_pUserData = pUserData;
	m_bIsAudio = bIsAudio;

	if (bIsBlock)
	{
		BOOL bRet = TRUE;
		std::string strUtf8FileName = AsciiToUtf8(m_szDestFilePathName);
		m_fileMp4 = MP4CreateEx(strUtf8FileName.c_str(), 0, 1, 1, 0, 0, 0, 0);
		if (m_fileMp4 == MP4_INVALID_FILE_HANDLE)
		{
			printf("open file fialed.\n");
			return FALSE;
		}
		unsigned long inputSamples = 0;
		int nAudioChannelNum = 1;
		int nMP4AudioDuration = 1024;			//音频时间刻度
		if (bIsAudio)
		{
			if (!m_bInitFaac)
			{
				//init faac
				int nBitsPerSample = 16;
				inputSamples = 0;
				m_faacEncHandle = faacEncOpen(8000, nAudioChannelNum, &inputSamples, (unsigned long *)&m_nAacMaxOutputBytes);
				m_nAacMaxInputBytes = inputSamples*nBitsPerSample / 8;
				m_nPcmDataBufferSize = m_nAacMaxInputBytes;
				nMP4AudioDuration = inputSamples / nAudioChannelNum;

				m_pPcmDataBuffer = new char[m_nPcmDataBufferSize + 1];
				m_nAacDataBufferSize = m_nAacMaxOutputBytes;
				m_pAacDataBuffer = new char[m_nAacMaxOutputBytes + 1];
				m_nTempDataBufferSize = 1024 * 8;
				m_pTempDataBuffer = new char[m_nTempDataBufferSize + 1];
				m_nTempDataStartPos = 0;
				// Get current encoding configuration
				faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_faacEncHandle);
				if (!pConfiguration)
				{
					printf("GetCurrentConfiguration error!\n");
					return FALSE;
				}
				//设置版本,录制MP4文件时要用MPEG4
				pConfiguration->version = MPEG4;
				pConfiguration->aacObjectType = LOW; //LC编码
													 //输入数据类型
				pConfiguration->inputFormat = FAAC_INPUT_16BIT;
				// outputFormat (0 = Raw; 1 = ADTS)
				// 录制MP4文件时,要用raw流。检验编码是否正确时可设置为 adts传输流,
				pConfiguration->outputFormat = 1;
				//瞬时噪声定形(temporal noise shaping,TNS)滤波器
				pConfiguration->shortctl = SHORTCTL_NORMAL;
				pConfiguration->useTns = true;
				//pConfiguration->useLfe=false;
				pConfiguration->quantqual = 100;
				pConfiguration->bandWidth = 0;
				pConfiguration->bitRate = 0;
				//  Set encoding configuration
				faacEncSetConfiguration(m_faacEncHandle, pConfiguration);

				m_bInitFaac = TRUE;
			}
		}
		MP4SetTimeScale(m_fileMp4, m_nTimeScale);
		int nDataBufferSize = 1920 * 1080 * 3;
		int nWriteSampleDataSize = 1920 * 1080 * 2;
		char * pWriteSampleData = new char[nWriteSampleDataSize + 1];
		int nFrameType = 0;
		int nTempDataBufferSize = nDataBufferSize;
		char *pDataBuffer = new char[nDataBufferSize + 1];
		unsigned long long ullTimeStamp = 0;
		while (true)
		{
			nTempDataBufferSize = nDataBufferSize;
			bRet = ReadFileData(pDataBuffer, nTempDataBufferSize, nFrameType);
			if (!bRet)
			{
				break;
			}
			REPAIRFILEFRAMEINFO *pFrameInfo = (REPAIRFILEFRAMEINFO *)pDataBuffer;
			if (pFrameInfo->FrameType == 0x63643030 || pFrameInfo->FrameType == 0x63643130)
			{
				//I或P帧
				AsfToMp4_NaluUnit nalu;
				int pos = 0, len = 0;
				pos = 0;
				nalu.data = NULL;
				nalu.size = 0;
				nalu.type = 0;
				while (len = ReadOneNaluFromBuf((unsigned char *)pDataBuffer + sizeof(REPAIRFILEFRAMEINFO), nTempDataBufferSize - sizeof(REPAIRFILEFRAMEINFO), pos, nalu))
				{
					if (nalu.type == 0x07) // sps          
					{
						if (!m_bIsAddH264VideoTrack)
						{
							//获取视频分辨率
							ASF_INFO_S aiAsfInfo = m_AsfFile.GetAsfFileInfo();
							if (aiAsfInfo.struVStream.u32samplePerSec == 0)
							{
								m_nFrameRate = m_AsfFile.GetFrameRateInVBR();
							}
							else
							{
								m_nFrameRate = aiAsfInfo.struAStream.u32SamplesPerSec;
							}
							//添加h264 track
							m_videoTrack = MP4AddH264VideoTrack(m_fileMp4,
								m_nTimeScale,
								m_nTimeScale / m_nFrameRate,
								aiAsfInfo.struVStream.u32BiWidth,
								aiAsfInfo.struVStream.u32BiHeight,
								nalu.data[1], // sps[1] AVCProfileIndication                   
								nalu.data[2], // sps[2] profile_compat                    
								nalu.data[3], // sps[3] AVCLevelIndication                    
								3);
							// 4 bytes length before each NAL unit                
							if (m_videoTrack == MP4_INVALID_TRACK_ID)
							{
								printf("add video track failed.\n");
								MP4Close(m_fileMp4);
								m_fileMp4 = NULL;
								if (pWriteSampleData != NULL)
								{
									delete[]pWriteSampleData;
									pWriteSampleData = NULL;
								}
								if (pDataBuffer != NULL)
								{
									delete[]pDataBuffer;
									pDataBuffer = NULL;
								}
								return FALSE;
							}
							MP4SetVideoProfileLevel(m_fileMp4, 1);
							//  Simple Profile @ Level 3                    
							MP4AddH264SequenceParameterSet(m_fileMp4, m_videoTrack, nalu.data, nalu.size);

							m_bIsAddH264VideoTrack = TRUE;
						}
						else
						{
							int jjj = 0;
						}
					}
					else if (nalu.type == 0x08) // pps            
					{
						if (!m_bIsAddH264PictureParameterSet)
						{
							if (m_bIsAddH264VideoTrack)
							{
								MP4AddH264PictureParameterSet(m_fileMp4, m_videoTrack, nalu.data, nalu.size);
								m_bIsAddH264PictureParameterSet = TRUE;
							}
						}
					}
					else
					{
						int datalen = nalu.size + 4;
						if (datalen > nWriteSampleDataSize)
						{
							delete[]pWriteSampleData;
							nWriteSampleDataSize = datalen;
							pWriteSampleData = new char[nWriteSampleDataSize + 1];
						}
						if (pWriteSampleData != NULL)
						{
							unsigned char *data = (unsigned char *)pWriteSampleData;
							// MP4 Nalu前四个字节表示Nalu长度                
							data[0] = nalu.size >> 24;
							data[1] = nalu.size >> 16;
							data[2] = nalu.size >> 8;
							data[3] = nalu.size & 0xff;
							memcpy(data + 4, nalu.data, nalu.size);
							if (!MP4WriteSample(m_fileMp4, m_videoTrack, data, datalen, MP4_INVALID_DURATION, 0, 1))
							{
								MP4Close(m_fileMp4);
								m_fileMp4 = NULL;
								if (pWriteSampleData != NULL)
								{
									delete[]pWriteSampleData;
									pWriteSampleData = NULL;
								}
								if (pDataBuffer != NULL)
								{
									delete[]pDataBuffer;
									pDataBuffer = NULL;
								}
								return FALSE;
							}
						}
					}
					pos += len;
				}
			}
			else if (pFrameInfo->FrameType == 0x62773130)
			{
				//音频
				if (bIsAudio)
				{
					if (!m_bIsAddAudioTrack)
					{
						//添加aac音频
						m_audioTrack = MP4AddAudioTrack(m_fileMp4, 8000, nMP4AudioDuration, MP4_MPEG4_AUDIO_TYPE);
						if (m_audioTrack == MP4_INVALID_TRACK_ID)
						{
							printf("add audio track failed.\n");
							MP4Close(m_fileMp4);
							m_fileMp4 = NULL;
							return FALSE;
						}
						MP4SetAudioProfileLevel(m_fileMp4, 0x2);
						unsigned long uLen = 0;
						unsigned char *apInfo = NULL;
						faacEncGetDecoderSpecificInfo(m_faacEncHandle, &apInfo, &uLen);
						MP4SetTrackESConfiguration(m_fileMp4, m_audioTrack, (unsigned char*)apInfo, uLen);
						if (apInfo != NULL)
						{
							delete apInfo;
						}
						m_bIsAddAudioTrack = TRUE;
					}
					if (m_bIsAddAudioTrack)
					{
						if (m_bInitFaac)
						{
							//转换g726转换aac
							char szPcmBuffer[2048] = { 0 };
							int nPcmBufferSize = 2048;
							BOOL bAudioFrameDecodeRet = m_G726EnDecoder.Decoder_DecodeFrame(pDataBuffer + sizeof(REPAIRFILEFRAMEINFO), nTempDataBufferSize - sizeof(REPAIRFILEFRAMEINFO), szPcmBuffer, &nPcmBufferSize);
							if (bAudioFrameDecodeRet)
							{
								memcpy(m_pTempDataBuffer + m_nTempDataStartPos, szPcmBuffer, nPcmBufferSize);
								m_nTempDataStartPos += nPcmBufferSize;
								if (m_nTempDataStartPos >= m_nAacMaxInputBytes)
								{
									memcpy(m_pPcmDataBuffer, m_pTempDataBuffer, m_nAacMaxInputBytes);
									//move data
									int nRemainSize = m_nTempDataStartPos - m_nAacMaxInputBytes;
									int j = 0;
									for (j = 0; j < nRemainSize; j++)
									{
										m_pTempDataBuffer[j] = m_pTempDataBuffer[m_nAacMaxInputBytes + j];
									}
									m_nTempDataStartPos -= m_nAacMaxInputBytes;
									int nRetFaacEncode = faacEncEncode(m_faacEncHandle, (int *)m_pPcmDataBuffer, inputSamples, (unsigned char *)m_pAacDataBuffer, m_nAacMaxOutputBytes);
									if (nRetFaacEncode > 0)
									{
										bool bMP4WriteSample = MP4WriteSample(m_fileMp4, m_audioTrack, (BYTE*)&m_pAacDataBuffer[7], nRetFaacEncode - 7, MP4_INVALID_DURATION, 0, true);
									}
									else if (nRetFaacEncode == 0)
									{
										//缓存处理,非错误
									}
									else
									{
										//编码失败,错误
									}
								}
							}
						}
					}
				}
			}
			else if (pFrameInfo->FrameType == 0x63643939)
			{
				//Binary
			}
			else
			{
				continue;
			}
		}
		if (m_faacEncHandle != NULL)
		{
			faacEncClose(m_faacEncHandle);
			m_faacEncHandle = NULL;
		}
		MP4Close(m_fileMp4);
		m_fileMp4 = NULL;
		if (pWriteSampleData != NULL)
		{
			delete[]pWriteSampleData;
			pWriteSampleData = NULL;
		}
		if (pDataBuffer != NULL)
		{
			delete[]pDataBuffer;
			pDataBuffer = NULL;
		}
		return bRet;
	}
	else
	{
		m_bIsStopConvert = FALSE;
		m_hConvertThread = (HANDLE)_beginthreadex(NULL, 0, ConvertThreadFun, this, 0, NULL);
		return TRUE;
	}
}
BOOL AsfToMp4::StopConvert()
{
	m_bIsStopConvert = TRUE;
	if (m_hConvertThread != NULL)
	{
		WaitForSingleObject(m_hConvertThread, INFINITE);
		CloseHandle(m_hConvertThread);
		m_hConvertThread = NULL;
	}
	if (m_fileMp4 != NULL)
	{
		MP4Close(m_fileMp4);
		m_fileMp4 = NULL;
	}
	if (m_faacEncHandle != NULL)
	{
		faacEncClose(m_faacEncHandle);
		m_faacEncHandle = NULL;
	}
	return TRUE;
}

//---------------------------------------------------------------------
//说明:从文件中读取数据
//参数:无
//返回:成功返回TRUE,失败返回FALSE
//---------------------------------------------------------------------
BOOL AsfToMp4::ReadFileData(char *pOutData, int & nOutDataSize, int & FrameType)
{
	if (m_AsfFile.IsOpened() == FALSE)
	{
		int iCntWnd = 0, iCh_id = 0;
		if (!m_AsfFile.OpenFileEx(m_szSrcFilePathName, iCntWnd, &iCh_id))
			return FALSE;
	}

	int BufSize = 0;
	FrameType = 0;
	LONGLONG Framestamp = 0;
	BOOL bRet = m_AsfFile.ReadFileData(pOutData, &BufSize);
	if (bRet == TRUE)
	{
		nOutDataSize = BufSize;
		FrameType = *(int *)pOutData;
		if (m_bFileOver == FALSE && m_AsfFile.m_TotalSecond == m_AsfFile.m_StartTime.Pts)
		{
			m_bFileOver = TRUE;
		}
	}
	else
	{
		return FALSE;
	}

	return TRUE;
}

//---------------------------------------------------------------------
//说明:取得P帧的偏移长度,P帧中可能存在一定的无效数据,因此需要删除
//参数:[in]stream:帧数据
//		[in]iLen:数据长度
//返回:返回P帧的偏移长度
//调用:ChangeFile()中调用
//---------------------------------------------------------------------
int	AsfToMp4::GetPFrameOffset(unsigned char *stream, int iLen)
{
	return 8;
}

//---------------------------------------------------------------------
//说明:取得P帧的偏移长度,P帧中可能存在一定的无效数据,因此需要删除
//参数:[in]stream:帧数据
//		[in]iLen:数据长度
//返回:返回P帧的偏移长度
//调用:ChangeFile()中调用
//---------------------------------------------------------------------
int	AsfToMp4::GetAFrameOffset(unsigned char *stream, int iLen)
{
	return 8;
}

// 获取Asf文件头信息结构体。
BOOL AsfToMp4::GetAsfFileInfo(ASF_INFO_S *struAsfInfo)
{
	CXMVSAsfFile TmpAsf;
	int iCntWnd = 0, iCh_id = 0;
	if (!TmpAsf.OpenFileEx(m_szSrcFilePathName, iCntWnd, &iCh_id))
		return FALSE;
	*struAsfInfo = TmpAsf.GetAsfFileInfo();
	if (TmpAsf.IsOpened() == TRUE)
		TmpAsf.CloseFile();

	return TRUE;
}

// read one nalu from H264 data buffer        
int AsfToMp4::ReadOneNaluFromBuf(const unsigned char *buffer, unsigned int nBufferSize, unsigned int offSet, AsfToMp4_NaluUnit &nalu)
{
	nalu.size = 0;
	nalu.type = 0;
	int i = offSet;
	while (i < nBufferSize)
	{
		if (buffer[i++] == 0x00 && buffer[i++] == 0x00 && buffer[i++] == 0x00 && buffer[i++] == 0x01)
		{
			int pos = i;
			while (pos < nBufferSize)
			{
				if (buffer[pos++] == 0x00 && buffer[pos++] == 0x00 && buffer[pos++] == 0x00 && buffer[pos++] == 0x01)
				{
					break;
				}
			}
			if (pos == nBufferSize)
			{
				nalu.size = pos - i;
			}
			else
			{
				nalu.size = (pos - 4) - i;
			}
			nalu.alltype = buffer[i];
			nalu.type = buffer[i] & 0x1f;
			nalu.data = (unsigned char*)&buffer[i];
			return (nalu.size + i - offSet);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/byxdaz/article/details/83184563