////////////////////////////////////////////////////////////////////////////
///
/// Populate the DecodeContext structure with parameters for MPEG audio.
/// This can be over-ridden by WMA to not have any output buffer, as it will
/// do an MME_SEND_BUFFERS instead of MME_TRANSFORM
///
CodecStatus_t Codec_MmeAudio_c::FillOutDecodeContext(void)
{
	CodecStatus_t     Status;
	//
	// Obtain a new buffer if needed
	//
	if (CurrentDecodeBufferIndex == INVALID_INDEX)
	{
		Status  = GetDecodeBuffer();
		if (Status != CodecNoError)
		{
			report(severity_error, "Codec_MmeAudio_c::Input(%s) - Failed to get decode buffer.\n", Configuration.CodecName);
			ReleaseDecodeContext(DecodeContext);
			return Status;
		}
	}
	//
	// Record the buffer being used in the decode context
	//
	DecodeContext->BufferIndex  = CurrentDecodeBufferIndex;
	//
	// Provide default values for the input and output buffers (the sub-class can change this if it wants to).
	//
	// Happily the audio firmware is less mad than the video firmware on the subject of buffers.
	//
	memset(&DecodeContext->MMECommand, 0x00, sizeof(MME_Command_t));
	SetCommandIO();
	OS_LockMutex(&Lock);
	DecodeContext->DecodeInProgress     = true;
	BufferState[CurrentDecodeBufferIndex].DecodesInProgress++;
	BufferState[CurrentDecodeBufferIndex].OutputOnDecodesComplete       = true;
	OS_UnLockMutex(&Lock);
	return CodecNoError;
}
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;
}