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; }
//////////////////////////////////////////////////////////////////////////// /// /// 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; }
//////////////////////////////////////////////////////////////////////////// /// /// Handle losing lock on the frame headers. /// /// This function is called to handle the data that was spuriously accumulated /// when the frame header was badly parsed. /// /// In principle this function is quite simple. We allocate a new accumulation buffer and /// use the currently accumulated data is the data source to run the elementary stream /// state machine. There is however a little extra logic to get rid of recursion. /// Specificially we change the error handling behaviour if this method is re-entered /// so that there error is reported back to the already executing copy of the method. /// /// \return Collator status code, CollatorNoError indicates success. /// CollatorStatus_t Collator_PesAudio_c::HandleMissingNextFrameHeader(void) { CollatorStatus_t Status; // // Mark the collator as having lost frame lock. // Yes! We really do want to do this before the re-entry checks. // CollatorState = SeekingSyncWord; // we really do want to do this before the re-entry checks AccumulatedFrameReady = false; // // Check for re-entry // if (AlreadyHandlingMissingNextFrameHeader) { COLLATOR_DEBUG("Re-entered the error recovery handler, initiating stack unwind\n"); return CollatorUnwindStack; } // // Check whether the sub-class wants trivial or aggressive error recovery // if (!ReprocessAccumulatedDataDuringErrorRecovery) { DiscardAccumulatedData(); return CollatorNoError; } // // Remember the original elementary stream pointers for when we return to 'normal' processing. // unsigned char *OldRemainingElementaryOrigin = RemainingElementaryOrigin; unsigned char *OldRemainingElementaryData = RemainingElementaryData; unsigned int OldRemainingElementaryLength = RemainingElementaryLength; // // Take ownership of the already accumulated data // Buffer_t ReprocessingDataBuffer = CodedFrameBuffer; unsigned char *ReprocessingData = BufferBase; unsigned int ReprocessingDataLength = AccumulatedDataSize; ReprocessingDataBuffer->SetUsedDataSize(ReprocessingDataLength); Status = ReprocessingDataBuffer->ShrinkBuffer(max(ReprocessingDataLength, 1)); if (Status != BufferNoError) { COLLATOR_ERROR("Failed to shrink the reprocessing buffer to size (%08x).\n", Status); // not fatal - we're merely wasting memory } // At the time of writing GetNewBuffer() doesn't check for leaks. This is good because otherwise // we wouldn't have transfer the ownership of the ReprocessingDataBuffer by making this call. Status = GetNewBuffer(); if (Status != CollatorNoError) { COLLATOR_ERROR("Cannot get new buffer during error recovery\n"); return CollatorError; } // // Remember that we are re-processing the previously accumulated elementary stream // AlreadyHandlingMissingNextFrameHeader = true; // // WARNING: From this point on we own the ReprocessingDataBuffer, have set the recursion avoidance // marker and may have damaged the RemainingElementaryData pointer. There should be no // short-circuit exit paths used after this point otherwise we risk avoiding the clean up // at the bottom of the method. // while (ReprocessingDataLength > 1) { // // Remove the first byte from the recovery buffer (to avoid detecting again the same start code). // ReprocessingData += 1; ReprocessingDataLength -= 1; // // Search for a start code in the reprocessing data. This allows us to throw away data that we // know will never need reprocessing which makes the recursion avoidance code more efficient. // RemainingElementaryOrigin = ReprocessingData; RemainingElementaryData = ReprocessingData; RemainingElementaryLength = ReprocessingDataLength; int CodeOffset; PotentialFrameHeaderLength = 0; // ensure no (now voided) historic data is considered by sub-class Status = FindNextSyncWord(&CodeOffset); if (Status == CodecNoError) { COLLATOR_ASSERT(CodeOffset >= 0); COLLATOR_DEBUG("Found start code during error recovery (byte %d of %d)\n", CodeOffset, ReprocessingDataLength); // We found a start code, snip off all preceding data ReprocessingData += CodeOffset; ReprocessingDataLength -= CodeOffset; } else { // We didn't find a start code, snip off everything except the last few bytes. This // final fragment may contain a partial start code so we want to pass if through the // elementary stream handler again. unsigned FinalBytes = min(ReprocessingDataLength, FrameHeaderLength - 1); COLLATOR_DEBUG("Found no start code during error recovery (processing final %d bytes of %d)\n", ReprocessingDataLength, FinalBytes); ReprocessingData += ReprocessingDataLength; ReprocessingDataLength = FinalBytes; ReprocessingData -= ReprocessingDataLength; } // // Process the elementary stream // Status = HandleElementaryStream(ReprocessingDataLength, ReprocessingData); if (CollatorNoError == Status) { COLLATOR_DEBUG("Error recovery completed, returning to normal processing\n"); // All data consumed and stored in the subsequent accumulation buffer break; // Success will propagate when we return Status } else if (CollatorUnwindStack == Status) { COLLATOR_DEBUG("Stack unwound successfully, re-trying error recovery\n"); // We found a frame header but lost lock again... let's have another go AccumulatedDataSize = 0; // make sure no accumulated data is carried round the loop continue; } else { COLLATOR_ERROR("Error handling elementary stream during error recovery\n"); break; // Failure will propagate when we return Status } } // // Free the buffer we just consumed and restore the original elementary stream pointers // RemainingElementaryOrigin = OldRemainingElementaryOrigin; RemainingElementaryData = OldRemainingElementaryData; RemainingElementaryLength = OldRemainingElementaryLength; (void) ReprocessingDataBuffer->DecrementReferenceCount(IdentifierCollator); AlreadyHandlingMissingNextFrameHeader = false; return Status; }
//////////////////////////////////////////////////////////////////////////// /// /// Determine the new state of the collator according to the incoming sub frame /// Also returns this sub frame length /// /// \return Collator status code, CollatorNoError indicates success. /// CollatorStatus_t Collator_PesAudioDtshd_c::DecideCollatorNextStateAndGetLength(unsigned int *FrameLength) { FrameParserStatus_t FPStatus; CollatorStatus_t Status; DtshdAudioParsedFrameHeader_t ParsedFrameHeader; // // first check if we know about the real frame size when it comes to dts core sync if (!GotCoreFrameSize) { int CodeOffset; DtshdStreamType_t Type; // To determine frame length, search for a synchro in the provided buffer Status = FindAnyNextSyncWord(&CodeOffset, &Type); if (Status == CollatorNoError) { GotCoreFrameSize = true; // CodeOffset may be negative, indicating the sync word has been found fully or // paritally within the frame header we already accumulated. Given this // meaning it is impossible for the FrameHeaderLength + CodeOffset to be // negative. COLLATOR_ASSERT(((int) FrameHeaderLength + CodeOffset) >= 0); *FrameLength = FrameHeaderLength + CodeOffset; if (0 == *FrameLength) { // The sync word is contained within the first byte of the StoredFrameHeader // just as it would be it we had known the CoreFrameSize originally. At this // stage therefore CoreFrameSize already has the right value (we are about to // add zero to it) so we can simply change the value of GotCoreFrameSize // (which we have already done) and try again. return DecideCollatorNextStateAndGetLength(FrameLength); } } else { // synchro not found, but frame is at least the size of the buffer we just searched *FrameLength = RemainingElementaryLength + FrameHeaderLength - DTSHD_RAW_SYNCHRO_BYTES_NEEDED; } CollatorState = ReadSubFrame; CoreFrameSize += *FrameLength; Status = CollatorNoError; } else { DtshdParseModel_t ParseModel = {ParseForSynchro, 0, 0}; /* We have already calculated the CoreFrameSize so better to set CodedFrameParameters->DataSpecificFlags here instead of state "GotCompleteFrame". Because it is possible that InternalFrameFlush is called from the drain and so the frame_parser called for already parsed frame. And the frame parser require DataSpecificFlags to see the core frame size. See the bz24622 */ CodedFrameParameters->DataSpecificFlags = CoreFrameSize; FPStatus = FrameParser_AudioDtshd_c::ParseSingleFrameHeader(StoredFrameHeader, &ParsedFrameHeader, &Bits, FrameHeaderLength, RemainingElementaryData, RemainingElementaryLength, ParseModel, 0); if (FPStatus == FrameParserNoError) { if (CollatorState == GotSynchronized) { // remember the first synchronized substream properties memcpy(&SyncFrameHeader, &ParsedFrameHeader, sizeof(DtshdAudioSyncFrameHeader_t)); } Status = CollatorNoError; if (ParsedFrameHeader.Type == TypeDtshdCore) { if (SyncFrameHeader.Type == TypeDtshdExt) { // we should not encounter such core streams, this means // we synchron ized on a false substream... // so we will accumulate t his wrong extension frame, plus the regular frame // and the frame parser will reanalyse this situation to tell the codec to // start decoding atfer he extension frame GotCoreFrameSize = false; // get rid of frame header *FrameLength = 0; // accumulate this frame... CollatorState = GotSynchronized; SyncFrameHeader.Type = TypeDtshdCore; } else { // regular case, the next frame is a core substream that means // that this frame is over *FrameLength = CoreFrameSize; CollatorState = GotCompleteFrame; } } else if (ParsedFrameHeader.Type == TypeDtshdExt) { if ((SyncFrameHeader.Type == TypeDtshdExt) && (SyncFrameHeader.SubStreamId == ParsedFrameHeader.SubStreamId) && (CollatorState != GotSynchronized)) { // case of a pure dts-hd frame composed of extension substreams only *FrameLength = ParsedFrameHeader.Length; CollatorState = GotCompleteFrame; } else { // ac cumulate this frame... CollatorState = ReadSubFrame; // we are confident wi th these data... *FrameLength = ParsedFrameHeader.Length; } } } else { Status = CollatorError; } } if (CollatorState == GotCompleteFrame) { ResetDvdSyncWordHeuristics(); } return Status; }
//////////////////////////////////////////////////////////////////////////// /// /// Determine the new state of the collator according to the incoming sub frame /// Also returns this sub frame length /// /// \return Collator status code, CollatorNoError indicates success. /// CollatorStatus_t Collator_PesAudioLpcm_c::DecideCollatorNextStateAndGetLength( unsigned int *FrameLength ) { CollatorStatus_t Status = CollatorNoError; // COLLATOR_DEBUG(">><<\n"); if ( IsFirstPacket ) { //case of very first packet, skip the packet portion before the FirstAccessUnitOffsetPointer CollatorState = SkipSubFrame; IsFirstPacket = false; // for the very first packet of dvd-audio, the stuffing bytes are not part of the PDA // since Configuration.ExtendedHeaderLength is not the same as PrivateHeaderLength, // so skip these bytes in this case *FrameLength = PesPrivateToSkip + NextParsedFrameHeader.FirstAccessUnitPointer + FirstAccessUnitOffset[StreamType] - NextParsedFrameHeader.PrivateHeaderLength; PesPrivateToSkip = 0; COLLATOR_TRACE("First packet: Skipping %d bytes\n", *FrameLength); return (Status); } // accumulate the private data area for the frame parser, // if some major parameter inside have changed... if ( AccumulatePrivateDataArea ) { // save the location of the private data area, to update it later... Status = AccumulateData( Configuration.ExtendedHeaderLength, &NewPesPrivateDataArea[0] ); if ( Status != CollatorNoError ) { return (Status); } AccumulatePrivateDataArea = false; COLLATOR_DEBUG("Accumulate PDA of length %d\n", Configuration.ExtendedHeaderLength); } if ( !IsPesPrivateDataAreaValid ) { //case of wrong packet passed to collator, skip the whole packet CollatorState = SkipSubFrame; *FrameLength = RemainingElementaryLength; } else if ( PesPrivateToSkip > 0 ) { CollatorState = SkipSubFrame; *FrameLength = min(PesPrivateToSkip, RemainingElementaryLength); PesPrivateToSkip -= *FrameLength; COLLATOR_DEBUG("Skipping %d bytes of pda\n", *FrameLength); } else if ( RemainingDataLength > 0 ) { CollatorState = ReadSubFrame; *FrameLength = min(RemainingDataLength, RemainingElementaryLength); RemainingDataLength -= *FrameLength; COLLATOR_DEBUG("Reading %d bytes (rest of frame)\n", *FrameLength); } else if ( (AccumulatedFrameNumber >= NbAudioFramesToGlob[StreamType][NextParsedFrameHeader.SamplingFrequency1]) || IsPesPrivateDataAreaNew ) { // flush the frame if we have already more than x accumulated frames // or if some pda key parameters are new CollatorState = GotCompleteFrame; COLLATOR_DEBUG("Flush after %d audio frames\n", AccumulatedFrameNumber); AccumulatedFrameNumber = 0; // prevent accumulating anything for this frame, the next thing we need to do // is accumlate the private data area for the frame parser but we can't do that // until we've cleared this frame from the accumulation buffer. *FrameLength = 0; // at next call of this function accumulate the pda AccumulatePrivateDataArea = true; // reset IsPesPrivateDataAreaNew = false; PlaybackTime += (GlobbedFramesOfNewPacket * LpcmPresentationTime[StreamType][NextParsedFrameHeader.SamplingFrequency1]); COLLATOR_DEBUG("PlaybackTime: %x\n", PlaybackTime); } else { // normal case: accumulate the audio frames CollatorState = ReadSubFrame; AccumulatedFrameNumber += 1; GlobbedFramesOfNewPacket += 1; COLLATOR_ASSERT(0 == RemainingDataLength); COLLATOR_ASSERT(0 == PesPrivateToSkip); // DVD-audio allows stuffing bytes to form part of the private data area (and these can be different // for each packet). We can't easily handle this in the PES layer since the length can't be predicted // and therefore we cannot set Configuration.ExtendedHeaderLength until it is too late. Instead // Collator_PesAudioLpcm_c::HandlePesPrivateData() records how many bytes we must skip // (PesPrivateToSkip) and leaves it to the state change logic to skip that data. This means that we // must ensure that this method will be called at the right point to skip data. We do this be making // sure we don't ever return a *FrameLength larger than the RemainingElementaryData . if ((RemainingElementaryLength < NextParsedFrameHeader.AudioFrameSize)) { RemainingDataLength = NextParsedFrameHeader.AudioFrameSize - RemainingElementaryLength; *FrameLength = RemainingElementaryLength; } else { // read the whole frame! *FrameLength = NextParsedFrameHeader.AudioFrameSize; } COLLATOR_DEBUG("Read frame of size %d (total frames in this chunk: %d)\n", *FrameLength, AccumulatedFrameNumber); } return Status; }
//{{{ 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; }