////////////////////////////////////////////////////////////////////////////
///
/// Update the prediction after consuming data.
///
/// \param Adjustment Number of bytes to adjust the prediciton by, this is
/// expected to be negative.
///
void Collator_PesAudioDvd_c::AdjustDvdSyncWordPredictionAfterConsumingData(int Adjustment)
{
	if (Adjustment > 0)
		COLLATOR_ERROR("Probably implementation error - positive adjustment requested (%d)\n",
					   Adjustment);
	if (-Adjustment > SyncWordPrediction)
		SyncWordPrediction = INVALID_PREDICTION;
	if (SyncWordPrediction != WILDCARD_PREDICTION && SyncWordPrediction != INVALID_PREDICTION)
	{
		COLLATOR_DEBUG("Adjusting prediction from %d to %d\n",
					   SyncWordPrediction, SyncWordPrediction + Adjustment);
		SyncWordPrediction += Adjustment;
	}
	else
		COLLATOR_DEBUG("Prediciton is %s - no adjustment made\n",
					   (SyncWordPrediction == WILDCARD_PREDICTION ? "wildcarded" : "invalid"));
}
예제 #2
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the full PES header.
///
/// Strictly speaking this method handles two sub-states. In the first state
/// we do not have sufficient data accumulated to determine how long the PES
/// header is. In the second we still don't have a complete PES packet but
/// at least we know how much more data we need.
///
/// This code assumes that PES packet uses >=9 bytes PES headers rather than
/// the 6 byte headers found in the program stream map, padding stream,
/// private stream 2, etc.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialPesHeader(void)
{
	CollatorStatus_t Status;
	unsigned int PesHeaderBytes, BytesNeeded, BytesToRead;
	unsigned char PesPrivateData[MAX_PES_PRIVATE_DATA_LENGTH];
//
	if (GotPartialPesHeaderBytes < PES_INITIAL_HEADER_SIZE)
	{
		COLLATOR_DEBUG("Waiting for first part of PES header\n");
		StoredPesHeader = BufferBase + AccumulatedDataSize - GotPartialPesHeaderBytes;
		BytesToRead = min(RemainingLength, PES_INITIAL_HEADER_SIZE - GotPartialPesHeaderBytes);
		Status = AccumulateData(BytesToRead, RemainingData);
		if (Status == CollatorNoError)
		{
			GotPartialPesHeaderBytes += BytesToRead;
			RemainingData += BytesToRead;
			RemainingLength -= BytesToRead;
		}
		else
		{
			COLLATOR_DEBUG("Cannot accumulate data #6 (%d)\n", Status);
		}
		return Status;
	}
	//
	// We now have accumulated sufficient data to know how long the PES header actually is!
	//
	// pass the stream_id field to the collator sub-class (might update Configuration.ExtendedHeaderLength)
	SetPesPrivateDataLength(StoredPesHeader[3]);
	PesHeaderBytes = PES_INITIAL_HEADER_SIZE + StoredPesHeader[8] + Configuration.ExtendedHeaderLength;
	BytesNeeded = PesHeaderBytes - GotPartialPesHeaderBytes;
	BytesToRead = min(RemainingLength, BytesNeeded);
	Status = AccumulateData(BytesToRead, RemainingData);
	if (Status == CollatorNoError)
	{
		GotPartialPesHeaderBytes += BytesToRead;
		RemainingData += BytesToRead;
		RemainingLength -= BytesToRead;
		COLLATOR_DEBUG("BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead);
		if (BytesNeeded == BytesToRead)
		{
			//
			// Woo hoo! We've got the whole header, examine it and change state
			//
			COLLATOR_DEBUG("Got entire PES header\n");
			//report_dump_hex( severity_note, StoredPesHeader, PesHeaderBytes, 32, 0);
			Status = CollatorNoError; // strictly speaking this is a no-op but the code might change
			if (StoredPesHeader[0] != 0x00 || StoredPesHeader[1] != 0x00 || StoredPesHeader[2] != 0x01 ||
					CollatorNoError != (Status = ReadPesHeader()))
			{
				COLLATOR_DEBUG("%s; seeking new PES header",
					       (Status == CollatorNoError ? "Start code not where expected" :
						"Badly formed PES header"));
				SeekingPesHeader = true;
				DiscardAccumulatedData();
				// we have contained the error by changing states...
				return CollatorNoError;
			}
			//
			// Placeholder: Generic stream id based PES filtering (configured by sub-class) could be inserted
			// here (set DiscardPesPacket to true to discard).
			//
			if (Configuration.ExtendedHeaderLength)
			{
				// store a pointer to the PES private header. it is located just above the end of the
				// accumulated data and is will be safely accumulated providing the private header is
				// smaller than the rest of the PES packet. if a very large PES private header is
				// encountered we will need to introduce a temporary buffer to store the header in.
				if (Configuration.ExtendedHeaderLength <= MAX_PES_PRIVATE_DATA_LENGTH)
				{
					memcpy(PesPrivateData, BufferBase + AccumulatedDataSize - Configuration.ExtendedHeaderLength, Configuration.ExtendedHeaderLength);
				}
				else
				{
					COLLATOR_ERROR("Implementation error: Pes Private data area too big for temporay buffer\n");
				}
				Status = HandlePesPrivateData(PesPrivateData);
				if (Status != CollatorNoError)
				{
					COLLATOR_ERROR("Unhandled error when parsing PES private data\n");
					return (Status);
				}
			}
			// discard the actual PES packet from the accumulate buffer
			AccumulatedDataSize -= PesHeaderBytes;
			// record the number of bytes we need to ignore before we reach the next start code
			PesPayloadRemaining = PesPayloadLength;
			// switch states and absorb the packet
			COLLATOR_DEBUG("Discovered PES packet (header %d bytes, payload %d bytes)\n",
				       PesPacketLength - PesPayloadLength + 6, PesPayloadLength);
			GotPartialPesHeader = false;
			if (PassPesPrivateDataToElementaryStreamHandler && Configuration.ExtendedHeaderLength)
			{
				// update PesPacketLength (to ensure that GetOffsetIntoPacket gives the correct value)
				PesPayloadLength += Configuration.ExtendedHeaderLength;
				Status = HandleElementaryStream(Configuration.ExtendedHeaderLength, PesPrivateData);
				if (Status != CollatorNoError)
				{
					COLLATOR_ERROR("Failed not accumulate the PES private data area\n");
				}
			}
		}
	}
	else
	{
		COLLATOR_DEBUG("Cannot accumulate data #7 (%d)\n", Status);
	}
	return Status;
}
예제 #3
0
////////////////////////////////////////////////////////////////////////////
///
/// Scan the input until an appropriate PES start code is found.
///
/// Scans any Collator_Pes_c::RemainingData searching for a PES start code.
/// The configuration for this comes from Collator_Base_c::Configuration and
/// is this means that only the interesting (e.g. PES audio packets) start
/// codes will be detected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::SearchForPesHeader(void)
{
	CollatorStatus_t Status;
	unsigned int CodeOffset;
//
	//
	// If there are any trailing start codes handle those.
	//
	while (TrailingStartCodeBytes && RemainingLength)
	{
		if (TrailingStartCodeBytes == 3)
		{
			// We've got the 0, 0, 1 so if the code is *not* in the ignore range then we've got one
			unsigned char SpecificCode = RemainingData[0];
			if (!inrange(SpecificCode, Configuration.IgnoreCodesRangeStart,
					Configuration.IgnoreCodesRangeEnd))
			{
				COLLATOR_DEBUG("Found a trailing startcode 00, 00, 01, %x\n", SpecificCode);
				// Consume the specific start code
				RemainingData++;
				RemainingLength--;
				// Switch state (and reflect the data we are about to accumulate)
				SeekingPesHeader = false;
				GotPartialPesHeader = true;
				//assert( AccumulatedDataSize == 0 );
				GotPartialPesHeaderBytes = 4;
				// There are now no trailing start code bytes
				TrailingStartCodeBytes = 0;
				// Finally, accumulate the data (by reconstructing it)
				unsigned char StartCode[4] = { 0, 0, 1, SpecificCode };
				Status = AccumulateData(4, StartCode);
				if (Status != CollatorNoError)
					COLLATOR_DEBUG("Cannot accumulate data #5 (%d)\n", Status);
				return Status;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing start code 00, 00, 01, %x was in the ignore range\n", SpecificCode);
			TrailingStartCodeBytes = 0;
			break;
		}
		else if (TrailingStartCodeBytes == 2)
		{
			// Got two zeros, a one gets us ready to read the code.
			if (RemainingData[0] == 1)
			{
				COLLATOR_DEBUG("Trailing start code looks good (found 00, 00; got 01)\n");
				TrailingStartCodeBytes++;
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Got two zeros, another zero still leaves us with two zeros.
			if (RemainingData[0] == 0)
			{
				COLLATOR_DEBUG("Trailing start code looks OK (found 00, 00; got 00)\n");
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing 00, 00 was not part of a start code\n");
			TrailingStartCodeBytes = 0;
			break;
		}
		else if (TrailingStartCodeBytes == 1)
		{
			// Got one zero, another zero gives us two (duh).
			if (RemainingData[0] == 0)
			{
				COLLATOR_DEBUG("Trailing start code looks good (found 00; got 00)\n");
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing 00 was not part of a start code\n");
			TrailingStartCodeBytes = 0;
			break;
		}
		else
		{
			COLLATOR_ERROR("TrailingStartCodeBytes has illegal value: %d\n", TrailingStartCodeBytes);
			TrailingStartCodeBytes = 0;
			return CollatorError;
		}
	}
	if (RemainingLength == 0)
	{
		return CollatorNoError;
	}
	//assert(TrailingStartCodeBytes == 0);
//
	Status = FindNextStartCode(&CodeOffset);
	if (Status == CollatorNoError)
	{
		COLLATOR_DEBUG("Locked to PES packet boundaries\n");
		// discard any data leading up to the start code
		RemainingData += CodeOffset;
		RemainingLength -= CodeOffset;
		// switch state
		SeekingPesHeader = false;
		GotPartialPesHeader = true;
		GotPartialPesHeaderBytes = 0;
	}
	else
	{
		// examine the end of the buffer to determine if there is a (potential) trailing start code
		//assert( RemainingLength >= 1 );
		if (RemainingData[RemainingLength - 1] < 1)
		{
			unsigned char LastBytes[3];
			LastBytes[0] = (RemainingLength >= 3 ? RemainingData[RemainingLength - 3] : 0xff);
			LastBytes[1] = (RemainingLength >= 2 ? RemainingData[RemainingLength - 2] : 0xff);
			LastBytes[2] = RemainingData[RemainingLength - 1];
			if (LastBytes[0] == 0 && LastBytes[1] == 0 && LastBytes[2] == 1)
			{
				TrailingStartCodeBytes = 3;
			}
			else if (LastBytes[1] == 0 && LastBytes[2] == 0)
			{
				TrailingStartCodeBytes = 2;
			}
			else if (LastBytes[2] == 0)
			{
				TrailingStartCodeBytes = 1;
			}
		}
		COLLATOR_DEBUG("Discarded %d bytes while searching for PES header (%d might be start code)\n",
			       RemainingLength, TrailingStartCodeBytes);
		RemainingLength = 0;
	}
//
	return CollatorNoError;
}
예제 #4
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;
}
예제 #5
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the parseable frame header.
///
/// Accumulate data until we have ::FrameHeaderLength
/// bytes stashed away. At this point there is sufficient data accumulated
/// to determine how many bytes will pass us by before the next frame header
/// is expected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialFrameHeader(void)
{
	CollatorStatus_t Status;
	unsigned int BytesNeeded, BytesToRead, FrameLength;
	CollatorState_t OldCollatorState;
	//
	COLLATOR_DEBUG(">><<\n");
	//
	BytesNeeded = FrameHeaderLength - GotPartialFrameHeaderBytes;
	BytesToRead = min(RemainingElementaryLength, BytesNeeded);
	Status = AccumulateData(BytesToRead, RemainingElementaryData);
	if (Status == CollatorNoError)
	{
		GotPartialFrameHeaderBytes += BytesToRead;
		RemainingElementaryData += BytesToRead;
		RemainingElementaryLength -= BytesToRead;
		COLLATOR_DEBUG("BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead);
		if (BytesNeeded == BytesToRead)
		{
			//
			// Woo hoo! We've got the whole header, examine it and change state
			//
			StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);
			COLLATOR_DEBUG("Got entire frame header packet\n");
			//report_dump_hex( severity_note, StoredFrameHeader, FrameHeaderLength, 32, 0);
			OldCollatorState = CollatorState;
			Status = DecideCollatorNextStateAndGetLength(&FrameLength);
			if (Status != CollatorNoError)
			{
				COLLATOR_DEBUG("Badly formed frame header; seeking new frame header\n");
				return HandleMissingNextFrameHeader();
			}
			if (FrameLength == 0)
			{
				// The LPCM collator needs to do this in order to get a frame evicted before
				// accumulating data from the PES private data area into the frame. The only
				// way it can do this is by reporting a zero length frame and updating some
				// internal state variables. On the next call it will report a non-zero value
				// (i.e. we won't loop forever accumulating no data).
				COLLATOR_DEBUG("Sub-class reported unlikely (but potentially legitimate) frame length (%d)\n", FrameLength);
			}
			if (FrameLength > MaximumCodedFrameSize)
			{
				COLLATOR_ERROR("Sub-class reported absurd frame length (%d)\n", FrameLength);
				return HandleMissingNextFrameHeader();
			}
			// this is the number of bytes we must absorb before switching state to SeekingFrameEnd.
			// if the value is negative then we've already started absorbing the subsequent frame
			// header.
			FramePayloadRemaining = FrameLength - FrameHeaderLength;
			if (CollatorState == GotCompleteFrame)
			{
				AccumulatedFrameReady = true;
				//
				// update the coded frame parameters using the parameters calculated the
				// last time we saw a frame header.
				//
				CodedFrameParameters->PlaybackTimeValid = NextPlaybackTimeValid;
				CodedFrameParameters->PlaybackTime = NextPlaybackTime;
				CodedFrameParameters->DecodeTimeValid = NextDecodeTimeValid;
				CodedFrameParameters->DecodeTime = NextDecodeTime;
			}
			else if (CollatorState == SkipSubFrame)
			{
				/* discard the accumulated frame header */
				AccumulatedDataSize -= FrameHeaderLength;
			}
			if (CollatorState == GotCompleteFrame || OldCollatorState == GotSynchronized)
			{
				//
				// at this point we have discovered a frame header and need to attach a time to it.
				// we can choose between the normal stamp (the stamp of the current PES packet) or the
				// spanning stamp (the stamp of the previous PES packet). Basically if we have accumulated
				// a greater number of bytes than our current offset into the PES packet then we want to
				// use the spanning time.
				//
				bool WantSpanningTime = GetOffsetIntoPacket() < (int) GotPartialFrameHeaderBytes;
				if (WantSpanningTime && !UseSpanningTime)
				{
					COLLATOR_ERROR("Wanted to take the spanning time but this was not available.");
					WantSpanningTime = false;
				}
				if (WantSpanningTime)
				{
					NextPlaybackTimeValid = SpanningPlaybackTimeValid;
					NextPlaybackTime = SpanningPlaybackTime;
					SpanningPlaybackTimeValid = false;
					NextDecodeTimeValid = SpanningDecodeTimeValid;
					NextDecodeTime = SpanningDecodeTime;
					SpanningDecodeTimeValid = false;
					UseSpanningTime = false;
				}
				else
				{
					NextPlaybackTimeValid = PlaybackTimeValid;
					NextPlaybackTime = PlaybackTime;
					PlaybackTimeValid = false;
					NextDecodeTimeValid = DecodeTimeValid;
					NextDecodeTime = DecodeTime;
					DecodeTimeValid = false;
				}
			}
			// switch states and absorb the packet
			COLLATOR_DEBUG("Discovered frame header (frame length %d bytes)\n", FrameLength);
		}
	}
	else
	{
		COLLATOR_DEBUG("Cannot accumulate data #3 (%d)\n", Status);
	}
	return Status;
}
예제 #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;
}
////////////////////////////////////////////////////////////////////////////
///
/// 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_PesAudioEAc3_c::DecideCollatorNextStateAndGetLength( unsigned int *FrameLength )
{
  FrameParserStatus_t FPStatus;
  CollatorStatus_t Status = CollatorNoError; // assume success unless told otherwise
  EAc3AudioParsedFrameHeader_t ParsedFrameHeader;

  //

  FPStatus = FrameParser_AudioEAc3_c::ParseSingleFrameHeader( StoredFrameHeader,
															  &ParsedFrameHeader,
															  false);

  if( FPStatus == FrameParserNoError )
  {
      *FrameLength = ParsedFrameHeader.Length;
	  
      if (CollatorState == SeekingFrameEnd)
	  {
		  // we already have an independant substream accumulated, check what to do with
		  // this next one
		  if (((ParsedFrameHeader.Type == TypeEac3Ind) && (ParsedFrameHeader.SubStreamId == ProgrammeId) && (NbAccumulatedSamples == EAC3_NBSAMPLES_NEEDED))
			  || (ParsedFrameHeader.Type == TypeAc3))
		  {
			  // this is another independant subframe
			  CollatorState = GotCompleteFrame;
			  NbAccumulatedSamples = ParsedFrameHeader.NumberOfSamples;
			  ResetDvdSyncWordHeuristics();
			  COLLATOR_DEBUG("Got a complete frame!\n");
		  }
		  else if ( ParsedFrameHeader.SubStreamId != ProgrammeId )
		  {
			  // skip any subframe (independant or dependant) that does not belong to the requested programme
			  CollatorState = SkipSubFrame;
		  }
		  else if ( NbAccumulatedSamples <= EAC3_NBSAMPLES_NEEDED )
		  {
			  // according to collator channel configuration,
			  // read or skip the dependant subframe of the right programme...
			  CollatorState = EightChannelsRequired?ReadSubFrame:SkipSubFrame;
			  if (ParsedFrameHeader.Type == TypeEac3Ind)
			  {
				  // acumulate samples only if this is an eac3 independant bistream (dependant bitstream provide additional channels only)
				  NbAccumulatedSamples += ParsedFrameHeader.NumberOfSamples;
			  }
			  COLLATOR_DEBUG("Accumulate a subframe of %d/%d samples\n", ParsedFrameHeader.NumberOfSamples, NbAccumulatedSamples);
		  }
		  else 
		  {
			  COLLATOR_ERROR("Accumulated too many samples (%d of %d)\n",
					 NbAccumulatedSamples, EAC3_NBSAMPLES_NEEDED);
			  Status = CollatorError; 
		  }
	  }
      else
	  {
		  COLLATOR_DEBUG("Synchronized first block is a good candidate for transcoding\n");
		  CollatorState = ReadSubFrame;
		  NbAccumulatedSamples = ParsedFrameHeader.NumberOfSamples;
	  }
  }
  else
  {
      Status = CollatorError;
  }
  
  return Status;
}
//}}}
//{{{ 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;
}
예제 #9
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the parseable frame header.
///
/// Accumulate data until we have ::FrameHeaderLength
/// bytes stashed away. At this point there is sufficient data accumulated
/// to determine how many bytes will pass us by before the next frame header
/// is expected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialFrameHeader( void )
{
    CollatorStatus_t Status;
    unsigned int BytesNeeded, BytesToRead, FrameLength;
    CollatorState_t OldCollatorState;

    //

    COLLATOR_DEBUG(">><<\n");

    //

    BytesNeeded = FrameHeaderLength - GotPartialFrameHeaderBytes;
    BytesToRead = min( RemainingElementaryLength, BytesNeeded );

    Status = AccumulateData( BytesToRead, RemainingElementaryData );
    if( Status == CollatorNoError )
    {
        GotPartialFrameHeaderBytes += BytesToRead;
        RemainingElementaryData += BytesToRead;
        RemainingElementaryLength -= BytesToRead;

        COLLATOR_DEBUG( "BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead );
        if( BytesNeeded == BytesToRead )
        {
            //
            // Woo hoo! We've got the whole header, examine it and change state
            //

            StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);

            COLLATOR_DEBUG("Got entire frame header packet\n");
            //report_dump_hex( severity_note, StoredFrameHeader, FrameHeaderLength, 32, 0);

            OldCollatorState = CollatorState;
            Status = DecideCollatorNextStateAndGetLength(&FrameLength);
            if( Status != CollatorNoError )
            {
                COLLATOR_DEBUG( "Badly formed frame header; seeking new frame header\n" );
                return HandleMissingNextFrameHeader();
            }

            FramePayloadRemaining = FrameLength - FrameHeaderLength;

            if ((int)FramePayloadRemaining < 0)
            {
                if (CollatorState == GotCompleteFrame)
                {
                    // accumulate the remainder of the frame before the FrameFlush method...
                    Status = AccumulateData( FrameLength, RemainingElementaryData );
                    if (Status != CollatorNoError )
                    {
                        COLLATOR_DEBUG( "Cannot accumulate data #2 (%d)\n", Status );
                        return Status;
                    }
                    StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);
                    RemainingElementaryData += FrameLength;
                    RemainingElementaryLength -= FrameLength;

                    // prepare the next call to ReadFrame by setting the correct FramePayloadRemaining
                    Status = GetSpecificFrameLength(&FrameLength);
                    if (Status != CollatorNoError )
                    {
                        COLLATOR_DEBUG( "Cannot get the specific frame length (%d)\n", Status );
                        return Status;
                    }

                    FramePayloadRemaining = FrameLength - FrameHeaderLength;
                }
                else
                {
                    // specific case: reading the header only accumulated too much data
                    // so discard the extra data
                    int NbBytesToDiscard = - (int)FramePayloadRemaining;
                    int temp = NbBytesToDiscard - BytesToRead;

                    AccumulatedDataSize -= NbBytesToDiscard;
                    GotPartialFrameHeaderBytes = (temp > 0)?temp:0;
                    NbBytesToDiscard = min((unsigned int) NbBytesToDiscard, BytesToRead);
                    RemainingElementaryData -= NbBytesToDiscard;
                    RemainingElementaryLength += NbBytesToDiscard;
                }
            }

            if (CollatorState == GotCompleteFrame)
            {
                AccumulatedFrameReady = true;

                //
                // update the coded frame parameters using the parameters calculated the
                // last time we saw a frame header.
                //
                CodedFrameParameters->PlaybackTimeValid = NextPlaybackTimeValid;
                CodedFrameParameters->PlaybackTime = NextPlaybackTime;
                CodedFrameParameters->DecodeTimeValid = NextDecodeTimeValid;
                CodedFrameParameters->DecodeTime = NextDecodeTime;
            }
            else if (CollatorState == SkipSubFrame)
            {
                /* discard the accumulated frame header */
                AccumulatedDataSize -= FrameHeaderLength;
            }

            if (CollatorState == GotCompleteFrame || OldCollatorState == GotSynchronized)
            {
                //
                // at this point we have discovered a frame header and need to attach a time to it.
                // we can choose between the normal stamp (the stamp of the current PES packet) or the
                // spanning stamp (the stamp of the previous PES packet). Basically if we have accumulated
                // a greater number of bytes than our current offset into the PES packet then we want to
                // use the spanning time.
                //

                bool WantSpanningTime = GetOffsetIntoPacket() < (int) GotPartialFrameHeaderBytes;

                if( WantSpanningTime && !UseSpanningTime)
                {
                    COLLATOR_ERROR("Wanted to take the spanning time but this was not available.");
                    WantSpanningTime = false;
                }

                if( WantSpanningTime )
                {
                    NextPlaybackTimeValid = SpanningPlaybackTimeValid;
                    NextPlaybackTime	= SpanningPlaybackTime;
                    SpanningPlaybackTimeValid = false;
                    NextDecodeTimeValid	= SpanningDecodeTimeValid;
                    NextDecodeTime	= SpanningDecodeTime;
                    SpanningDecodeTimeValid = false;
                    UseSpanningTime       = false;
                }
                else
                {
                    NextPlaybackTimeValid = PlaybackTimeValid;
                    NextPlaybackTime	= PlaybackTime;
                    PlaybackTimeValid	= false;
                    NextDecodeTimeValid	= DecodeTimeValid;
                    NextDecodeTime	= DecodeTime;
                    DecodeTimeValid	= false;
                }
            }

            // switch states and absorb the packet
            COLLATOR_DEBUG( "Discovered frame header (frame length %d bytes)\n", FrameLength );
        }
    }
    else
    {
        COLLATOR_DEBUG( "Cannot accumulate data #3 (%d)\n", Status );
    }
    return Status;
}
예제 #10
0
////////////////////////////////////////////////////////////////////////////
///
/// Get the actual frame length once the frame is completed
///
/// This is a stub implementation for collators other than DTS-HD
/// Normally this method should not be called...
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::GetSpecificFrameLength(unsigned int * FrameLength)
{
    *FrameLength = 0;
    COLLATOR_ERROR("Call to GetSpecificLength should not occur: general error\n");
    return CollatorError;
}
예제 #11
0
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;
}