librtmp获取视频流和音频流2

来源:互联网 发布:淘宝怎么买汽车票报销 编辑:程序博客网 时间:2024/06/09 20:55

        在上篇文章中,使用librtmp库中包流函数(比如:RTMP_ReadPacket,RTMP_ClientPacket等)读取视频数据包,音频数据包。但在实际过程中连接rtmp服务器请求视频流时只能获取到I帧,无法获取P帧,B帧,从而导致视频不流畅,关于无法获取到P帧、B帧数据包与rtmp服务器有关。连接crtmpserver服务器获取视频流时只能获取到I帧,无法获取P帧,B帧;而连接香港卫视的直播流对应的rtmp服务器时,就可以获取到P帧。无论那个rtmp服务器通过RTMP_Read可以获取I帧、P帧等。本文重点介绍使用RTMP_Read获取视频流和音频流。

    获取数据流流程:

1、RTMP_SetupURL,指定直播流地址。

2、设置参数,比如:RTMP_SetBufferMS,设置缓存大小

3、RTMP_Connect

4、RTMP_ConnectStream

5、循环使用RTMP_Read读取数据流,将数据流存放到一个内存区域中。

6、按照FLV格式,循环从内存区域中读取数据,解析文件头,meta数据,视频数据,音频数据等。

       主要流程代码:

