开发工具:
文件大小: 141kb
下载次数: 0
上传时间: 2010-12-27
详细说明: int WriteStream( CRTMP* rtmp, char **buf, // target pointer, maybe preallocated unsigned int len, // length of buffer if preallocated uint32_t *tsm, // pointer to timestamp, will contain timestamp of last video packet returned bool bNoHeader, // resuming mode, will not write FLV header and compare metaHeader and first kexframe char *metaHeader, // pointer to meta header (if bNoHeader == TRUE) uint32_t nMetaHeaderSize, // length of meta header, if zero meta header check omitted (if bNoHeader == TRUE) c har *initialFrame, // pointer to initial keyframe (no FLV header or tagSize, raw data) (if bNoHeader == TRUE) uint8_t initialFrameType, // initial frame type (audio or video) uint32_t nInitialFrameSize, // length of initial frame in bytes, if zero initial frame check omitted (if bNoHeader == TRUE) uint8_t *dataType // whenever we get a video/audio packet we set an appropriate flag here, this will be later written to the FLV header ) { char flvHeader[] = { 'F', 'L', 'V', 0x01, 0x00,//5, // video + audio 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00 // first prevTagSize=0 }; static bool bStopIgnoring = false; static bool bSentHeader = false; static bool bFoundKeyframe = false; static bool bFoundFlvKeyframe = false; uint32_t prevTagSize = 0; RTMPPacket packet; if(rtmp->GetNextMediaPacket(packet)) { char *packetBody = packet.m_body; unsigned int nPacketLen = packet.m_nBodySize; // skip video info/command packets if(packet.m_packetType == 0x09 && nPacketLen == 2 && ((*packetBody & 0xf0) == 0x50)) { return 0; } if(packet.m_packetType == 0x09 && nPacketLen <= 5) { Log(LOGWARNING, "ignoring too small video packet: size: %d", nPacketLen); return 0; } if(packet.m_packetType == 0x08 && nPacketLen <= 1) { Log(LOGWARNING, "ignoring too small audio packet: size: %d", nPacketLen); return 0; } #ifdef _DEBUG debugTS += packet.m_nInfoField1; Log(LOGDEBUG, "type: %02X, size: %d, TS: %d ms, sent TS: %d ms", packet.m_packetType, nPacketLen, debugTS, packet.m_nInfoField1); if(packet.m_packetType == 0x09) Log(LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0)); #endif // check the header if we get one if(bNoHeader && packet.m_nInfoField1 == 0) { if(nMetaHeaderSize > 0 && packet.m_packetType == 0x12) { RTMP_LIB::AMFObject metaObj; int nRes = metaObj.Decode(packetBody, nPacketLen); if(nRes >= 0) { std::string metastring = metaObj.GetProperty(0).GetString(); if(metastring == "onMetaData") { // comapre if((nMetaHeaderSize != nPacketLen) || (memcmp(metaHeader, packetBody, nMetaHeaderSize) != 0)) { return -2; } } } } // check first keyframe to make sure we got the right position in the stream! // (the first non ignored frame) if(nInitialFrameSize > 0) { // video or audio data if(packet.m_packetType == initialFrameType && nInitialFrameSize == nPacketLen) { // we don't compare the sizes since the packet can contain several FLV packets, just make // sure the first frame is our keyframe (which we are going to rewrite) if(memcmp(initialFrame, packetBody, nInitialFrameSize) == 0) { Log(LOGDEBUG, "Checked keyframe successfully!"); bFoundKeyframe = true; return 0; // ignore it! (what about audio data after it? it is handled by ignoring all 0ms frames, see below) } } // hande FLV streams, even though the server resends the keyframe as an extra video packet // it is also included in the first FLV stream chunk and we have to compare it and // filter it out !! // if(packet.m_packetType == 0x16) { // basically we have to find the keyframe with the correct TS being nTimeStamp unsigned int pos=0; uint32_t ts = 0; while(pos+11 < nPacketLen) { uint32_t dataSize = CRTMP::ReadInt24(packetBody+pos+1); // size without header (11) and prevTagSize (4) ts = CRTMP::ReadInt24(packetBody+pos+4); ts |= (packetBody[pos+7]<<24); #ifdef _DEBUG Log(LOGDEBUG, "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms", packetBody[pos], dataSize, ts); #endif // ok, is it a keyframe!!!: well doesn't work for audio! if(packetBody[0] == initialFrameType /* && (packetBody[11]&0xf0) == 0x10*/) { if(ts == nTimeStamp) { Log(LOGDEBUG, "Found keyframe with resume-keyframe timestamp!"); if(nInitialFrameSize != dataSize || memcmp(initialFrame, packetBody+pos+11, nInitialFrameSize) != 0) { Log(LOGERROR, "FLV Stream: Keyframe doesn't match!"); return -2; } bFoundFlvKeyframe = true; // ok, skip this packet // check whether skipable: if(pos+11+dataSize+4 > nPacketLen) { Log(LOGWARNING, "Non skipable packet since it doesn't end with chunk, stream corrupt!"); return -2; } packetBody += (pos+11+dataSize+4); nPacketLen -= (pos+11+dataSize+4); goto stopKeyframeSearch; } else if(nTimeStamp < ts) { goto stopKeyframeSearch; // the timestamp ts will only increase with further packets, wait for seek } } pos += (11+dataSize+4); } if(ts < nTimeStamp) { Log(LOGERROR, "First packet does not contain keyframe, all timestamps are smaller than the keyframe timestamp, so probably the resume seek failed?"); } stopKeyframeSearch: ; //* if(!bFoundFlvKeyframe) { Log(LOGERROR, "Couldn't find the seeked keyframe in this chunk!"); return 0;//-2; }//*/ } } } if(bNoHeader && packet.m_nInfoField1 > 0 && (bFoundFlvKeyframe || bFoundKeyframe)) { // another problem is that the server can actually change from 09/08 video/audio packets to an FLV stream // or vice versa and our keyframe check will prevent us from going along with the new stream if we resumed // // in this case set the 'found keyframe' variables to true // We assume that if we found one keyframe somewhere and were already beyond TS > 0 we have written // data to the output which means we can accept all forthcoming data inclusing the change between 08/09 <-> FLV // packets bFoundFlvKeyframe = true; bFoundKeyframe = true; } // skip till we find out keyframe (seeking might put us somewhere before it) if(bNoHeader && !bFoundKeyframe && packet.m_packetType != 0x16) { Log(LOGWARNING, "Stream does not start with requested frame, ignoring data... "); nIgnoredFrameCounter++; if(nIgnoredFrameCounter > MAX_IGNORED_FRAMES) return -2; return 0; } // ok, do the same for FLV streams if(bNoHeader && !bFoundFlvKeyframe && packet.m_packetType == 0x16) { Log(LOGWARNING, "Stream does not start with requested FLV frame, ignoring data... "); nIgnoredFlvFrameCounter++; if(nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES) return -2; return 0; } // if bNoHeader, we continue a stream, we have to ignore the 0ms frames since these are the first keyframes, we've got these // so don't mess around with multiple copies sent by the server to us! (if the keyframe is found at a later position // there is only one copy and it will be ignored by the preceding if clause) if(!bStopIgnoring && bNoHeader && packet.m_packetType != 0x16) { // exclude type 0x16 (FLV) since it can conatin several FLV packets if(packet.m_nInfoField1 == 0) { return 0; } else { bStopIgnoring = true; // stop ignoring packets } } // calculate packet size and reallocate buffer if necessary unsigned int size = nPacketLen + ((bSentHeader || bNoHeader) ? 0 : sizeof(flvHeader)) + ((packet.m_packetType == 0x08 || packet.m_packetType == 0x09 || packet.m_packetType == 0x12) ? 11 : 0) + (packet.m_packetType != 0x16 ? 4 : 0); if(size+4 > len) { // the extra 4 is for the case of an FLV stream without a last prevTagSize (we need extra 4 bytes to append it) *buf = (char *)realloc(*buf, size+4); if(*buf == 0) { Log(LOGERROR, "Couldn't reallocate memory!"); return -1; // fatal error } } char *ptr = *buf; if(!bSentHeader && !bNoHeader) { memcpy(ptr, flvHeader, sizeof(flvHeader)); ptr+=sizeof(flvHeader); bSentHeader = true; } // audio (0x08), video (0x09) or metadata (0x12) packets : // construct 11 byte header then add rtmp packet's data if(packet.m_packetType == 0x08 || packet.m_packetType == 0x09 || packet.m_packetType == 0x12) { // set data type *dataType |= (((packet.m_packetType == 0x08)<<2)|(packet.m_packetType == 0x09)); nTimeStamp += packet.m_nInfoField1; prevTagSize = 11 + nPacketLen; //nTimeStamp += packet.m_nInfoField1; //Log(LOGDEBUG, "%02X: Added TS: %d ms, TS: %d", packet.m_packetType, packet.m_nInfoField1, nTimeStamp); *ptr = packet.m_packetType; ptr++; ptr += CRTMP::EncodeInt24(ptr, nPacketLen); /*if(packet.m_packetType == 0x09) { // video // H264 fix: if((packetBody[0] & 0x0f) == 7) { // CodecId = H264 uint8_t packetType = *(packetBody+1); uint32_t ts = CRTMP::ReadInt24(packetBody+2); // composition time int32_t cts = (ts+0xff800000)^0xff800000; Log(LOGDEBUG, "cts : %d\n", cts); nTimeStamp -= cts; // get rid of the composition time CRTMP::EncodeInt24(packetBody+2, 0); } Log(LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp); }*/ ptr += CRTMP::EncodeInt24(ptr, nTimeStamp); *ptr = (char)((nTimeStamp & 0xFF000000) >> 24); ptr++; // stream id ptr += CRTMP::EncodeInt24(ptr, 0); } memcpy(ptr, packetBody, nPacketLen); unsigned int len = nPacketLen; // correct tagSize and obtain timestamp if we have an FLV stream if(packet.m_packetType == 0x16) { unsigned int pos=0; while(pos+11 < nPacketLen) { uint32_t dataSize = CRTMP::ReadInt24(packetBody+pos+1); // size without header (11) or prevTagSize (4) nTimeStamp = CRTMP::ReadInt24(packetBody+pos+4); nTimeStamp |= (packetBody[pos+7]<<24); // set data type *dataType |= (((*(packetBody+pos) == 0x08)<<2)|(*(packetBody+pos) == 0x09)); if(pos+11+dataSize+4 > nPacketLen) { Log(LOGWARNING, "No tagSize found, appending!"); // we have to append a last tagSize! prevTagSize = dataSize+11; CRTMP::EncodeInt32(ptr+pos+11+dataSize, prevTagSize); size+=4; len+=4; } else { prevTagSize = CRTMP::ReadInt32(packetBody+pos+11+dataSize); #ifdef _DEBUG Log(LOGDEBUG, "FLV Packet: type %02X, dataSize: %d, tagSize: %d, timeStamp: %d ms", packetBody[pos], dataSize, prevTagSize, nTimeStamp); #endif if(prevTagSize != (dataSize+11)) { #ifdef _DEBUG Log(LOGWARNING, "tag size and data size are not consitent, writing tag size according to data size %d", dataSize+11); #endif prevTagSize = dataSize+11; CRTMP::EncodeInt32(ptr+pos+11+dataSize, prevTagSize); } } pos += (11+dataSize+4); } } ptr += len; if(packet.m_packetType != 0x16) { // FLV tag packets contain their own prevTagSize CRTMP::EncodeInt32(ptr, prevTagSize); //ptr += 4; } if(tsm) *tsm = nTimeStamp; return size; } return -1; // no more media packets } ...展开收缩
(系统自动生成,下载前可以参看下载内容)
下载文件列表
相关说明
- 本站资源为会员上传分享交流与学习,如有侵犯您的权益,请联系我们删除.
- 本站是交换下载平台,提供交流渠道,下载内容来自于网络,除下载问题外,其它问题请自行百度。
- 本站已设置防盗链,请勿用迅雷、QQ旋风等多线程下载软件下载资源,下载后用WinRAR最新版进行解压.
- 如果您发现内容无法下载,请稍后再次尝试;或者到消费记录里找到下载记录反馈给我们.
- 下载后发现下载的内容跟说明不相乎,请到消费记录里找到下载记录反馈给我们,经确认后退回积分.
- 如下载前有疑问,可以通过点击"提供者"的名字,查看对方的联系方式,联系对方咨询.