//////////////////////////////////////////////////////////////////////////// /// /// 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; }