/// <summary> /// Sends the flv tag to the RTMP server. /// </summary> /// <param name="tagData"></param> /// <param name="tag"></param> public override bool sendFLVTag(byte[] tagData, FLVTag tag) { if (!isConnected) { return(false); } outputBuff.Position = 0; chunkBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x8); header.RTMPType = AMFHeader.RTMP_TYPE_VIDEO; header.TimeStamp = tag.TimeStamp; header.EndPoint = 0x00000001; header.BodySize = tag.getTagSizeInBytes() - 11; //write the header to teh chunkbuffer header.writeHeader(chunkBuff); //the size remaining in the data buffer int size = tag.getTagSizeInBytes() - 11; //the position in the data buffer (from which to start sending bytes) int position = 0; //write the header to the chunk buffer header.writeHeader(chunkBuff); //copy <= 128 bytes from the tagData into the chunk buffer to send. Array.Copy(tagData, 11, chunk_buffer, header.getHeaderSize(), size > 128 ? 128 : size); //send the first packet of information connectionSocket.Send(chunk_buffer, (header.getHeaderSize() + (size > 128 ? 128 : size)), SocketFlags.None); size -= 128; position += 128 + 11; //while there is still bytes while (size > 0) { //add a header byte byte t = tagData[position - 1]; tagData[position - 1] = header.get_1_HeaderByte(); //send out the data connectionSocket.Send(tagData, position - 1, size > 128 ? 129 : size + 1, SocketFlags.None); //restore where the header was tagData[position - 1] = t; position += 128; size -= 128; } return(true); }
/// <summary> /// Sends the flv tag to the RTMP server. /// </summary> /// <param name="tagData"></param> /// <param name="tag"></param> public override bool sendFLVTag(byte[] tagData, FLVTag tag) { if (!isConnected) return false; outputBuff.Position = 0; chunkBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x8); header.RTMPType = AMFHeader.RTMP_TYPE_VIDEO; header.TimeStamp = tag.TimeStamp; header.EndPoint = 0x00000001; header.BodySize = tag.getTagSizeInBytes() - 11; //write the header to teh chunkbuffer header.writeHeader(chunkBuff); //the size remaining in the data buffer int size = tag.getTagSizeInBytes() - 11; //the position in the data buffer (from which to start sending bytes) int position = 0; //write the header to the chunk buffer header.writeHeader(chunkBuff); //copy <= 128 bytes from the tagData into the chunk buffer to send. Array.Copy(tagData, 11, chunk_buffer, header.getHeaderSize(), size > 128 ? 128 : size); //send the first packet of information connectionSocket.Send(chunk_buffer, (header.getHeaderSize() + (size > 128 ? 128 : size)), SocketFlags.None); size -= 128; position += 128 + 11; //while there is still bytes while (size > 0) { //add a header byte byte t = tagData[position - 1]; tagData[position - 1] = header.get_1_HeaderByte(); //send out the data connectionSocket.Send(tagData, position - 1, size > 128 ? 129 : size + 1, SocketFlags.None); //restore where the header was tagData[position - 1] = t; position += 128; size -= 128; } return true; }
/// <summary> /// Appends another frame / or tag to the current FLV file. Instead of using /// built in timing mechanisms within the class itself, a timestamp value /// can be used to override the "pre calculated" time stamp. /// </summary> /// <param name="frame">A raw array of pixel data to encode.</param> /// <param name="timestamp">The time at which this frame will apply.</param> /// <returns>The time in ms to encode the frame, or -1 if an error occured.</returns> public double EncodeFrame(byte[] frame, long timestamp) { if ((!streamFile && !streamLive) && !encodeInProgress) { return(-1); } //make sure the buffer represents the "supposed" video dimensions //if its too small, return an error if (frame.Length < par.VideoHeight * par.VideoWidth * par.SourceBytesPerPixel) { return(-1); } //record the time at the "start" of encoding of this frame double start = timer.Duration; //reset the buffer memoryStream.Position = 0; bool isKeyFrame = false; //determine whether or not to send a key frame if (frameCount == 0) //if this is the first frame { isKeyFrame = true; } //if the duration has passed the frame frequency if (timestamp - lastKeyFrameTime > par.KeyFrameFrequency * 1000) { isKeyFrame = true; lastKeyFrameTime = (int)timestamp; System.GC.Collect(); } //set up the new tag tag = new FLVTag(FLVTag.TAGTYPE_VIDEO, frame, this.previousFrame, (frameCount > 0) ? (int)timestamp : 0, par.VideoWidth, par.VideoHeight, srcBlockBuffer, destBlockBuffer, isKeyFrame, par.CompressionLevel, par.SourceBytesPerPixel); //write the tag to the inmemory buffer (faster seeks) tag.writeTag(memoryStream); //get the size of the tag int tagSize = tag.getTagSizeInBytes(); //write the tag in memory out to file //and only if information is changed (no point writing an empty frame and //wasting space) if (tag.isFrameDirty()) { if (streamFile) { output.Write(buffer, 0, (int)memoryStream.Position); this.output.WriteByte((byte)(tagSize >> 24)); this.output.WriteByte((byte)(tagSize >> 16)); this.output.WriteByte((byte)(tagSize >> 8)); this.output.WriteByte((byte)(tagSize)); this.output.Flush(); } if (streamLive) { try { client.sendFLVTag(buffer, tag); //dont need the size } catch (Exception e) { this.streamLive = false; throw e; } } } //increment the frame counter frameCount++; //store the frame for comparison this.previousFrame = frame; //store the timestamp of this encoded frame this.lastTimeStamp = timestamp; //return the duration of of the this frame's encode time return(timer.Duration - start); }
/// <summary> /// Appends another frame / or tag to the current FLV file. Instead of using /// built in timing mechanisms within the class itself, a timestamp value /// can be used to override the "pre calculated" time stamp. /// </summary> /// <param name="frame">A raw array of pixel data to encode.</param> /// <param name="timestamp">The time at which this frame will apply.</param> /// <returns>The time in ms to encode the frame, or -1 if an error occured.</returns> public double EncodeFrame(byte[] frame, long timestamp) { if ((!streamFile && !streamLive) && !encodeInProgress) { return -1; } //make sure the buffer represents the "supposed" video dimensions //if its too small, return an error if (frame.Length < par.VideoHeight * par.VideoWidth * par.SourceBytesPerPixel) { return -1; } //record the time at the "start" of encoding of this frame double start = timer.Duration; //reset the buffer memoryStream.Position = 0; bool isKeyFrame = false; //determine whether or not to send a key frame if (frameCount == 0) //if this is the first frame isKeyFrame = true; //if the duration has passed the frame frequency if (timestamp - lastKeyFrameTime > par.KeyFrameFrequency * 1000) { isKeyFrame = true; lastKeyFrameTime = (int)timestamp; System.GC.Collect(); } //set up the new tag tag = new FLVTag(FLVTag.TAGTYPE_VIDEO, frame, this.previousFrame, (frameCount > 0) ? (int)timestamp : 0, par.VideoWidth, par.VideoHeight, srcBlockBuffer, destBlockBuffer, isKeyFrame, par.CompressionLevel, par.SourceBytesPerPixel); //write the tag to the inmemory buffer (faster seeks) tag.writeTag(memoryStream); //get the size of the tag int tagSize = tag.getTagSizeInBytes(); //write the tag in memory out to file //and only if information is changed (no point writing an empty frame and //wasting space) if (tag.isFrameDirty()) { if (streamFile) { output.Write(buffer, 0, (int)memoryStream.Position); this.output.WriteByte((byte)(tagSize >> 24)); this.output.WriteByte((byte)(tagSize >> 16)); this.output.WriteByte((byte)(tagSize >> 8)); this.output.WriteByte((byte)(tagSize)); this.output.Flush(); } if (streamLive) { try { client.sendFLVTag(buffer, tag); //dont need the size } catch (Exception e) { this.streamLive = false; throw e; } } } //increment the frame counter frameCount++; //store the frame for comparison this.previousFrame = frame; //store the timestamp of this encoded frame this.lastTimeStamp = timestamp; //return the duration of of the this frame's encode time return timer.Duration - start; }