////////////////////////////////////////////////////////////////////////////
///
/// Pass accumulated data to the output ring and maintain class state variables.
///
/// \todo If we were more clever about buffer management we wouldn't have to
/// copy the frame header onto the stack.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::InternalFrameFlush(void)
{
	CollatorStatus_t Status;
	unsigned char CopiedFrameHeader[FrameHeaderLength];
//
	AssertComponentState("Collator_PesAudio_c::InternalFrameFlush", ComponentRunning);
//
	COLLATOR_DEBUG(">><<\n");
	// temporarily copy the following frame header (if there is one) to the stack
	if (AccumulatedFrameReady)
	{
		memcpy(CopiedFrameHeader, StoredFrameHeader, FrameHeaderLength);
		AccumulatedDataSize -= FrameHeaderLength;
		//Assert( BufferBase + AccumulatedDataLength == StoredFrameHeader );
	}
	// now pass the complete frame onward
	Status = Collator_Pes_c::InternalFrameFlush();
	if (Status != CodecNoError)
		return Status;
	if (AccumulatedFrameReady)
	{
		// put the stored frame header into the new buffer
		Status = AccumulateData(FrameHeaderLength, CopiedFrameHeader);
		if (Status != CollatorNoError)
			COLLATOR_DEBUG("Cannot accumulate data #8 (%d)\n", Status);
		AccumulatedFrameReady = false;
	}
	else
	{
		ResetCollatorStateAfterForcedFrameFlush();
	}
	return CodecNoError;
}
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;
}
FrameParserStatus_t FrameParser_Audio_c::Input(Buffer_t CodedBuffer)
{
	FrameParserStatus_t Status;
	//
	// Are we allowed in here
	//
	AssertComponentState("FrameParser_Audio_c::Input", ComponentRunning);
	//
	// Initialize context pointers
	//
	ParsedAudioParameters = NULL;
	//
	// First perform base operations
	//
	Status = FrameParser_Base_c::Input(CodedBuffer);
	if (Status != FrameParserNoError)
		return Status;
	st_relayfs_write(ST_RELAY_TYPE_CODED_AUDIO_BUFFER, ST_RELAY_SOURCE_AUDIO_FRAME_PARSER, (unsigned char *)BufferData, BufferLength, 0);
	//
	// Obtain audio specific pointers to data associated with the buffer.
	//
	Status = Buffer->ObtainMetaDataReference(Player->MetaDataParsedAudioParametersType, (void **)(&ParsedAudioParameters));
	if (Status != PlayerNoError)
	{
		report(severity_error, "FrameParser_Audio_c::Input - Unable to obtain the meta data \"ParsedVideoParameters\".\n");
		return Status;
	}
	memset(ParsedAudioParameters, 0x00, sizeof(ParsedAudioParameters_t));
	//
	// Now execute the processing chain for a buffer
	//
	return ProcessBuffer();
}
CollatorStatus_t Collator_PesFrame_c::InternalFrameFlush(void)
{
	CollatorStatus_t Status;
	AssertComponentState("Collator_PesFrame_c::InternalFrameFlush", ComponentRunning);
	CodedFrameParameters->PlaybackTimeValid = PlaybackTimeValid;
	CodedFrameParameters->PlaybackTime = PlaybackTime;
	PlaybackTimeValid = false;
	CodedFrameParameters->DecodeTimeValid = DecodeTimeValid;
	CodedFrameParameters->DecodeTime = DecodeTime;
	DecodeTimeValid = false;
	Status = Collator_Pes_c::InternalFrameFlush();
	if (Status != CodecNoError)
		return Status;
	SeekingPesHeader = true;
	GotPartialHeader = false; // New style most video
	GotPartialZeroHeader = false; // Old style used by divx only
	GotPartialPesHeader = false;
	GotPartialPaddingHeader = false;
	Skipping = 0;
	return CodecNoError;
}
CollatorStatus_t   Collator_Pes_c::InputJump(   bool                      SurplusDataInjected,
						bool                      ContinuousReverseJump )
{
CollatorStatus_t        Status;

//

    AssertComponentState( "Collator_Pes_c::InputJump", ComponentRunning );

//

    Status                      = Collator_Base_c::InputJump( SurplusDataInjected, ContinuousReverseJump );
    if( Status != CodecNoError )
	return Status;

    PlaybackTimeValid           = false;
    DecodeTimeValid             = false;
    UseSpanningTime             = false;
    SpanningPlaybackTimeValid   = false;
    SpanningDecodeTimeValid     = false;

    return Status;
}
CollatorStatus_t   Collator_Pes_c::DiscardAccumulatedData(      void )
{
CollatorStatus_t        Status;

//

    AssertComponentState( "Collator_Pes_c::DiscardAccumulatedData", ComponentRunning );

//

    Status                      = Collator_Base_c::DiscardAccumulatedData();
    if( Status != CodecNoError )
	return Status;

    SeekingPesHeader            = true;
    GotPartialZeroHeader        = false;
    GotPartialPesHeader         = false;
    GotPartialPaddingHeader     = false;
    Skipping                    = 0;
    UseSpanningTime             = false;

    return Status;
}
CodecStatus_t   Codec_MmeVideo_c::Input(	Buffer_t	  CodedBuffer )
{
unsigned int		  i;
CodecStatus_t		  Status;
ParsedVideoParameters_t	 *PreviousFieldParameters;
bool			  LastSlice;
bool			  SeenBothFields;
bool			  LastDecodeIntoThisBuffer;
CodecBufferState_t	 *State;
Rational_t		  BaseWorkload;
Rational_t		  Workload;

    //
    // Are we allowed in here
    //

    AssertComponentState( "Codec_MmeVideo_c::Input", ComponentRunning );

    //
    // First perform base operations
    //

    Status      = Codec_MmeBase_c::Input( CodedBuffer );
    if( Status != CodecNoError )
        return Status;

    //
    // Do we need to issue a new set of stream parameters
    //

    if( ParsedFrameParameters->NewStreamParameters )
    {
	Status		= FillOutSetStreamParametersCommand();
	if( Status == CodecNoError )
	    Status	= SendMMEStreamParameters();
	if( Status != CodecNoError )
	{
	    report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to fill out, and send, a set stream parameters command.\n", Configuration.CodecName );
	    ForceStreamParameterReload		= true;
	    StreamParameterContextBuffer->DecrementReferenceCount();
	    StreamParameterContextBuffer	= NULL;
	    StreamParameterContext		= NULL;
	    return Status;
	}

	StreamParameterContextBuffer	= NULL;
	StreamParameterContext		= NULL;
    }

    //
    // If there is no frame to decode then exit now.
    //

    if( !ParsedFrameParameters->NewFrameParameters )
	return CodecNoError;

    //
    // Test if this frame indicates completion of any previous decodes (for slice decoding)
    //

    if( Configuration.SliceDecodePermitted &&
	ParsedVideoParameters->FirstSlice &&
	(CurrentDecodeBufferIndex != INVALID_INDEX) &&
	(BufferState[CurrentDecodeBufferIndex].ParsedVideoParameters->PictureStructure == StructureFrame) )
    {
	// Operation cannot fail
	SetOutputOnDecodesComplete( CurrentDecodeBufferIndex, true );
	CurrentDecodeBufferIndex	= INVALID_INDEX;
    }

    //
    // Check for a half buffer
    //

    if( (CurrentDecodeBufferIndex != INVALID_INDEX) && ParsedFrameParameters->FirstParsedParametersForOutputFrame )
    {
	report( severity_error, "Codec_MmeVideo_c::Input(%s) - New frame starts when we have one field in decode buffer.\n", Configuration.CodecName );
	Codec_MmeVideo_c::OutputPartialDecodeBuffers();
    }

    //
    // Obtain a new buffer if needed
    //

    if( CurrentDecodeBufferIndex == INVALID_INDEX )
    {
	Status	= GetDecodeBuffer();
	if( Status != CodecNoError )
	{
	    report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to get decode buffer.\n", Configuration.CodecName );
	    ReleaseDecodeContext( DecodeContext );
	    return Status;
	}

	//
	// reset the buffer content to contain no data, and derive the chroma and luma pointers.
	//

	State	= &BufferState[CurrentDecodeBufferIndex];

	State->ParsedVideoParameters->PictureStructure	= StructureEmpty;
	if( Manifestor != NULL )
	{
	    if( State->BufferStructure->ComponentCount == 1 )
	    {
		State->BufferLumaPointer    = NULL;
		State->BufferChromaPointer  = NULL;
		State->BufferRasterPointer  = State->BufferPointer + State->BufferStructure->ComponentOffset[0];
	    }
	    else if( State->BufferStructure->ComponentCount == 2 )
	    {
	    State->BufferLumaPointer	= State->BufferPointer + State->BufferStructure->ComponentOffset[0];
	    State->BufferChromaPointer	= State->BufferPointer + State->BufferStructure->ComponentOffset[1];
		State->BufferRasterPointer  = NULL;
	    }
	    else
		report( severity_fatal, "Codec_MmeVideo_c::Input(%s) - Decode buffer structure contains unsupported number of components (%d).\n", Configuration.CodecName, State->BufferStructure->ComponentCount );
	}
    }

    //
    // If we are re-using the buffer, and this is the first slice 
    // (hence of a second field) we update the field counts in the 
    // buffer record.
    //

    else if( ParsedVideoParameters->FirstSlice )
    {
	Status	= MapBufferToDecodeIndex( ParsedFrameParameters->DecodeFrameIndex, CurrentDecodeBufferIndex );
	if( Status != CodecNoError )
	{
	    report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to map second field index to decode buffer - Implementation error.\n", Configuration.CodecName );
	    Codec_MmeVideo_c::OutputPartialDecodeBuffers();
	    return PlayerImplementationError;
	}

//

	PreviousFieldParameters				= BufferState[CurrentDecodeBufferIndex].ParsedVideoParameters;
	if( PreviousFieldParameters->DisplayCount[1] != 0 )
	{
	    report( severity_error, "Codec_MmeVideo_c::Input(%s) - DisplayCount for second field non-zero after decoding only first field - Implementation error.\n", Configuration.CodecName );
	    Codec_MmeVideo_c::OutputPartialDecodeBuffers();
	    return PlayerImplementationError;
	}

	PreviousFieldParameters->DisplayCount[1]	= ParsedVideoParameters->DisplayCount[0];

//

	if( (PreviousFieldParameters->PanScan.Count + ParsedVideoParameters->PanScan.Count) >
	    MAX_PAN_SCAN_VALUES )
	{
	    report( severity_error, "Codec_MmeVideo_c::Input(%s) - Cummulative PanScanCount in two fields too great (%d + %d) - Implementation error.\n", Configuration.CodecName, PreviousFieldParameters->PanScan.Count, ParsedVideoParameters->PanScan.Count );
	    Codec_MmeVideo_c::OutputPartialDecodeBuffers();
	    return PlayerImplementationError;
	}

	for( i=0; i<ParsedVideoParameters->PanScan.Count; i++ )
	{
	    PreviousFieldParameters->PanScan.DisplayCount[i + PreviousFieldParameters->PanScan.Count]		= ParsedVideoParameters->PanScan.DisplayCount[i];
	    PreviousFieldParameters->PanScan.HorizontalOffset[i + PreviousFieldParameters->PanScan.Count]	= ParsedVideoParameters->PanScan.HorizontalOffset[i];
	    PreviousFieldParameters->PanScan.VerticalOffset[i + PreviousFieldParameters->PanScan.Count]		= ParsedVideoParameters->PanScan.VerticalOffset[i];
	}
	PreviousFieldParameters->PanScan.Count	+= ParsedVideoParameters->PanScan.Count;
    }

    //
    // Record the buffer being used in the decode context
    //

    DecodeContext->BufferIndex	= CurrentDecodeBufferIndex;

    //
    // Translate reference lists, and Update the reference frame access counts
    //

    Status	= TranslateReferenceFrameLists( ParsedVideoParameters->FirstSlice );
    if( Status != CodecNoError )
    {
	report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to find all reference frames - Implementation error.\n", Configuration.CodecName );
    }

    //
    // Provide default arguments for the input and output buffers. Default to no buffers not because there
    // are no buffers but because the video firmware interface uses a backdoor to gain access to the buffers.
    // Yes, this does violate the spec. but does nevertheless work on the current crop of systems.
    //

    DecodeContext->MMECommand.NumberInputBuffers		= 0;
    DecodeContext->MMECommand.NumberOutputBuffers		= 0;
    DecodeContext->MMECommand.DataBuffers_p			= NULL;
    
    //
    // Load the parameters into MME command
    //

    Status	= FillOutDecodeCommand();
    if( Status != CodecNoError )
    {
	report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to fill out a decode command.\n", Configuration.CodecName );
	ReleaseDecodeContext( DecodeContext );
	return Status;
    }

    //
    // Update ongoing decode count, and completion flags
    //

    BufferState[CurrentDecodeBufferIndex].ParsedVideoParameters->PictureStructure	|= ParsedVideoParameters->PictureStructure;

    LastSlice			= Configuration.SliceDecodePermitted ? KnownLastSliceInFieldFrame : true;
    SeenBothFields		= BufferState[CurrentDecodeBufferIndex].ParsedVideoParameters->PictureStructure == StructureFrame;
    LastDecodeIntoThisBuffer	= SeenBothFields && LastSlice;

    OS_LockMutex( &Lock );

    DecodeContext->DecodeInProgress	= true;
    BufferState[CurrentDecodeBufferIndex].DecodesInProgress++;
    BufferState[CurrentDecodeBufferIndex].OutputOnDecodesComplete	= LastDecodeIntoThisBuffer;

    OS_UnLockMutex( &Lock );

    //
    // Ensure that the coded frame will be available throughout the 
    // life of the decode by attaching the coded frame to the decode 
    // context prior to launching the decode.
    //

    DecodeContextBuffer->AttachBuffer( CodedFrameBuffer );

    //! set up MME_TRANSFORM - SendMMEDecodeCommand no longer does this as we nned to do
    //! MME_SEND_BUFFERS instead for certain codecs, WMA being one, OGG Vorbis another
    DecodeContext->MMECommand.CmdCode = MME_TRANSFORM;

    Status	= SendMMEDecodeCommand();
    if( Status != CodecNoError )
    {
	report( severity_error, "Codec_MmeVideo_c::Input(%s) - Failed to send a decode command.\n", Configuration.CodecName );
	ReleaseDecodeContext( DecodeContext );
	return Status;
    }

    //
    // have we finished decoding into this buffer
    //
	
    if( LastDecodeIntoThisBuffer )
    {
	CurrentDecodeBufferIndex	= INVALID_INDEX;
	CurrentDecodeIndex		= INVALID_INDEX;
    }
    else
    {
	CurrentDecodeIndex		= ParsedFrameParameters->DecodeFrameIndex;
    }

    //
    // Are we in a position to upgrade the trick mode parameters, say 
    // for a smaller resolution screen, or a slower source frame rate.
    //

    if( Configuration.TrickModeParameters.AutoAdjustDecodeRates )
    {
	BaseWorkload	= (Configuration.TrickModeParameters.PixelsAtNormalRate/256) * Configuration.TrickModeParameters.FrameRateAtNormalRate;
	Workload	= ((ParsedVideoParameters->Content.Width * ParsedVideoParameters->Content.Height) / 256) *
			  ParsedVideoParameters->Content.FrameRate;

	if( (Workload != LastWorkload) && 
	    !inrange( Workload/BaseWorkload, Rational_t(95,100), Rational_t(105,100) ) )
	{
	    Configuration.TrickModeParameters.MaximumNormalDecodeRate		= Configuration.TrickModeParameters.BaseNormalDecodeRate * (BaseWorkload/Workload);
	    Configuration.TrickModeParameters.MaximumSubstandardDecodeRate	= Configuration.TrickModeParameters.BaseSubstandardDecodeRate * (BaseWorkload/Workload);

	    Configuration.TrickModeParameters.MaximumNormalDecodeRate		= Configuration.TrickModeParameters.MaximumNormalDecodeRate.TruncateDenominator(8);
	    Configuration.TrickModeParameters.MaximumSubstandardDecodeRate	= Configuration.TrickModeParameters.MaximumSubstandardDecodeRate.TruncateDenominator(8);

	    Clamp( Configuration.TrickModeParameters.MaximumNormalDecodeRate,      DECODE_RATE_LOWER_LIMIT, DECODE_RATE_UPPER_LIMIT );
	    Clamp( Configuration.TrickModeParameters.MaximumSubstandardDecodeRate, DECODE_RATE_LOWER_LIMIT, DECODE_RATE_UPPER_LIMIT );
	} 

	LastWorkload	= LastWorkload;
    }

//

    return CodecNoError;
}
CodecStatus_t   Codec_MmeAudio_c::Input(Buffer_t          CodedBuffer)
{
	CodecStatus_t     Status;
	//
	// Are we allowed in here
	//
	AssertComponentState("Codec_MmeAudio_c::Input", ComponentRunning);
	//
	// First perform base operations
	//
	Status      = Codec_MmeBase_c::Input(CodedBuffer);
	if (Status != CodecNoError)
		return Status;
	CODEC_DEBUG("Handling frame %d\n", ParsedFrameParameters->DisplayFrameIndex);
	//
	// Do we need to issue a new set of stream parameters
	//
	if (ParsedFrameParameters->NewStreamParameters)
	{
		memset(&StreamParameterContext->MMECommand, 0x00, sizeof(MME_Command_t));
		Status          = FillOutSetStreamParametersCommand();
		if (Status == CodecNoError)
			Status      = SendMMEStreamParameters();
		if (Status != CodecNoError)
		{
			report(severity_error, "Codec_MmeAudio_c::Input(%s) - Failed to fill out, and send, a set stream parameters command.\n", Configuration.CodecName);
			StreamParameterContextBuffer->DecrementReferenceCount();
			return Status;
		}
		StreamParameterContextBuffer    = NULL;
		StreamParameterContext          = NULL;
	}
	//
	// If there is no frame to decode then exit now.
	//
	if (!ParsedFrameParameters->NewFrameParameters)
		return CodecNoError;
	Status      = FillOutDecodeContext();
	if (Status != CodecNoError)
	{
		return Status;
	}
	//
	// Load the parameters into MME command
	//
	//! set up default to MME_TRANSFORM - fine for most codecs
	DecodeContext->MMECommand.CmdCode                           = MME_TRANSFORM;
	//! will change to MME_SEND_BUFFERS in WMA/OGG over-ridden FillOutDecodeCommand(), thread to do MME_TRANSFORMs
	Status      = FillOutDecodeCommand();
	if (Status != CodecNoError)
	{
		report(severity_error, "Codec_MmeAudio_c::Input(%s) - Failed to fill out a decode command.\n", Configuration.CodecName);
		ReleaseDecodeContext(DecodeContext);
		return Status;
	}
	//
	// Ensure that the coded frame will be available throughout the
	// life of the decode by attaching the coded frame to the decode
	// context prior to launching the decode.
	//
	AttachCodedFrameBuffer();
	Status      = SendMMEDecodeCommand();
	if (Status != CodecNoError)
	{
		report(severity_error, "Codec_MmeAudio_c::Input(%s) - Failed to send a decode command.\n", Configuration.CodecName);
		ReleaseDecodeContext(DecodeContext);
		return Status;
	}
	//
	// We have finished decoding into this buffer
	//
	FinishedDecode();
	return CodecNoError;
}
////////////////////////////////////////////////////////////////////////////
///
/// 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;
}
Exemple #10
0
ManifestorStatus_t Manifestor_Audio_c::QueueDecodeBuffer(class Buffer_c *Buffer)
{
	ManifestorStatus_t Status;
	BufferStatus_t BufferStatus;
	unsigned int BufferIndex;
	//MANIFESTOR_DEBUG(">><<\n");
	AssertComponentState("Manifestor_Audio_c::QueueDecodeBuffer", ComponentRunning);
	//
	// Obtain the index for the buffer and populate the parameter data.
	//
	BufferStatus = Buffer->GetIndex(&BufferIndex);
	if (BufferStatus != BufferNoError)
	{
		MANIFESTOR_ERROR("Unable to lookup buffer index %x.\n", BufferStatus);
		return ManifestorError;
	}
	StreamBuffer[BufferIndex].Buffer = Buffer;
	StreamBuffer[BufferIndex].EventPending = EventPending;
	EventPending = false;
	BufferStatus = Buffer->ObtainMetaDataReference(Player->MetaDataParsedFrameParametersReferenceType,
						       (void **) &StreamBuffer[BufferIndex].FrameParameters);
	if (BufferStatus != BufferNoError)
	{
		MANIFESTOR_ERROR("Unable to access buffer parsed frame parameters %x.\n", BufferStatus);
		return ManifestorError;
	}
	BufferStatus = Buffer->ObtainMetaDataReference(Player->MetaDataParsedAudioParametersType,
						       (void **) &StreamBuffer[BufferIndex].AudioParameters);
	if (BufferStatus != BufferNoError)
	{
		MANIFESTOR_ERROR("Unable to access buffer parsed audio parameters %x.\n", BufferStatus);
		return ManifestorError;
	}
	Buffer->DumpToRelayFS(ST_RELAY_TYPE_DECODED_AUDIO_BUFFER, ST_RELAY_SOURCE_AUDIO_MANIFESTOR + RelayfsIndex, (void *)Player);
	BufferStatus = Buffer->ObtainMetaDataReference(Player->MetaDataAudioOutputTimingType,
						       (void **) &StreamBuffer[BufferIndex].AudioOutputTiming);
	if (BufferStatus != BufferNoError)
	{
		MANIFESTOR_ERROR("Unable to access buffer audio output timing parameters %x.\n", BufferStatus);
		return ManifestorError;
	}
	BufferStatus = Buffer->ObtainDataReference(NULL, NULL,
						   (void **)(&StreamBuffer[BufferIndex].Data), UnCachedAddress);
	if (BufferStatus != BufferNoError)
	{
		MANIFESTOR_ERROR("Unable to obtain buffer's data reference %x.\n", BufferStatus);
		return ManifestorError;
	}
	StreamBuffer[BufferIndex].QueueAsCodedData = true;
	//
	// Check if there are new audio parameters (i.e. change of sample rate etc.) and note this
	//
	if (0 == memcmp(&LastSeenAudioParameters, StreamBuffer[BufferIndex].AudioParameters,
			sizeof(LastSeenAudioParameters)))
	{
		StreamBuffer[BufferIndex].UpdateAudioParameters = false;
	}
	else
	{
		StreamBuffer[BufferIndex].UpdateAudioParameters = true;
		memcpy(&LastSeenAudioParameters, StreamBuffer[BufferIndex].AudioParameters,
		       sizeof(LastSeenAudioParameters));
	}
	//
	// Allow the sub-class to have a peek at the buffer before we queue it for display
	//
	Status = QueueBuffer(BufferIndex);
	if (Status != ManifestorNoError)
	{
		MANIFESTOR_ERROR("Unable to queue buffer %x.\n", Status);
		return Status;
	}
	//
	// Enqueue the buffer for display within the playback thread
	//
	OS_LockMutex(&BufferQueueLock);
	QueuedBufferCount++;
	StreamBuffer[BufferIndex].NextIndex = INVALID_BUFFER_ID; // end marker
	if (BufferQueueHead == INVALID_BUFFER_ID)
	{
		BufferQueueHead = BufferIndex;
	}
	else
	{
		StreamBuffer[BufferQueueTail].NextIndex = BufferIndex;
	}
	BufferQueueTail = BufferIndex;
	OS_UnLockMutex(&BufferQueueLock);
	OS_SetEvent(&BufferQueueUpdated);
	return ManifestorNoError;
}
//{{{ 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;
}