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