#define ONE_PACKET_PCM_DATA_LEN320//ACC音频ADTStypedef struct tagAACDecoderSpecific{unsigned char nAudioFortmatType;//音频编码类型(0:Liner PCM platform endian,1:PCM,2:mp3,4:Nellymoser 16-kHz mono,5:Nellymoser 8-kHz mono,6:Nellymoser,7:G.711 A-law logarithmic PCM,8:G.711 mu-law logarithmic PCM,9:reserved,10:?AAC,14:MP3 8-Khz,15:Device-specific sound)unsigned char nAudioSampleType;//音频采样率(0:5.5kHz,1:11KHz,2:22 kHz,3:44 kHz)unsigned char nAudioSizeType;//音频采样精度(0:8bits,1:16bits)unsigned char nAudioStereo;//是否立体声(0:sndMono,1:sndStereo)unsigned char nAccPacketType;}AACDecoderSpecific;typedef struct tagAACAudioSpecificConfig{unsigned char nAudioObjectType;unsigned char nSampleFrequencyIndex;unsigned char nChannels;unsigned char nFrameLengthFlag;unsigned char nDependOnCoreCoder;unsigned char nExtensionFlag;}AACAudioSpecificConfig;intm_nImageWidth;intm_nImageHeight;intm_nFrameRate;charm_szSPSData[512];intm_nSPSDataLength;boolm_bFindSPSData;charm_szPPSData[512];intm_nPPSDataLength;boolm_bFindPPSData;boolm_bSendSPSData;boolm_bSendPPSData;boolm_bRequireSendIFrame;AAC2PCMm_aacOjbect;CammPoFrameDataProcess m_cfdCammPoFrameDataProcess;boolm_bInitCammPoFrameDataProcess;FlvToStream m_ftsFlvToStream;//flv内存文件类char *m_pVideoTempBuffer;//视频流缓存区unsigned int   m_nVideoTempBufferSize;unsigned int   m_nVideoTempBufferActualSize;intm_nDelayTime;AACAudioSpecificConfig m_ascAudioSpecificConfig;char m_szSPSDataTmp[512];SPS m_spsFlag;unsigned long long m_ullBaseTimeStamps;uint32_t m_ullStartTimeStamps;uint32_t m_ullCurrentTimeStamps;uint32_t m_ullDiffTimeStamps;uint32_t m_uPacketStartTimeStamps;uint32_t m_uPacketCurrentTimeStamps;uint32_t m_uPacketDiffTimeStamps;uint32_t m_uPacketLastTimeStamps;uint32_t m_uPacketTempTimeStamps;bool m_bFindNextIFrame;unsigned int m_nPackTiemStampSecondTmp;int m_nTempBufferSize;char *m_pTempBuffer;unsigned char start_code[4];bool m_bRawAcc; //ACC原始数据音频包bool m_bAccObjectInit;char *m_pAccTempBuffer;//acc音频流缓冲区unsigned int   m_nAccTempBufferSize;unsigned int   m_nAccTempBufferActualSize;char *m_pPcmLineBuffer;//pcm音频流缓存区unsigned int m_nPcmLineBufferSize;unsigned int m_nPcmLineBufferActualSize;unsigned int m_nPcmLineBufferReadPos;unsigned int m_nPcmLineBufferWritePos;unsigned char m_ucTempPcmData[ONE_PACKET_PCM_DATA_LEN+1];char *m_pG726TempBuffer;unsigned int m_nG726TempBufferSize;RTMP *m_rtmp;m_rtmp = RTMP_Alloc();RTMP_Init(m_rtmp);//10秒RTMP_SetBufferMS(m_rtmp,10 * 1000);if (!RTMP_Connect(m_rtmp, NULL)){RTMP_Log(RTMP_LOGERROR, "Connect Err\n");RTMP_Free(m_rtmp);m_rtmp = NULL;return -1;}if (!RTMP_ConnectStream(m_rtmp, 0)){RTMP_Log(RTMP_LOGERROR, "ConnectStream Err\n");RTMP_Close(m_rtmp);RTMP_Free(m_rtmp);m_rtmp = NULL;return -1;}int nRead = 0;int bufsize = 1024*1024;char *buf = new char[bufsize];memset(buf,0,bufsize);long countbufsize = 0;m_ftsFlvToStream.Init(bufsize*10);bool bIsOnePackage = false;int  nTagType = 0;int nTimeStamp = 0;int nWriteRawData = 0;int nDiffTimeStamp = 0;bool bFirstTickCount = true;DWORD dwStart = 0;DWORD dwNow = 0;DWORD dwDiffTickCountTmp = 0;int   nTimeSpan = 0;bool bFirstStartTimeStamp = true;int  nStartTimeStampTmp = 0;int  nStopTimeStampTmp = 0;int  nDiffTimeStampTmp = 0;while (IsRunning() && !IsException()){nRead = RTMP_Read(m_rtmp,buf,bufsize);if(nRead == 0 || RTMP_IsTimedout(m_rtmp)){SetException(true);//回调设备状态if(m_pDeviceAnswerCallback != NULL){m_pDeviceAnswerCallback(DVRNetSDK_ErrorCode_Exception,m_nDeviceAnswerUserData1,m_nDeviceAnswerUserData2);}break;}if(bFirstTickCount){dwStart = GetTickCount();dwNow = dwStart;dwDiffTickCountTmp = 0;bFirstTickCount = false;}else{dwNow = GetTickCount();dwDiffTickCountTmp = dwNow - dwStart;}//获取到数据,写入到内存缓冲区nWriteRawData = m_ftsFlvToStream.WriteRawData(buf,nRead);if(nWriteRawData == 2){//空间不够while(true){//循环读数据,解析数据bIsOnePackage = m_ftsFlvToStream.IsOnePackageData();if(bIsOnePackage){//读取数据m_ftsFlvToStream.ReadFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);//解析数据ParseFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);}else{break;}}}else{if(m_ftsFlvToStream.GetBufferEmptySize() >= bufsize){//缓存区有太大多数据,丢弃int nStartTimeStampTmp2 = 0;int nStopTimeStampTmp2 = 0;nDiffTimeStamp = m_ftsFlvToStream.GetDiffTime(nStartTimeStampTmp2,nStopTimeStampTmp2);if(nDiffTimeStamp >= 3000){m_ftsFlvToStream.SkipToLastFrame(0);}else{while(true){//循环读数据,解析数据bIsOnePackage = m_ftsFlvToStream.IsOnePackageData();if(bIsOnePackage){//读取数据m_ftsFlvToStream.ReadFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);//解析数据ParseFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);}else{break;}}}}else{//解析数据bIsOnePackage = m_ftsFlvToStream.IsOnePackageData();if(bIsOnePackage){//读取数据m_ftsFlvToStream.ReadFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);//解析数据ParseFrameData(nTagType,nTimeStamp,m_pTempBuffer,m_nTempBufferSize);}}}if(bFirstStartTimeStamp){nStartTimeStampTmp = 0;nStopTimeStampTmp = 0;nDiffTimeStampTmp = 0;bFirstStartTimeStamp = false;}else{int nStartTimeStampTmp1 = 0;int nStopTimeStampTmp1 = 0;m_ftsFlvToStream.GetDiffTime(nStartTimeStampTmp1,nStopTimeStampTmp1);nStopTimeStampTmp = nStopTimeStampTmp1;nDiffTimeStampTmp = nStopTimeStampTmp - nStartTimeStampTmp;}nTimeSpan = GetTickCount() - dwNow;if(dwDiffTickCountTmp >= (nDiffTimeStampTmp+nTimeSpan)){Sleep(10);}else{Sleep(25);}}//释放空间if(buf != NULL){delete []buf;}if(m_rtmp != NULL){RTMP_DeleteStream(m_rtmp);}//数据解析int ParseFrameData(int nTagType,int nTimeStamp,char * pTempBuffer,int nTempBufferSize){int nFrameType = 0;unsigned char result = 0;unsigned char nAVCPacketType = 0;char *data = NULL;if(m_uPacketStartTimeStamps == 0){m_uPacketStartTimeStamps = nTimeStamp;m_uPacketCurrentTimeStamps = m_uPacketStartTimeStamps;}else{m_uPacketStartTimeStamps = m_uPacketCurrentTimeStamps;m_uPacketCurrentTimeStamps = nTimeStamp;}m_uPacketDiffTimeStamps = m_uPacketCurrentTimeStamps - m_uPacketStartTimeStamps;m_ullStartTimeStamps = m_ullCurrentTimeStamps;m_ullCurrentTimeStamps = RTMP_GetTime();m_ullDiffTimeStamps = m_ullCurrentTimeStamps - m_ullStartTimeStamps;if(nTagType == RTMP_PACKET_TYPE_INFO){int nVideoCodecId = 0;int nVideoWidth = 0;int nVideoHeight = 0;int nVideoFrameRate = 25;int nAudioCodecId = 0;int nAudioSampleRate = 0;int nAudioSampleSize = 0;bool bStereo = false;//立体声int nFileSize = 0;ParseScriptTag(pTempBuffer, nTempBufferSize, nVideoCodecId, nVideoWidth, nVideoHeight, nVideoFrameRate, nAudioCodecId, nAudioSampleRate, nAudioSampleSize, bStereo, nFileSize);m_nImageWidth = nVideoWidth;m_nImageHeight = nVideoHeight;m_nFrameRate = nVideoFrameRate;if(m_nImageWidth != 0 && m_nImageHeight != 0){m_nDelayTime = 15 < 1000.0/m_nFrameRate ? 1000.0/m_nFrameRate:15;//头帧码流回调HeaderFrameStreamCallback();}}else if(nTagType == RTMP_PACKET_TYPE_VIDEO){data = pTempBuffer;result = pTempBuffer[0];nAVCPacketType = pTempBuffer[1];bool bIsKeyFrame = false;nFrameType = 11;if (result == 0x17)//I frame{bIsKeyFrame = true;nFrameType = 10;}else if (result == 0x27){nFrameType = 11;}else{return 0;}if (nAVCPacketType == 0){//AVCsequence header//Access to SPSint spsnum = data[10] & 0x1f;int number_sps = 11;int count_sps = 1;while (count_sps <= spsnum){int spslen = (data[number_sps] & 0x000000FF) << 8 | (data[number_sps + 1] & 0x000000FF);number_sps += 2;memset(m_szSPSData, 0, sizeof(m_szSPSData));memcpy(m_szSPSData, start_code, 4);memcpy(m_szSPSData + 4, data + number_sps, spslen);m_nSPSDataLength = 4 + spslen;memcpy(m_szSPSDataTmp, m_szSPSData, sizeof(m_szSPSData));m_bFindSPSData = true;//如果没有获取图像宽高,帧率if (0 == m_nImageWidth){//分析spsget_bit_context spsRawData;spsRawData.buf = (unsigned char *)m_szSPSDataTmp + 5;spsRawData.buf_size = m_nSPSDataLength - 5;spsRawData.bit_pos = 0;spsRawData.cur_bit_pos = 0;spsRawData.total_bit = 0;int nSpsParseRet = h264dec_seq_parameter_set(&spsRawData, &m_spsFlag);if (0 == nSpsParseRet){//解析成功m_nImageWidth = (m_spsFlag.pic_width_in_mbs_minus1 + 1) * 16;m_nImageHeight = (m_spsFlag.pic_height_in_map_units_minus1 + 1) * 16;m_nFrameRate = m_spsFlag.vui_parameters.time_scale / m_spsFlag.vui_parameters.num_units_in_tick;m_nDelayTime = 15 < 1000.0/m_nFrameRate ? 1000.0/m_nFrameRate:15;//头帧码流回调HeaderFrameStreamCallback();}}number_sps += spslen;count_sps++;}//Get PPSint ppsnum = data[number_sps] & 0x1f;int number_pps = number_sps + 1;int count_pps = 1;while (count_pps <= ppsnum){int ppslen = (data[number_pps] & 0x000000FF) << 8 | data[number_pps + 1] & 0x000000FF;number_pps += 2;memset(m_szPPSData, 0, sizeof(m_szPPSData));memcpy(m_szPPSData, start_code, 4);memcpy(m_szPPSData+4, data + number_pps, ppslen);m_nPPSDataLength = 4 + ppslen;m_bFindPPSData = true;number_pps += ppslen;count_pps++;}}else if (nAVCPacketType == 1){//AVC NALUint len = 0;int num = 5;int nNALVNumbers = 0;while (num < nTempBufferSize){len = (data[num] & 0x000000FF) << 24 | (data[num + 1] & 0x000000FF) << 16 | (data[num + 2] & 0x000000FF) << 8 | data[num + 3] & 0x000000FF;if(len > nTempBufferSize){break;}num += 4;if((len+4+8) >m_nVideoTempBufferSize-1){m_nVideoTempBufferSize = len + 1024*5;delete []m_pVideoTempBuffer;m_pVideoTempBuffer = new char[m_nVideoTempBufferSize];}if(m_pVideoTempBuffer != NULL){//8个字节时间戳unsigned long long ullTimeStamps = 0;if (!m_bSendSPSData && m_bFindSPSData){ullTimeStamps = m_ullBaseTimeStamps + nTimeStamp;memcpy(m_pVideoTempBuffer,&ullTimeStamps,8);m_nVideoTempBufferActualSize = 8;memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,m_szSPSData,m_nSPSDataLength);m_nVideoTempBufferActualSize +=m_nSPSDataLength;if(m_pCallback != NULL){//回调码流//m_pCallback(m_szDeviceID,m_uiChannel,0,0,e_DVRNET_FrameType_Video_IFrame,m_pVideoTempBuffer,m_nVideoTempBufferActualSize,m_uiCallbackUserData1,m_uiCallbackUserData2);}//m_bSendSPSData = true;}if (!m_bSendPPSData && m_bFindPPSData){ullTimeStamps = m_ullBaseTimeStamps + nTimeStamp;memcpy(m_pVideoTempBuffer,&ullTimeStamps,8);m_nVideoTempBufferActualSize = 8;memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,m_szPPSData,m_nPPSDataLength);m_nVideoTempBufferActualSize +=m_nPPSDataLength;if(m_pCallback != NULL){//回调码流//m_pCallback(m_szDeviceID,m_uiChannel,0,0,e_DVRNET_FrameType_Video_IFrame,m_pVideoTempBuffer,m_nVideoTempBufferActualSize,m_uiCallbackUserData1,m_uiCallbackUserData2);}//m_bSendPPSData = true;}//8个字节时间戳/*ullTimeStamps = m_ullBaseTimeStamps + nTimeStamp + nNALVNumbers;memcpy(m_pVideoTempBuffer,&ullTimeStamps,8);m_nVideoTempBufferActualSize = 8;memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,start_code,4);m_nVideoTempBufferActualSize +=4;memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,data + num,len);m_nVideoTempBufferActualSize +=len;*/ullTimeStamps = m_ullBaseTimeStamps + nTimeStamp + nNALVNumbers;memcpy(m_pVideoTempBuffer,&ullTimeStamps,8);m_nVideoTempBufferActualSize = 8;memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,start_code,4);m_nVideoTempBufferActualSize +=4;if (!m_bSendSPSData && m_bFindSPSData){memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,m_szSPSData,m_nSPSDataLength);m_nVideoTempBufferActualSize +=m_nSPSDataLength;m_bSendSPSData = true;}if (!m_bSendPPSData && m_bFindPPSData){memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,m_szPPSData,m_nPPSDataLength);m_nVideoTempBufferActualSize +=m_nPPSDataLength;m_bSendPPSData = true;}memcpy(m_pVideoTempBuffer+m_nVideoTempBufferActualSize,data + num,len);m_nVideoTempBufferActualSize +=len;if(m_pCallback != NULL){//启动缓存区读写线程if(!m_bInitCammPoFrameDataProcess){int nMaxFrameNum = 25;if(m_nFrameRate > 0 && m_nFrameRate < 80){nMaxFrameNum = m_nFrameRate;}m_cfdCammPoFrameDataProcess.Init(Max_Video_Width*Max_Video_Width*5,1000,m_nFrameRate);m_cfdCammPoFrameDataProcess.SetDeviceID(m_szDeviceID);m_cfdCammPoFrameDataProcess.SetChannel(m_uiChannel);m_cfdCammPoFrameDataProcess.SetRealAVStreamDataCallback(m_pCallback,m_uiCallbackUserData1,m_uiCallbackUserData2);m_cfdCammPoFrameDataProcess.StartThread();m_bInitCammPoFrameDataProcess = true;}//回调码流if(m_cfdCammPoFrameDataProcess.RemainWriteFrameNum() > 0){TraceDebug("rtmp client llTimeStampsTmp=%lld,frameType=%d,framenum=%d,frametime=%d\n",ullTimeStamps,nFrameType,m_cfdCammPoFrameDataProcess.RemainWriteFrameNum(),m_cfdCammPoFrameDataProcess.m_fbVideoFrameBuffer.GetBufferFrameTime());if(m_bFindNextIFrame){if(bIsKeyFrame){m_bFindNextIFrame = false;m_cfdCammPoFrameDataProcess.WriteFrameData(nFrameType,(unsigned char *)m_pVideoTempBuffer,m_nVideoTempBufferActualSize);}}else{m_cfdCammPoFrameDataProcess.WriteFrameData(nFrameType,(unsigned char *)m_pVideoTempBuffer,m_nVideoTempBufferActualSize);}}else{m_cfdCammPoFrameDataProcess.m_fbVideoFrameBuffer.ResetToSaveVideoIFrame();m_bFindNextIFrame = true;//Sleep(15);}//m_pCallback(m_szDeviceID,m_uiChannel,0,0,nFrameType,pVideoTempBuffer,nVideoTempBufferActualSize,m_uiCallbackUserData1,m_uiCallbackUserData2);}}num +=len;nNALVNumbers++;}}else if (nAVCPacketType == 2){//AVC end of sequence (lower level NALU sequence ender is not required or supported)}}else if(nTagType == RTMP_PACKET_TYPE_AUDIO){nFrameType = 9;data = pTempBuffer;//判断是否ACC音频同步包,还是ACC原始数据音频包if (!m_bRawAcc && nTempBufferSize>=4){//ACC音频同步包(1bytes+3bytes AccAudioData) (4bytes 包含了AACDecoderSpecific和AudioSpecificConfig)AACDecoderSpecific adsAACDecoderSpecific = { 0 };adsAACDecoderSpecific.nAudioFortmatType = (data[0] & 0xf0) >> 4;//音频编码类型(0:Liner PCM platform endian,1:PCM,2:mp3,4:Nellymoser 16-kHz mono,5:Nellymoser 8-kHz mono,6:Nellymoser,7:G.711 A-law logarithmic PCM,8:G.711 mu-law logarithmic PCM,9:reserved,10:?AAC,14:MP3 8-Khz,15:Device-specific sound)adsAACDecoderSpecific.nAudioSampleType = (data[0] & 0x0c) >> 2;//音频采样率(0:5.5kHz,1:11KHz,2:22 kHz,3:44 kHz)adsAACDecoderSpecific.nAudioSizeType = (data[0] & 0x02) >> 1;//音频采样精度(0:8bits,1:16bits)adsAACDecoderSpecific.nAudioStereo = data[0] & 0x01;//是否立体声(0:sndMono,1:sndStereo)if (adsAACDecoderSpecific.nAudioFortmatType == 10){//The following values are defined://0 = AAC sequence header//1 = AAC rawadsAACDecoderSpecific.nAccPacketType = data[1];unsigned short audioSpecificConfig = 0;audioSpecificConfig = (data[2] & 0xff) << 8;audioSpecificConfig += 0x00ff & data[3];m_ascAudioSpecificConfig.nAudioObjectType = (audioSpecificConfig & 0xF800) >> 11;m_ascAudioSpecificConfig.nSampleFrequencyIndex = (audioSpecificConfig & 0x0780) >> 7;m_ascAudioSpecificConfig.nChannels = (audioSpecificConfig & 0x78) >> 3;m_ascAudioSpecificConfig.nFrameLengthFlag = (audioSpecificConfig & 0x04) >> 2;m_ascAudioSpecificConfig.nDependOnCoreCoder = (audioSpecificConfig & 0x02) >> 1;m_ascAudioSpecificConfig.nExtensionFlag = audioSpecificConfig & 0x01;m_bRawAcc = true;}else if (adsAACDecoderSpecific.nAudioFortmatType == 11){//speex类型数据时,后面的4位数据不起作用,固定的是16KHZ,单声道,16bit/sampleadsAACDecoderSpecific.nAudioStereo = 0;adsAACDecoderSpecific.nAudioSizeType = 1;adsAACDecoderSpecific.nAudioSampleType = 4;m_bRawAcc = true;}}else{//raw data 获取 audio payloadif (nTempBufferSize > 2 && data[1] == 1){//写ADTS数据到文件char szADTSTemp[8] = { 0 };CreateADTS(m_ascAudioSpecificConfig, nTempBufferSize - 2 + 7, szADTSTemp);//转换aac数据到g726memcpy(m_pAccTempBuffer, szADTSTemp, 7);memcpy(m_pAccTempBuffer + 7, pTempBuffer + 2, nTempBufferSize - 2);m_nAccTempBufferSize = 7 + nTempBufferSize - 2;if (!m_bAccObjectInit){m_aacOjbect.init(m_ascAudioSpecificConfig.nAudioObjectType, GetSampleRate(m_ascAudioSpecificConfig.nSampleFrequencyIndex));m_bAccObjectInit = true;}if((m_nPcmLineBufferSize-m_nPcmLineBufferWritePos) <= 4096){//移动数据,pcm缓冲区int kk = 0;for(int k=m_nPcmLineBufferReadPos; k<m_nPcmLineBufferWritePos; k++){m_pPcmLineBuffer[kk] = m_pPcmLineBuffer[k];kk++;}m_nPcmLineBufferReadPos = 0;m_nPcmLineBufferWritePos = kk;}char *pTmp = m_pPcmLineBuffer + m_nPcmLineBufferWritePos;m_nPcmLineBufferActualSize = 0;int nAccConvertResult = m_aacOjbect.convert2PCM((unsigned char *)m_pAccTempBuffer, m_nAccTempBufferSize,(unsigned char *)pTmp, m_nPcmLineBufferActualSize);if(nAccConvertResult == 0){m_nPcmLineBufferWritePos += m_nPcmLineBufferActualSize;//从pcm缓冲区读取数据while((m_nPcmLineBufferWritePos - m_nPcmLineBufferReadPos) >= ONE_PACKET_PCM_DATA_LEN){memcpy(m_ucTempPcmData,m_pPcmLineBuffer+m_nPcmLineBufferReadPos,ONE_PACKET_PCM_DATA_LEN);m_nPcmLineBufferReadPos +=ONE_PACKET_PCM_DATA_LEN;//音频PCM转换G726size_t buf_sizeG726 = 0;nAccConvertResult = m_aacOjbect.Pcm2G726(m_ucTempPcmData,ONE_PACKET_PCM_DATA_LEN,(unsigned char *)m_pG726TempBuffer+8,buf_sizeG726);if(nAccConvertResult == 0){if(m_pCallback != NULL){//8个字节时间戳unsigned long long ullTimeStamps = 0;ullTimeStamps = m_ullBaseTimeStamps + nTimeStamp;memcpy(m_pG726TempBuffer,&ullTimeStamps,8);buf_sizeG726 +=8;//回调码流if(m_bInitCammPoFrameDataProcess){if(m_cfdCammPoFrameDataProcess.RemainWriteFrameNum() > 0){m_cfdCammPoFrameDataProcess.WriteFrameData(nFrameType,(unsigned char *)m_pG726TempBuffer,buf_sizeG726);}}//m_pCallback(m_szDeviceID,m_uiChannel,0,0,nFrameType,m_pG726TempBuffer,buf_sizeG726,m_uiCallbackUserData1,m_uiCallbackUserData2);}}}}}else if (nTempBufferSize > 4 && data[1] == 0){int jjjjj = 0;}}//The actual audio content for the pkt-> m_body+1, size is pkt-> m_nBodySize-1. Here is the voice of Speex code.}return 0;}

       FlvToStream类,FLV内存文件解析类。

      FlvToStream.h

