下载 >  开发技术 >  C > rtmp源文件代码 rtmp实现代码

rtmp源文件代码 rtmp实现代码

2010-12-27 上传大小:141KB
分享
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
}                        
...展开收缩
综合评分:3
开通VIP 立即下载

评论共有13条

meteorite91 2015-12-21 20:16:33
资料还可以吧
ars_txy 2015-10-21 11:37:35
代码有点用,但是编译不过啊
jackmfq 2015-01-04 13:40:13
资源有点深度,学习中
 

热点文章

VIP会员动态

推荐下载

linux rtmp代码
3C币 256下载
播放rtmp代码
13C币 301下载
rtmp播放器 代码
3C币 108下载
rtmp client 代码
3C币 139下载
rtmp播放代码
13C币 301下载
关闭
img

spring mvc+mybatis+mysql+maven+bootstrap 整合实现增删查改简单实例.zip

资源所需积分/C币 当前拥有积分 当前拥有C币
5 0 0
点击完成任务获取下载码
输入下载码
为了良好体验,不建议使用迅雷下载
img

rtmp源文件代码 rtmp实现代码

会员到期时间: 剩余下载个数: 剩余C币: 剩余积分:0
为了良好体验,不建议使用迅雷下载
VIP下载
您今日下载次数已达上限(为了良好下载体验及使用,每位用户24小时之内最多可下载20个资源)

积分不足!

资源所需积分/C币 当前拥有积分
您可以选择
开通VIP
4000万
程序员的必选
600万
绿色安全资源
现在开通
立省522元
或者
购买C币兑换积分 C币抽奖
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
为了良好体验,不建议使用迅雷下载
确认下载
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 0 0
为了良好体验,不建议使用迅雷下载
开通VIP
img

资源所需积分/C币 当前拥有积分 当前拥有C币
5 4 45
您的积分不足,将扣除 10 C币
为了良好体验,不建议使用迅雷下载
确认下载
下载
无法举报自己的资源

兑换成功

你当前的下载分为234开始下载资源
你还不是VIP会员
开通VIP会员权限,免积分下载
立即开通

你下载资源过于频繁,请输入验证码

您因违反CSDN下载频道规则而被锁定帐户,如有疑问,请联络:webmaster@csdn.net!

举报

若举报审核通过,可返还被扣除的积分

  • 举报人:
  • 被举报人:
  • *类型:
    • *投诉人姓名:
    • *投诉人联系方式:
    • *版权证明:
  • *详细原因: