PlayerStatus_t Player_Generic_c::ProcessAccumulatedControlMessages( PlayerStream_t Stream, unsigned int *MessageCount, unsigned int MessageTableSize, PlayerBufferRecord_t *MessageTable, unsigned long long SequenceNumber, unsigned long long Time ) { unsigned int i; bool SequenceCheck; bool ProcessNow; // // If we have no messages to scan return in a timely fashion // if( *MessageCount == 0 ) return PlayerNoError; // // Perform the scan // for( i=0; i<MessageTableSize; i++ ) if( MessageTable[i].Buffer != NULL ) { SequenceCheck = (MessageTable[i].ControlStructure->SequenceType == SequenceTypeBeforeSequenceNumber) || (MessageTable[i].ControlStructure->SequenceType == SequenceTypeAfterSequenceNumber); ProcessNow = SequenceCheck ? ((SequenceNumber != INVALID_SEQUENCE_VALUE) && (MessageTable[i].ControlStructure->SequenceValue <= SequenceNumber)) : ((Time != INVALID_SEQUENCE_VALUE) && (MessageTable[i].ControlStructure->SequenceValue <= Time)); if( ProcessNow ) { ProcessControlMessage( Stream, MessageTable[i].Buffer, MessageTable[i].ControlStructure ); MessageTable[i].Buffer = NULL; MessageTable[i].ControlStructure = NULL; (*MessageCount)--; } } return PlayerNoError; }
/*********************** * ParseData * Process incomming data **********************/ void RTMPConnection::ParseData(BYTE *data,const DWORD size) { RTMPChunkInputStreams::iterator it; int len = 0; int digesOffsetMethod = 0; //Get pointer and data size BYTE *buffer = data; DWORD bufferSize = size; DWORD digestPosServer = 0; //Increase current window curWindowSize += size; //And total size recvSize += size; //Check current window if (windowSize && curWindowSize>windowSize) { //Send SendControlMessage(RTMPMessage::Acknowledgement,RTMPAcknowledgement::Create(recvSize)); //Reset window curWindowSize = 0; } //While there is data while(bufferSize>0) { //Check connection state switch(state) { case HEADER_C0_WAIT: //Parse c0 len = c0.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c0.IsParsed()) { //Move to next state state = HEADER_C1_WAIT; //Debug Log("Received c0 version: %d\n",c0.GetRTMPVersion()); } break; case HEADER_C1_WAIT: //Parse c1 len = c1.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c1.IsParsed()) { Log("-Received C1 client version [%d,%d,%d,%d]\n",c1.GetVersion()[0],c1.GetVersion()[1],c1.GetVersion()[2],c1.GetVersion()[3]); //Set s0 data s01.SetRTMPVersion(3); //Set current timestamp s01.SetTime(getDifTime(&startTime)/1000); //Check which version are we using if (c1.GetVersion()[3]) { //Verify client digesOffsetMethod = VerifyC1Data(c1.GetData(),c1.GetSize()); //Set version s01.SetVersion(3,5,1,1); //Check if found diggest ofset digest = (digesOffsetMethod>0); } else { //Seet version to zero s01.SetVersion(0,0,0,0); //Do not calculate digest digest = false; } //Set random data from memory BYTE* random = s01.GetRandom(); //Fill it for (int i=0;i<s01.GetRandomSize();i++) //With random random[i] = rand(); //If we have to calculate digest if (digest) //calculate digest for s1 only, skipping s0 digestPosServer = GenerateS1Data(digesOffsetMethod,s01.GetData()+1,s01.GetSize()-1); //Send S01 data WriteData(s01.GetData(),s01.GetSize()); //Move to next state state = HEADER_C2_WAIT; //Debug Log("Sending s0 and s1 with digest %s offset method %d\n",digest?"on":"off",digesOffsetMethod); } break; case HEADER_C2_WAIT: //Parse c2 len = c2.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (c2.IsParsed()) { //Set s2 data s2.SetTime(c1.GetTime()); //Set current timestamp s2.SetTime2(getDifTime(&startTime)/1000); //Echo c1 data s2.SetRandom(c1.GetRandom(),c1.GetRandomSize()); //If we have to calculate digest if (digest) //calculate digest for s1 GenerateS2Data(digesOffsetMethod,s2.GetData(),s2.GetSize()); //Send S2 data WriteData(s2.GetData(),s2.GetSize()); //Move to next state state = CHUNK_HEADER_WAIT; //Debug Log("Received c2, sending c2. CONNECTED.\n"); } break; case CHUNK_HEADER_WAIT: //Parse c2 len = header.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (header.IsParsed()) { //Clean all buffers type0.Reset(); type1.Reset(); type2.Reset(); extts.Reset(); //Move to next state state = CHUNK_TYPE_WAIT; //Debug //Log("Received header [fmt:%d,stream:%d]\n",header.GetFmt(),header.GetStreamId()); //header.Dump(); } break; case CHUNK_TYPE_WAIT: //Get sream id chunkStreamId = header.GetStreamId(); //Find chunk stream it = chunkInputStreams.find(chunkStreamId); //Check if we have a new chunk stream or already got one if (it==chunkInputStreams.end()) { //Log //Log("Creating new chunk stream [id:%d]\n",chunkStreamId); //Create it chunkInputStream = new RTMPChunkInputStream(); //Append it chunkInputStreams[chunkStreamId] = chunkInputStream; } else //Set the stream chunkInputStream = it->second; //Switch type switch(header.GetFmt()) { case 0: //Check if the buffer type has been parsed len = type0.Parse(buffer,bufferSize); //Check if it is parsed if (type0.IsParsed()) { //Debug //Debug("Got type 0 header [timestamp:%lu,messagelength:%d,type:%d,streamId:%d]\n",type0.GetTimestamp(),type0.GetMessageLength(),type0.GetMessageTypeId(),type0.GetMessageStreamId()); //type0.Dump(); //Set data for stream chunkInputStream->SetMessageLength (type0.GetMessageLength()); chunkInputStream->SetMessageTypeId (type0.GetMessageTypeId()); chunkInputStream->SetMessageStreamId (type0.GetMessageStreamId()); //Check if we have extended timestamp if (type0.GetTimestamp()!=0xFFFFFF) { //Set timesptamp chunkInputStream->SetTimestamp(type0.GetTimestamp()); //No timestamp delta chunkInputStream->SetTimestampDelta(0); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 1: //Check if the buffer type has been parsed len = type1.Parse(buffer,bufferSize); //Check if it is parsed if (type1.IsParsed()) { //Debug //Debug("Got type 1 header [timestampDelta:%u,messagelength:%d,type:%d]\n",type1.GetTimestampDelta(),type1.GetMessageLength(),type1.GetMessageTypeId()); //type1.Dump(); //Set data for stream chunkInputStream->SetMessageLength(type1.GetMessageLength()); chunkInputStream->SetMessageTypeId(type1.GetMessageTypeId()); //Check if we have extended timestam if (type1.GetTimestampDelta()!=0xFFFFFF) { //Set timestamp delta chunkInputStream->SetTimestampDelta(type1.GetTimestampDelta()); //Set timestamp chunkInputStream->IncreaseTimestampWithDelta(); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 2: //Check if the buffer type has been parsed len = type2.Parse(buffer,bufferSize); //Check if it is parsed if (type2.IsParsed()) { //Debug //Debug("Got type 2 header [timestampDelta:%lu]\n",type2.GetTimestampDelta()); //type2.Dump(); //Check if we have extended timestam if (type2.GetTimestampDelta()!=0xFFFFFF) { //Set timestamp delta chunkInputStream->SetTimestampDelta(type2.GetTimestampDelta()); //Increase timestamp chunkInputStream->IncreaseTimestampWithDelta(); //Move to next state state = CHUNK_DATA_WAIT; } else //We have to read 4 more bytes state = CHUNK_EXT_TIMESTAMP_WAIT; //Start data reception chunkInputStream->StartChunkData(); //Reset sent bytes in buffer chunkLen = 0; } break; case 3: //Debug("Got type 3 header\n"); //No header chunck len = 0; //If it is the first chunk if (chunkInputStream->IsFirstChunk()) //Increase timestamp with previous delta chunkInputStream->IncreaseTimestampWithDelta(); //Start data reception chunkInputStream->StartChunkData(); //Move to next state state = CHUNK_DATA_WAIT; //Reset sent bytes in buffer chunkLen = 0; break; } //Move pointer buffer += len; bufferSize -= len; break; case CHUNK_EXT_TIMESTAMP_WAIT: //Parse extended timestamp len = extts.Parse(buffer,bufferSize); //Move buffer+=len; bufferSize-=len; //If it is parsed if (extts.IsParsed()) { //Check header type if (header.GetFmt()==1) { //Set the timestamp chunkInputStream->SetTimestamp(extts.GetTimestamp()); //No timestamp delta chunkInputStream->SetTimestampDelta(0); } else { //Set timestamp delta chunkInputStream->SetTimestampDelta(extts.GetTimestamp()); //Increase timestamp chunkInputStream->IncreaseTimestampWithDelta(); } //Move to next state state = CHUNK_DATA_WAIT; } break; case CHUNK_DATA_WAIT: //Check max buffer size if (maxChunkSize && chunkLen+bufferSize>maxChunkSize) //Parse only max chunk size len = maxChunkSize-chunkLen; else //parse all data len = bufferSize; //Check size if (!len) { //Debug Error("Chunk data of size zero [maxChunkSize:%d,chunkLen:%d]\n"); //Skip break; } //Parse data len = chunkInputStream->Parse(buffer,len); //Check if it has parsed a msg if (chunkInputStream->IsParsed()) { //Log("Got message [timestamp:%lu]\n",chunkInputStream->GetTimestamp()); //Get message RTMPMessage* msg = chunkInputStream->GetMessage(); //Get message stream DWORD messageStreamId = msg->GetStreamId(); //Check message type if (msg->IsControlProtocolMessage()) { //Get message type BYTE type = msg->GetType(); //Get control protocl message RTMPObject* ctrl = msg->GetControlProtocolMessage(); //Procces msg ProcessControlMessage(messageStreamId,type,ctrl); } else if (msg->IsCommandMessage()) { //Get Command message RTMPCommandMessage* cmd = msg->GetCommandMessage(); //Dump msg cmd->Dump(); //Proccess msg ProcessCommandMessage(messageStreamId,cmd); } else if (msg->IsMedia()) { //Get media frame RTMPMediaFrame* frame = msg->GetMediaFrame(); //Check if we have it if (frame) //Process message ProcessMediaData(messageStreamId,frame); } else if (msg->IsMetaData() || msg->IsSharedObject()) { //Get object RTMPMetaData *meta = msg->GetMetaData(); //Debug it meta->Dump(); //Process meta data ProcessMetaData(messageStreamId,meta); } else { //UUh?? Error("Unknown rtmp message, should never happen\n"); } //Delete msg delete(msg); //Move to next chunck state = CHUNK_HEADER_WAIT; //Clean header header.Reset(); } //Increase buffer length chunkLen += len; //Move pointer buffer += len; bufferSize -= len; //Check max chunk size if (maxChunkSize && chunkLen>=maxChunkSize) { //Wait for next buffer header state = CHUNK_HEADER_WAIT; //Clean header header.Reset(); } break; } } }
void Player_Generic_c::ProcessPostManifest( PlayerStream_t Stream ) { PlayerStatus_t Status; RingStatus_t RingStatus; Buffer_t Buffer; Buffer_t OriginalCodedFrameBuffer; BufferType_t BufferType; PlayerControlStructure_t *ControlStructure; ParsedFrameParameters_t *ParsedFrameParameters; PlayerSequenceNumber_t *SequenceNumberStructure; unsigned long long LastEntryTime; unsigned long long SequenceNumber; unsigned long long MaximumActualSequenceNumberSeen; unsigned long long Time; unsigned int AccumulatedBeforeControlMessagesCount; unsigned int AccumulatedAfterControlMessagesCount; bool ProcessNow; unsigned int *Count; PlayerBufferRecord_t *Table; VideoOutputTiming_t *OutputTiming; unsigned long long Now; // LastEntryTime = OS_GetTimeInMicroSeconds(); SequenceNumber = INVALID_SEQUENCE_VALUE; MaximumActualSequenceNumberSeen = 0; Time = INVALID_TIME; AccumulatedBeforeControlMessagesCount = 0; AccumulatedAfterControlMessagesCount = 0; // // Signal we have started // OS_LockMutex( &Lock ); Stream->ProcessRunningCount++; if( Stream->ProcessRunningCount == Stream->ExpectedProcessCount ) OS_SetEvent( &Stream->StartStopEvent ); OS_UnLockMutex( &Lock ); // // Main Loop // while( !Stream->Terminating ) { RingStatus = Stream->ManifestedBufferRing->Extract( (unsigned int *)(&Buffer), PLAYER_MAX_EVENT_WAIT ); Now = OS_GetTimeInMicroSeconds(); if( Stream->ReTimeQueuedFrames && ((Now - Stream->ReTimeStart) > PLAYER_MAX_TIME_IN_RETIMING) ) Stream->ReTimeQueuedFrames = false; if( RingStatus == RingNothingToGet ) continue; Buffer->GetType( &BufferType ); Buffer->TransferOwnership( IdentifierProcessPostManifest ); // // Deal with a coded frame buffer // if( BufferType == Stream->DecodeBufferType ) { Stream->FramesFromManifestorCount++; #if 0 { static unsigned long long LastTime = 0; static unsigned long long LastActualTime = 0; AudioOutputTiming_t *OutputTiming; Buffer->ObtainMetaDataReference( MetaDataAudioOutputTimingType, (void **)&OutputTiming); report( severity_info, "Post Dn = %d, DS= %6lld, DAS = %6lld, S = %016llx,AS = %016llx\n", OutputTiming->DisplayCount, OutputTiming->SystemPlaybackTime - LastTime, OutputTiming->ActualSystemPlaybackTime - LastActualTime, OutputTiming->SystemPlaybackTime, OutputTiming->ActualSystemPlaybackTime ); LastTime = OutputTiming->SystemPlaybackTime; LastActualTime = OutputTiming->ActualSystemPlaybackTime; } #endif #if 0 { static unsigned long long LastTime = 0; static unsigned long long LastActualTime = 0; VideoOutputTiming_t *OutputTiming; Buffer->ObtainMetaDataReference( MetaDataVideoOutputTimingType, (void **)&OutputTiming ); report( severity_info, "Post Dn = %d %d, I = %d, TFF = %d, DS= %6lld, DAS = %6lld, S = %016llx, AS = %016llx\n", OutputTiming->DisplayCount[0], OutputTiming->DisplayCount[1], OutputTiming->Interlaced, OutputTiming->TopFieldFirst, OutputTiming->SystemPlaybackTime - LastTime, OutputTiming->ActualSystemPlaybackTime - LastActualTime, OutputTiming->SystemPlaybackTime, OutputTiming->ActualSystemPlaybackTime ); LastTime = OutputTiming->SystemPlaybackTime; LastActualTime = OutputTiming->ActualSystemPlaybackTime; } #endif // // Obtain a sequence number from the buffer // Status = Buffer->ObtainAttachedBufferReference( Stream->CodedFrameBufferType, &OriginalCodedFrameBuffer ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessPostManifest - Unable to obtain the the original coded frame buffer - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessPostManifest ); continue; } Status = OriginalCodedFrameBuffer->ObtainMetaDataReference( MetaDataSequenceNumberType, (void **)(&SequenceNumberStructure) ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessPostManifest - Unable to obtain the meta data \"SequenceNumber\" - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessPostManifest ); continue; } Status = Buffer->ObtainMetaDataReference( MetaDataParsedFrameParametersReferenceType, (void **)(&ParsedFrameParameters) ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessPostManifest - Unable to obtain the meta data \"ParsedFrameParametersReference\" - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessPostManifest ); continue; } // // Check for whether or not we are in re-timing // if( Stream->ReTimeQueuedFrames && !SequenceNumberStructure->MarkerFrame ) { Status = Buffer->ObtainMetaDataReference( (Stream->StreamType == StreamTypeVideo ? MetaDataVideoOutputTimingType : MetaDataAudioOutputTimingType), (void **)&OutputTiming ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessPostManifest - Unable to obtain the meta data \"%s\" - Implementation error\n", (Stream->StreamType == StreamTypeVideo ? "VideoOutputTiming" : "AudioOutputTiming") ); Buffer->DecrementReferenceCount( IdentifierProcessPostManifest ); continue; } if( ValidTime(OutputTiming->ActualSystemPlaybackTime) ) { Stream->ReTimeQueuedFrames = false; } else { Stream->OutputTimer->GenerateFrameTiming( Buffer ); Status = Stream->OutputTimer->TestForFrameDrop( Buffer, OutputTimerBeforeManifestation ); if( !Stream->Terminating && (Status == OutputTimerNoError) ) { Stream->FramesToManifestorCount++; Stream->Manifestor->QueueDecodeBuffer( Buffer ); continue; } } } // // Extract the sequence number, and write the timing statistics // //report( severity_info, "MQ Post Man %d - %d\n", Stream->StreamType, ParsedFrameParameters->DisplayFrameIndex ); SequenceNumberStructure->TimeEntryInProcess3 = OS_GetTimeInMicroSeconds(); SequenceNumberStructure->DeltaEntryInProcess3 = SequenceNumberStructure->TimeEntryInProcess3 - LastEntryTime; LastEntryTime = SequenceNumberStructure->TimeEntryInProcess3; SequenceNumber = SequenceNumberStructure->Value; MaximumActualSequenceNumberSeen = max(SequenceNumber, MaximumActualSequenceNumberSeen); Time = ParsedFrameParameters->NativePlaybackTime; #ifndef __TDT__ ProcessStatistics( Stream, SequenceNumberStructure ); #endif if( SequenceNumberStructure->MarkerFrame ) { Stream->DiscardingUntilMarkerFramePostM = false; Time = INVALID_TIME; } // // Process any outstanding control messages to be applied before this buffer // ProcessAccumulatedControlMessages( Stream, &AccumulatedBeforeControlMessagesCount, PLAYER_MAX_POSTM_MESSAGES, Stream->AccumulatedBeforePostMControlMessages, SequenceNumber, Time ); // // Pass buffer back into output timer // and release the buffer. // if( !SequenceNumberStructure->MarkerFrame ) { Stream->OutputTimer->RecordActualFrameTiming( Buffer ); Stream->Codec->ReleaseDecodeBuffer( Buffer ); } else Buffer->DecrementReferenceCount( IdentifierProcessPostManifest ); // // Process any outstanding control messages to be applied after this buffer // ProcessAccumulatedControlMessages( Stream, &AccumulatedAfterControlMessagesCount, PLAYER_MAX_POSTM_MESSAGES, Stream->AccumulatedAfterPostMControlMessages, SequenceNumber, Time ); } // // Deal with a player control structure // else if( BufferType == BufferPlayerControlStructureType ) { Buffer->ObtainDataReference( NULL, NULL, (void **)(&ControlStructure) ); ProcessNow = (ControlStructure->SequenceType == SequenceTypeImmediate) || ((SequenceNumber != INVALID_SEQUENCE_VALUE) && (ControlStructure->SequenceValue <= MaximumActualSequenceNumberSeen)); if( ProcessNow ) ProcessControlMessage( Stream, Buffer, ControlStructure ); else { if( (ControlStructure->SequenceType == SequenceTypeBeforeSequenceNumber) || (ControlStructure->SequenceType == SequenceTypeBeforePlaybackTime) ) { Count = &AccumulatedBeforeControlMessagesCount; Table = Stream->AccumulatedBeforePostMControlMessages; } else { Count = &AccumulatedAfterControlMessagesCount; Table = Stream->AccumulatedAfterPostMControlMessages; } AccumulateControlMessage( Buffer, ControlStructure, Count, PLAYER_MAX_POSTM_MESSAGES, Table ); } } else { report( severity_error, "Player_Generic_c::ProcessPostManifest - Unknown buffer type received - Implementation error.\n" ); Buffer->DecrementReferenceCount(); } } report( severity_info, "3333 Holding control strutures %d\n", AccumulatedBeforeControlMessagesCount + AccumulatedAfterControlMessagesCount ); // // Make sur no one will wait for these // Stream->ReTimeQueuedFrames = false; // // Signal we have terminated // OS_LockMutex( &Lock ); Stream->ProcessRunningCount--; if( Stream->ProcessRunningCount == 0 ) OS_SetEvent( &Stream->StartStopEvent ); OS_UnLockMutex( &Lock ); }
void Player_Generic_c::ProcessDecodeToManifest( PlayerStream_t Stream ) { unsigned int i; PlayerStatus_t Status; RingStatus_t RingStatus; unsigned int AccumulatedBufferTableOccupancy; PlayerBufferRecord_t *AccumulatedBufferTable; Buffer_t Buffer = NULL; Buffer_t OriginalCodedFrameBuffer; BufferType_t BufferType; PlayerControlStructure_t *ControlStructure; ParsedFrameParameters_t *ParsedFrameParameters; unsigned int LowestIndex; unsigned int LowestDisplayFrameIndex; unsigned int DesiredFrameIndex; unsigned int PossibleDecodeBuffers; unsigned int MaxDecodesOutOfOrder; PlayerSequenceNumber_t *SequenceNumberStructure; unsigned long long LastEntryTime; unsigned long long SequenceNumber; unsigned long long MinumumSequenceNumberAccumulated; unsigned long long MaximumActualSequenceNumberSeen; unsigned long long Time; unsigned int AccumulatedBeforeControlMessagesCount; unsigned int AccumulatedAfterControlMessagesCount; bool SequenceCheck; bool ProcessNow; unsigned int *Count; PlayerBufferRecord_t *Table; Buffer_t MarkerFrameBuffer; bool FirstFrame; bool DiscardBuffer; bool LastPreManifestDiscardBuffer; unsigned char SubmitInitialFrame; Buffer_t InitialFrameBuffer; // // Set parameters // AccumulatedBufferTableOccupancy = 0; AccumulatedBufferTable = Stream->AccumulatedDecodeBufferTable; LastEntryTime = OS_GetTimeInMicroSeconds(); SequenceNumber = INVALID_SEQUENCE_VALUE; Time = INVALID_TIME; AccumulatedBeforeControlMessagesCount = 0; AccumulatedAfterControlMessagesCount = 0; MinumumSequenceNumberAccumulated = 0xffffffffffffffffULL; MaximumActualSequenceNumberSeen = 0; DesiredFrameIndex = 0; FirstFrame = true; MarkerFrameBuffer = NULL; InitialFrameBuffer = NULL; LastPreManifestDiscardBuffer = false; // // Signal we have started // OS_LockMutex( &Lock ); Stream->ProcessRunningCount++; if( Stream->ProcessRunningCount == Stream->ExpectedProcessCount ) OS_SetEvent( &Stream->StartStopEvent ); OS_UnLockMutex( &Lock ); // // Main Loop // while( !Stream->Terminating ) { // // Buffer re-ordering loop // while( !Stream->Terminating ) { // // Scan the list of accumulated buffers to see if the next display frame is available // (whether because it was already accumulated, or because its display frame index has been updated) // MinumumSequenceNumberAccumulated = 0xffffffffffffffffULL; if( AccumulatedBufferTableOccupancy != 0 ) { LowestIndex = INVALID_INDEX; LowestDisplayFrameIndex = INVALID_INDEX; for( i=0; i<Stream->NumberOfDecodeBuffers; i++ ) if( AccumulatedBufferTable[i].Buffer != NULL ) { MinumumSequenceNumberAccumulated = min(MinumumSequenceNumberAccumulated, AccumulatedBufferTable[i].SequenceNumber); if( (AccumulatedBufferTable[i].ParsedFrameParameters->DisplayFrameIndex != INVALID_INDEX) && ((LowestIndex == INVALID_INDEX) || (AccumulatedBufferTable[i].ParsedFrameParameters->DisplayFrameIndex < LowestDisplayFrameIndex)) ) { LowestDisplayFrameIndex = AccumulatedBufferTable[i].ParsedFrameParameters->DisplayFrameIndex; LowestIndex = i; } } Stream->Manifestor->GetDecodeBufferCount( &PossibleDecodeBuffers ); MaxDecodesOutOfOrder = (Stream->Playback->Direction == PlayForward) ? (PossibleDecodeBuffers >> 1) : (3 * PossibleDecodeBuffers)/4; MaxDecodesOutOfOrder = min( (PossibleDecodeBuffers - PLAYER_MINIMUM_NUMBER_OF_WORKING_DECODE_BUFFERS), MaxDecodesOutOfOrder ); if( Stream->Playback->Direction == PlayForward ) MaxDecodesOutOfOrder = min( PLAYER_LIMIT_ON_OUT_OF_ORDER_DECODES, MaxDecodesOutOfOrder ); if( (LowestIndex != INVALID_INDEX) && ( (LowestDisplayFrameIndex == DesiredFrameIndex) || (AccumulatedBufferTableOccupancy >= MaxDecodesOutOfOrder) || (AccumulatedBufferTable[LowestIndex].ParsedFrameParameters->CollapseHolesInDisplayIndices) || (MarkerFrameBuffer != NULL) ) ) { Buffer = AccumulatedBufferTable[LowestIndex].Buffer; ParsedFrameParameters = AccumulatedBufferTable[LowestIndex].ParsedFrameParameters; SequenceNumber = AccumulatedBufferTable[LowestIndex].SequenceNumber; BufferType = Stream->DecodeBufferType; AccumulatedBufferTable[LowestIndex].Buffer = NULL; AccumulatedBufferTable[LowestIndex].ParsedFrameParameters = NULL; AccumulatedBufferTableOccupancy--; break; } } // // Skip any frame indices that were unused // while( CheckForNonDecodedFrame( Stream, DesiredFrameIndex ) ) DesiredFrameIndex++; // // If we get here with a marker frame, then we have emptied our accumulated list // if( MarkerFrameBuffer != NULL ) { SequenceNumber = SequenceNumberStructure->Value; MaximumActualSequenceNumberSeen = max(SequenceNumber, MaximumActualSequenceNumberSeen); ProcessAccumulatedControlMessages( Stream, &AccumulatedBeforeControlMessagesCount, PLAYER_MAX_DTOM_MESSAGES, Stream->AccumulatedBeforeDtoMControlMessages, SequenceNumber, Time ); ProcessAccumulatedControlMessages( Stream, &AccumulatedAfterControlMessagesCount, PLAYER_MAX_DTOM_MESSAGES, Stream->AccumulatedAfterDtoMControlMessages, SequenceNumber, Time ); Stream->ManifestedBufferRing->Insert( (unsigned int)MarkerFrameBuffer ); // Pass on the marker MarkerFrameBuffer = NULL; Stream->DiscardingUntilMarkerFrameDtoM = false; continue; } // // Get a new buffer (continue will still perform the scan) // RingStatus = Stream->DecodedFrameRing->Extract( (unsigned int *)(&Buffer), PLAYER_NEXT_FRAME_EVENT_WAIT ); if( (RingStatus == RingNothingToGet) || (Buffer == NULL) || Stream->Terminating ) continue; Buffer->TransferOwnership( IdentifierProcessDecodeToManifest ); Buffer->GetType( &BufferType ); if( BufferType != Stream->DecodeBufferType ) break; // // Obtain a sequence number from the buffer // Status = Buffer->ObtainAttachedBufferReference( Stream->CodedFrameBufferType, &OriginalCodedFrameBuffer ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Unable to obtain the the original coded frame buffer - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessDecodeToManifest ); continue; } Status = OriginalCodedFrameBuffer->ObtainMetaDataReference( MetaDataSequenceNumberType, (void **)(&SequenceNumberStructure) ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Unable to obtain the meta data \"SequenceNumber\" - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessDecodeToManifest ); continue; } SequenceNumberStructure->TimeEntryInProcess2 = OS_GetTimeInMicroSeconds(); SequenceNumberStructure->DeltaEntryInProcess2 = SequenceNumberStructure->TimeEntryInProcess2 - LastEntryTime; LastEntryTime = SequenceNumberStructure->TimeEntryInProcess2; SequenceNumber = SequenceNumberStructure->Value; // // Check, is this a marker frame // if( SequenceNumberStructure->MarkerFrame ) { MarkerFrameBuffer = Buffer; continue; // allow us to empty the accumulated buffer list } // // If this is the first seen decode buffer do we wish to offer it up as an initial frame // if( FirstFrame ) { FirstFrame = false; SubmitInitialFrame = PolicyValue( Stream->Playback, Stream, PolicyManifestFirstFrameEarly ); if( SubmitInitialFrame == PolicyValueApply ) { Status = Stream->Manifestor->InitialFrame( Buffer ); if( Status != ManifestorNoError ) report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Failed to apply InitialFrame action.\n" ); if( InitialFrameBuffer != NULL ) Stream->Codec->ReleaseDecodeBuffer( InitialFrameBuffer ); InitialFrameBuffer = Buffer; InitialFrameBuffer->IncrementReferenceCount(); } } // // Do we want to insert this in the table // Status = Buffer->ObtainMetaDataReference( MetaDataParsedFrameParametersReferenceType, (void **)(&ParsedFrameParameters) ); if( Status != PlayerNoError ) { report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Unable to obtain the meta data \"ParsedFrameParametersReference\" - Implementation error\n" ); Buffer->DecrementReferenceCount( IdentifierProcessDecodeToManifest ); continue; } #if 0 { unsigned int A, B; Stream->DecodeBufferPool->GetPoolUsage( &A, &B, NULL, NULL, NULL ); report( severity_info, "Got(%d) %3d (R = %d, K = %d) %d, %016llx - %d %d/%d\n", Stream->StreamType, ParsedFrameParameters->DecodeFrameIndex, ParsedFrameParameters->ReferenceFrame, ParsedFrameParameters->KeyFrame, ParsedFrameParameters->DisplayFrameIndex, ParsedFrameParameters->NormalizedPlaybackTime, AccumulatedBufferTableOccupancy, B, A ); } #endif if( ParsedFrameParameters->DisplayFrameIndex <= DesiredFrameIndex ) break; for( i=0; i<Stream->NumberOfDecodeBuffers; i++ ) if( AccumulatedBufferTable[i].Buffer == NULL ) { AccumulatedBufferTable[i].Buffer = Buffer; AccumulatedBufferTable[i].SequenceNumber = SequenceNumber; AccumulatedBufferTable[i].ParsedFrameParameters = ParsedFrameParameters; AccumulatedBufferTableOccupancy++; break; } if( i >= Stream->NumberOfDecodeBuffers ) { report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Unable to insert buffer in table - Implementation error.\n" ); break; // Assume it is immediate, as an implementation error this is pretty nasty } } if( Stream->Terminating ) continue; // -------------------------------------------------------------------------------------------- // We now have a buffer after frame re-ordering // // First calculate the sequence number that applies to this frame // this calculation may appear wierd, the idea is this, assume you // have a video stream IPBB, sequence numbers 0 1 2 3, frame reordering // will yield sequence numbers 0 2 3 1 IE any command to be executed at // the end of the stream will appear 1 frame early, the calculations // below will re-wossname the sequence numbers to 0 1 1 3 causing the // signal to occur at the correct point. // // // Deal with a coded frame buffer // if( BufferType == Stream->DecodeBufferType ) { // // Report any re-ordering problems // if( ParsedFrameParameters->CollapseHolesInDisplayIndices && (ParsedFrameParameters->DisplayFrameIndex > DesiredFrameIndex) ) DesiredFrameIndex = ParsedFrameParameters->DisplayFrameIndex; if( ParsedFrameParameters->DisplayFrameIndex > DesiredFrameIndex ) report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Hole in display frame indices (Got %d Expected %d).\n", ParsedFrameParameters->DisplayFrameIndex, DesiredFrameIndex ); if( ParsedFrameParameters->DisplayFrameIndex < DesiredFrameIndex ) report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Frame re-ordering failure (Got %d Expected %d) - Implementation error.\n", ParsedFrameParameters->DisplayFrameIndex, DesiredFrameIndex ); // // First calculate the sequence number that applies to this frame // this calculation may appear wierd, the idea is this, assume you // have a video stream IPBB, sequence numbers 0 1 2 3, frame reordering // will yield sequence numbers 0 2 3 1 IE any command to be executed at // the end of the stream will appear 1 frame early, the calculations // below will re-wossname the sequence numbers to 0 1 1 3 causing the // signal to occur at the correct point. // MaximumActualSequenceNumberSeen = max(SequenceNumber, MaximumActualSequenceNumberSeen); SequenceNumber = min(MaximumActualSequenceNumberSeen, MinumumSequenceNumberAccumulated ); Time = ParsedFrameParameters->NativePlaybackTime; // // Process any outstanding control messages to be applied before this buffer // ProcessAccumulatedControlMessages( Stream, &AccumulatedBeforeControlMessagesCount, PLAYER_MAX_DTOM_MESSAGES, Stream->AccumulatedBeforeDtoMControlMessages, SequenceNumber, Time ); // // If we are paused, then we loop waiting for something to happen // if( Stream->Playback->Speed == 0 ) { while( (Stream->Playback->Speed == 0) && !Stream->Step && !Stream->Terminating && !Stream->DiscardingUntilMarkerFrameDtoM ) { OS_WaitForEvent( &Stream->SingleStepMayHaveHappened, PLAYER_NEXT_FRAME_EVENT_WAIT ); OS_ResetEvent( &Stream->SingleStepMayHaveHappened ); } Stream->Step = false; } // // If we are not discarding everything, then procede to process the buffer // DiscardBuffer = Stream->DiscardingUntilMarkerFrameDtoM; // // Handle output timing functions, await entry into the decode window, // Then check for frame drop (whether due to trick mode, or because // we are running late). // NOTE1 Indicating we are not before decode, means // reference frames can be dropped, we will simply not display them // NOTE2 We may block in these functions, so it is important to // recheck flags // if( !DiscardBuffer ) { Status = Stream->OutputTimer->TestForFrameDrop( Buffer, OutputTimerBeforeOutputTiming ); if( Status == OutputTimerNoError ) { // // Note we loop here if we are engaged in re-timing the decoded frames // while( !Stream->Terminating && Stream->ReTimeQueuedFrames ) OS_SleepMilliSeconds( PLAYER_RETIMING_WAIT ); Stream->OutputTimer->GenerateFrameTiming( Buffer ); Status = Stream->OutputTimer->TestForFrameDrop( Buffer, OutputTimerBeforeManifestation ); } if( Stream->DiscardingUntilMarkerFrameDtoM || Stream->Terminating || (Status != OutputTimerNoError) ) DiscardBuffer = true; if( (DiscardBuffer != LastPreManifestDiscardBuffer) && (Status == OutputTimerUntimedFrame) ) { report( severity_error, "Discarding untimed frames.\n" ); } LastPreManifestDiscardBuffer = DiscardBuffer; #if 0 // Nick debug data if( Status != OutputTimerNoError ) report( severity_info, "Timer Discard(%d) %3d (before Manifest) %08x\n", Stream->StreamType, ParsedFrameParameters->DecodeFrameIndex, Status ); #endif } // // Pass the buffer to the manifestor for manifestation // we do not release our hold on this buffer, buffers passed // to the manifestor always re-appear on its output ring. // NOTE calculate next desired frame index before we // give away the buffer, because ParsedFrameParameters // can become invalid after either of the calls below. // DesiredFrameIndex = ParsedFrameParameters->DisplayFrameIndex + 1; if( !DiscardBuffer ) { SequenceNumberStructure->TimePassToManifestor = OS_GetTimeInMicroSeconds(); #if 0 { static unsigned long long LastOutputTime = 0; static unsigned long long LastOutputTime1 = 0; VideoOutputTiming_t *OutputTiming; unsigned int C0,C1,C2,C3; Buffer->ObtainMetaDataReference( MetaDataVideoOutputTimingType, (void **)&OutputTiming ); Stream->CodedFrameBufferPool->GetPoolUsage( &C0, &C1, NULL, NULL, NULL ); Stream->DecodeBufferPool->GetPoolUsage( &C2, &C3, NULL, NULL, NULL ); report( severity_info, "Ord %3d (R = %d, K = %d) %d, %6lld %6lld %6lld %6lld (%d/%d %d/%d) (%d %d) %6lld %6lld\n", ParsedFrameParameters->DecodeFrameIndex, ParsedFrameParameters->ReferenceFrame, ParsedFrameParameters->KeyFrame, ParsedFrameParameters->DisplayFrameIndex, OutputTiming->SystemPlaybackTime - SequenceNumberStructure->TimePassToManifestor, SequenceNumberStructure->TimePassToManifestor - SequenceNumberStructure->TimeEntryInProcess2, SequenceNumberStructure->TimePassToManifestor - SequenceNumberStructure->TimeEntryInProcess1, SequenceNumberStructure->TimePassToManifestor - SequenceNumberStructure->TimeEntryInProcess0, C0, C1, C2, C3, Stream->FramesToManifestorCount, Stream->FramesFromManifestorCount, OutputTiming->SystemPlaybackTime - LastOutputTime, ParsedFrameParameters->NormalizedPlaybackTime - LastOutputTime1 ); //Buffer->TransferOwnership( IdentifierProcessDecodeToManifest, IdentifierManifestor ); //if( (OutputTiming->SystemPlaybackTime - SequenceNumberStructure->TimePassToManifestor) > 0xffffffffULL ) // Stream->DecodeBufferPool->Dump( DumpAll ); LastOutputTime = OutputTiming->SystemPlaybackTime; LastOutputTime1 = ParsedFrameParameters->NormalizedPlaybackTime; } if( Stream->FramesToManifestorCount >= 55 ) { OS_SleepMilliSeconds( 1000 ); report( severity_info, "Ord(%d) %3d (R = %d, K = %d) %d, %016llx %016llx\n", Stream->StreamType, ParsedFrameParameters->DecodeFrameIndex, ParsedFrameParameters->ReferenceFrame, ParsedFrameParameters->KeyFrame, ParsedFrameParameters->DisplayFrameIndex, ParsedFrameParameters->NormalizedPlaybackTime, ParsedFrameParameters->NativePlaybackTime ); OS_SleepMilliSeconds( 4000 ); } #endif Stream->FramesToManifestorCount++; Status = Stream->Manifestor->QueueDecodeBuffer( Buffer ); if( Status != ManifestorNoError ) DiscardBuffer = true; if( InitialFrameBuffer != NULL ) { Stream->Codec->ReleaseDecodeBuffer( InitialFrameBuffer ); InitialFrameBuffer = NULL; } } if( DiscardBuffer ) { Stream->Codec->ReleaseDecodeBuffer( Buffer ); if( Stream->Playback->Speed == 0 ) Stream->Step = true; } // // Process any outstanding control messages to be applied after this buffer // ProcessAccumulatedControlMessages( Stream, &AccumulatedAfterControlMessagesCount, PLAYER_MAX_DTOM_MESSAGES, Stream->AccumulatedAfterDtoMControlMessages, SequenceNumber, Time ); } // // Deal with a player control structure // else if( BufferType == BufferPlayerControlStructureType ) { Buffer->ObtainDataReference( NULL, NULL, (void **)(&ControlStructure) ); ProcessNow = (ControlStructure->SequenceType == SequenceTypeImmediate); if( !ProcessNow ) { SequenceCheck = (ControlStructure->SequenceType == SequenceTypeBeforeSequenceNumber) || (ControlStructure->SequenceType == SequenceTypeAfterSequenceNumber); ProcessNow = SequenceCheck ? ((SequenceNumber != INVALID_SEQUENCE_VALUE) && (ControlStructure->SequenceValue <= MaximumActualSequenceNumberSeen)) : ((Time != INVALID_SEQUENCE_VALUE) && (ControlStructure->SequenceValue <= Time)); } if( ProcessNow ) ProcessControlMessage( Stream, Buffer, ControlStructure ); else { if( (ControlStructure->SequenceType == SequenceTypeBeforeSequenceNumber) || (ControlStructure->SequenceType == SequenceTypeBeforePlaybackTime) ) { Count = &AccumulatedBeforeControlMessagesCount; Table = Stream->AccumulatedBeforeDtoMControlMessages; } else { Count = &AccumulatedAfterControlMessagesCount; Table = Stream->AccumulatedAfterDtoMControlMessages; } AccumulateControlMessage( Buffer, ControlStructure, Count, PLAYER_MAX_DTOM_MESSAGES, Table ); } } else { report( severity_error, "Player_Generic_c::ProcessDecodeToManifest - Unknown buffer type received - Implementation error.\n" ); Buffer->DecrementReferenceCount(); } }