//帧缓冲区#ifndef  __FlvToStream_H__#define  __FlvToStream_H__#pragma once#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>using namespace std;//int h264space = 0x01000000;//H264内容间隔标识00000001#define HTON16(x)  ((x>>8&0xff)|(x<<8&0xff00))#define HTON24(x)  ((x>>16&0xff)|(x<<16&0xff0000)|x&0xff00)#define HTON32(x)  ((x>>24&0xff)|(x>>8&0xff00)|\(x << 8 & 0xff0000) | (x << 24 & 0xff000000))class FlvToStream{public:FlvToStream(void);virtual ~FlvToStream(void);//初始化int Init(int nAllocSize);//反初始化int UnInit();//写数据int WriteRawData(char *pBuffer,int nBufferSize);//是否有一包完整数据bool IsOnePackageData();//读取数据int ReadFrameData(int & nFrameType,int & nTimeStamp,char *pBuffer,int & nBufferSize);/*功能:跳转至最后一帧数据参数:nLastFrameDataType,数据帧类型,0:帧;1:视频主帧;2:视频虚帧;3:音频帧*/void SkipToLastFrame(int nLastFrameDataType);//获取帧数据时间差(总数据差)int  GetDiffTime(int & nStartTimeStamp,int & nStopTimeStamp);//获取剩余空间unsigned int  GetBufferEmptySize();protected://调整位置void Resize();//清除void Clear();//读字节数据bool Read8(int &i8, char *pBuffer);bool Read16(int &i16,char *pBuffer);bool Read24(int &i24, char *pBuffer);bool Read32(int &i32, char *pBuffer);bool ReadTime(int &itime, char *pBuffer);bool Peek8(int &i8, char *pBuffer);bool ReadHead();void VideoParse(int datalength);void AudioParse(int datalength);void MediaInfoParse(int datalength);char *m_pAllocBuffer;unsigned int   m_nAllocBufferSize;unsigned int   m_nAllocBufferEmptySize;unsigned int   m_nReadPos;unsigned int   m_nWritePos;bool  m_bReadFileHeader;bool  m_bPreviousTagSize0Read;char *m_pTempBuffer;//流缓存区unsigned int   m_nTempBufferSize;int  m_nFrameType;int   m_nDateStamp;//FILE *h264file;};#endif
FlvToStream.cpp

