CollatorStatus_t Collator_PacketDvp_c::Input(PlayerInputDescriptor_t  *Input,
		unsigned int          DataLength,
		void                     *Data,
		bool              NonBlocking,
		unsigned int         *DataLengthRemaining)
{
	CollatorStatus_t     Status;
	StreamInfo_t        *CapturedFrameDescriptor = (StreamInfo_t *)Data;
	Buffer_t         CapturedBuffer;
//
	COLLATOR_ASSERT(!NonBlocking);
	AssertComponentState("Collator_Packet_c::Input", ComponentRunning);
	InputEntry(Input, DataLength, Data, NonBlocking);
	//
	// Attach the decode buffer mentioned in the input packet
	// to the current coded data frame, to ensure release
	// at the appropriate time.
	//
	if (DataLength != sizeof(StreamInfo_t))
	{
		report(severity_error, "Collator_Packet_c::Input - Packet is wrong size (%d != %d)\n", DataLength, sizeof(StreamInfo_t));
		return CollatorError;
	}
	CapturedBuffer  = (Buffer_t)(CapturedFrameDescriptor->buffer_class);
	CodedFrameBuffer->AttachBuffer(CapturedBuffer);
	//
	// Perform the standard packet handling
	//
	Status  = Collator_Packet_c::Input(Input, DataLength, Data);
	InputExit();
	return Status;
}
Example #2
0
////////////////////////////////////////////////////////////////////////////
///
/// De-packetize incoming data and pass it to the elementary stream handler.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::Input(PlayerInputDescriptor_t *Input,
					    unsigned int DataLength,
					    void *Data,
					    bool NonBlocking,
					    unsigned int *DataLengthRemaining)
{
	CollatorStatus_t Status;
//
	st_relayfs_write(ST_RELAY_TYPE_PES_AUDIO_BUFFER, ST_RELAY_SOURCE_AUDIO_COLLATOR, (unsigned char *)Data, DataLength, 0);
	COLLATOR_ASSERT(!NonBlocking);
	AssertComponentState("Collator_PesAudio_c::Input", ComponentRunning);
	InputEntry(Input, DataLength, Data, NonBlocking);
	ActOnInputDescriptor(Input);
	//
	// Copy our arguments to class members so the utility functions can
	// act upon it.
	//
	RemainingData = (unsigned char *)Data;
	RemainingLength = DataLength;
	//
	// Continually handle units of input until all input is exhausted (or an error occurs).
	//
	// Be aware that our helper functions may, during their execution, cause state changes
	// that result in a different branch being taken next time round the loop.
	//
	Status = CollatorNoError;
	while (Status == CollatorNoError && RemainingLength != 0)
	{
		//COLLATOR_DEBUG("De-PESing loop has %d bytes remaining\n", RemainingLength);
		//report_dump_hex( severity_note, RemainingData, min(RemainingLength, 188), 32, 0);
		if (SeekingPesHeader)
		{
			//
			// Try to lock to incoming PES headers
			//
			Status = SearchForPesHeader();
		}
		else if (GotPartialPesHeader)
		{
			//
			// Read in the remains of the PES header
			//
			Status = ReadPartialPesHeader();
		}
		else
		{
			//
			// Send the PES packet for frame level analysis
			//
			Status = ReadPesPacket();
		}
	}
	if (Status != CollatorNoError)
	{
		// if anything when wrong then we need to resynchronize
		COLLATOR_DEBUG("General failure; seeking new PES header\n");
		DiscardAccumulatedData();
		SeekingPesHeader = true;
	}
	InputExit();
	return Status;
}
Example #3
0
////////////////////////////////////////////////////////////////////////////
///
/// Handle losing lock on the frame headers.
///
/// This function is called to handle the data that was spuriously accumulated
/// when the frame header was badly parsed.
///
/// In principle this function is quite simple. We allocate a new accumulation buffer and
/// use the currently accumulated data is the data source to run the elementary stream
/// state machine. There is however a little extra logic to get rid of recursion.
/// Specificially we change the error handling behaviour if this method is re-entered
/// so that there error is reported back to the already executing copy of the method.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::HandleMissingNextFrameHeader(void)
{
	CollatorStatus_t Status;
	//
	// Mark the collator as having lost frame lock.
	// Yes! We really do want to do this before the re-entry checks.
	//
	CollatorState = SeekingSyncWord; // we really do want to do this before the re-entry checks
	AccumulatedFrameReady = false;
	//
	// Check for re-entry
	//
	if (AlreadyHandlingMissingNextFrameHeader)
	{
		COLLATOR_DEBUG("Re-entered the error recovery handler, initiating stack unwind\n");
		return CollatorUnwindStack;
	}
	//
	// Check whether the sub-class wants trivial or aggressive error recovery
	//
	if (!ReprocessAccumulatedDataDuringErrorRecovery)
	{
		DiscardAccumulatedData();
		return CollatorNoError;
	}
	//
	// Remember the original elementary stream pointers for when we return to 'normal' processing.
	//
	unsigned char *OldRemainingElementaryOrigin = RemainingElementaryOrigin;
	unsigned char *OldRemainingElementaryData = RemainingElementaryData;
	unsigned int OldRemainingElementaryLength = RemainingElementaryLength;
	//
	// Take ownership of the already accumulated data
	//
	Buffer_t ReprocessingDataBuffer = CodedFrameBuffer;
	unsigned char *ReprocessingData = BufferBase;
	unsigned int ReprocessingDataLength = AccumulatedDataSize;
	ReprocessingDataBuffer->SetUsedDataSize(ReprocessingDataLength);
	Status = ReprocessingDataBuffer->ShrinkBuffer(max(ReprocessingDataLength, 1));
	if (Status != BufferNoError)
	{
		COLLATOR_ERROR("Failed to shrink the reprocessing buffer to size (%08x).\n", Status);
		// not fatal - we're merely wasting memory
	}
	// At the time of writing GetNewBuffer() doesn't check for leaks. This is good because otherwise
	// we wouldn't have transfer the ownership of the ReprocessingDataBuffer by making this call.
	Status = GetNewBuffer();
	if (Status != CollatorNoError)
	{
		COLLATOR_ERROR("Cannot get new buffer during error recovery\n");
		return CollatorError;
	}
	//
	// Remember that we are re-processing the previously accumulated elementary stream
	//
	AlreadyHandlingMissingNextFrameHeader = true;
	//
	// WARNING: From this point on we own the ReprocessingDataBuffer, have set the recursion avoidance
	// marker and may have damaged the RemainingElementaryData pointer. There should be no
	// short-circuit exit paths used after this point otherwise we risk avoiding the clean up
	// at the bottom of the method.
	//
	while (ReprocessingDataLength > 1)
	{
		//
		// Remove the first byte from the recovery buffer (to avoid detecting again the same start code).
		//
		ReprocessingData += 1;
		ReprocessingDataLength -= 1;
		//
		// Search for a start code in the reprocessing data. This allows us to throw away data that we
		// know will never need reprocessing which makes the recursion avoidance code more efficient.
		//
		RemainingElementaryOrigin = ReprocessingData;
		RemainingElementaryData = ReprocessingData;
		RemainingElementaryLength = ReprocessingDataLength;
		int CodeOffset;
		PotentialFrameHeaderLength = 0; // ensure no (now voided) historic data is considered by sub-class
		Status = FindNextSyncWord(&CodeOffset);
		if (Status == CodecNoError)
		{
			COLLATOR_ASSERT(CodeOffset >= 0);
			COLLATOR_DEBUG("Found start code during error recovery (byte %d of %d)\n",
				       CodeOffset, ReprocessingDataLength);
			// We found a start code, snip off all preceding data
			ReprocessingData += CodeOffset;
			ReprocessingDataLength -= CodeOffset;
		}
		else
		{
			// We didn't find a start code, snip off everything except the last few bytes. This
			// final fragment may contain a partial start code so we want to pass if through the
			// elementary stream handler again.
			unsigned FinalBytes = min(ReprocessingDataLength, FrameHeaderLength - 1);
			COLLATOR_DEBUG("Found no start code during error recovery (processing final %d bytes of %d)\n",
				       ReprocessingDataLength, FinalBytes);
			ReprocessingData += ReprocessingDataLength;
			ReprocessingDataLength = FinalBytes;
			ReprocessingData -= ReprocessingDataLength;
		}
		//
		// Process the elementary stream
		//
		Status = HandleElementaryStream(ReprocessingDataLength, ReprocessingData);
		if (CollatorNoError == Status)
		{
			COLLATOR_DEBUG("Error recovery completed, returning to normal processing\n");
			// All data consumed and stored in the subsequent accumulation buffer
			break; // Success will propagate when we return Status
		}
		else if (CollatorUnwindStack == Status)
		{
			COLLATOR_DEBUG("Stack unwound successfully, re-trying error recovery\n");
			// We found a frame header but lost lock again... let's have another go
			AccumulatedDataSize = 0; // make sure no accumulated data is carried round the loop
			continue;
		}
		else
		{
			COLLATOR_ERROR("Error handling elementary stream during error recovery\n");
			break; // Failure will propagate when we return Status
		}
	}
	//
	// Free the buffer we just consumed and restore the original elementary stream pointers
	//
	RemainingElementaryOrigin = OldRemainingElementaryOrigin;
	RemainingElementaryData = OldRemainingElementaryData;
	RemainingElementaryLength = OldRemainingElementaryLength;
	(void) ReprocessingDataBuffer->DecrementReferenceCount(IdentifierCollator);
	AlreadyHandlingMissingNextFrameHeader = false;
	return Status;
}
////////////////////////////////////////////////////////////////////////////
///
/// Determine the new state of the collator according to the incoming sub frame
/// Also returns this sub frame length
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudioDtshd_c::DecideCollatorNextStateAndGetLength(unsigned int *FrameLength)
{
	FrameParserStatus_t FPStatus;
	CollatorStatus_t Status;
	DtshdAudioParsedFrameHeader_t ParsedFrameHeader;
	//
	// first check if we know about the real frame size when it comes to dts core sync
	if (!GotCoreFrameSize)
	{
		int CodeOffset;
		DtshdStreamType_t Type;
		// To determine frame length, search for a synchro in the provided buffer
		Status = FindAnyNextSyncWord(&CodeOffset, &Type);
		if (Status == CollatorNoError)
		{
			GotCoreFrameSize = true;
			// CodeOffset may be negative, indicating the sync word has been found fully or
			// paritally within the frame header we already accumulated. Given this
			// meaning it is impossible for the FrameHeaderLength + CodeOffset to be
			// negative.
			COLLATOR_ASSERT(((int) FrameHeaderLength + CodeOffset) >= 0);
			*FrameLength = FrameHeaderLength + CodeOffset;
			if (0 == *FrameLength)
			{
				// The sync word is contained within the first byte of the StoredFrameHeader
				// just as it would be it we had known the CoreFrameSize originally. At this
				// stage therefore CoreFrameSize already has the right value (we are about to
				// add zero to it) so we can simply change the value of GotCoreFrameSize
				// (which we have already done) and try again.
				return DecideCollatorNextStateAndGetLength(FrameLength);
			}
		}
		else
		{
			// synchro not found, but frame is at least the size of the buffer we just searched
			*FrameLength = RemainingElementaryLength + FrameHeaderLength - DTSHD_RAW_SYNCHRO_BYTES_NEEDED;
		}
		CollatorState = ReadSubFrame;
		CoreFrameSize += *FrameLength;
		Status = CollatorNoError;
	}
	else
	{
		DtshdParseModel_t ParseModel = {ParseForSynchro, 0, 0};
		/* We have already calculated the CoreFrameSize so better to set CodedFrameParameters->DataSpecificFlags here instead of state "GotCompleteFrame".
		 Because it is possible that InternalFrameFlush is called from the drain and so the frame_parser called for already parsed frame.
		 And the frame parser require DataSpecificFlags to see the core frame size. See the bz24622 */
		CodedFrameParameters->DataSpecificFlags = CoreFrameSize;
		FPStatus = FrameParser_AudioDtshd_c::ParseSingleFrameHeader(StoredFrameHeader,
									    &ParsedFrameHeader,
									    &Bits,
									    FrameHeaderLength,
									    RemainingElementaryData,
									    RemainingElementaryLength,
									    ParseModel,
									    0);
		if (FPStatus == FrameParserNoError)
		{
			if (CollatorState == GotSynchronized)
			{
				// remember the first synchronized substream properties
				memcpy(&SyncFrameHeader, &ParsedFrameHeader, sizeof(DtshdAudioSyncFrameHeader_t));
			}
			Status = CollatorNoError;
			if (ParsedFrameHeader.Type == TypeDtshdCore)
			{
				if (SyncFrameHeader.Type == TypeDtshdExt)
				{
					// we should not encounter such core streams, this means
					// we synchron ized on a false substream...
					// so we will accumulate t his wrong extension frame, plus the regular frame
					// and the frame parser will reanalyse this situation to tell the codec to
					// start decoding atfer he extension frame
					GotCoreFrameSize = false;
					// get rid of frame header
					*FrameLength = 0;
					// accumulate this frame...
					CollatorState = GotSynchronized;
					SyncFrameHeader.Type = TypeDtshdCore;
				}
				else
				{
					// regular case, the next frame is a core substream that means
					// that this frame is over
					*FrameLength = CoreFrameSize;
					CollatorState = GotCompleteFrame;
				}
			}
			else if (ParsedFrameHeader.Type == TypeDtshdExt)
			{
				if ((SyncFrameHeader.Type == TypeDtshdExt) &&
						(SyncFrameHeader.SubStreamId == ParsedFrameHeader.SubStreamId) &&
						(CollatorState != GotSynchronized))
				{
					// case of a pure dts-hd frame composed of extension substreams only
					*FrameLength = ParsedFrameHeader.Length;
					CollatorState = GotCompleteFrame;
				}
				else
				{
					// ac cumulate this frame...
					CollatorState = ReadSubFrame;
					// we are confident wi th these data...
					*FrameLength = ParsedFrameHeader.Length;
				}
			}
		}
		else
		{
			Status = CollatorError;
		}
	}
	if (CollatorState == GotCompleteFrame)
	{
		ResetDvdSyncWordHeuristics();
	}
	return Status;
}
////////////////////////////////////////////////////////////////////////////
///
/// Determine the new state of the collator according to the incoming sub frame
/// Also returns this sub frame length
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudioLpcm_c::DecideCollatorNextStateAndGetLength( unsigned int *FrameLength )
{
  CollatorStatus_t Status = CollatorNoError;

  //
  COLLATOR_DEBUG(">><<\n");
  
  if ( IsFirstPacket )
    {
      //case of very first packet, skip the packet portion before the FirstAccessUnitOffsetPointer
      CollatorState = SkipSubFrame;

      IsFirstPacket = false;

      // for the very first packet of dvd-audio, the stuffing bytes are not part of the PDA
      // since Configuration.ExtendedHeaderLength is not the same as PrivateHeaderLength,
      // so skip these bytes in this case
      
      *FrameLength = PesPrivateToSkip +
	             NextParsedFrameHeader.FirstAccessUnitPointer + 
	             FirstAccessUnitOffset[StreamType] -
	             NextParsedFrameHeader.PrivateHeaderLength;
      PesPrivateToSkip = 0;

      COLLATOR_TRACE("First packet: Skipping %d bytes\n", *FrameLength);

      return (Status);
    }

  // accumulate the private data area for the frame parser, 
  // if some major parameter inside have changed...

  if ( AccumulatePrivateDataArea )
    {
      // save the location of the private data area, to update it later...
      Status = AccumulateData( Configuration.ExtendedHeaderLength, &NewPesPrivateDataArea[0] );
      if ( Status != CollatorNoError )
	{
	  return (Status);
	}
      AccumulatePrivateDataArea = false;
      COLLATOR_DEBUG("Accumulate PDA of length %d\n", Configuration.ExtendedHeaderLength);
    }

  if ( !IsPesPrivateDataAreaValid )
    {
      //case of wrong packet passed to collator, skip the whole packet
      CollatorState = SkipSubFrame;
      *FrameLength = RemainingElementaryLength;
    }
  else if ( PesPrivateToSkip > 0 )
    {
      CollatorState = SkipSubFrame;
      *FrameLength = min(PesPrivateToSkip, RemainingElementaryLength);
      PesPrivateToSkip -= *FrameLength;
      COLLATOR_DEBUG("Skipping %d bytes of pda\n", *FrameLength);
    }
  else if ( RemainingDataLength > 0 )
    {
      CollatorState = ReadSubFrame;
      *FrameLength = min(RemainingDataLength, RemainingElementaryLength);
      RemainingDataLength -= *FrameLength;
      COLLATOR_DEBUG("Reading %d bytes (rest of frame)\n", *FrameLength);
    }
  else if ( (AccumulatedFrameNumber >= NbAudioFramesToGlob[StreamType][NextParsedFrameHeader.SamplingFrequency1]) ||
       IsPesPrivateDataAreaNew )
    {
      // flush the frame if we have already more than x accumulated frames
      // or if some pda key parameters are new
      CollatorState = GotCompleteFrame;
      COLLATOR_DEBUG("Flush after %d audio frames\n", AccumulatedFrameNumber);

      AccumulatedFrameNumber = 0;
      // prevent accumulating anything for this frame, the next thing we need to do
      // is accumlate the private data area for the frame parser but we can't do that
      // until we've cleared this frame from the accumulation buffer.
      *FrameLength = 0;
      // at next call of this function accumulate the pda
      AccumulatePrivateDataArea = true;
      // reset
      IsPesPrivateDataAreaNew = false;

      PlaybackTime += (GlobbedFramesOfNewPacket * LpcmPresentationTime[StreamType][NextParsedFrameHeader.SamplingFrequency1]);

      COLLATOR_DEBUG("PlaybackTime: %x\n", PlaybackTime);
    }
  else
    {
      // normal case: accumulate the audio frames
      CollatorState = ReadSubFrame;
      AccumulatedFrameNumber += 1;
      GlobbedFramesOfNewPacket += 1;
      
      COLLATOR_ASSERT(0 == RemainingDataLength);
      COLLATOR_ASSERT(0 == PesPrivateToSkip);

      // DVD-audio allows stuffing bytes to form part of the private data area (and these can be different
      // for each packet). We can't easily handle this in the PES layer since the length can't be predicted
      // and therefore we cannot set Configuration.ExtendedHeaderLength until it is too late. Instead
      // Collator_PesAudioLpcm_c::HandlePesPrivateData() records how many bytes we must skip
      // (PesPrivateToSkip) and leaves it to the state change logic to skip that data. This means that we
      // must ensure that this method will be called at the right point to skip data. We do this be making
      // sure we don't ever return a *FrameLength larger than the RemainingElementaryData .
      if ((RemainingElementaryLength < NextParsedFrameHeader.AudioFrameSize))
	{
	  RemainingDataLength = NextParsedFrameHeader.AudioFrameSize - RemainingElementaryLength;
	  *FrameLength        = RemainingElementaryLength;
	}
      else
	{
	  // read the whole frame!
	  *FrameLength        = NextParsedFrameHeader.AudioFrameSize;
	}

      COLLATOR_DEBUG("Read frame of size %d (total frames in this chunk: %d)\n", 
		     *FrameLength, 
		     AccumulatedFrameNumber);
    }

 return Status;
}
Example #6
0
//{{{ Input
////////////////////////////////////////////////////////////////////////////
///
/// Extract Frame length from Pes Private Data area if present.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesFrame_c::Input(PlayerInputDescriptor_t *Input,
					    unsigned int DataLength,
					    void *Data,
					    bool NonBlocking,
					    unsigned int *DataLengthRemaining)
{
	CollatorStatus_t Status = CollatorNoError;
	bool PrivateDataPresent;
	unsigned char *DataBlock = (unsigned char *)Data;
	unsigned char *PesHeader;
	unsigned char *PayloadStart;
	unsigned int PayloadLength;
	unsigned int PesLength;
	unsigned int Offset;
	COLLATOR_ASSERT(!NonBlocking);
	AssertComponentState("Collator_PesFrame_c::Input", ComponentRunning);
	InputEntry(Input, DataLength, Data, NonBlocking);
	Offset = 0;
	while (Offset < DataLength)
	{
		// Read the length of the payload
		PrivateDataPresent = false;
		PesHeader = DataBlock + Offset;
		PesLength = (PesHeader[4] << 8) + PesHeader[5];
		if (PesLength != 0)
			PayloadLength = PesLength - PesHeader[8] - 3;
		else
			PayloadLength = 0;
		COLLATOR_DEBUG("DataLength %d, PesLength %d; PayloadLength %d, Offset %d\n", DataLength, PesLength, PayloadLength, Offset);
		Offset += PesLength + 6; // PES packet is PesLength + 6 bytes long
		Bits.SetPointer(PesHeader + 9); // Set bits pointer ready to process optional fields
		if ((PesHeader[7] & 0x80) == 0x80) // PTS present?
			//{{{ read PTS
		{
			Bits.FlushUnseen(4);
			PlaybackTime = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			PlaybackTime |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			PlaybackTime |= Bits.Get(15);
			Bits.FlushUnseen(1);
			PlaybackTimeValid = true;
			COLLATOR_DEBUG("PTS %llu.\n", PlaybackTime);
		}
		//}}}
		if ((PesHeader[7] & 0xC0) == 0xC0) // DTS present?
			//{{{ read DTS
		{
			Bits.FlushUnseen(4);
			DecodeTime = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			DecodeTime |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			DecodeTime |= Bits.Get(15);
			Bits.FlushUnseen(1);
			DecodeTimeValid = true;
		}
		//}}}
		else if ((PesHeader[7] & 0xC0) == 0x40)
		{
			COLLATOR_ERROR("Malformed pes header contains DTS without PTS.\n");
			DiscardAccumulatedData(); // throw away previous frame as incomplete
			InputExit();
			return CollatorError;
		}
		//}}}
		//{{{ walk down optional bits
		if ((PesHeader[7] & 0x20) == 0x20) // ESCR present
			Bits.FlushUnseen(48); // Size of ESCR
		if ((PesHeader[7] & 0x10) == 0x10) // ES Rate present
			Bits.FlushUnseen(24); // Size of ES Rate
		if ((PesHeader[7] & 0x08) == 0x08) // Trick mode control present
			Bits.FlushUnseen(8); // Size of Trick mode control
		if ((PesHeader[7] & 0x04) == 0x04) // Additional copy info present
			Bits.FlushUnseen(8); // Size of additional copy info
		if ((PesHeader[7] & 0x02) == 0x02) // PES CRC present
			Bits.FlushUnseen(16); // Size of previous packet CRC
		if ((PesHeader[7] & 0x01) == 0x01) // PES Extension flag
		{
			PrivateDataPresent = Bits.Get(1);
			Bits.FlushUnseen(7); // Size of Pes extension data
		}
		//}}}
		if (PrivateDataPresent)
		{
			if (RemainingDataLength != 0)
			{
				COLLATOR_ERROR("%s: Warning new frame indicated but %d bytes missing\n", __FUNCTION__, RemainingDataLength);
				DiscardAccumulatedData(); // throw away previous frame as incomplete
			}
			FrameSize = Bits.Get(8) + (Bits.Get(8) << 8) + (Bits.Get(8) << 16);
			RemainingDataLength = FrameSize;
			COLLATOR_DEBUG("%s: PlaybackTimeValid %d, PlaybackTime %llx, FrameSize %d\n", __FUNCTION__, PlaybackTimeValid, PlaybackTime, FrameSize);
		}
		if ((int)PayloadLength > RemainingDataLength) // Too much data - have some packets been lost?
		{
			if (RemainingDataLength != 0)
			{
				COLLATOR_ERROR("%s: Warning packet contains more bytes than needed %d bytes missing?\n", __FUNCTION__, RemainingDataLength);
				DiscardAccumulatedData(); // throw away previous frame as incomplete
				//RemainingDataLength = 0;
				//InputExit();
				//return CollatorError;
			}
			RemainingDataLength = PayloadLength; // assume new packet is stand alone frame
		}
		AccumulateStartCode(PackStartCode(AccumulatedDataSize, 0x42));
		PayloadStart = PesHeader + (PesLength + 6 - PayloadLength);
		Status = AccumulateData(PayloadLength, (unsigned char *)PayloadStart);
		if (Status != CollatorNoError)
		{
			InputExit();
			return Status;
		}
		RemainingDataLength -= PayloadLength;
		if (RemainingDataLength <= 0)
		{
			Status = InternalFrameFlush(); // flush out collected frame
			if (Status != CollatorNoError)
			{
				InputExit();
				return Status;
			}
		}
		COLLATOR_DEBUG("%s PrivateDataPresent %d, RemainingDataLength %d, PayloadLength %d\n",
			       __FUNCTION__, PrivateDataPresent, RemainingDataLength, PayloadLength);
	}
	InputExit();
	return CollatorNoError;
}
//}}}
//{{{ Input
////////////////////////////////////////////////////////////////////////////
///
/// Extract Frame length from Pes Private Data area if present.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesVideoMjpeg_c::Input(PlayerInputDescriptor_t *Input,
												 unsigned int DataLength,
												 void *Data,
												 bool NonBlocking,
												 unsigned int *DataLengthRemaining)
{
	CollatorStatus_t Status = CollatorNoError;
	unsigned char *DataBlock = (unsigned char *)Data;
	unsigned char *PesHeader;
	unsigned int PesLength;
	unsigned int PayloadLength;
	unsigned int Offset;
	unsigned int CodeOffset;
	unsigned int Code;
	AssertComponentState("Collator_PacketPes_c::Input", ComponentRunning);
	COLLATOR_ASSERT(!NonBlocking);
	InputEntry(Input, DataLength, Data, NonBlocking);
	Offset = 0;
	RemainingData = (unsigned char *)Data;
	RemainingLength = DataLength;
	TerminationFlagIsSet = false;
	Offset = 0;
	while (Offset < DataLength)
	{
		// Read the length of the payload
		PesHeader = DataBlock + Offset;
		PesLength = (PesHeader[4] << 8) + PesHeader[5];
		if (PesLength != 0)
			PayloadLength = PesLength - PesHeader[8] - 3;
		else
			PayloadLength = 0;
		COLLATOR_DEBUG("DataLength %d, PesLength %d; PayloadLength %d, Offset %d\n", DataLength, PesLength, PayloadLength, Offset);
		Offset += PesLength + 6; // PES packet is PesLength + 6 bytes long
		Bits.SetPointer(PesHeader + 9); // Set bits pointer ready to process optional fields
		if ((PesHeader[7] & 0x80) == 0x80) // PTS present?
			//{{{ read PTS
		{
			Bits.FlushUnseen(4);
			PlaybackTime = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			PlaybackTime |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			PlaybackTime |= Bits.Get(15);
			Bits.FlushUnseen(1);
			PlaybackTimeValid = true;
			COLLATOR_DEBUG("PTS %llu.\n", PlaybackTime);
		}
		//}}}
		if ((PesHeader[7] & 0xC0) == 0xC0) // DTS present?
			//{{{ read DTS
		{
			Bits.FlushUnseen(4);
			DecodeTime = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			DecodeTime |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			DecodeTime |= Bits.Get(15);
			Bits.FlushUnseen(1);
			DecodeTimeValid = true;
		}
		//}}}
		else if ((PesHeader[7] & 0xC0) == 0x40)
		{
			COLLATOR_ERROR("Malformed pes header contains DTS without PTS.\n");
			DiscardAccumulatedData(); // throw away previous frame as incomplete
			InputExit();
			return CollatorError;
		}
		RemainingData = PesHeader + (PesLength + 6 - PayloadLength);
		RemainingLength = PayloadLength;
		while (RemainingLength > 0)
		{
			Status = FindNextStartCode(&CodeOffset);
			if (Status != CollatorNoError) // Error indicates no start code found
			{
				Status = AccumulateData(RemainingLength, RemainingData);
				if (Status != CollatorNoError)
					DiscardAccumulatedData();
				RemainingLength = 0;
				break;
			}
			// Got one accumulate up to and including it
			Status = AccumulateData(CodeOffset + 2, RemainingData);
			if (Status != CollatorNoError)
			{
				DiscardAccumulatedData();
				break;
			}
			Code = RemainingData[CodeOffset + 1];
			RemainingLength -= CodeOffset + 2;
			RemainingData += CodeOffset + 2;
			// Is it a block terminate code
			if ((Code == Configuration.BlockTerminateCode) && (AccumulatedDataSize > 2))
			{
				AccumulatedDataSize -= 2;
				Status = InternalFrameFlush((Configuration.StreamTerminateFlushesFrame && (Code == Configuration.StreamTerminationCode)));
				if (Status != CollatorNoError)
					break;
				BufferBase[0] = 0xff;
				BufferBase[1] = Code;
				AccumulatedDataSize = 2;
			}
			// Accumulate the start code
			Status = AccumulateStartCode(PackStartCode(AccumulatedDataSize - 2, Code));
			if (Status != CollatorNoError)
			{
				DiscardAccumulatedData();
				InputExit();
				return Status;
			}
		}
	}
	InputExit();
	return CollatorNoError;
}
CollatorStatus_t   Collator_PesVideoRaw_c::Input(PlayerInputDescriptor_t        *Input,
		unsigned int                    DataLength,
		void                           *Data,
		bool                            NonBlocking,
		unsigned int                   *DataLengthRemaining)
{
	PlayerStatus_t                      Status = PlayerNoError;
	COLLATOR_ASSERT(!NonBlocking);
	AssertComponentState("Collator_PesRaw_c::Input", ComponentRunning);
	InputEntry(Input, DataLength, Data, NonBlocking);
	// Extract the descriptor timing information
	ActOnInputDescriptor(Input);
	COLLATOR_DEBUG("DataLength    : %d\n", DataLength);
	if (DataRemaining == 0)
		//{{{  Treat the packet as a header, read metadata and build stream info
	{
		BufferStructure_t               BufferStructure;
		class Buffer_c*                 Buffer;
		unsigned int                    Format;
		unsigned char*                  DataBlock;
		unsigned char*                  PesHeader       = (unsigned char*)Data;
		unsigned int                    PesLength;
		unsigned int                    PesHeaderLength;
		unsigned int                    PayloadLength;
		COLLATOR_DEBUG("Header : %d\n", DataLength);
		//{{{  Read pes header
		// Read the length of the payload
		PesLength                       = (PesHeader[4] << 8) + PesHeader[5];
		PesHeaderLength                 = PesHeader[8];
		if (PesLength != 0)
			PayloadLength               = PesLength - PesHeaderLength - 3;
		else
			PayloadLength               = 0;
		COLLATOR_DEBUG("DataLength %d, PesLength %d, PesHeaderLength %d, PayloadLength %d\n", DataLength, PesLength, PesHeaderLength, PayloadLength);
		Bits.SetPointer(PesHeader + 9);                 // Set bits pointer ready to process optional fields
		if ((PesHeader[7] & 0x80) == 0x80)              // PTS present?
			//{{{  read PTS
		{
			Bits.FlushUnseen(4);
			PlaybackTime        = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			PlaybackTime       |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			PlaybackTime       |= Bits.Get(15);
			Bits.FlushUnseen(1);
			PlaybackTimeValid   = true;
			COLLATOR_DEBUG("PTS %llu.\n", PlaybackTime);
		}
		//}}}
		if ((PesHeader[7] & 0xC0) == 0xC0)              // DTS present?
			//{{{  read DTS
		{
			Bits.FlushUnseen(4);
			DecodeTime          = (unsigned long long)(Bits.Get(3)) << 30;
			Bits.FlushUnseen(1);
			DecodeTime         |= Bits.Get(15) << 15;
			Bits.FlushUnseen(1);
			DecodeTime         |= Bits.Get(15);
			Bits.FlushUnseen(1);
			DecodeTimeValid     = true;
		}
		//}}}
		else if ((PesHeader[7] & 0xC0) == 0x40)
		{
			COLLATOR_ERROR("Malformed pes header contains DTS without PTS.\n");
			InputExit();
			return CollatorError;
		}
		//}}}
		DataBlock                               = PesHeader + 9 + PesHeaderLength;
		//{{{  Trace
#if 0
		report(severity_info, "(%d)\n%06d: ", PayloadLength, 0);
		for (int i = 0; i < PayloadLength; i++)
		{
			report(severity_info, "%02x ", DataBlock[i]);
			if (((i + 1) & 0x1f) == 0)
				report(severity_info, "\n%06d: ", i + 1);
		}
		report(severity_info, "\n");
#endif
		//}}}
		// Check that this is what we think it is
		if (strcmp((char*)DataBlock, "STMicroelectronics") != 0)
		{
			//COLLATOR_TRACE("Id            : %s\n", Id);
			InputExit();
			return FrameParserNoError;
		}
		DataBlock                              += strlen((char*)DataBlock) + 1;
		// Fill in stream info for frame parser
		memcpy(&StreamInfo.width, DataBlock, sizeof(unsigned int));
		DataBlock                              += sizeof(unsigned int);
		memcpy(&StreamInfo.height, DataBlock, sizeof(unsigned int));
		DataBlock                              += sizeof(unsigned int);
		memcpy(&StreamInfo.FrameRateNumerator, DataBlock, sizeof(unsigned long long));
		DataBlock                              += sizeof(unsigned long long);
		memcpy(&StreamInfo.FrameRateDenominator, DataBlock, sizeof(unsigned long long));
		DataBlock                              += sizeof(unsigned long long);
		memcpy(&Format, DataBlock, sizeof(unsigned int));
		DataBlock                              += sizeof(unsigned int);
		//memcpy (&StreamInfo.interlaced, DataBlock, sizeof (unsigned int));
		//DataBlock                              += sizeof (unsigned int);
		memcpy(&DataRemaining, DataBlock, sizeof(unsigned int));
		DataBlock                              += sizeof(unsigned int);
		StreamInfo.interlaced                   = 0;
		StreamInfo.pixel_aspect_ratio.Numerator = 1;
		StreamInfo.pixel_aspect_ratio.Denominator = 1;
		//StreamInfo.FrameRateNumerator           = 25;
		//StreamInfo.FrameRateDenominator         = 1;
		StreamInfo.InputWindow.X                = 0;
		StreamInfo.InputWindow.Y                = 0;
		StreamInfo.InputWindow.Width            = StreamInfo.width;
		StreamInfo.InputWindow.Height           = StreamInfo.height;
		StreamInfo.OutputWindow                 = StreamInfo.InputWindow;
		memset(&StreamInfo.OutputWindow, 0, sizeof(StreamInfo.OutputWindow));
		if (DecodeBuffer == NULL)
		{
			// Fill out the buffer structure request
			memset(&BufferStructure, 0x00, sizeof(BufferStructure_t));
			BufferStructure.DimensionCount      = 2;
			BufferStructure.Dimension[0]        = StreamInfo.width;
			BufferStructure.Dimension[1]        = StreamInfo.height;
			//{{{  determine buffer format
			switch (Format)
			{
				case CodeToInteger('N', 'V', '2', '2'):
					BufferStructure.Format          = FormatVideo422_Raster;
					break;
				case CodeToInteger('R', 'G', 'B', 'P'):
					BufferStructure.Format          = FormatVideo565_RGB;
					break;
				case CodeToInteger('R', 'G', 'B', '3'):
					BufferStructure.Format          = FormatVideo888_RGB;
					break;
				case CodeToInteger('R', 'G', 'B', '4'):
					BufferStructure.Format          = FormatVideo8888_ARGB;
					break;
				case CodeToInteger('Y', 'U', 'Y', 'V'):
					BufferStructure.Format          = FormatVideo422_YUYV;
					break;
				default:
					COLLATOR_ERROR("Unsupported decode buffer format request %.4s\n", (char*) &Format);
					InputExit();
					return CollatorError;
			}
			//}}}
			// Ask the manifestor for the buffer
			Status                              = Manifestor->GetDecodeBuffer(&BufferStructure, &Buffer);
			if (Status != ManifestorNoError)
			{
				COLLATOR_ERROR("Failed to get decode buffer\n");
				InputExit();
				return CollatorError;
			}
			StreamInfo.buffer_class             = (unsigned int*)Buffer;
			// Get physical address of data buffer (not actually used later in pipeline)
			Status                              = Buffer->ObtainDataReference(NULL, NULL, (void**)&StreamInfo.buffer, PhysicalAddress);
			if (Status != BufferNoError)
			{
				COLLATOR_ERROR("Failed to get decode buffer data reference\n");
				InputExit();
				return CollatorError;
			}
			// Remember cached address so we can write to it
			Status                              = Buffer->ObtainDataReference(NULL, NULL, (void**)&DecodeBuffer, CachedAddress);
			if (Status != BufferNoError)
			{
				COLLATOR_ERROR("Failed to get decode buffer data reference\n");
				InputExit();
				return CollatorError;
			}
			CodedFrameBuffer->AttachBuffer(Buffer);                         // Attach to decode buffer (so it will be freed at the same time)
			Buffer->DecrementReferenceCount();                              // and release ownership of the buffer to the decode buffer
		}
		COLLATOR_DEBUG("%s: ImageSize          %6d\n", __FUNCTION__, DataRemaining);
		COLLATOR_DEBUG("%s: ImageWidth         %6d\n", __FUNCTION__, StreamInfo.width);
		COLLATOR_DEBUG("%s: ImageHeight        %6d\n", __FUNCTION__, StreamInfo.height);
		COLLATOR_DEBUG("%s: Format             %.4s\n", __FUNCTION__, (char *) &Format);
		Status                                  = CollatorNoError;
	}
	//}}}
	else
		//{{{  Assume packet is part of data - copy to decode buffer
	{
		if (DecodeBuffer == NULL)
		{
			COLLATOR_ERROR("No decode buffer available\n");
			InputExit();
			return CodecError;
		}
		// Transfer the packet to the next coded data frame and pass on
		memcpy(DecodeBuffer + DataCopied, Data, DataLength);
		DataRemaining                          -= DataLength;
		DataCopied                             += DataLength;
		if (DataRemaining <= 0)
		{
			Status                              = AccumulateData(sizeof(StreamInfo_t), (unsigned char*)&StreamInfo);
			DataRemaining                       = 0;
			DataCopied                          = 0;
			DecodeBuffer                        = NULL;
			if (Status != CollatorNoError)
			{
				COLLATOR_ERROR("Failed to accumulate StreamInfo\n");
				InputExit();
				return Status;
			}
			Status                              = InternalFrameFlush();
			if (Status != CollatorNoError)
				COLLATOR_ERROR("Failed to flush frame\n");
		}
	}
	//}}}
	InputExit();
	return Status;
}