コード例 #1
0
int main(int argc,char **argv)
{
	int inited;
	State state;

	RTMPHandshake01 s01;
	RTMPHandshake0 s0;
	RTMPHandshake0 c0;
	RTMPHandshake1 s1;
	RTMPHandshake1 c1;
	RTMPHandshake2 s2;
	RTMPHandshake2 c2;

	bool digest;

	DWORD videoCodecs;
	DWORD audioCodecs;

	RTMPChunkBasicHeader header;
	RTMPChunkType0	type0;
	RTMPChunkType1	type1;
	RTMPChunkType2	type2;
	RTMPExtendedTimestamp extts;


	RTMPChunkInputStreams  	chunkInputStreams;
	RTMPChunkOutputStreams  chunkOutputStreams;
	RTMPChunkInputStream* 	chunkInputStream;

	DWORD chunkStreamId;
	DWORD chunkLen;
	DWORD maxChunkSize;

	pthread_t thread;
	pthread_mutex_t mutex;

	RTMPStreams streams;
	DWORD maxStreamId;
	DWORD maxTransId;

	timeval startTime;

	//Set initial state
	state = HEADER_C0_WAIT;
	//Set chunk size
	maxChunkSize = 128;
	//Set first media id
	maxStreamId = 3;

	//Check fd
	if (argc<2)
		return Error("Usage:\n\trmpttest file\n");

	//Open file
	int fd = open(argv[1],O_RDONLY);

	//Check fd
	if (fd==-1)
		return Error("Could not open file [%s]\n",argv[1]);	

	RTMPChunkInputStreams::iterator it;
	int len;

	BYTE data[4096];
	DWORD size;
	
	

	while((size=read(fd,data,4096))>0)
	{
		//Get pointer and data size
		BYTE *buffer = data;
		DWORD bufferSize = size;
		BYTE *i = data;

		//While there is data
		while(bufferSize>0)
		{
			//Store previous buffer pos
			i = buffer;
			//Check connection state
			switch(state)
			{
				case HEADER_C0_WAIT:
					//Parse c0
					len = c0.Parse(buffer,bufferSize);
					//Move
					buffer+=len;
					bufferSize-=len;
					//If it is parsed
					if (c0.IsParsed())
					{
						//Depending on the client version
						if (c0.GetRTMPVersion()!=3)
							throw std::runtime_error("Unsupported Version\n");
						//Move to next state
						state = HEADER_C1_WAIT;
						//Debug
						Log("Received c0 version: %d\n",c0.GetRTMPVersion());
					}
					break;
				case HEADER_C1_WAIT:
					//Parse c1
					len = c1.Parse(buffer,bufferSize);
					//Move
					buffer+=len;
					bufferSize-=len;
					//If it is parsed
					if (c1.IsParsed())
					{
						Log("-Received C1 client version [%d,%d,%d,%d]\n",c1.GetVersion()[0],c1.GetVersion()[1],c1.GetVersion()[2],c1.GetVersion()[2]);
						//Move to next state
						state = HEADER_C2_WAIT;
					}
					break;
				case HEADER_C2_WAIT:
					//Parse c2
					len = c2.Parse(buffer,bufferSize);
					//Move
					buffer+=len;
					bufferSize-=len;
					//If it is parsed
					if (c2.IsParsed())
					{
						//Move to next state
						state = CHUNK_HEADER_WAIT;
						//Debug
						Log("Received c2, sending c2. CONNECTED.\n");
					}
					break;
				case CHUNK_HEADER_WAIT:
					//Parse c2
					len = header.Parse(buffer,bufferSize);
					//Move
					buffer+=len;
					bufferSize-=len;
					//If it is parsed
					if (header.IsParsed())
					{
						//Clean all buffers
						type0.Reset();
						type1.Reset();
						type2.Reset();
						extts.Reset();
						//Move to next state
						state = CHUNK_TYPE_WAIT;
						//Debug
						Log("Received header [fmt:%d,stream:%d,data:0x%x]\n",header.GetFmt(),header.GetStreamId(),header.GetData()[0]);
					}
					break;
				case CHUNK_TYPE_WAIT:
					//Get sream id
					chunkStreamId = header.GetStreamId();
					//Find chunk stream
					it = chunkInputStreams.find(chunkStreamId);
					//Check if we have a new chunk stream or already got one
					if (it==chunkInputStreams.end())
					{
						//Log
						Log("Creating new chunk stream [id:%d]\n",chunkStreamId);
						//Create it
						chunkInputStream = new RTMPChunkInputStream();
						//Append it
						chunkInputStreams[chunkStreamId] = chunkInputStream;	
					} else 
						//Set the stream
						chunkInputStream = it->second;
					//Switch type
					switch(header.GetFmt())
					{
						case 0:
							//Check if the buffer type has been parsed
							len = type0.Parse(buffer,bufferSize);
							//Check if it is parsed
							if (type0.IsParsed())
							{
								Log("Got type 0 header [timestamp:%u,messagelength:%d,type:%d,streamId:%d]\n",type0.GetTimestamp(),type0.GetMessageLength(),type0.GetMessageTypeId(),type0.GetMessageStreamId());
					//			type0.Dump();
								//Set data for stream
								chunkInputStream->SetMessageLength	(type0.GetMessageLength());
								chunkInputStream->SetMessageTypeId	(type0.GetMessageTypeId());
								chunkInputStream->SetMessageStreamId	(type0.GetMessageStreamId());
								//Check if we have extended timestamp
								if (type0.GetTimestamp()!=0xFFFFFF)
								{
									//Set timesptamp
									chunkInputStream->SetTimestamp(type0.GetTimestamp());
									//No timestamp delta
									chunkInputStream->SetTimestampDelta(0);
									//Move to next state
									state = CHUNK_DATA_WAIT;
								} else
									//We have to read 4 more bytes
									state = CHUNK_EXT_TIMESTAMP_WAIT;
								//Start data reception
								chunkInputStream->StartChunkData();
								//Reset sent bytes in buffer
								chunkLen = 0;
							}	
							break;
						case 1:
							//Check if the buffer type has been parsed
							len = type1.Parse(buffer,bufferSize);
							//Check if it is parsed
							if (type1.IsParsed())
							{
								Log("Got type 1 header [timestampDelta:%u,messagelength:%d,type:%d]\n",type1.GetTimestampDelta(),type1.GetMessageLength(),type1.GetMessageTypeId());
								//type1.Dump();
								//Set data for stream
								chunkInputStream->SetMessageLength(type1.GetMessageLength());
								chunkInputStream->SetMessageTypeId(type1.GetMessageTypeId());
								//Check if we have extended timestam
								if (type1.GetTimestampDelta()!=0xFFFFFF)
								{
									//Set timestamp delta
									chunkInputStream->SetTimestampDelta(type1.GetTimestampDelta());
									//Set timestamp
									chunkInputStream->IncreaseTimestampWithDelta();
									//Move to next state
									state = CHUNK_DATA_WAIT;
								} else
									//We have to read 4 more bytes
									state = CHUNK_EXT_TIMESTAMP_WAIT;
								//Start data reception
								chunkInputStream->StartChunkData();
								//Reset sent bytes in buffer
								chunkLen = 0;
							}	
							break;
						case 2:
							//Check if the buffer type has been parsed
							len = type2.Parse(buffer,bufferSize);
							//Check if it is parsed
							if (type2.IsParsed())
							{
								Log("Got type 2 header [timestampDelta:%u]\n",type2.GetTimestampDelta());
								//type2.Dump();
								//Check if we have extended timestam
								if (type2.GetTimestampDelta()!=0xFFFFFF)
								{
									//Set timestamp delta
									chunkInputStream->SetTimestampDelta(type2.GetTimestampDelta());
									//Increase timestamp
									chunkInputStream->IncreaseTimestampWithDelta();
									//Move to next state
									state = CHUNK_DATA_WAIT;
								} else
									//We have to read 4 more bytes
									state = CHUNK_EXT_TIMESTAMP_WAIT;
								//Start data reception
								chunkInputStream->StartChunkData();
								//Reset sent bytes in buffer
								chunkLen = 0;
							}	
							break;
						case 3:
							//No header chunck
							len = 0;
							//Increase timestamp with previous delta
							chunkInputStream->IncreaseTimestampWithDelta();
							//Start data reception
							chunkInputStream->StartChunkData();
							//Move to next state
							state = CHUNK_DATA_WAIT;
							//Reset sent bytes in buffer
							chunkLen = 0;
							break;
					}
					//Move pointer
					buffer += len;
					bufferSize -= len;
					break;
				case CHUNK_EXT_TIMESTAMP_WAIT:
					//Parse extended timestamp
					len = extts.Parse(buffer,bufferSize);
					//Move
					buffer+=len;
					bufferSize-=len;
					//If it is parsed
					if (extts.IsParsed())
					{
						//Check header type
						if (header.GetFmt()==1)
						{
							//Set the timestamp
							chunkInputStream->SetTimestamp(extts.GetTimestamp());
							//No timestamp delta
							chunkInputStream->SetTimestampDelta(0);
						} else {
							//Set timestamp delta
							chunkInputStream->SetTimestampDelta(extts.GetTimestamp());
							//Increase timestamp
							chunkInputStream->IncreaseTimestampWithDelta();
						}
						//Move to next state
						state = CHUNK_DATA_WAIT;
					}
					break;
				case CHUNK_DATA_WAIT:
					//Check max buffer size
					if (maxChunkSize && chunkLen+bufferSize>maxChunkSize)
					//Parse only max chunk size
						len = maxChunkSize-chunkLen;
				else
					//parse all data
						len = bufferSize;
				//Check size
				if (!len)
				{
					//Debug
					Error("Chunk data of size zero  [maxChunkSize:%d,chunkLen:%d]\n");
					//Skip
					break;
					}
					//Parse data
					len = chunkInputStream->Parse(buffer,len);
					//Check if it has parsed a msg
					if (chunkInputStream->IsParsed())
					{
						//Get message
						RTMPMessage* msg = chunkInputStream->GetMessage();
						//Get message stream
						DWORD messageStreamId = msg->GetStreamId();
						//Get message type
						BYTE type = msg->GetType();
						Log("Got message [timestamp:%llu,type:%d,stream:%d]\n",chunkInputStream->GetTimestamp(),type,messageStreamId);
						//Check message type
						if (msg->IsControlProtocolMessage())
						{
							RTMPUserControlMessage *event;
							//Get control protocl message
							RTMPObject* ctrl = msg->GetControlProtocolMessage();

							//Check type
							switch((RTMPMessage::Type)msg->GetType())
							{
								case RTMPMessage::SetChunkSize:
									//Get new chunk size
									maxChunkSize = ((RTMPSetChunkSize *)ctrl)->GetChunkSize();
									Log("SetChunkSize [size:%d]\n",maxChunkSize);
									break;
								case RTMPMessage:: AbortMessage:
									Log("AbortMessage [chunkId:%d]\n",((RTMPAbortMessage*)ctrl)->GetChunkStreamId());
									break;
								case RTMPMessage::Acknowledgement:
									Log("Acknowledgement [seq:%d]\n",((RTMPAcknowledgement*)ctrl)->GetSeNumber());
									break;
								case RTMPMessage::UserControlMessage:
									//Get event
									event = (RTMPUserControlMessage*)ctrl;
									event->Dump();
									Log("UC [%d]\n",event->GetEventType());
									//Depending on the event received
									switch(event->GetEventType())
									{
										case RTMPUserControlMessage::StreamBegin:
											Log("StreamBegin [stream:%d]\n",event->GetEventData());
											break;
										case RTMPUserControlMessage::StreamEOF:
											Log("StreamEOF [stream:%d]\n",event->GetEventData());
											break;
										case RTMPUserControlMessage::StreamDry:
											Log("StreamDry [stream:%d]\n",event->GetEventData());
											break;
										case RTMPUserControlMessage::SetBufferLength:
											Log("SetBufferLength [stream:%d,size:%d]\n",event->GetEventData(),event->GetEventData2());
											break;
										case RTMPUserControlMessage::StreamIsRecorded:
											Log("StreamIsRecorded [stream:%d]\n",event->GetEventData());
											break;
										case RTMPUserControlMessage::PingRequest:
											Log("PingRequest [milis:%d]\n",event->GetEventData());
											break;
										case RTMPUserControlMessage::PingResponse:
											Log("PingResponse [milis:%d]\n",event->GetEventData());
											break;
										
									}
									break;
								case RTMPMessage::WindowAcknowledgementSize:
									Log("WindowAcknowledgementSize [size:%d]\n",((RTMPWindowAcknowledgementSize*)ctrl)->GetWindowSize());
									break;
								case RTMPMessage::SetPeerBandwidth:
									Log("SetPeerBandwidth [size:%d]\n",((RTMPSetPeerBandWidth*)ctrl)->GetWindowSize());
									break;
							}

						} else if (msg->IsCommandMessage()) {
							//Get Command message
							RTMPCommandMessage* cmd = msg->GetCommandMessage();
							//Dump msg
							cmd->Dump();
						} else if (msg->IsMedia()) {
							//Get media frame
							RTMPMediaFrame* frame = msg->GetMediaFrame();
							//Check frame
							if (!frame)
								continue;
							switch (frame->GetType())
							{
								case RTMPMediaFrame::Audio:
								{
									//Audio
									RTMPAudioFrame *audio = (RTMPAudioFrame *)frame;
									//Log
									Log("Audio frame [codec:%d,timestamp:%lld]\n",audio->GetAudioCodec(),audio->GetTimestamp());
									break;
								}
								case RTMPMediaFrame::Video:
								{
									//Video
									RTMPVideoFrame *video = (RTMPVideoFrame *)frame;
									//Log
									Log("Video frame [codec:%d,timestamp:%lld]\n",video->GetVideoCodec(),video->GetTimestamp());
									break;
								}
							}
						} else if (msg->IsMetaData() || msg->IsSharedObject()) {
							//Get object
							RTMPMetaData *meta = msg->GetMetaData();
							//Debug it
							meta->Dump();
						} else {
							//UUh??
							Error("Unknown rtmp message, should never happen\n");
						}
						//Delete msg
						delete(msg);
						//Move to next chunck
						state = CHUNK_HEADER_WAIT;	
						//Clean header
						header.Reset();
					}
					//Increase buffer length
					chunkLen += len;
					//Move pointer
					buffer += len;
					bufferSize -= len;
					break;
			}
			//Dump consumed data
			//Dump(i,buffer-i);
		}

	}
}
コード例 #2
0
ファイル: mediabridgesession.cpp プロジェクト: crubia/wt
int MediaBridgeSession::SendVideo()
{
	VideoDecoder *decoder = VideoCodecFactory::CreateDecoder(VideoCodec::SORENSON);
	VideoEncoder *encoder = VideoCodecFactory::CreateEncoder(rtpVideoCodec);
	DWORD width = 0;
	DWORD height = 0;
	DWORD numpixels = 0;

	QWORD	lastVideoTs = 0;

	Log(">SendVideo\n");

	//Set video format
	if (!rtpVideo.SetSendingCodec(rtpVideoCodec))
		//Error
		return Error("Peer do not support [%d,%s]\n",rtpVideoCodec,VideoCodec::GetNameFor(rtpVideoCodec));

	//While sending video
	while (sendingVideo)
	{
		//Wait for next video
		if (!videoFrames.Wait(0))
			//Check again
			continue;

		//Get audio grame
		RTMPVideoFrame* video = videoFrames.Pop();
		//check
		if (!video)
			//Again
			continue;

		//Get time difference
		DWORD diff = 0;
		//Get timestam
		QWORD ts = video->GetTimestamp();
		//If it is not the first frame
		if (lastVideoTs)
			//Calculate it
			diff = ts - lastVideoTs;
		//Set the last audio timestamp
		lastVideoTs = ts;

		//Check
		if (video->GetVideoCodec()!=RTMPVideoFrame::FLV1)
			//Error
			continue;

		//Decode frame
		if (!decoder->Decode(video->GetMediaData(),video->GetMediaSize()))
		{
			Error("decode packet error");
			//Next
			continue;
		}

		//Check size
		if (decoder->GetWidth()!=width || decoder->GetHeight()!=height)
		{
			//Get dimension
			width = decoder->GetWidth();
			height = decoder->GetHeight();

			//Set size
			numpixels = width*height*3/2;

			//Set also frame rate and bps
			encoder->SetFrameRate(25,300,500);

			//Set them in the encoder
			encoder->SetSize(width,height);
		}
		//Check size
		if (!numpixels)
		{
			Error("numpixels equals 0");
			//Next
			continue;
		}
		//Check fpu
		if (sendFPU)
		{
			//Send it
			encoder->FastPictureUpdate();
			//Reset
			sendFPU = false;
		}

		//Encode it
		VideoFrame *videoFrame = encoder->EncodeFrame(decoder->GetFrame(),numpixels);

		//If was failed
		if (!videoFrame)
		{
			Log("No video frame\n");
			//Next
			continue;
		}

		//Set frame time
		videoFrame->SetTimestamp(diff);

		//Send it smoothly
		smoother.SendFrame(videoFrame,diff);

		//Delete video frame
		delete(video);
	}

	Log("<SendVideo\n");

	return 1;
}
コード例 #3
0
void RTMPMP4Stream::onMediaFrame(MediaFrame &media)
{
	//Depending on the media type
	switch (media.GetType())
	{
		case MediaFrame::Audio:
		{
			//Create rtmp frame
			RTMPAudioFrame *frame = new RTMPAudioFrame(0,512);
			//Get audio frame
			AudioFrame& audio = (AudioFrame&)media;
			//Check codec
			switch(audio.GetCodec())
			{
				case AudioCodec::PCMA:
				case AudioCodec::PCMU:
				{
					WORD raw[512];
					DWORD rawsize = 512;
					//Decode audio frame
					DWORD rawlen = decoder->Decode(audio.GetData(),audio.GetLength(),raw,rawsize);
					//Encode frame
					DWORD len = encoder->Encode(raw,rawlen,frame->GetMediaData(),frame->GetMaxMediaSize());
					//Set length
					frame->SetMediaSize(len);
					//Set type
					frame->SetAudioCodec(RTMPAudioFrame::SPEEX);
					frame->SetSoundRate(RTMPAudioFrame::RATE11khz);
					frame->SetSamples16Bits(1);
					frame->SetStereo(0);
					//Set timestamp
					frame->SetTimestamp(audio.GetTimeStamp()/8);
					break;
				}
				default:
					//Not supported
					return;
			}
			//Send it
			PlayMediaFrame(frame);
		}
		break;
		case MediaFrame::Video:
		{
			//Get video frame
			VideoFrame& video = (VideoFrame&)media;
			//Create rtmp frame
			RTMPVideoFrame *frame = new RTMPVideoFrame(video.GetTimeStamp()/90,video.GetLength());
			//Check codec
			switch(video.GetCodec())
			{
				case VideoCodec::H263_1996:
				case VideoCodec::H263_1998:
				#ifdef FLV1PARSER
				{
					//Create FLV1parser in case we need it
					flv1Parser *parser = new flv1Parser(frame->GetMediaData(),frame->GetMaxMediaSize());
					//Proccess
					if (!parser->FrameFromH263(video.GetData(),video.GetLength()))
						throw new std::exception();
					//Set lengtht
					frame->SetMediaSize(parser->GetSize());
					//If it is intra
					if (video.IsIntra())
						//Set type
						frame->SetFrameType(RTMPVideoFrame::INTRA);
					else
						//Set type
						frame->SetFrameType(RTMPVideoFrame::INTER);
					//Set type
					frame->SetVideoCodec(RTMPVideoFrame::FLV1);
				}
				#endif
					break;
				case VideoCodec::H264:
				{
					//Set Codec
					frame->SetVideoCodec(RTMPVideoFrame::AVC);
					//If it is intra
					if (video.IsIntra())
					{
						//Set type
						frame->SetFrameType(RTMPVideoFrame::INTRA);
						//If we have one
						if (desc)
						{
							//Create the fraame
							RTMPVideoFrame fdesc(frame->GetTimestamp(),desc);
							//Play it
							PlayMediaFrame(&fdesc);
						}
					} else {
						//Set type
						frame->SetFrameType(RTMPVideoFrame::INTER);
					}
					//Set NALU type
					frame->SetAVCType(1);
					//Set no delay
					frame->SetAVCTS(0);
					//Set Data
					frame->SetVideoFrame(video.GetData(),video.GetLength());
					break;
				}
				default:
					//Not supported
					return;
			}
			//Send it
			PlayMediaFrame(frame);
			//Delete it
			delete(frame);
		}
		break;
	}
}