Example #1
0
////////////////////////////////////////////////////////////////////////////
///
/// 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;
}
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate data until we reach the next frame header.
///
/// The function has little or no intelligence. Basically it will squirrel
/// away data until Collator_PesAudio_c::GotPartialFrameHeaderBytes reaches
/// Collator_PesAudio_c::FrameHeaderLength and then set
/// Collator_PesAudio_c::GotPartialFrameHeader.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadFrame( void )
{
  CollatorStatus_t Status;
  unsigned int BytesToRead;
  
  //
  
  COLLATOR_DEBUG(">><<\n");

  
  //
  
  // if the FramePayloadRemaining is -ve then we have no work to do except
  // record the fact that we've already accumulated part of the next frame header
  if (FramePayloadRemaining < 0)
    {
      GotPartialFrameHeaderBytes = -FramePayloadRemaining;
      CollatorState = SeekingFrameEnd;
      return CollatorNoError;
    }
  
  //
  
  BytesToRead = min( FramePayloadRemaining, RemainingElementaryLength );
  
  if (CollatorState == ReadSubFrame)
    {
      Status = AccumulateData( BytesToRead, RemainingElementaryData );
      if( Status != CollatorNoError )
          COLLATOR_DEBUG( "Cannot accumulate data #4 (%d)\n", Status );
    }
  else
    {
      Status = CollatorNoError;
    }

  if( Status == CollatorNoError )
    {
      if (BytesToRead == FramePayloadRemaining) 
	{
	  GotPartialFrameHeaderBytes = 0;
	  CollatorState = SeekingFrameEnd;
	}
      
      RemainingElementaryData += BytesToRead;
      RemainingElementaryLength -= BytesToRead;
      FramePayloadRemaining -= BytesToRead;
    }
  
  //
  
  return Status;
}
Example #3
0
void
MemoryProfiler::Reset(LPCWSTR name, ArenaMemoryData * memoryData)
{
    MemoryProfiler * memoryProfiler = memoryData->profiler;
    ArenaMemoryDataSummary * arenaMemoryDataSummary;
    bool hasItem = memoryProfiler->arenaDataMap.TryGetValue((LPWSTR)name, &arenaMemoryDataSummary);
    Assert(hasItem);


    AccumulateData(arenaMemoryDataSummary, memoryData, true);
    memoryData->allocatedBytes = 0;
    memoryData->alignmentBytes = 0;
    memoryData->requestBytes = 0;
    memoryData->requestCount = 0;
    memoryData->reuseBytes = 0;
    memoryData->reuseCount = 0;
    memoryData->freelistBytes = 0;
    memoryData->freelistCount = 0;
    memoryData->resetCount++;
}
Example #4
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate data until we reach the next frame header.
///
/// The function has little or no intelligence. Basically it will squirrel
/// away data until Collator_PesAudio_c::GotPartialFrameHeaderBytes reaches
/// Collator_PesAudio_c::FrameHeaderLength and then set
/// Collator_PesAudio_c::GotPartialFrameHeader.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadFrame( void )
{
    CollatorStatus_t Status;
    unsigned int BytesToRead;

    //

    COLLATOR_DEBUG(">><<\n");

    BytesToRead = min( FramePayloadRemaining, RemainingElementaryLength );

    if (CollatorState == ReadSubFrame)
    {
        Status = AccumulateData( BytesToRead, RemainingElementaryData );
        if( Status != CollatorNoError )
            COLLATOR_DEBUG( "Cannot accumulate data #4 (%d)\n", Status );
    }
    else
    {
        Status = CollatorNoError;
    }

    if( Status == CollatorNoError )
    {
        if (BytesToRead == FramePayloadRemaining)
        {
            GotPartialFrameHeaderBytes = 0;
            CollatorState = SeekingFrameEnd;
        }

        RemainingElementaryData += BytesToRead;
        RemainingElementaryLength -= BytesToRead;
        FramePayloadRemaining -= BytesToRead;
    }

    //

    return Status;
}
Example #5
0
void
MemoryProfiler::End(LPCWSTR name, ArenaMemoryData * memoryData)
{
    MemoryProfiler * memoryProfiler = memoryData->profiler;
    ArenaMemoryDataSummary * arenaMemoryDataSummary;
    bool hasItem = memoryProfiler->arenaDataMap.TryGetValue((LPWSTR)name, &arenaMemoryDataSummary);
    Assert(hasItem);

    if (memoryData->next != nullptr)
    {
        memoryData->next->prev = memoryData->prev;
    }

    if (memoryData->prev != nullptr)
    {
        memoryData->prev->next = memoryData->next;
    }
    else
    {
        Assert(arenaMemoryDataSummary->data == memoryData);
        arenaMemoryDataSummary->data = memoryData->next;
    }
    AccumulateData(arenaMemoryDataSummary, memoryData);
}
Example #6
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the full PES header.
///
/// Strictly speaking this method handles two sub-states. In the first state
/// we do not have sufficient data accumulated to determine how long the PES
/// header is. In the second we still don't have a complete PES packet but
/// at least we know how much more data we need.
///
/// This code assumes that PES packet uses >=9 bytes PES headers rather than
/// the 6 byte headers found in the program stream map, padding stream,
/// private stream 2, etc.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialPesHeader(void)
{
	CollatorStatus_t Status;
	unsigned int PesHeaderBytes, BytesNeeded, BytesToRead;
	unsigned char PesPrivateData[MAX_PES_PRIVATE_DATA_LENGTH];
//
	if (GotPartialPesHeaderBytes < PES_INITIAL_HEADER_SIZE)
	{
		COLLATOR_DEBUG("Waiting for first part of PES header\n");
		StoredPesHeader = BufferBase + AccumulatedDataSize - GotPartialPesHeaderBytes;
		BytesToRead = min(RemainingLength, PES_INITIAL_HEADER_SIZE - GotPartialPesHeaderBytes);
		Status = AccumulateData(BytesToRead, RemainingData);
		if (Status == CollatorNoError)
		{
			GotPartialPesHeaderBytes += BytesToRead;
			RemainingData += BytesToRead;
			RemainingLength -= BytesToRead;
		}
		else
		{
			COLLATOR_DEBUG("Cannot accumulate data #6 (%d)\n", Status);
		}
		return Status;
	}
	//
	// We now have accumulated sufficient data to know how long the PES header actually is!
	//
	// pass the stream_id field to the collator sub-class (might update Configuration.ExtendedHeaderLength)
	SetPesPrivateDataLength(StoredPesHeader[3]);
	PesHeaderBytes = PES_INITIAL_HEADER_SIZE + StoredPesHeader[8] + Configuration.ExtendedHeaderLength;
	BytesNeeded = PesHeaderBytes - GotPartialPesHeaderBytes;
	BytesToRead = min(RemainingLength, BytesNeeded);
	Status = AccumulateData(BytesToRead, RemainingData);
	if (Status == CollatorNoError)
	{
		GotPartialPesHeaderBytes += BytesToRead;
		RemainingData += BytesToRead;
		RemainingLength -= BytesToRead;
		COLLATOR_DEBUG("BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead);
		if (BytesNeeded == BytesToRead)
		{
			//
			// Woo hoo! We've got the whole header, examine it and change state
			//
			COLLATOR_DEBUG("Got entire PES header\n");
			//report_dump_hex( severity_note, StoredPesHeader, PesHeaderBytes, 32, 0);
			Status = CollatorNoError; // strictly speaking this is a no-op but the code might change
			if (StoredPesHeader[0] != 0x00 || StoredPesHeader[1] != 0x00 || StoredPesHeader[2] != 0x01 ||
					CollatorNoError != (Status = ReadPesHeader()))
			{
				COLLATOR_DEBUG("%s; seeking new PES header",
					       (Status == CollatorNoError ? "Start code not where expected" :
						"Badly formed PES header"));
				SeekingPesHeader = true;
				DiscardAccumulatedData();
				// we have contained the error by changing states...
				return CollatorNoError;
			}
			//
			// Placeholder: Generic stream id based PES filtering (configured by sub-class) could be inserted
			// here (set DiscardPesPacket to true to discard).
			//
			if (Configuration.ExtendedHeaderLength)
			{
				// store a pointer to the PES private header. it is located just above the end of the
				// accumulated data and is will be safely accumulated providing the private header is
				// smaller than the rest of the PES packet. if a very large PES private header is
				// encountered we will need to introduce a temporary buffer to store the header in.
				if (Configuration.ExtendedHeaderLength <= MAX_PES_PRIVATE_DATA_LENGTH)
				{
					memcpy(PesPrivateData, BufferBase + AccumulatedDataSize - Configuration.ExtendedHeaderLength, Configuration.ExtendedHeaderLength);
				}
				else
				{
					COLLATOR_ERROR("Implementation error: Pes Private data area too big for temporay buffer\n");
				}
				Status = HandlePesPrivateData(PesPrivateData);
				if (Status != CollatorNoError)
				{
					COLLATOR_ERROR("Unhandled error when parsing PES private data\n");
					return (Status);
				}
			}
			// discard the actual PES packet from the accumulate buffer
			AccumulatedDataSize -= PesHeaderBytes;
			// record the number of bytes we need to ignore before we reach the next start code
			PesPayloadRemaining = PesPayloadLength;
			// switch states and absorb the packet
			COLLATOR_DEBUG("Discovered PES packet (header %d bytes, payload %d bytes)\n",
				       PesPacketLength - PesPayloadLength + 6, PesPayloadLength);
			GotPartialPesHeader = false;
			if (PassPesPrivateDataToElementaryStreamHandler && Configuration.ExtendedHeaderLength)
			{
				// update PesPacketLength (to ensure that GetOffsetIntoPacket gives the correct value)
				PesPayloadLength += Configuration.ExtendedHeaderLength;
				Status = HandleElementaryStream(Configuration.ExtendedHeaderLength, PesPrivateData);
				if (Status != CollatorNoError)
				{
					COLLATOR_ERROR("Failed not accumulate the PES private data area\n");
				}
			}
		}
	}
	else
	{
		COLLATOR_DEBUG("Cannot accumulate data #7 (%d)\n", Status);
	}
	return Status;
}
Example #7
0
////////////////////////////////////////////////////////////////////////////
///
/// Scan the input until an appropriate PES start code is found.
///
/// Scans any Collator_Pes_c::RemainingData searching for a PES start code.
/// The configuration for this comes from Collator_Base_c::Configuration and
/// is this means that only the interesting (e.g. PES audio packets) start
/// codes will be detected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::SearchForPesHeader(void)
{
	CollatorStatus_t Status;
	unsigned int CodeOffset;
//
	//
	// If there are any trailing start codes handle those.
	//
	while (TrailingStartCodeBytes && RemainingLength)
	{
		if (TrailingStartCodeBytes == 3)
		{
			// We've got the 0, 0, 1 so if the code is *not* in the ignore range then we've got one
			unsigned char SpecificCode = RemainingData[0];
			if (!inrange(SpecificCode, Configuration.IgnoreCodesRangeStart,
					Configuration.IgnoreCodesRangeEnd))
			{
				COLLATOR_DEBUG("Found a trailing startcode 00, 00, 01, %x\n", SpecificCode);
				// Consume the specific start code
				RemainingData++;
				RemainingLength--;
				// Switch state (and reflect the data we are about to accumulate)
				SeekingPesHeader = false;
				GotPartialPesHeader = true;
				//assert( AccumulatedDataSize == 0 );
				GotPartialPesHeaderBytes = 4;
				// There are now no trailing start code bytes
				TrailingStartCodeBytes = 0;
				// Finally, accumulate the data (by reconstructing it)
				unsigned char StartCode[4] = { 0, 0, 1, SpecificCode };
				Status = AccumulateData(4, StartCode);
				if (Status != CollatorNoError)
					COLLATOR_DEBUG("Cannot accumulate data #5 (%d)\n", Status);
				return Status;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing start code 00, 00, 01, %x was in the ignore range\n", SpecificCode);
			TrailingStartCodeBytes = 0;
			break;
		}
		else if (TrailingStartCodeBytes == 2)
		{
			// Got two zeros, a one gets us ready to read the code.
			if (RemainingData[0] == 1)
			{
				COLLATOR_DEBUG("Trailing start code looks good (found 00, 00; got 01)\n");
				TrailingStartCodeBytes++;
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Got two zeros, another zero still leaves us with two zeros.
			if (RemainingData[0] == 0)
			{
				COLLATOR_DEBUG("Trailing start code looks OK (found 00, 00; got 00)\n");
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing 00, 00 was not part of a start code\n");
			TrailingStartCodeBytes = 0;
			break;
		}
		else if (TrailingStartCodeBytes == 1)
		{
			// Got one zero, another zero gives us two (duh).
			if (RemainingData[0] == 0)
			{
				COLLATOR_DEBUG("Trailing start code looks good (found 00; got 00)\n");
				RemainingData++;
				RemainingLength--;
				continue;
			}
			// Nope, that's not a suitable start code.
			COLLATOR_DEBUG("Trailing 00 was not part of a start code\n");
			TrailingStartCodeBytes = 0;
			break;
		}
		else
		{
			COLLATOR_ERROR("TrailingStartCodeBytes has illegal value: %d\n", TrailingStartCodeBytes);
			TrailingStartCodeBytes = 0;
			return CollatorError;
		}
	}
	if (RemainingLength == 0)
	{
		return CollatorNoError;
	}
	//assert(TrailingStartCodeBytes == 0);
//
	Status = FindNextStartCode(&CodeOffset);
	if (Status == CollatorNoError)
	{
		COLLATOR_DEBUG("Locked to PES packet boundaries\n");
		// discard any data leading up to the start code
		RemainingData += CodeOffset;
		RemainingLength -= CodeOffset;
		// switch state
		SeekingPesHeader = false;
		GotPartialPesHeader = true;
		GotPartialPesHeaderBytes = 0;
	}
	else
	{
		// examine the end of the buffer to determine if there is a (potential) trailing start code
		//assert( RemainingLength >= 1 );
		if (RemainingData[RemainingLength - 1] < 1)
		{
			unsigned char LastBytes[3];
			LastBytes[0] = (RemainingLength >= 3 ? RemainingData[RemainingLength - 3] : 0xff);
			LastBytes[1] = (RemainingLength >= 2 ? RemainingData[RemainingLength - 2] : 0xff);
			LastBytes[2] = RemainingData[RemainingLength - 1];
			if (LastBytes[0] == 0 && LastBytes[1] == 0 && LastBytes[2] == 1)
			{
				TrailingStartCodeBytes = 3;
			}
			else if (LastBytes[1] == 0 && LastBytes[2] == 0)
			{
				TrailingStartCodeBytes = 2;
			}
			else if (LastBytes[2] == 0)
			{
				TrailingStartCodeBytes = 1;
			}
		}
		COLLATOR_DEBUG("Discarded %d bytes while searching for PES header (%d might be start code)\n",
			       RemainingLength, TrailingStartCodeBytes);
		RemainingLength = 0;
	}
//
	return CollatorNoError;
}
Example #8
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the parseable frame header.
///
/// Accumulate data until we have ::FrameHeaderLength
/// bytes stashed away. At this point there is sufficient data accumulated
/// to determine how many bytes will pass us by before the next frame header
/// is expected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialFrameHeader(void)
{
	CollatorStatus_t Status;
	unsigned int BytesNeeded, BytesToRead, FrameLength;
	CollatorState_t OldCollatorState;
	//
	COLLATOR_DEBUG(">><<\n");
	//
	BytesNeeded = FrameHeaderLength - GotPartialFrameHeaderBytes;
	BytesToRead = min(RemainingElementaryLength, BytesNeeded);
	Status = AccumulateData(BytesToRead, RemainingElementaryData);
	if (Status == CollatorNoError)
	{
		GotPartialFrameHeaderBytes += BytesToRead;
		RemainingElementaryData += BytesToRead;
		RemainingElementaryLength -= BytesToRead;
		COLLATOR_DEBUG("BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead);
		if (BytesNeeded == BytesToRead)
		{
			//
			// Woo hoo! We've got the whole header, examine it and change state
			//
			StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);
			COLLATOR_DEBUG("Got entire frame header packet\n");
			//report_dump_hex( severity_note, StoredFrameHeader, FrameHeaderLength, 32, 0);
			OldCollatorState = CollatorState;
			Status = DecideCollatorNextStateAndGetLength(&FrameLength);
			if (Status != CollatorNoError)
			{
				COLLATOR_DEBUG("Badly formed frame header; seeking new frame header\n");
				return HandleMissingNextFrameHeader();
			}
			if (FrameLength == 0)
			{
				// The LPCM collator needs to do this in order to get a frame evicted before
				// accumulating data from the PES private data area into the frame. The only
				// way it can do this is by reporting a zero length frame and updating some
				// internal state variables. On the next call it will report a non-zero value
				// (i.e. we won't loop forever accumulating no data).
				COLLATOR_DEBUG("Sub-class reported unlikely (but potentially legitimate) frame length (%d)\n", FrameLength);
			}
			if (FrameLength > MaximumCodedFrameSize)
			{
				COLLATOR_ERROR("Sub-class reported absurd frame length (%d)\n", FrameLength);
				return HandleMissingNextFrameHeader();
			}
			// this is the number of bytes we must absorb before switching state to SeekingFrameEnd.
			// if the value is negative then we've already started absorbing the subsequent frame
			// header.
			FramePayloadRemaining = FrameLength - FrameHeaderLength;
			if (CollatorState == GotCompleteFrame)
			{
				AccumulatedFrameReady = true;
				//
				// update the coded frame parameters using the parameters calculated the
				// last time we saw a frame header.
				//
				CodedFrameParameters->PlaybackTimeValid = NextPlaybackTimeValid;
				CodedFrameParameters->PlaybackTime = NextPlaybackTime;
				CodedFrameParameters->DecodeTimeValid = NextDecodeTimeValid;
				CodedFrameParameters->DecodeTime = NextDecodeTime;
			}
			else if (CollatorState == SkipSubFrame)
			{
				/* discard the accumulated frame header */
				AccumulatedDataSize -= FrameHeaderLength;
			}
			if (CollatorState == GotCompleteFrame || OldCollatorState == GotSynchronized)
			{
				//
				// at this point we have discovered a frame header and need to attach a time to it.
				// we can choose between the normal stamp (the stamp of the current PES packet) or the
				// spanning stamp (the stamp of the previous PES packet). Basically if we have accumulated
				// a greater number of bytes than our current offset into the PES packet then we want to
				// use the spanning time.
				//
				bool WantSpanningTime = GetOffsetIntoPacket() < (int) GotPartialFrameHeaderBytes;
				if (WantSpanningTime && !UseSpanningTime)
				{
					COLLATOR_ERROR("Wanted to take the spanning time but this was not available.");
					WantSpanningTime = false;
				}
				if (WantSpanningTime)
				{
					NextPlaybackTimeValid = SpanningPlaybackTimeValid;
					NextPlaybackTime = SpanningPlaybackTime;
					SpanningPlaybackTimeValid = false;
					NextDecodeTimeValid = SpanningDecodeTimeValid;
					NextDecodeTime = SpanningDecodeTime;
					SpanningDecodeTimeValid = false;
					UseSpanningTime = false;
				}
				else
				{
					NextPlaybackTimeValid = PlaybackTimeValid;
					NextPlaybackTime = PlaybackTime;
					PlaybackTimeValid = false;
					NextDecodeTimeValid = DecodeTimeValid;
					NextDecodeTime = DecodeTime;
					DecodeTimeValid = false;
				}
			}
			// switch states and absorb the packet
			COLLATOR_DEBUG("Discovered frame header (frame length %d bytes)\n", FrameLength);
		}
	}
	else
	{
		COLLATOR_DEBUG("Cannot accumulate data #3 (%d)\n", Status);
	}
	return Status;
}
Example #9
0
////////////////////////////////////////////////////////////////////////////
///
/// Scan the input until an appropriate synchronization sequence is found.
///
/// Scans any ::RemainingElementaryData searching for a
/// synchronization sequence using ::FindNextSyncWord,
/// a pure virtual method provided by sub-classes.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::SearchForSyncWord(void)
{
	CollatorStatus_t Status;
	int CodeOffset;
//
	COLLATOR_DEBUG(">><<\n");
	Status = FindNextSyncWord(&CodeOffset);
	if (Status == CollatorNoError)
	{
		COLLATOR_DEBUG("Tentatively locked to synchronization sequence (at %d)\n", CodeOffset);
		// switch state
		CollatorState = GotSynchronized;
		GotPartialFrameHeaderBytes = 0;
		if (CodeOffset >= 0)
		{
			// discard any data leading up to the start code
			RemainingElementaryData += CodeOffset;
			RemainingElementaryLength -= CodeOffset;
		}
		else
		{
			COLLATOR_DEBUG("Synchronization sequence spans multiple PES packets\n");
			// accumulate any data from the old block
			Status = AccumulateData(-1 * CodeOffset,
						PotentialFrameHeader + PotentialFrameHeaderLength + CodeOffset);
			if (Status != CollatorNoError)
				COLLATOR_DEBUG("Cannot accumulate data #1 (%d)\n", Status);
			GotPartialFrameHeaderBytes += (-1 * CodeOffset);
		}
		PotentialFrameHeaderLength = 0;
	}
	else
	{
		// copy the last few bytes of the frame into PotentialFrameHeader (so that FindNextSyncWord
		// can return a negative CodeOffset if the synchronization sequence spans blocks)
		if (RemainingElementaryLength < FrameHeaderLength)
		{
			if (PotentialFrameHeaderLength + RemainingElementaryLength > FrameHeaderLength)
			{
				// shuffle the existing potential frame header downwards
				unsigned int BytesToKeep = FrameHeaderLength - RemainingElementaryLength;
				unsigned int ShuffleBy = PotentialFrameHeaderLength - BytesToKeep;
				memmove(PotentialFrameHeader, PotentialFrameHeader + ShuffleBy, BytesToKeep);
				PotentialFrameHeaderLength = BytesToKeep;
			}
			memcpy(PotentialFrameHeader + PotentialFrameHeaderLength,
			       RemainingElementaryData,
			       RemainingElementaryLength);
			PotentialFrameHeaderLength += RemainingElementaryLength;
		}
		else
		{
			memcpy(PotentialFrameHeader,
			       RemainingElementaryData + RemainingElementaryLength - FrameHeaderLength,
			       FrameHeaderLength);
			PotentialFrameHeaderLength = FrameHeaderLength;
		}
		COLLATOR_DEBUG("Discarded %d bytes while searching for synchronization sequence\n",
			       RemainingElementaryLength);
		RemainingElementaryLength = 0;
		// we have contained the 'error' and don't want to propagate it
		Status = CollatorNoError;
	}
//
	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;
}
Example #11
0
//{{{ 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;
}
Example #13
0
////////////////////////////////////////////////////////////////////////////
///
/// Accumulate incoming data until we have the parseable frame header.
///
/// Accumulate data until we have ::FrameHeaderLength
/// bytes stashed away. At this point there is sufficient data accumulated
/// to determine how many bytes will pass us by before the next frame header
/// is expected.
///
/// \return Collator status code, CollatorNoError indicates success.
///
CollatorStatus_t Collator_PesAudio_c::ReadPartialFrameHeader( void )
{
    CollatorStatus_t Status;
    unsigned int BytesNeeded, BytesToRead, FrameLength;
    CollatorState_t OldCollatorState;

    //

    COLLATOR_DEBUG(">><<\n");

    //

    BytesNeeded = FrameHeaderLength - GotPartialFrameHeaderBytes;
    BytesToRead = min( RemainingElementaryLength, BytesNeeded );

    Status = AccumulateData( BytesToRead, RemainingElementaryData );
    if( Status == CollatorNoError )
    {
        GotPartialFrameHeaderBytes += BytesToRead;
        RemainingElementaryData += BytesToRead;
        RemainingElementaryLength -= BytesToRead;

        COLLATOR_DEBUG( "BytesNeeded %d; BytesToRead %d\n", BytesNeeded, BytesToRead );
        if( BytesNeeded == BytesToRead )
        {
            //
            // Woo hoo! We've got the whole header, examine it and change state
            //

            StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);

            COLLATOR_DEBUG("Got entire frame header packet\n");
            //report_dump_hex( severity_note, StoredFrameHeader, FrameHeaderLength, 32, 0);

            OldCollatorState = CollatorState;
            Status = DecideCollatorNextStateAndGetLength(&FrameLength);
            if( Status != CollatorNoError )
            {
                COLLATOR_DEBUG( "Badly formed frame header; seeking new frame header\n" );
                return HandleMissingNextFrameHeader();
            }

            FramePayloadRemaining = FrameLength - FrameHeaderLength;

            if ((int)FramePayloadRemaining < 0)
            {
                if (CollatorState == GotCompleteFrame)
                {
                    // accumulate the remainder of the frame before the FrameFlush method...
                    Status = AccumulateData( FrameLength, RemainingElementaryData );
                    if (Status != CollatorNoError )
                    {
                        COLLATOR_DEBUG( "Cannot accumulate data #2 (%d)\n", Status );
                        return Status;
                    }
                    StoredFrameHeader = BufferBase + (AccumulatedDataSize - FrameHeaderLength);
                    RemainingElementaryData += FrameLength;
                    RemainingElementaryLength -= FrameLength;

                    // prepare the next call to ReadFrame by setting the correct FramePayloadRemaining
                    Status = GetSpecificFrameLength(&FrameLength);
                    if (Status != CollatorNoError )
                    {
                        COLLATOR_DEBUG( "Cannot get the specific frame length (%d)\n", Status );
                        return Status;
                    }

                    FramePayloadRemaining = FrameLength - FrameHeaderLength;
                }
                else
                {
                    // specific case: reading the header only accumulated too much data
                    // so discard the extra data
                    int NbBytesToDiscard = - (int)FramePayloadRemaining;
                    int temp = NbBytesToDiscard - BytesToRead;

                    AccumulatedDataSize -= NbBytesToDiscard;
                    GotPartialFrameHeaderBytes = (temp > 0)?temp:0;
                    NbBytesToDiscard = min((unsigned int) NbBytesToDiscard, BytesToRead);
                    RemainingElementaryData -= NbBytesToDiscard;
                    RemainingElementaryLength += NbBytesToDiscard;
                }
            }

            if (CollatorState == GotCompleteFrame)
            {
                AccumulatedFrameReady = true;

                //
                // update the coded frame parameters using the parameters calculated the
                // last time we saw a frame header.
                //
                CodedFrameParameters->PlaybackTimeValid = NextPlaybackTimeValid;
                CodedFrameParameters->PlaybackTime = NextPlaybackTime;
                CodedFrameParameters->DecodeTimeValid = NextDecodeTimeValid;
                CodedFrameParameters->DecodeTime = NextDecodeTime;
            }
            else if (CollatorState == SkipSubFrame)
            {
                /* discard the accumulated frame header */
                AccumulatedDataSize -= FrameHeaderLength;
            }

            if (CollatorState == GotCompleteFrame || OldCollatorState == GotSynchronized)
            {
                //
                // at this point we have discovered a frame header and need to attach a time to it.
                // we can choose between the normal stamp (the stamp of the current PES packet) or the
                // spanning stamp (the stamp of the previous PES packet). Basically if we have accumulated
                // a greater number of bytes than our current offset into the PES packet then we want to
                // use the spanning time.
                //

                bool WantSpanningTime = GetOffsetIntoPacket() < (int) GotPartialFrameHeaderBytes;

                if( WantSpanningTime && !UseSpanningTime)
                {
                    COLLATOR_ERROR("Wanted to take the spanning time but this was not available.");
                    WantSpanningTime = false;
                }

                if( WantSpanningTime )
                {
                    NextPlaybackTimeValid = SpanningPlaybackTimeValid;
                    NextPlaybackTime	= SpanningPlaybackTime;
                    SpanningPlaybackTimeValid = false;
                    NextDecodeTimeValid	= SpanningDecodeTimeValid;
                    NextDecodeTime	= SpanningDecodeTime;
                    SpanningDecodeTimeValid = false;
                    UseSpanningTime       = false;
                }
                else
                {
                    NextPlaybackTimeValid = PlaybackTimeValid;
                    NextPlaybackTime	= PlaybackTime;
                    PlaybackTimeValid	= false;
                    NextDecodeTimeValid	= DecodeTimeValid;
                    NextDecodeTime	= DecodeTime;
                    DecodeTimeValid	= false;
                }
            }

            // switch states and absorb the packet
            COLLATOR_DEBUG( "Discovered frame header (frame length %d bytes)\n", FrameLength );
        }
    }
    else
    {
        COLLATOR_DEBUG( "Cannot accumulate data #3 (%d)\n", Status );
    }
    return Status;
}
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;
}