public override TransportPacket TakePacket() { if (TransportPackets.Count == 0) { while ((inputFile.Position < inputFile.Length) && TransportPackets.Count < (10000000 / 188)) { if (!ReadNextSequence()) { if (TransportPackets.Count == 0) { return(null); } break; } Packetize(InitialDTS); } } TransportPacket result = TransportPackets.TakeFirst(); if (TransportPackets.Count == 0) { BufferMore(); } return(result); }
public TransportMultiplexer() { if (FirstInstance == null) { FirstInstance = this; } NullPacket = new TransportPacket(); NullPacket.ConstructNullPacket(); }
public TransportPacket Last() { if (Count == 0) { return(null); } TransportPacket result = packetList[Count - 1]; return(result); }
/// <summary> /// This function is a hack to remove a padding packet if it's transmitted after a valid /// subtitle packet. The correct solution is to go back and properly design the stream buffer /// for the subtitle stream /// </summary> private void KillPacketsAfterTime(ulong time) { TransportPacket packet = Packets.Last(); while (packet != null && packet.StreamTime >= (ulong)time) { Packets.RemoveLast(); packet = Packets.Last(); ContinuityCounter--; // Rolling back the continuity indicator should do the trick } }
public TransportPacket TakeFirst() { if (Count == 0) { return(null); } TransportPacket result = packetList[0]; Count--; packetList.RemoveAt(0); return(result); }
public void AddPacket(TransportPacket packet) { Count++; packetList.Add(packet); }
private void ReadNextBuffer(long timeDivision) { long bytesBeforeTime = BytesBeforeEndOfFrame; long frames = 2; bytesBeforeTime += frames * FrameSize; StreamBufferEvent ev = new StreamBufferEvent(0 - (FrameSize + 14), InitialPTS + (audioSample * TimePerFrame)); streamBuffer.AddEvent(ev); audioSample++; for (int currentFrame = 1; currentFrame < frames; currentFrame++) { ev = new StreamBufferEvent(0 - FrameSize, InitialPTS + (audioSample * TimePerFrame)); audioSample++; streamBuffer.AddEvent(ev); } // Attempt to compensate for stream ending if (bytesBeforeTime > reader.Remaining) { bytesBeforeTime = reader.Remaining; } long packets = 1 + ((bytesBeforeTime - PACKET_PAYLOAD_LENGTH_PES) / PACKET_PAYLOAD_LENGTH); long bytesToConsume = PACKET_PAYLOAD_LENGTH_PES + (packets - 1) * PACKET_PAYLOAD_LENGTH; BytesBeforeEndOfFrame = bytesBeforeTime - bytesToConsume; if (bytesBeforeTime == reader.Remaining) { BytesBeforeEndOfFrame = 0; } int padding = 0; if (bytesToConsume > bytesBeforeTime) { padding = (int)(bytesToConsume - bytesBeforeTime); bytesToConsume = bytesBeforeTime; } long timeToTransfer = 27000000 * bytesToConsume / ((BitRate * 1000) / 8); long timePerPacket = timeToTransfer / packets; long packetTime = timeDivision / packets + 30000; long prebufferTime = (packetTime * packets) + 6000000; long decoderStamp = (nextTimeStamp * 300); //long streamTime = decoderStamp - timeToTransfer; for (int i = 0; i < packets; i++) { ByteArray transportData = new ByteArray(); transportData.MaxSize = 188; //------------------------------ // Transport Packet Header //------------------------------ // sync_byte = 0x47 (8 bits) transportData.Append((byte)0x47); transportData.EnterBitMode(); // transport_error_indicator (1 bit) transportData.AppendBit(0); // payload_unit_start_indicator (1 bit) transportData.AppendBit((byte)((i == 0) ? 1 : 0)); // transport_priority (1 bit) transportData.AppendBit(0); // PID (13 bits) transportData.AppendBits(PID, 12, 0); // transport_scrambling_code (2 bits) transportData.AppendBits((byte)0x0, 1, 0); // adaptation_field_control (2 bits) transportData.AppendBits((byte)((padding > 0) ? 0x3 : 0x1), 1, 0); // continuity_counter (4 bits) transportData.AppendBits(ContinuityCounter, 3, 0); ContinuityCounter++; transportData.LeaveBitMode(); int used = 4; if (padding > 0) { transportData.Append((byte)(padding - 1)); if (padding > 1) { transportData.Append((byte)0x00); } for (int paddingIndex = 2; paddingIndex < padding; paddingIndex++) { transportData.Append((byte)0xff); } used += (int)padding; padding = 0; } if (i == 0) { //------------------------------- // PES Packet Header //------------------------------- // packet_start_code_prefix (24 bits) (24) transportData.Append((byte)0x00); transportData.Append((byte)0x00); transportData.Append((byte)0x01); // stream_id (8 bits) (32) transportData.Append(StreamId); long packetLengthPosition = transportData.length; ushort packetLength = (ushort)(bytesToConsume + 8); // Fill with dummy value transportData.Append(packetLength); // '10' (2 bits) (02) 0x8000 // PES_scrambling_code (2 bits) (04) 0x0000 // PES_priority (1 bit) (05) 0x0000 // data_alignment_indicator (1 bit) (06) 0x0000 // copyright (1 bit) (07) 0x0000 // original_or_copy (1 bit) (08) 0x0000 // PTS_DTS_flags = '10' (2 bits) (10) 0x0080 // ESCR_flag (1 bit) (11) 0x0000 // ES_rate_flag (1 bit) (12) 0x0000 // DSM_trick_mode_flag (1 bit) (13) 0x0000 // additional_copy_info (1 bit) (14) 0x0000 // PES_CRC_flag (1 bit) (15) 0x0000 // PES_extension_flag (1 bit) (16) 0x0000 // 0x8080 transportData.Append((ushort)0x8480); // PES_header_data_length = 0x05 (8 bits) (08) transportData.Append((byte)0x05); // '0010' (4 bits) (76) // PTS[32..30] (3 bits) (79) // marker_bit (1 bit) (80) // PTS[29..15] (15 bits) (95) // marker_bit (1 bit) (96) // PTS[14..0] (15 bits) (111) // marker_bit (1 bit) (112) transportData.EnterBitMode(); transportData.AppendBits((byte)0x2, 3, 0); transportData.AppendBits(nextTimeStamp, 32, 30); transportData.AppendBit(1); transportData.AppendBits(nextTimeStamp, 29, 15); transportData.AppendBit(1); transportData.AppendBits(nextTimeStamp, 14, 0); transportData.AppendBit(1); transportData.LeaveBitMode(); nextTimeStamp += Pts * frames; used += 14; } int payloadLength = PACKET_LENGTH - used; long payloadTransmissionTime = (long)27000000 * (long)payloadLength / (((long)BitRate * 1000) / 8); for (int k = 0; k < payloadLength; k++) { transportData.Append((byte)reader.ReadByte()); } TransportPacket newPacket = new TransportPacket(transportData.buffer); long streamTime = (InitialTime - ((long)((TimePerFrame * 2) * 27000000)) + LastStamp); streamBuffer.SetTime(streamTime); while (!streamBuffer.CanAdd(184)) { long newStreamTime = streamBuffer.NextEventTime; LastStamp += newStreamTime - streamTime; streamTime = newStreamTime; streamBuffer.SetTime(streamTime); } streamBuffer.AddEvent(184, (long)streamTime); newPacket.StreamTime = (ulong)streamTime; LastStamp += payloadTransmissionTime; newPacket.DecoderStamp = (ulong)decoderStamp; decoderStamp += payloadTransmissionTime; Packets.AddPacket(newPacket); /*newPacket.StreamTime = (ulong)(InitialTime + LastStamp); * LastStamp += payloadTransmissionTime; * newPacket.DecoderStamp = (ulong)decoderStamp;*/ //if (newPacket.DecoderStamp < (ulong)(InitialTime - (0.100 * 27000000) + LastStamp)) // throw new Exception("Buffer Underrun"); //Packets.AddPacket(newPacket); } CurrentStreamTime += timeToTransfer; }
private void ThreadRun() { if (writer == null) { Failed = true; return; } double packetsPerSecond = (double)(BitsPerSecond / 8) / 188; ulong packetTime = 27000000 / (ulong)packetsPerSecond; currentTime = 0; ulong nextPacketTime = Streams.NextPacketTime; while (nextPacketTime != 0xFFFFFFFFFFFFFFFF && currentTime < EndAfter) { if (currentTime >= ProgramTables.NextPacketTime) { // Checking for cancel here means that the mutex on the cancel bool will only be triggered about // 20 times per second of video processed. This theoretically can cause a mutex lock as many as // 1000 times a second if I ever tweak the buffer reader on the MPEG-2 video stream to handle // peeking more efficiently if (Cancelled) { break; } writer.Write(ProgramTables.NextPacket().Packet, 0, 188); currentTime += packetTime; } else if (currentTime >= nextPacketTime) { TransportPacket nextPacket = Streams.TakePacket(currentTime); if (nextPacket.HasPCR) { nextPacket.SetPCR(currentTime); } if (nextPacket.DecoderStamp < currentTime) { throw new Exception(nextPacket.PID.ToString("{0:X4}") + " Decoder Stamp " + nextPacket.DecoderStamp.ToString() + " > current time " + currentTime.ToString()); } writer.Write(nextPacket.Packet, 0, 188); nextPacketTime = Streams.NextPacketTime; currentTime += packetTime; } else { if (PadToConstant) { NullPacket.IncrementContinuityCounter(); writer.Write(NullPacket.Packet, 0, 188); } currentTime += packetTime; } } Close(); Finished = true; return; }
public void GenerateProgramAssociationTable() { ByteArray output = new ByteArray(); // sync_byte = 0x47 (8 bits) output.Append((byte)0x47); output.EnterBitMode(); // transport_error_indicator = '0b' (1 bit) output.AppendBit(0); // payload_unit_start_indicator = '1b' (1 bit) output.AppendBit(1); // transport_priority = '0b' (1 bit) output.AppendBit(0); // PID (13 bits) output.AppendBits((ushort)0x0000, 12, 0); // transport_scrambling_control = '00b' (2 bits) output.AppendBits((byte)0x00, 1, 0); // adaptation_field_control = '01b' (2 bits) //output.appendBits((byte) 0x03, 1, 0); output.AppendBits((byte)0x01, 1, 0); // continuity_counter (4 bits) output.AppendBits((byte)0x00, 3, 0); // pointer_field output.AppendBits((byte)0x00, 7, 0); long packetStart = output.length; // table_id = 0x00 (program_association_section) (8 bits) output.AppendBits((byte)0x00, 7, 0); // section_syntax_indicator = 1 (1 bit) output.AppendBit(1); // '0' (1 bit) output.AppendBit(0); // Reserved = '11' (2 bits) output.AppendBits((byte)0x3, 1, 0); // section_length (12 bits) long sectionLengthPosition = output.length; output.AppendBits((ushort)0x000, 11, 0); // transport_stream_id (16 bits) output.AppendBits(TransportStreamId, 15, 0); // Reserved = '11' (2 bits) output.AppendBits((byte)0x3, 1, 0); // version_number = 0x00 (5 bits) output.AppendBits((byte)0x00, 4, 0); // current_next_indicator = 1 (1 bit) output.AppendBit(1); // section_number = 0 (8 bits) output.AppendBits((byte)0x00, 7, 0); // last_section_number = 0 (8 bits) output.AppendBits((byte)0x00, 7, 0); // Loop here for more than one program, not supported at the moment { // program_number (16 bits) output.AppendBits(ProgramNumber, 15, 0); // reserved (3 bits) output.AppendBits((byte)7, 2, 0); // program_map_PID (13 bits) output.AppendBits(ProgramMapPID, 12, 0); } output.LeaveBitMode(); ushort sectionLength = (ushort)(output.length - sectionLengthPosition + 2); output[sectionLengthPosition] = (byte)(output[sectionLengthPosition] | ((sectionLength >> 8) & 0xF)); output[sectionLengthPosition + 1] = (byte)(sectionLength & 0xFF); uint crc = CRC.Calculate(output.buffer, packetStart, output.length - packetStart); output.Append(crc); while (output.length < 188) { output.Append((byte)0xFF); } byte [] buffer = new byte[188]; for (int i = 0; i < 188; i++) { buffer[i] = output.buffer[i]; } pat = new TransportPacket(buffer); }
public void GenerateProgramMap(ushort pid, ushort programNumber, InputStreams streams) { ProgramMapPID = pid; ProgramNumber = programNumber; ByteArray output = new ByteArray(); // sync_byte = 0x47 (8 bits) output.Append((byte)0x47); output.EnterBitMode(); // transport_error_indicator = '0b' (1 bit) output.AppendBit(0); // payload_unit_start_indicator = '1b' (1 bit) output.AppendBit(1); // transport_priority = '0b' (1 bit) output.AppendBit(0); // PID (13 bits) output.AppendBits(pid, 12, 0); // transport_scrambling_control = '00b' (2 bits) output.AppendBits((byte)0x00, 1, 0); // adaptation_field_control = '01b' (2 bits) output.AppendBits((byte)0x01, 1, 0); // continuity_counter (4 bits) output.AppendBits((byte)0x00, 3, 0); // pointer_field output.AppendBits((byte)0x00, 7, 0); long packetStart = output.length; // table_id = 0x02 (8 bits) output.AppendBits((byte)0x02, 7, 0); // section_syntax_indicator '1' (1 bit) output.AppendBit(1); // '0' (1 bit) output.AppendBit(0); // Reserved = '11' (2 bits) output.AppendBits((byte)0x3, 1, 0); // section_length (calculate later) (12 bits) long sectionLengthPosition = output.length; output.AppendBits((ushort)0x000, 11, 0); // program_number (16 bits) output.AppendBits(programNumber, 15, 0); // Reserved = '11' (2 bits) output.AppendBits((byte)0x3, 1, 0); // version_number = 0x0 (5 bits) output.AppendBits((byte)0x00, 4, 0); // current_next_indicator = 0x0 (1 bit) output.AppendBit(1); // section_number = 0x00 (8 bits) output.AppendBits((byte)0x00, 7, 0); // current_section_number = 0x00 (8 bits) output.AppendBits((byte)0x00, 7, 0); // Reserved = '111' (3 bits) output.AppendBits((byte)0x7, 2, 0); // PCR_ID (13 bits) output.AppendBits(streams.PcrPID, 12, 0); // Reserved = '1111' (4 bits) output.AppendBits((byte)0xF, 3, 0); // program_info_length = 0x00 (12 bits) // - we ignore this field since it doesn't really matter output.AppendBits((ushort)0x000, 11, 0); for (long i = 0; i < streams.Count; i++) { streams[i].GenerateProgramMap(output); } output.LeaveBitMode(); ushort sectionLength = (ushort)(output.length - sectionLengthPosition + 2); output[sectionLengthPosition] = (byte)(output[sectionLengthPosition] | ((sectionLength >> 8) & 0xF)); output[sectionLengthPosition + 1] = (byte)(sectionLength & 0xFF); uint crc = CRC.Calculate(output.buffer, packetStart, output.length - packetStart); output.Append(crc); while (output.length < 188) { output.Append((byte)0xFF); } byte[] buffer = new byte[188]; for (int i = 0; i < 188; i++) { buffer[i] = output.buffer[i]; } pmt = new TransportPacket(buffer); GenerateProgramAssociationTable(); }
private TransportPackets PacketizeFile(long InitialPTS, ushort PID, ref int ContinuityCounter) { TransportPackets result = new TransportPackets(); FileStream inputFileStream = new FileStream(SourceFile, FileMode.Open, FileAccess.Read); BigEndianReader reader = new BigEndianReader(inputFileStream); long timeStamp = PresentationTimeStamp + InitialPTS; long bytesRemaining = ItemLength; int i = 0; while (bytesRemaining > 0) { long stuffingBytes = 0; int headerSize = (i == 0) ? 18 : 4; if (bytesRemaining < 188 - headerSize) { stuffingBytes = 188 - headerSize - bytesRemaining; } ByteArray transportData = new ByteArray(); transportData.MaxSize = 188; //------------------------------ // Transport Packet Header //------------------------------ // sync_byte = 0x47 (8 bits) transportData.Append((byte)0x47); transportData.EnterBitMode(); // transport_error_indicator (1 bit) transportData.AppendBit(0); // payload_unit_start_indicator (1 bit) transportData.AppendBit((byte)((i == 0) ? 1 : 0)); // transport_priority (1 bit) transportData.AppendBit(0); // PID (13 bits) transportData.AppendBits(PID, 12, 0); // transport_scrambling_code (2 bits) transportData.AppendBits((byte)0x0, 1, 0); // adaptation_field_control (2 bits) transportData.AppendBits((byte)((stuffingBytes > 0) ? 0x3 : 0x1), 1, 0); // continuity_counter (4 bits) transportData.AppendBits(ContinuityCounter, 3, 0); ContinuityCounter++; transportData.LeaveBitMode(); long used = 4; if (stuffingBytes > 0) { // Adaptation field for stuffing stuffingBytes--; used++; transportData.Append((byte)stuffingBytes); if (stuffingBytes > 0) { used += stuffingBytes; stuffingBytes--; transportData.Append((byte)0x00); // flags field for (int k = 0; k < stuffingBytes; k++) { transportData.Append((byte)0xFF); // stuffing byte } } //else // throw new Exception("Adaptation Field length = 0"); } if (i == 0) { //------------------------------- // PES Packet Header //------------------------------- // packet_start_code_prefix (24 bits) (24) // stream_id (8 bits) (32) transportData.Append((uint)0x000001BD); long packetLengthPosition = transportData.length; ushort packetLength = (ushort)(ItemLength + 8); // Fill with dummy value transportData.Append(packetLength); // '10' (2 bits) (02) 0x8000 // PES_scrambling_code (2 bits) (04) 0x0000 // PES_priority (1 bit) (05) 0x0000 // data_alignment_indicator (1 bit) (06) 0x0400 // copyright (1 bit) (07) 0x0000 // original_or_copy (1 bit) (08) 0x0000 // PTS_DTS_flags = '10' (2 bits) (10) 0x0080 // ESCR_flag (1 bit) (11) 0x0000 // ES_rate_flag (1 bit) (12) 0x0000 // DSM_trick_mode_flag (1 bit) (13) 0x0000 // additional_copy_info (1 bit) (14) 0x0000 // PES_CRC_flag (1 bit) (15) 0x0000 // PES_extension_flag (1 bit) (16) 0x0000 // 0x8480 transportData.Append((ushort)0x8480); // PES_header_data_length = 0x05 (8 bits) (08) transportData.Append((byte)0x05); // '0010' (4 bits) (76) // PTS[32..30] (3 bits) (79) // marker_bit (1 bit) (80) // PTS[29..15] (15 bits) (95) // marker_bit (1 bit) (96) // PTS[14..0] (15 bits) (111) // marker_bit (1 bit) (112) transportData.EnterBitMode(); transportData.AppendBits((byte)0x2, 3, 0); transportData.AppendBits(timeStamp, 32, 30); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 29, 15); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 14, 0); transportData.AppendBit(1); transportData.LeaveBitMode(); used += 14; } int payloadLength = TimelineRegionList.PacketSize - (int)used; bytesRemaining -= payloadLength; for (int k = 0; k < payloadLength; k++) { transportData.Append((byte)reader.ReadByte()); } long bytesIntoStream = ((PacketStart - 1) + i) * TimelineRegionList.PacketSize * 27000000 / TimelineRegionList.ByteRate; long streamTime = bytesIntoStream + (InitialPTS * 300); TransportPacket newPacket = new TransportPacket(transportData.buffer); newPacket.StreamTime = (ulong)streamTime; newPacket.DecoderStamp = (ulong)timeStamp * 300; newPacket.PID = PID; if (newPacket.StreamTime >= newPacket.DecoderStamp) { throw new Exception("Packet is scheduled for delivery after decoder time"); } result.AddPacket(newPacket); i++; } reader.Close(); inputFileStream.Close(); return(result); }
private TransportPacket GeneratePTSPadding(long InitialPTS, ushort PID, ref int ContinuityCounter) { // Stuffing bytes = 188 - (packet header length - pes header length - 4 bytes of padding) int stuffingBytes = 188 - (TimelineRegionList.PESHeaderSize + TimelineRegionList.PacketHeaderSize + 12); long timeStamp = PresentationTimeStamp + InitialPTS; ByteArray transportData = new ByteArray(); transportData.MaxSize = 188; //------------------------------ // Transport Packet Header //------------------------------ // sync_byte = 0x47 (8 bits) transportData.Append((byte)0x47); transportData.EnterBitMode(); // transport_error_indicator (1 bit) transportData.AppendBit(0); // payload_unit_start_indicator (1 bit) transportData.AppendBit((byte)(1)); // transport_priority (1 bit) transportData.AppendBit(0); // PID (13 bits) transportData.AppendBits(PID, 12, 0); // transport_scrambling_code (2 bits) transportData.AppendBits((byte)0x0, 1, 0); // adaptation_field_control (2 bits) transportData.AppendBits((byte)((stuffingBytes > 0) ? 0x3 : 0x1), 1, 0); // continuity_counter (4 bits) transportData.AppendBits(ContinuityCounter, 3, 0); ContinuityCounter++; transportData.LeaveBitMode(); long used = 4; if (stuffingBytes > 0) { // Adaptation field for stuffing stuffingBytes--; used++; transportData.Append((byte)stuffingBytes); // adaptation_field_length if (stuffingBytes > 0) { used += stuffingBytes; stuffingBytes--; transportData.Append((byte)0x00); // flags field for (int k = 0; k < stuffingBytes; k++) { transportData.Append((byte)0xFF); // stuffing byte } } } //------------------------------- // PES Packet Header //------------------------------- // packet_start_code_prefix (24 bits) (24) // stream_id (8 bits) (32) transportData.Append((uint)0x000001BD); long packetLengthPosition = transportData.length; ushort packetLength = (ushort)(20); // Fill with dummy value transportData.Append(packetLength); // '10' (2 bits) (02) 0x8000 // PES_scrambling_code (2 bits) (04) 0x0000 // PES_priority (1 bit) (05) 0x0000 // data_alignment_indicator (1 bit) (06) 0x0400 // copyright (1 bit) (07) 0x0000 // original_or_copy (1 bit) (08) 0x0000 // PTS_DTS_flags = '10' (2 bits) (10) 0x0080 // ESCR_flag (1 bit) (11) 0x0000 // ES_rate_flag (1 bit) (12) 0x0000 // DSM_trick_mode_flag (1 bit) (13) 0x0000 // additional_copy_info (1 bit) (14) 0x0000 // PES_CRC_flag (1 bit) (15) 0x0000 // PES_extension_flag (1 bit) (16) 0x0000 // 0x8480 transportData.Append((ushort)0x8480); // PES_header_data_length = 0x05 (8 bits) (08) transportData.Append((byte)0x05); // '0010' (4 bits) (76) // PTS[32..30] (3 bits) (79) // marker_bit (1 bit) (80) // PTS[29..15] (15 bits) (95) // marker_bit (1 bit) (96) // PTS[14..0] (15 bits) (111) // marker_bit (1 bit) (112) transportData.EnterBitMode(); transportData.AppendBits((byte)0x2, 3, 0); transportData.AppendBits(timeStamp, 32, 30); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 29, 15); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 14, 0); transportData.AppendBit(1); transportData.LeaveBitMode(); used += 14; transportData.Append((byte)0x20); // data_identifier transportData.Append((byte)0x00); // subtitle_stream_id transportData.Append((byte)0x0F); // sync_byte transportData.Append((byte)0xFF); //4 // segment_type = stuffing transportData.Append((byte)0x00); // page_id = 0x0002 transportData.Append((byte)0x02); transportData.Append((byte)0x00); // segment_length = 0x0003 transportData.Append((byte)0x03); //8 transportData.Append((byte)0xFF); // stuffing byte 1 transportData.Append((byte)0xFF); // stuffing byte 2 transportData.Append((byte)0xFF); // stuffing byte 3 transportData.Append((byte)0xFF); //12 // end_of_PES_data_field_marker long decoderStamp = (timeStamp * 300); //long insertTime = (long)(27000000 * 0.040); //long streamTime = decoderStamp - insertTime; long bytesIntoStream = (PacketStart - 1) * TimelineRegionList.PacketSize * 27000000 / TimelineRegionList.ByteRate; long streamTime = bytesIntoStream + (InitialPTS * 300); TransportPacket newPacket = new TransportPacket(transportData.buffer); newPacket.StreamTime = (ulong)streamTime; newPacket.DecoderStamp = (ulong)decoderStamp; newPacket.PID = PID; newPacket.IsPadding = true; return(newPacket); }
private void PacketizeFile(string fileName, long timeStamp) { FileStream inputFileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); BigEndianReader reader = new BigEndianReader(inputFileStream); long dataLength = inputFileStream.Length; /*int expectedAdaptationFieldLength = 0; // (int)((dataLength + PES_HEADER_LENGTH_PTS) % 184); * * int endStuffing = (expectedAdaptationFieldLength == 1) ? 12 : 0; * * byte [] readBuffer = new byte[dataLength + endStuffing]; * reader.Read(readBuffer, 0, (int) dataLength); * if (expectedAdaptationFieldLength == 1) * { * readBuffer[dataLength++] = 0x20; * readBuffer[dataLength++] = 0x00; * readBuffer[dataLength++] = 0x0F; * readBuffer[dataLength++] = 0xFF;//4 * readBuffer[dataLength++] = 0x00; * readBuffer[dataLength++] = 0x02; * readBuffer[dataLength++] = 0x00; * readBuffer[dataLength++] = 0x03;//8 * readBuffer[dataLength++] = 0xFF; * readBuffer[dataLength++] = 0xFF; * readBuffer[dataLength++] = 0xFF; * readBuffer[dataLength++] = 0xFF;//12 * } * int readIndex = 0;*/ long lengthAfterPESHeader = dataLength - 14; long packets = (lengthAfterPESHeader / 184) + (((lengthAfterPESHeader % 184) == 0) ? 0 : 1); timeStamp *= 90; timeStamp += InitialPtsInt; long decoderStamp = (timeStamp * 300); long insertTime = 27000000 * dataLength / MultiplexByteRate; long packetSpacingTime = insertTime / packets; insertTime += packetSpacingTime; long streamTime = decoderStamp - insertTime; long bytesRemaining = dataLength; int i = 0; while (bytesRemaining > 0) { long stuffingBytes = 0; int headerSize = (i == 0) ? 18 : 4; if (bytesRemaining < 188 - headerSize) { stuffingBytes = 188 - headerSize - bytesRemaining; } ByteArray transportData = new ByteArray(); transportData.MaxSize = 188; //------------------------------ // Transport Packet Header //------------------------------ // sync_byte = 0x47 (8 bits) transportData.Append((byte)0x47); transportData.EnterBitMode(); // transport_error_indicator (1 bit) transportData.AppendBit(0); // payload_unit_start_indicator (1 bit) transportData.AppendBit((byte)((i == 0) ? 1 : 0)); // transport_priority (1 bit) transportData.AppendBit(0); // PID (13 bits) transportData.AppendBits(PID, 12, 0); // transport_scrambling_code (2 bits) transportData.AppendBits((byte)0x0, 1, 0); // adaptation_field_control (2 bits) transportData.AppendBits((byte)((stuffingBytes > 0) ? 0x3 : 0x1), 1, 0); // continuity_counter (4 bits) transportData.AppendBits(ContinuityCounter, 3, 0); ContinuityCounter++; transportData.LeaveBitMode(); long used = 4; if (stuffingBytes > 0) { // Adaptation field for stuffing stuffingBytes--; used++; transportData.Append((byte)stuffingBytes); if (stuffingBytes > 0) { used += stuffingBytes; stuffingBytes--; transportData.Append((byte)0x00); // flags field for (int k = 0; k < stuffingBytes; k++) { transportData.Append((byte)0xFF); // stuffing byte } } //else // throw new Exception("Adaptation Field length = 0"); } if (i == 0) { //------------------------------- // PES Packet Header //------------------------------- // packet_start_code_prefix (24 bits) (24) // stream_id (8 bits) (32) transportData.Append((uint)0x000001BD); long packetLengthPosition = transportData.length; ushort packetLength = (ushort)(dataLength + 8); // Fill with dummy value transportData.Append(packetLength); // '10' (2 bits) (02) 0x8000 // PES_scrambling_code (2 bits) (04) 0x0000 // PES_priority (1 bit) (05) 0x0000 // data_alignment_indicator (1 bit) (06) 0x0400 // copyright (1 bit) (07) 0x0000 // original_or_copy (1 bit) (08) 0x0000 // PTS_DTS_flags = '10' (2 bits) (10) 0x0080 // ESCR_flag (1 bit) (11) 0x0000 // ES_rate_flag (1 bit) (12) 0x0000 // DSM_trick_mode_flag (1 bit) (13) 0x0000 // additional_copy_info (1 bit) (14) 0x0000 // PES_CRC_flag (1 bit) (15) 0x0000 // PES_extension_flag (1 bit) (16) 0x0000 // 0x8480 transportData.Append((ushort)0x8480); // PES_header_data_length = 0x05 (8 bits) (08) transportData.Append((byte)0x05); // '0010' (4 bits) (76) // PTS[32..30] (3 bits) (79) // marker_bit (1 bit) (80) // PTS[29..15] (15 bits) (95) // marker_bit (1 bit) (96) // PTS[14..0] (15 bits) (111) // marker_bit (1 bit) (112) transportData.EnterBitMode(); transportData.AppendBits((byte)0x2, 3, 0); transportData.AppendBits(timeStamp, 32, 30); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 29, 15); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 14, 0); transportData.AppendBit(1); transportData.LeaveBitMode(); used += 14; } int payloadLength = PACKET_LENGTH - (int)used; bytesRemaining -= payloadLength; for (int k = 0; k < payloadLength; k++) { transportData.Append((byte)reader.ReadByte()); } TransportPacket newPacket = new TransportPacket(transportData.buffer); newPacket.StreamTime = (ulong)streamTime + (ulong)(i * packetSpacingTime); newPacket.DecoderStamp = (ulong)decoderStamp; newPacket.PID = PID; if (newPacket.StreamTime >= newPacket.DecoderStamp) { throw new Exception("Packet is scheduled for delivery after decoder time"); } KillPacketsAfterTime(newPacket.StreamTime); Packets.AddPacket(newPacket); i++; } reader.Close(); inputFileStream.Close(); }
private void PacketizePadding(long timeStamp) { // Stuffing bytes = 188 - (packet header length - pes header length - 4 bytes of padding) int stuffingBytes = 188 - (PES_HEADER_LENGTH_PTS + PACKET_HEADER_LENGTH + 12); timeStamp *= 90; // Correct for 90Khz clock timeStamp += InitialPtsInt; // Increase spacing for initial PTS ByteArray transportData = new ByteArray(); transportData.MaxSize = 188; //------------------------------ // Transport Packet Header //------------------------------ // sync_byte = 0x47 (8 bits) transportData.Append((byte)0x47); transportData.EnterBitMode(); // transport_error_indicator (1 bit) transportData.AppendBit(0); // payload_unit_start_indicator (1 bit) transportData.AppendBit((byte)(1)); // transport_priority (1 bit) transportData.AppendBit(0); // PID (13 bits) transportData.AppendBits(PID, 12, 0); // transport_scrambling_code (2 bits) transportData.AppendBits((byte)0x0, 1, 0); // adaptation_field_control (2 bits) transportData.AppendBits((byte)((stuffingBytes > 0) ? 0x3 : 0x1), 1, 0); // continuity_counter (4 bits) transportData.AppendBits(ContinuityCounter, 3, 0); ContinuityCounter++; transportData.LeaveBitMode(); long used = 4; if (stuffingBytes > 0) { // Adaptation field for stuffing stuffingBytes--; used++; transportData.Append((byte)stuffingBytes); // adaptation_field_length if (stuffingBytes > 0) { used += stuffingBytes; stuffingBytes--; transportData.Append((byte)0x00); // flags field for (int k = 0; k < stuffingBytes; k++) { transportData.Append((byte)0xFF); // stuffing byte } } } //------------------------------- // PES Packet Header //------------------------------- // packet_start_code_prefix (24 bits) (24) // stream_id (8 bits) (32) transportData.Append((uint)0x000001BD); long packetLengthPosition = transportData.length; ushort packetLength = (ushort)(20); // Fill with dummy value transportData.Append(packetLength); // '10' (2 bits) (02) 0x8000 // PES_scrambling_code (2 bits) (04) 0x0000 // PES_priority (1 bit) (05) 0x0000 // data_alignment_indicator (1 bit) (06) 0x0400 // copyright (1 bit) (07) 0x0000 // original_or_copy (1 bit) (08) 0x0000 // PTS_DTS_flags = '10' (2 bits) (10) 0x0080 // ESCR_flag (1 bit) (11) 0x0000 // ES_rate_flag (1 bit) (12) 0x0000 // DSM_trick_mode_flag (1 bit) (13) 0x0000 // additional_copy_info (1 bit) (14) 0x0000 // PES_CRC_flag (1 bit) (15) 0x0000 // PES_extension_flag (1 bit) (16) 0x0000 // 0x8480 transportData.Append((ushort)0x8480); // PES_header_data_length = 0x05 (8 bits) (08) transportData.Append((byte)0x05); // '0010' (4 bits) (76) // PTS[32..30] (3 bits) (79) // marker_bit (1 bit) (80) // PTS[29..15] (15 bits) (95) // marker_bit (1 bit) (96) // PTS[14..0] (15 bits) (111) // marker_bit (1 bit) (112) transportData.EnterBitMode(); transportData.AppendBits((byte)0x2, 3, 0); transportData.AppendBits(timeStamp, 32, 30); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 29, 15); transportData.AppendBit(1); transportData.AppendBits(timeStamp, 14, 0); transportData.AppendBit(1); transportData.LeaveBitMode(); used += 14; transportData.Append((byte)0x20); transportData.Append((byte)0x00); transportData.Append((byte)0x0F); transportData.Append((byte)0xFF);//4 transportData.Append((byte)0x00); transportData.Append((byte)0x02); transportData.Append((byte)0x00); transportData.Append((byte)0x03);//8 transportData.Append((byte)0xFF); transportData.Append((byte)0xFF); transportData.Append((byte)0xFF); transportData.Append((byte)0xFF);//12 long decoderStamp = (timeStamp * 300); long insertTime = (long)(27000000 * 0.040); long streamTime = decoderStamp - insertTime; TransportPacket newPacket = new TransportPacket(transportData.buffer); newPacket.StreamTime = (ulong)streamTime; newPacket.DecoderStamp = (ulong)decoderStamp; newPacket.PID = PID; newPacket.IsPadding = true; Packets.AddPacket(newPacket); }
private void Packetize(double initialDTS) { int added = 0; for (int i = 0; i < Frames.Count; i++) { ByteArray pesData = PesForFrame(0, i, initialDTS); byte[] pes = pesData.buffer; double time = Frames[i].DTS - AdjustedVBVDelay; if (Frames[i].VBVDelay != 0) { time = Frames[i].DTS - Frames[i].VBVDelay; } if (time < 0) { time = 0; } ulong streamTime = (ulong)(27000000.0 * time); ulong decoderStamp = (ulong)(27000000.0 * Frames[i].DTS); long frameTransmissionTime = (long)27000000 * (long)(pesData.length) / (long)(ByteRate * 100 / 100); // * 112 / 100); long timeIncrement = frameTransmissionTime / ((pesData.length / 184) + 1); long lastPCR = 0; long index = 0; int packetNumber = 0; while (index < pesData.length) { TransportPacket newPacket = new TransportPacket(); newPacket.PID = PID; newPacket.ContinuityIndicator = ContinuityIndicator; ContinuityIndicator++; if (index == 0) { newPacket.IsAligned = true; newPacket.HasAdaptation = true; newPacket.HasPCR = true; if (firstPacket) { // MD-SP-VOD-CEP-I01040107 - Part 4.6 Transport Stream Requirements // The first PCR packet of the stream must have the transport discontinuity_indicator flag set to 1. newPacket.DiscontinuityIndicator = true; firstPacket = false; } if (Frames[i].StartOfGOP) { // MD-SP-VOD-CEP-I01040107 - Part 4.6 Transport Stream Requirements // Transport packet at the start of a GOP must have random_access_indicator set to 1. newPacket.RandomAccess = true; } } // This section forces a PCR stamp if the current frame is just so big that it will take longer than // the maximum PCR interval to transmit. if ((index - lastPCR) > BytesPerPCRMax) { newPacket.HasAdaptation = true; newPacket.HasPCR = true; lastPCR = index; } newPacket.DecoderStamp = decoderStamp; newPacket.StreamTime = streamTime + ((ulong)timeIncrement * (ulong)packetNumber); if (newPacket.StreamTime > decoderStamp) { throw new Exception("Buffer Overflow"); } packetNumber++; index += newPacket.Construct(pes, index, pesData.length); added++; TransportPackets.AddPacket(newPacket); } } return; }