/** * */ public void AddTsPacket(TsPacketMetadata tsPacket, byte[] packetBuffer, Int64 packetOffsetInBuffer) { List <TsPacketMetadata> singlePacketMetadataList = new List <TsPacketMetadata>(); singlePacketMetadataList.Add(tsPacket); channelDataCallback(pid, packetBuffer, packetOffsetInBuffer, (Int64)tsPacket.PacketSize, singlePacketMetadataList); }//AddTsPacket
public override void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { //In search mode, we may need to skip several TS packets according to the request. if (tsPacketMetadata.PacketNumber >= searchRequest.CountOfSkipTsPacket) { //Invoke the stream parser to process a TS packet. streamDemux.ProcessTsPacket(tsPacketMetadata, packetBuffer, packetOffsetInBuffer); } }
}//AddTsPacket /** * Add the data into the channel buffer. * * @param tsPacketMetadata packet information. * @param newData byte array containing the data to be added into the channel buffer. * @param leftDataLengthInBit how many bits left in the byte array.\n * On input, it indicates how many bits left in the byte array.\n * On output, it indicates how many bits left in the byte array after reading out requested data from the byte array. * @param newDataOffsetInBit offset of the position to read in the data from the byte array.\n * On input, it indicates the offset to read in data.\n * On output, it indicates the offset after reading out requested data from the byte array. * @param newDataLengthInBit how many bits to be read out from the byte array. * * @retval result */ public void AddPesData(TsPacketMetadata tsPacketMetadata, Int64 startIndicator, byte[] newData, Int64 newDataOffsetInBit, Int64 newDataLengthInBit) { Result result = new Result(); //Convert bits to bytes. Int64 newDataLengthInByte = newDataLengthInBit / 8; Int64 newDataOffsetInByte = newDataOffsetInBit / 8; if (null == dataBuffer) { bufferSize = 8 * 1024; dataBuffer = new byte[bufferSize];//Allocate 8 K bytes as the intial buffer. } if (1 == startIndicator) { //Start indicator is set to 1. We will notify all existing data as a PES packet. if (currentDataLength != 0) { channelDataCallback(pid, dataBuffer, 0, currentDataLength, packetMetadataList); //Clean up everything so that we are ready to accept new packet. Reset(); } }//if (1 == startIndicator) //Save the packetMetadata. packetMetadataList.Add(tsPacketMetadata); if (result.Fine) { //If no enough space to save the data. if ((currentDataLength + newDataLengthInByte) > bufferSize) { //No enough buffer. Allocate a larger buffer to save the content. Increase 8K each time. Int64 newBufferSize = bufferSize + 8 * 1024; byte[] newBuffer = new byte[newBufferSize]; Array.Copy(dataBuffer, newBuffer, currentDataLength);//Copy from the old one into the new one. dataBuffer = newBuffer; bufferSize = newBufferSize; }//if ((currentDataLength + newDataLengthInByte) > bufferSize) //Now, we must have enough buffer to hold the incoming data. Array.Copy(newData, newDataOffsetInByte, dataBuffer, currentDataLength, newDataLengthInByte);//Note that the forth parameter is indeed the offset! //Increase the lenght of current data after appending the new data. currentDataLength += newDataLengthInByte; } }//AddPesData
public void NewTsPacket(TsPacketMetadata tsPacketMetadata, UInt16 pid) { PidBitrate pidBitrate = null; if (!pidBitrateList.TryGetValue(pid, out pidBitrate)) { //Create a new one. pidBitrate = new PidBitrate(pid); pidBitrateList.Add(pid, pidBitrate); } //Increase the exsiting size. pidBitrate.AddTsPacket(tsPacketMetadata); }
public void ParseAdaptationField(TsPacketMetadata tsPacketMetadata, UInt16 pid, byte[] packetBuffer, Result result, Int64 dataLeftInBit, Int64 bitOffset, Int64 adaptationFieldControl) { Int64 pcr = 0; Int64 discontinuityIndicator = 0; MuxBitrate streamBitrate = null; bool pcrFound = GetPCR(tsPacketMetadata, packetBuffer, dataLeftInBit, bitOffset, adaptationFieldControl, ref pcr, ref discontinuityIndicator); if (pcrFound) { if (!streamBitrateList.TryGetValue(pid, out streamBitrate)) { streamBitrate = new MuxBitrate(pid); streamBitrateList.Add(pid, streamBitrate); } if (!streamBitrate.BitrateAvailable) { if (1 == discontinuityIndicator) { //Discontinuity is detected, the new PCR will be used as the first PCR. streamBitrate.SaveFirstPcr(pcr, tsPacketMetadata.FileOffset); }//if (1 == discontinuityIndicator) else { if (streamBitrate.FirsPcrReady()) { //Save second PCR if the first one is available. streamBitrate.SaveSecondPcr(pcr, tsPacketMetadata.FileOffset); } else { //Save as the first one. streamBitrate.SaveFirstPcr(pcr, tsPacketMetadata.FileOffset); } } //else } //if (!streamBitrate.BitrateAvailable) } //if (pcrFound) }
public override void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { Result result = new Result(); //Int64 dataLeftInBit = (Int64)tsPacketMetadata.PacketSize; Int64 dataLeftInBit = (Int64)TsPacketSize.SIZE_188 * 8; //Important!!!!No matter 188 or 204 bytes, the valid data will always be 188 bytes.16 bytes are checksum that is not useful for parsing. Int64 bitOffset = packetOffsetInBuffer * 8; //Key point to set the beginning offset!!!!! if (result.Fine) { //8-bit sync_byte. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 8); } if (result.Fine) { //1-bit transport_error_indicator. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 payloadUnitStartIndicator = 0; if (result.Fine) { //1-bit payload_unit_start_indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref payloadUnitStartIndicator); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 1) + Environment.NewLine); } if (result.Fine) { //1-bit transport_priority. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 pid = 0; if (result.Fine) { //13-bit PID. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 13, ref pid); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 13) + Environment.NewLine); } //To update the PID according to the request. if (result.Fine) { PidUpdate pidUpdate = null; //If this pid needs update. if (pidUpdateList.TryGetValue((UInt16)pid, out pidUpdate)) { //To update the PID. packetBuffer[packetOffsetInBuffer + 1] = (byte)((packetBuffer[packetOffsetInBuffer + 1] & (byte)0xE0) | (pidUpdate.NewPid >> 8)); //To update the high 5 bits of PID. packetBuffer[packetOffsetInBuffer + 2] = (byte)(pidUpdate.NewPid & 0xFF); //To update the low 8 bits of PID. //Write to output file now. outputFileStream.Write(packetBuffer, (int)packetOffsetInBuffer, (int)tsPacketMetadata.PacketSize); } else { //Write the original packet directly. outputFileStream.Write(packetBuffer, (int)packetOffsetInBuffer, (int)tsPacketMetadata.PacketSize); } } }
public override void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { Result result = new Result(); //Int64 dataLeftInBit = (Int64)tsPacketMetadata.PacketSize; Int64 dataLeftInBit = (Int64)TsPacketSize.SIZE_188 * 8; //Important!!!!No matter 188 or 204 bytes, the valid data will always be 188 bytes.16 bytes are checksum that is not useful for parsing. Int64 bitOffset = packetOffsetInBuffer * 8; //Key point to set the beginning offset!!!!! if (result.Fine) { //8-bit sync_byte. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 8); } if (result.Fine) { //1-bit transport_error_indicator. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 payloadUnitStartIndicator = 0; if (result.Fine) { //1-bit payload_unit_start_indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref payloadUnitStartIndicator); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 1) + Environment.NewLine); } if (result.Fine) { //1-bit transport_priority. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 pid = 0; if (result.Fine) { //13-bit PID. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 13, ref pid); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 13) + Environment.NewLine); } //Notify to ManagerPidBitrate to calculate realtime bitrate. if (result.Fine) { managerPidBitrate.NewTsPacket(tsPacketMetadata, (UInt16)pid); } if ((totalLengthOfDataParsed - previousTotalLengthOfDataParsed) * 8 >= (streamBitrate)) { //Time to fetch current bitstream. SortedDictionary <UInt16, PidBitrate> currentBitrate = managerPidBitrate.FetchCurrentBitrates(); KeyValuePair <DateTime, SortedDictionary <UInt16, PidBitrate> > bitrateForNow = new KeyValuePair <DateTime, SortedDictionary <ushort, PidBitrate> >(DateTime.Now, currentBitrate); //Send it to the form now. messageCallback(MessageId.MESSAGE_PID_BITRATE_DATA, bitrateForNow); //Save the new value as the previous one. previousTotalLengthOfDataParsed = totalLengthOfDataParsed; } }
public override void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { Result result = new Result(); //Int64 dataLeftInBit = (Int64)tsPacketMetadata.PacketSize; Int64 dataLeftInBit = (Int64)TsPacketSize.SIZE_188 * 8; //Important!!!!No matter 188 or 204 bytes, the valid data will always be 188 bytes.16 bytes are checksum that is not useful for parsing. Int64 bitOffset = packetOffsetInBuffer * 8; //Key point to set the beginning offset!!!!! if (result.Fine) { //8-bit sync_byte. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 8); } if (result.Fine) { //1-bit transport_error_indicator. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 payloadUnitStartIndicator = 0; if (result.Fine) { //1-bit payload_unit_start_indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref payloadUnitStartIndicator); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 1) + Environment.NewLine); } if (result.Fine) { //1-bit transport_priority. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 pid = 0; if (result.Fine) { //13-bit PID. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 13, ref pid); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 13) + Environment.NewLine); } Int64 scrambled = 0; if (result.Fine) { //1-bit scrambling indicator. If 1, scrambled, else clear. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref scrambled); } Int64 evenOdd = 0; if (result.Fine) { //1-bit even/odd indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref evenOdd); } if ((totalLengthOfDataParsed - previousTotalLengthOfDataParsed) * 8 >= (muxBitrate * cwPeriod))//Need to do a CW cycle. { //To switch the CW. //Get the control word. int realControlWordId = currentControlWord; currentControlWord++; //Increase so that we can pick up next control word. realControlWordId = realControlWordId % controlWordCount; //We like to loop back if necessary. byte[] csaKey = new byte[8]; Array.Copy(controlWordSerials, realControlWordId * 8, csaKey, 0, 8);//Copy the key into a new buffer. //Set the CW. csaDescrambler.SetCW(csaKey, doEntropy); //Switch even/odd flag. evenOddFlag = (evenOddFlag + 1) % 2; //Save the new value as the previous one. previousTotalLengthOfDataParsed = totalLengthOfDataParsed; } //To process the PID according to the request. if (result.Fine) { PidUpdate pidToProcess = null; //If this pid needs to be extracted. if (pidUpdateList.TryGetValue((UInt16)pid, out pidToProcess)) { //Scramble the packet in place. csaDescrambler.EncryptTSPacket(packetBuffer, (int)packetOffsetInBuffer, (int)TsPacketSize.SIZE_188, evenOddFlag); } //Write the output no matter clear or descrambled. outputFileStream.Write(packetBuffer, (int)packetOffsetInBuffer, (int)tsPacketMetadata.PacketSize); } }
public Result ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { Result result = new Result(); //Int64 dataLeftInBit = (Int64)tsPacketMetadata.PacketSize; Int64 dataLeftInBit = (Int64)TsPacketSize.SIZE_188 * 8; //Important!!!!No matter 188 or 204 bytes, the valid data will always be 188 bytes.16 bytes are checksum that is not useful for parsing. Int64 bitOffset = packetOffsetInBuffer * 8; //Key point to set the beginning offset!!!!! //Important!!! Pass a copy of the TS packe to the demux module, so that it can assemble ts packet into section or PES packet. streamDemux.ProcessTsPacket(tsPacketMetadata, packetBuffer, packetOffsetInBuffer); if (result.Fine) { //8-bit sync_byte. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 8); } if (result.Fine) { //1-bit transport_error_indicator. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 payloadUnitStartIndicator = 0; if (result.Fine) { //1-bit payload_unit_start_indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref payloadUnitStartIndicator); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 1) + Environment.NewLine); } if (result.Fine) { //1-bit transport_priority. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 pid = 0; if (result.Fine) { //13-bit PID. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 13, ref pid); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 13) + Environment.NewLine); } if (result.Fine) { //2-bit transport_scrambling_control. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 2); } Int64 adaptationFieldControl = 0; if (result.Fine) { //2-bit adaptation_field_control. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 2, ref adaptationFieldControl); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 2) + Environment.NewLine); } if (result.Fine) { //4-bit continuity_counter. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 4); } //To parse adaption fields. Int64 adaptationFieldLength = 0; if (result.Fine) { //If adaptationFieldControl is 0b10(Adaptation_field only, no payload) or 0b11(Adaptation_field followed by payload),there is a adaption_field. We need to skip the adaption fields. if ((0x2 == adaptationFieldControl) || (0x3 == adaptationFieldControl)) { //8-bit adaptation_field_length result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 8, ref adaptationFieldLength); if (result.Fine) { /*Parse adaptation field to get PCR etc.*/ streamBitrateManager.ParseAdaptationField(tsPacketMetadata, (UInt16)pid, packetBuffer, result, dataLeftInBit, bitOffset, adaptationFieldControl); } //Skip adaption fields according to the adaption_field_length. if (result.Fine) { result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, (adaptationFieldLength * 8)); } } } if (result.Fine) { //Notify a new packet to PidManager so that it can do the statistics. pidManager.AddPacket((UInt16)pid); } return(result); }
public void DoWork(object data) { Result result = new Result(); byte[] tsPacketBuffer = new byte[TS_PACKET_BUFFER_SIZE]; int lengthOfDataReadIn = 0; //Length of data read in from file. Int64 lengthOfDataToParse = 0; //Length of data to be parsed. Int64 validPacketOffset = 0; //Offset of packet in the buffer. TsPacketSize tsPacketSize = TsPacketSize.SIZE_UNKNOWN; Int64 packetNumber = 0; //Number of packet. //Give the child class to do something. OnStart(); GetContext().WriteLog("Start to parse stream file: " + fileStream.Name + ".\n"); //To check current datetime.//TIME_LIMIT DateTime currentTime = DateTime.Now; if (result.Fine) { //Read in some TS packets to detect the TS packet size. lengthOfDataToParse = fileStream.Read(tsPacketBuffer, 0, tsPacketBuffer.Length); //We will detect whether it is a valid transport stream first. result = StreamDemux.DetectPacketSize(tsPacketBuffer, lengthOfDataToParse, ref validPacketOffset, ref tsPacketSize);//validPacketOffset and tsPacketSize will be changed by this function. if (result.Fine) { GetContext().WriteLog("Packet size: " + tsPacketSize + ".\n"); GetContext().WriteLog("Offset of first packet: " + validPacketOffset + ".\n"); GetContext().WriteLog("Stream size: " + fileStream.Length + " bytes.\n"); messageCallback(MessageId.MESSAGE_TS_PACKET_SIZE, (int)tsPacketSize); } else { GetContext().WriteLog("Invalid transport stream.\n"); result.SetResult(ResultCode.FAILURE); } //Skip invalid data bytes. lengthOfDataToParse -= validPacketOffset; } Int64 currentProgress = 0; Int64 savedProgress = 0; Int64 fileSize = fileStream.Length; if (result.Fine) { totalLengthOfDataParsed += validPacketOffset; totalLengthOfDataSkipped += validPacketOffset; /*TIME_LIMIT * if ((currentTime.Year * 12 + currentTime.Month) >= 2015 * 12 + 6) * { * canRun = false; * } * * if ((currentTime.Year * 12 + currentTime.Month) < 2014 * 12 + 5) * { * canRun = false; * } */ //It is a valid transport stream. while (canRun) { currentProgress = totalLengthOfDataParsed * 100 / fileSize; if (currentProgress > savedProgress) { //Progress has been updated. savedProgress = currentProgress; //Update the progress shown in the form by sending a message. OnProgress(savedProgress); } //If left data in the buffer is shorter than the size of a TS packet, we will need to read more data before processing it. if (lengthOfDataToParse < (Int64)tsPacketSize) { //The left data will be moved to the beginning of the buffer. //In case there is any data left, we will copy it to the beginning of the buffer. if (0 != lengthOfDataToParse) { Array.Copy(tsPacketBuffer, tsPacketBuffer.Length - lengthOfDataToParse, tsPacketBuffer, 0, lengthOfDataToParse); } //Console.WriteLine("-----lengthOfDataToParse:" + lengthOfDataToParse + " totalLengthOfDataParsed " + totalLengthOfDataParsed + " ts byte :" + tsPacketBuffer[0]); //Read the data from the file into the buffer. lengthOfDataReadIn = fileStream.Read(tsPacketBuffer, (int)lengthOfDataToParse, (int)(tsPacketBuffer.Length - lengthOfDataToParse)); //To parse all the data in the buffer. lengthOfDataToParse += lengthOfDataReadIn; //Console.WriteLine("===================lengthOfDataToParse:" + lengthOfDataToParse + " totalLengthOfDataParsed " + totalLengthOfDataParsed + " ts byte :" + tsPacketBuffer[0]); //If there is still no valid TS packet after a read operation, we have reached the end of the file. if (lengthOfDataToParse < (Int64)tsPacketSize) { GetContext().WriteLog("Parsing has been successfully done! There are " + lengthOfDataToParse + " bytes left.\n"); break; } //Reset the offset. validPacketOffset = 0; } //Get a TS packet from the block. if (StreamDemux.SYNC_BYTE == tsPacketBuffer[validPacketOffset]) { TsPacketMetadata transportPacket = new TsPacketMetadata(); //It is a valid TS packet. Process this TS packet. transportPacket.PacketSource = TsPacketSource.SOURCE_FILE; transportPacket.FileOffset = totalLengthOfDataParsed; transportPacket.PacketNumber = packetNumber; //Increase the packet number since we have got one valid TS packet. transportPacket.PacketSize = tsPacketSize; //Invoke the function in the child class to process the TS packet. ProcessTsPacket(transportPacket, tsPacketBuffer, validPacketOffset); //Increase the packet number since we have got one valid TS packet. packetNumber++; //Increase the length of data parsed. totalLengthOfDataParsed += (Int64)tsPacketSize; validPacketOffset += (Int64)tsPacketSize; lengthOfDataToParse -= (Int64)tsPacketSize; } else { //The stream is out of the syncrhonization. We will need to re-locate the position in order to find a valid TS packet. GetContext().WriteLog("Out of synchronization at " + totalLengthOfDataParsed + " bytes of the stream file.\n"); String str = String.Format("{0,2:X2} {1,2:X2} {2,2:X2} {3,2:X2} {4,2:X2} {5,2:X2} ", tsPacketBuffer[validPacketOffset], tsPacketBuffer[validPacketOffset + 1], tsPacketBuffer[validPacketOffset + 2], tsPacketBuffer[validPacketOffset + 3], tsPacketBuffer[validPacketOffset + 4], tsPacketBuffer[validPacketOffset + 5]); Console.WriteLine("Out of synchronization at " + totalLengthOfDataParsed + " bytes of the stream file.\n"); Console.WriteLine(str); Int64 validPacketOffsetTemp = validPacketOffset; result = StreamDemux.DetectPacketSize(tsPacketBuffer, lengthOfDataToParse, ref validPacketOffset, ref tsPacketSize);//validPacketOffset and tsPacketSize will be changed by this function. if (result.Fine) { //We can continue since we have successfully located a valid TS packet, but we need to know how many bytes we have skipped while relocating. totalLengthOfDataParsed += (validPacketOffset - validPacketOffsetTemp); lengthOfDataToParse -= (validPacketOffset - validPacketOffsetTemp); totalLengthOfDataSkipped += (validPacketOffset - validPacketOffsetTemp); GetContext().WriteLog("Skip " + (validPacketOffset - validPacketOffsetTemp) + " bytes.\n"); continue; } else { GetContext().WriteLog("Failed to re-locate the valid TS packet. " + (fileStream.Length - totalLengthOfDataParsed) + " bytes are left.\n"); break; } } } //Give a summary at the end. GetContext().WriteLog("Processed packets: " + packetNumber + Environment.NewLine); GetContext().WriteLog("There are totally " + totalLengthOfDataSkipped + " bytes skipped. " + 100 * (float)totalLengthOfDataSkipped / fileStream.Length + "% is invalid.\n"); //Update to 100% no matter how. if (100 != savedProgress) { OnProgress((Int64)100); } } //Close the stream immediately. fileStream.Close(); fileStream = null; parserThread = null; //Give the child class to do something. OnStop(); }
//To be overrided by by base class. public virtual void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { }
private bool GetPCR(TsPacketMetadata tsPacketMetadata, byte[] data, Int64 dataLeftInBit, Int64 bitOffset, Int64 adaptationFieldLength, ref Int64 pcr, ref Int64 discontinuityIndicator) { bool pcrValid = false; Int64 fieldValue = 0; Result result = new Result(); adaptationFieldLength = adaptationFieldLength * 8;//Convert to bits. if (adaptationFieldLength <= 0) { result.SetResult(ResultCode.DATA_MISMATCH); } if (result.Fine) { //discontinuity_indicator result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 1, ref discontinuityIndicator); } if (result.Fine) { //random_access_indicator,elementary_stream_priority_indicator result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 2, ref fieldValue); } Int64 pcrFlag = 0; if (result.Fine) { result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 1, ref pcrFlag);//PCR_flag } if (result.Fine) { //OPCR_flag,splicing_point_flag,transport_private_data_flag,adaptation_field_extension_flag result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 4, ref fieldValue); } if (result.Fine && (1 == pcrFlag)) { Int64 programClockReferenceBase = 0; if (result.Fine) { result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 33, ref programClockReferenceBase);//program_clock_reference_base } if (result.Fine) { //Reserved result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 1, ref fieldValue); } Int64 programClockReferenceExtension = 0; if (result.Fine) { //program_clock_reference_extension result = Utility.ByteArrayReadBits(data, ref dataLeftInBit, ref bitOffset, 9, ref programClockReferenceExtension); } if (result.Fine) { //Convert to complete PCR. pcrValid = true; pcr = programClockReferenceBase * 300 + programClockReferenceExtension; } } return(pcrValid); }
public override void ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { //Invoke the stream parser to process a TS packet. streamParserCore.ProcessTsPacket(tsPacketMetadata, packetBuffer, packetOffsetInBuffer); }
public void AddTsPacket(TsPacketMetadata tsPacketMetadata) { totalSize += (Int64)tsPacketMetadata.PacketSize; }
/** * Add the data into the channel buffer. * * @param tsPacketMetadata packet information. * @param newData byte array containing the data to be added into the channel buffer. * @param leftDataLengthInBit how many bits left in the byte array.\n * On input, it indicates how many bits left in the byte array.\n * On output, it indicates how many bits left in the byte array after reading out requested data from the byte array. * @param newDataOffsetInBit offset of the position to read in the data from the byte array.\n * On input, it indicates the offset to read in data.\n * On output, it indicates the offset after reading out requested data from the byte array. * @param newDataLengthInBit how many bits to be read out from the byte array. * * @retval result */ public void AddSectionData(TsPacketMetadata tsPacketMetadata, byte[] newData, ref Int64 leftDataLengthInBit, ref Int64 newDataOffsetInBit, Int64 newDataLengthInBit) { Result result = new Result(); if (newDataLengthInBit > 0) { if (null == dataBuffer) { this.bufferSize = 5 * 1024; dataBuffer = new byte[bufferSize]; } //Convert bits to bytes. Int64 newDataLengthInByte = newDataLengthInBit / 8; Int64 newDataOffsetInByte = newDataOffsetInBit / 8; //Save the packetMetadata. packetMetadataList.Add(tsPacketMetadata); if (result.Fine) { //Check whether there is enough data left in the buffer. if (newDataLengthInBit > leftDataLengthInBit) { result.SetResult(ResultCode.INSUFFICIENT_DATA); //Report an error. GetContext().WriteLog("Invalid data length has been detected!" + Environment.NewLine); } } if (result.Fine) { //If no enough space to save the data. if ((currentDataLength + currentOffset + newDataLengthInByte) > bufferSize) { //Copy the data to the beginning of the buffer first. Array.Copy(dataBuffer, currentOffset, dataBuffer, 0, currentDataLength); currentOffset = 0; } //Have a check again! if ((currentDataLength + currentOffset + newDataLengthInByte) > bufferSize) { //result.SetResult(ResultCode.INSUFFICIENT_DATA); //GetContext().WriteLog("Error:Insufficient channel buffer!" + Environment.NewLine); //No enough buffer. Allocate a larger buffer to save the content. Increase 4 bytes each time. Int64 newBufferSize = bufferSize + 4 * 1024;//We need this because to endure some "bad" streams!!!!!!!!!!!!!!!!!! byte[] newBuffer = new byte[newBufferSize]; Array.Copy(dataBuffer, newBuffer, currentDataLength);//Copy from the old one into the new one. dataBuffer = newBuffer; bufferSize = newBufferSize; } //Enough space.Save the data into the space. Array.Copy(newData, newDataOffsetInByte, dataBuffer, currentOffset + currentDataLength, newDataLengthInByte);//Note that the forth parameter is offset + length! //Increase the data length! currentDataLength += newDataLengthInByte; //Decrease the left data length. leftDataLengthInBit -= newDataLengthInBit; //Increase the offset. newDataOffsetInBit += newDataLengthInBit; if (dataType == DataType.SECTION) { CheckSectionAvailable();//Notify any available section if any! } } } }
public Result ProcessTsPacket(TsPacketMetadata tsPacketMetadata, byte[] packetBuffer, Int64 packetOffsetInBuffer) { Result result = new Result(); //Int64 dataLeftInBit = (Int64)tsPacketMetadata.PacketSize; Int64 dataLeftInBit = (Int64)TsPacketSize.SIZE_188 * 8; //Important!!!!No matter 188 or 204 bytes, the valid data will always be 188 bytes.16 bytes are checksum that is not useful for parsing. Int64 bitOffset = packetOffsetInBuffer * 8; //Key point to set the beginning offset!!!!! if (result.Fine) { //8-bit sync_byte. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 8); } if (result.Fine) { //1-bit transport_error_indicator. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 payloadUnitStartIndicator = 0; if (result.Fine) { //1-bit payload_unit_start_indicator. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 1, ref payloadUnitStartIndicator); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 1) + Environment.NewLine); } if (result.Fine) { //1-bit transport_priority. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 1); } Int64 pid = 0; if (result.Fine) { //13-bit PID. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 13, ref pid); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 13) + Environment.NewLine); } if (result.Fine) { //2-bit transport_scrambling_control. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 2); } Int64 adaptationFieldControl = 0; if (result.Fine) { //2-bit adaptation_field_control. result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 2, ref adaptationFieldControl); //GetContext().WriteLog(Utility.GetValueBinaryString(fieldValue, 2) + Environment.NewLine); } if (result.Fine) { //4-bit continuity_counter. result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, 4); } //To parse adaption fields. Int64 adaptationFieldLength = 0; if (result.Fine) { //If adaptationFieldControl is 0b10(Adaptation_field only, no payload) or 0b11(Adaptation_field followed by payload),there is a adaption_field. We need to skip the adaption fields. if ((0x2 == adaptationFieldControl) || (0x3 == adaptationFieldControl)) { //8-bit adaptation_field_length result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 8, ref adaptationFieldLength); //Skip adaption fields according to the adaption_field_length. if (result.Fine) { result = Utility.ByteArraySkipBits(ref dataLeftInBit, ref bitOffset, (adaptationFieldLength * 8)); } } } //If the packet is what we want. if (result.Fine) { DataType pidDataType = GetChannelType((UInt16)pid); if (DataType.SECTION == pidDataType) { Channel channelDataStore = null; //Check start indicator. if (0 == payloadUnitStartIndicator) { //No complete section is expected. /* * At the first beginning of parsing, we may receive some TS packets with payloadUnitStartIndicator ZERO. * We will ignore these packets if there is nothing in the buffer, because these packets are not expected contain the start of a section. * Having these kinds of TS packets is useless. */ if (channelList.TryGetValue((UInt16)pid, out channelDataStore)) { //We already get the item in the channel list. Save it into the ChannelDataStore. channelDataStore.AddSectionData(tsPacketMetadata, packetBuffer, ref dataLeftInBit, ref bitOffset, dataLeftInBit); } } else { //Start indicator is set to 1. A new section is expected. Get the pointer field. //8-bit pointer_field. Int64 pointerField = 0; result = Utility.ByteArrayReadBits(packetBuffer, ref dataLeftInBit, ref bitOffset, 8, ref pointerField); if (result.Fine) { if (!channelList.TryGetValue((UInt16)pid, out channelDataStore)) { //No existing Channel. Create a new one to store section. channelDataStore = new Channel(owner, (UInt16)pid, HandleDataFromChannel, DataType.SECTION); //Insert to the channel list. channelList.Add((UInt16)pid, channelDataStore); } } //Save the data belonged to the previous section and have a clean-up first. if (result.Fine) { //Save the data with length indicated pointer_field. The data belongs to the previous section. channelDataStore.AddSectionData(tsPacketMetadata, packetBuffer, ref dataLeftInBit, ref bitOffset, pointerField * 8);//Pay attention to the third parameter. if (result.Fine) { //Clean up data NO MATTER HOW in case we may have received some invalid data that may disturb the parsing!!!!!!!!!!!!!!!!!!!!!! channelDataStore.Reset(); } } if (result.Fine) { //Save the data belonged to the new section. channelDataStore.AddSectionData(tsPacketMetadata, packetBuffer, ref dataLeftInBit, ref bitOffset, dataLeftInBit); } } }//PID for section filtering. else if (DataType.PES_PACKET == pidDataType) { Channel channelDataStore = null; //Check start indicator. if (0 == payloadUnitStartIndicator) { //No complete PES is expected. /* * At the first beginning of parsing, we may receive some TS packets with payloadUnitStartIndicator ZERO. * We will ignore these packets if there is nothing in the buffer, because these packets will not contain the start of a PES. * Having these kinds of TS packets is useless. */ if (channelList.TryGetValue((UInt16)pid, out channelDataStore))//Existing Channel for this PID. { //We already get the item in the channel list. Save it into the ChannelDataStore. channelDataStore.AddPesData(tsPacketMetadata, payloadUnitStartIndicator, packetBuffer, bitOffset, dataLeftInBit); } } else { //Start indicator is set to 1. A new PES is expected. Send out all existing data as a PES packet. if (result.Fine) { if (!channelList.TryGetValue((UInt16)pid, out channelDataStore))//No existing Channel for this PID. { //No existing ChannelDataStore. Create a new one to store PES data. channelDataStore = new Channel(owner, (UInt16)pid, HandleDataFromChannel, DataType.PES_PACKET); //Insert to the channel list. channelList.Add((UInt16)pid, channelDataStore); } } if (result.Fine) { //Save the data belonged to the new PES. channelDataStore.AddPesData(tsPacketMetadata, payloadUnitStartIndicator, packetBuffer, bitOffset, dataLeftInBit); } } }//PID for PES filtering. else if (DataType.TS_PACKET == pidDataType) { Channel channelDataStore = null; if (!channelList.TryGetValue((UInt16)pid, out channelDataStore)) { //No existing Channel. Create a new one to store the TS. channelDataStore = new Channel(owner, (UInt16)pid, HandleDataFromChannel, DataType.TS_PACKET); //Insert to the channel list. channelList.Add((UInt16)pid, channelDataStore); } //Add it into the channel buffer. channelDataStore.AddTsPacket(tsPacketMetadata, packetBuffer, packetOffsetInBuffer); }//PID for TS packet filtering. } return(result); }