public WorkerFileDataSearch(StreamParserContext owner, MessageHandlerDelegate messageCallbackFromOwner, SearchRequest searchRequest) : base(owner, messageCallbackFromOwner) { this.sectionManager = new ManagerSection(owner); this.streamDemux = new StreamDemux(owner); this.searchRequest = searchRequest; //In search mode. We will not parse standard SI/PSI sections, instead ,we will set up a filter for the expected data. Filter filterForSearch = null; if (searchRequest.SearchType == DataType.SECTION) { //To search sections. filterForSearch = new Filter(owner, HandleDataFromDemux, searchRequest.SearchType, searchRequest.SelectedPid, searchRequest.FilterMask.Length, searchRequest.FilterMask, searchRequest.FilterMatch); } else { //To search TS packet or PES packet. filterForSearch = new Filter(owner, HandleDataFromDemux, searchRequest.SearchType, searchRequest.SelectedPid); } //In order to fitler out what we are expecting. streamDemux.AddFilter(filterForSearch); }
public StreamParserCore(StreamParserContext owner, MessageHandlerDelegate messageCallback) : base(owner) { this.streamDemux = new StreamDemux(owner); /** * Create all necessary modules even we don't need all them in some cases. * In live environment,i.e. IP network or device, we will need all of them. */ sectionManager = new ManagerSection(owner); serviceManager = new ManagerService(owner); streamBitrateManager = new ManagerMuxBitrate(); pidManager = new ManagerPid(owner); AddDefaultPidType(); this.messageCallback = messageCallback; //Set up filters to receive standard SI/PSI sections. EnableStandardFilters(streamDemux); }
//Enable standard filters to receive SI/PSI sections. public void EnableStandardFilters(StreamDemux streamDemux) { //To filter PAT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.PAT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.PAT })); //Match. //To filter CAT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.CAT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.CAT })); //Match. //To filter TSDT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.TSDT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.TSDT })); //Match. //To filter NIT for current network and for other network. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.NIT, //PID. 1, //Filter depth. new byte[1] { 0xFE }, //Mask. To filter out table ID 0x40 and 0x41. new byte[1] { (byte)TableId.NIT_ACTUAL })); //Match. //To filter SDT for current stream and for other stream. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.BAT_SDT, //PID. 1, //Filter depth. new byte[1] { 0xFB }, //Mask.To filter out table ID 0x42 and 0x46. new byte[1] { (byte)TableId.SDT_ACTUAL })); //Match. //To filter BAT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.BAT_SDT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.BAT })); //Match. //To filter EIT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.EIT, //PID. 1, //Filter depth. new byte[1] { 0xFE }, //Mask. To filter out table ID 0x4E and 0x4F. new byte[1] { (byte)TableId.EIT_PF_ACTUAL })); //Match. //To filter EIT schedule for current stream. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.EIT, //PID. 1, //Filter depth. new byte[1] { 0xF0 }, //Mask. To filter out table ID 0x50 to 0x5F. new byte[1] { (byte)TableId.EIT_SCHEDULE_ACTUAL })); //Match. //To filter EIT schedule for other stream. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.EIT, //PID. 1, //Filter depth. new byte[1] { 0xF0 }, //Mask. To filter out table ID 0x50 to 0x5F. new byte[1] { (byte)TableId.EIT_SCHEDULE_OTHER })); //Match. //To filter RST. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.RST, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.RST })); //Match. //To filter TDT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.TDT_TOT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.TDT })); //Match. //To filter TOT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.TDT_TOT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.TOT })); //Match. //To filter DIT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.DIT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.DIT })); //Match. //To filter SIT. streamDemux.AddFilter(new Filter(GetContext(), ProcessFilteredData, DataType.SECTION, (UInt16)TsPID.SIT, //PID. 1, //Filter depth. new byte[1] { 0xFF }, //Mask. new byte[1] { (byte)TableId.SIT })); //Match. }
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(); }