#include "stdafx.h"#include "FlvToStream.h"#defineMax_Video_Width1024//视频宽度#defineMax_Video_Height720//视频高度FlvToStream::FlvToStream(void){m_pAllocBuffer = NULL;m_nAllocBufferSize = 0;m_nAllocBufferEmptySize = 0;m_nReadPos = 0;m_nWritePos = 0;m_bReadFileHeader = false;m_bPreviousTagSize0Read = false;m_pTempBuffer = NULL;m_nTempBufferSize = 0;}FlvToStream::~FlvToStream(void){UnInit();}//初始化int FlvToStream::Init(int nAllocSize){m_nAllocBufferSize = nAllocSize;m_nAllocBufferEmptySize = m_nAllocBufferSize;m_nReadPos = 0;m_nWritePos = 0;if(m_pAllocBuffer != NULL){delete []m_pAllocBuffer;}m_pAllocBuffer = new char[m_nAllocBufferSize*1];memset(m_pAllocBuffer,0,sizeof(char)*(m_nAllocBufferSize*1));m_bReadFileHeader = false;m_bPreviousTagSize0Read = false;m_pTempBuffer = new  char[Max_Video_Width * Max_Video_Height+1];m_nTempBufferSize = Max_Video_Width * Max_Video_Height+1;//h264file = fopen("FlvToStream.h264", "wb");return 0;}//反初始化int FlvToStream::UnInit(){if(m_pAllocBuffer != NULL){delete []m_pAllocBuffer;m_pAllocBuffer = NULL;}if(m_pTempBuffer != NULL){delete []m_pTempBuffer;m_pTempBuffer = NULL;}return 0;}//调整位置void FlvToStream::Resize(){int n = 0;for(n=m_nReadPos;n<m_nWritePos;n++){m_pAllocBuffer[n-m_nReadPos] = m_pAllocBuffer[n];}unsigned int nTmp = m_nWritePos-m_nReadPos;m_nReadPos = 0;m_nWritePos = nTmp;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;}//清除void FlvToStream::Clear(){m_nAllocBufferEmptySize = m_nAllocBufferSize;m_nReadPos = 0;m_nWritePos = 0;}//写数据int FlvToStream::WriteRawData(char *pBuffer,int nBufferSize){unsigned int nTmp = m_nWritePos-m_nReadPos;if(nBufferSize > (m_nAllocBufferSize-m_nWritePos)){if(nBufferSize <= (m_nAllocBufferSize - nTmp)){//调整位置(线性缓冲区)Resize();}else{return 2;//空间不够}}if((m_nAllocBufferSize - m_nWritePos) < nBufferSize){return 2;}memcpy(m_pAllocBuffer+m_nWritePos,pBuffer,nBufferSize);m_nWritePos +=nBufferSize;nTmp = m_nWritePos-m_nReadPos;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;return 0;}//读取数据int FlvToStream::ReadFrameData(int & nFrameType,int & nTimeStamp,char *pBuffer,int & nBufferSize){nFrameType = m_nFrameType;nTimeStamp = m_nDateStamp;nBufferSize = m_nTempBufferSize;memcpy(pBuffer,m_pAllocBuffer+m_nReadPos,nBufferSize);//更新位置m_nReadPos = m_nReadPos+nBufferSize+4;//4个字节tag sizeunsigned int nTmp = m_nWritePos-m_nReadPos;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;return 0;}/*功能:跳转至最后一帧数据参数:nLastFrameDataType,数据帧类型,0:帧;1:视频主帧;2:视频虚帧;3:音频帧*/void FlvToStream::SkipToLastFrame(int nLastFrameDataType){int nFrameType = 0;int nTimeStamp = 0;int nBufferSize = 0;unsigned int nTmp = 0;while(true){if(IsOnePackageData()){//读取数据nFrameType = m_nFrameType;nTimeStamp = m_nDateStamp;nBufferSize = m_nTempBufferSize;//更新位置m_nReadPos = m_nReadPos+nBufferSize+4;//4个字节tag sizenTmp = m_nWritePos-m_nReadPos;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;}else{break;}}}//获取帧数据时间差int  FlvToStream::GetDiffTime(int & nStartTimeStamp,int & nStopTimeStamp){unsigned int nReadPosOld = m_nReadPos;unsigned int nWritePosOld = m_nWritePos;bool bReadFileHeaderOld = m_bReadFileHeader;bool bPreviousTagSize0Read = m_bPreviousTagSize0Read;int nFrameType = 0;int nFirstTimeStamp = 0;int nTimeStamp = 0;int nBufferSize = 0;unsigned int nTmp = 0;bool bFirstFrame = false;while(true){if(IsOnePackageData()){//读取数据nFrameType = m_nFrameType;nTimeStamp = m_nDateStamp;nBufferSize = m_nTempBufferSize;if(!bFirstFrame){nFirstTimeStamp = nTimeStamp;nStartTimeStamp = nTimeStamp;nStopTimeStamp = nTimeStamp;bFirstFrame = true;}else{nStopTimeStamp = nTimeStamp;}//更新位置m_nReadPos = m_nReadPos+nBufferSize+4;//4个字节tag sizenTmp = m_nWritePos-m_nReadPos;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;}else{break;}}//恢复位置m_bReadFileHeader = bReadFileHeaderOld;m_bPreviousTagSize0Read =  bPreviousTagSize0Read;m_nReadPos = nReadPosOld;m_nWritePos = nWritePosOld;nTmp = m_nWritePos-m_nReadPos;m_nAllocBufferEmptySize = m_nAllocBufferSize - nTmp;int nDiffTimeStamp = nTimeStamp - nFirstTimeStamp;return nDiffTimeStamp;}//获取剩余空间unsigned int  FlvToStream::GetBufferEmptySize(){return m_nAllocBufferEmptySize;}bool FlvToStream::Read8(int &i8,char *pBuffer){if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 1)return false;memcpy(&i8,m_pAllocBuffer+m_nReadPos,1);m_nReadPos +=1;m_nAllocBufferEmptySize +=1;return true;}bool FlvToStream::Read16(int &i16,char *pBuffer){if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 2)return false;memcpy(&i16,m_pAllocBuffer+m_nReadPos,2);m_nReadPos +=2;m_nAllocBufferEmptySize +=2;i16 = HTON16(i16);return true;}bool FlvToStream::Read24(int &i24,char *pBuffer){if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 3)return false;memcpy(&i24,m_pAllocBuffer+m_nReadPos,3);m_nReadPos +=3;m_nAllocBufferEmptySize +=3;i24 = HTON24(i24);return true;}bool FlvToStream::Read32(int &i32,char *pBuffer){if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 4)return false;memcpy(&i32,m_pAllocBuffer+m_nReadPos,4);m_nReadPos +=4;m_nAllocBufferEmptySize +=4;i32 = HTON32(i32);return true;}bool FlvToStream::Peek8(int &i8,char *pBuffer){if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 1)return false;memcpy(&i8,m_pAllocBuffer+m_nReadPos,1);return true;}bool FlvToStream::ReadTime(int &itime,char *pBuffer){int temp = 0;if(m_nReadPos > m_nWritePos || (m_nWritePos - m_nReadPos) < 4)return false;memcpy(&temp,m_pAllocBuffer+m_nReadPos,4);m_nReadPos +=4;m_nAllocBufferEmptySize +=4;itime = HTON24(temp);itime |= (temp & 0xff000000);return true;}bool FlvToStream::ReadHead(){int headlength = 0;int filetype = 0;unsigned int nReadPosOld = m_nReadPos;unsigned int nAllocBufferEmptySizeOld = m_nAllocBufferEmptySize;if (!Read24(filetype, m_pAllocBuffer))return false;int typel = 'flv';int typeh = 'FLV';if (filetype != typeh && filetype != typel){//printf("not flv file\n");return false;}m_nReadPos +=2;m_nAllocBufferEmptySize +=2;if (!Read32(headlength, m_pAllocBuffer))return false;//printf("headlength:%d\n", headlength);/////////跳过头部长度/////m_nReadPos = nReadPosOld;m_nAllocBufferEmptySize = nAllocBufferEmptySizeOld;m_nReadPos +=headlength;m_nAllocBufferEmptySize +=headlength;return true;}//是否有一包完整数据bool FlvToStream::IsOnePackageData(){//首先读取文件头if(!m_bReadFileHeader){m_bReadFileHeader = ReadHead();if(!m_bReadFileHeader){return false;}}//读取文件数据unsigned int nDataSize = m_nWritePos - m_nReadPos;if(!m_bPreviousTagSize0Read){//读取PriviousTagSize 0    4字节if(nDataSize > 4){m_nReadPos +=4;m_nAllocBufferEmptySize +=4;m_bPreviousTagSize0Read = true;}else{return false;}}//读取Tag1 ... NnDataSize = m_nWritePos - m_nReadPos;if(nDataSize > 11){//读取tag类型,数据区长度,时间戳,时间戳扩展,StreamsID,数据区int type = 0;int time = 0;int htime = 0;int datalength = 0;int info = 0;unsigned int nReadPosOld = m_nReadPos;//char buff[256] = { 0 };if (!Read8(type, m_pAllocBuffer)){m_nReadPos = nReadPosOld;return false;}if (!Read24(datalength, m_pAllocBuffer)){m_nReadPos = nReadPosOld;return false;}if(nDataSize < (datalength+11+4)){m_nReadPos = nReadPosOld;return false;}if (!ReadTime(time, m_pAllocBuffer)){m_nReadPos = nReadPosOld;return false;}m_nFrameType = type;m_nDateStamp = time;m_nTempBufferSize = datalength;////////跳过StreamID////////////////m_nReadPos +=3;m_nAllocBufferEmptySize +=3;if (type == 9){//视频VideoParse(datalength);}else if(type == 8){//音频AudioParse(datalength);}else if(type == 18){//脚本MediaInfoParse(datalength);}else{//保留int jjj = 0;}return true;}else{return false;}}void FlvToStream::AudioParse(int datalength){}void FlvToStream::MediaInfoParse(int datalength){}void FlvToStream::VideoParse(int datelength){/*int h264space = 0x01000000;//H264内容间隔标识00000001unsigned int nReadPosOld = m_nReadPos;int info = 0;Read8(info, m_pAllocBuffer);int avctype = 0;Read8(avctype, m_pAllocBuffer);m_nReadPos +=3;int templength = 0;char*tempbuff = NULL;if (avctype == 0){m_nReadPos +=6;Read16(templength, m_pAllocBuffer);printf("sssize:%d\n", templength);tempbuff = (char*)malloc(templength);//fread(tempbuff, 1, templength, m_pAllocBuffer);memcpy(tempbuff,m_pAllocBuffer+m_nReadPos,templength);m_nReadPos +=templength;fwrite(&h264space, 1, 4, h264file);fwrite(tempbuff, 1, templength, h264file);free(tempbuff);Read8(templength, m_pAllocBuffer);//ppsnumRead16(templength, m_pAllocBuffer);//ppssizeprintf("ppsize:%d\n", templength);tempbuff = (char*)malloc(templength);//fread(tempbuff, 1, templength, flvfile);memcpy(tempbuff,m_pAllocBuffer+m_nReadPos,templength);m_nReadPos +=templength;fwrite(&h264space, 1, 4, h264file);fwrite(tempbuff, 1, templength, h264file);free(tempbuff);}else{//Read32(templength,flvfile);//tempbuff=(char*)malloc(templength);//fread(tempbuff,1,templength,flvfile);//fwrite(&h264space,1,4,h264file);//fwrite(tempbuff,1,templength,h264file);//free(tempbuff);//可能存在多个nal,需全部读取int countsize = 2 + 3;while (countsize<datelength){Read32(templength, m_pAllocBuffer);tempbuff = (char*)malloc(templength);//fread(tempbuff, 1, templength, flvfile);memcpy(tempbuff,m_pAllocBuffer+m_nReadPos,templength);m_nReadPos +=templength;fwrite(&h264space, 1, 4, h264file);fwrite(tempbuff, 1, templength, h264file);free(tempbuff);countsize += (templength + 4);}}m_nReadPos = nReadPosOld;*/}


0 0
原创粉丝点击