XnStatus PlayerNode::UndoRecord(PlayerNode::RecordUndoInfo& undoInfo, XnUInt32 nDestPos, XnBool& bUndone) { XnStatus nRetVal = XN_STATUS_OK; XnUInt32 nOriginalPos = TellStream(); bUndone = FALSE; Record record(m_pRecordBuffer, RECORD_MAX_SIZE); while ((undoInfo.nRecordPos > nDestPos) && (undoInfo.nUndoRecordPos != 0)) { nRetVal = SeekStream(XN_OS_SEEK_SET, undoInfo.nUndoRecordPos); XN_IS_STATUS_OK(nRetVal); nRetVal = ReadRecordHeader(record); XN_IS_STATUS_OK(nRetVal); undoInfo.nRecordPos = undoInfo.nUndoRecordPos; undoInfo.nUndoRecordPos = record.GetUndoRecordPos(); } if (undoInfo.nRecordPos <= nDestPos) { /*We found a record that can undo the record originally pointed to by undoInfo.nDestRecordPos, so now we handle it. */ nRetVal = ReadRecordFields(record); XN_IS_STATUS_OK(nRetVal); nRetVal = HandleRecord(record, FALSE); XN_IS_STATUS_OK(nRetVal); bUndone = TRUE; } else { nRetVal = SeekStream(XN_OS_SEEK_SET, nOriginalPos); XN_IS_STATUS_OK(nRetVal); } return XN_STATUS_OK; }
XnStatus PlayerNode::HandleStringPropRecord(StringPropRecord record) { XN_VALIDATE_INPUT_PTR(m_pNodeNotifications); XnStatus nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); DEBUG_LOG_RECORD(record, "StringProp"); PlayerNodeInfo* pPlayerNodeInfo = GetPlayerNodeInfo(record.GetNodeID()); XN_VALIDATE_PTR(pPlayerNodeInfo, XN_STATUS_CORRUPT_FILE); if (!pPlayerNodeInfo->bValid) { XN_ASSERT(FALSE); return XN_STATUS_CORRUPT_FILE; } nRetVal = m_pNodeNotifications->OnNodeStringPropChanged(m_pNotificationsCookie, pPlayerNodeInfo->strName, record.GetPropName(), record.GetValue()); XN_IS_STATUS_OK(nRetVal); nRetVal = SaveRecordUndoInfo(pPlayerNodeInfo, record.GetPropName(), TellStream() - record.GetSize(), record.GetUndoRecordPos()); XN_IS_STATUS_OK(nRetVal); return XN_STATUS_OK; }
XnStatus PlayerNode::SeekToRecordByType(XnUInt32 nNodeID, RecordType type) { XnStatus nRetVal = XN_STATUS_OK; Record record(m_pRecordBuffer, RECORD_MAX_SIZE); XnUInt32 nStartPos = TellStream(); XnBool bFound = FALSE; XnUInt32 nPosBeforeRecord = 0; while (!bFound && nRetVal == XN_STATUS_OK) { nPosBeforeRecord = TellStream(); nRetVal = ReadRecord(record); XN_IS_STATUS_OK(nRetVal); if ((record.GetType() == type) && (record.GetNodeID() == nNodeID)) { bFound = TRUE; } else if (record.GetType() == RECORD_END) { nRetVal = XN_STATUS_NO_MATCH; } else { // if record has payload, skip it nRetVal = SkipRecordPayload(record); } } if (bFound) { // seek to before requested record nRetVal = SeekStream(XN_OS_SEEK_SET, nPosBeforeRecord); XN_IS_STATUS_OK(nRetVal); } else { // seek back to starting position SeekStream(XN_OS_SEEK_SET, nStartPos); return (nRetVal); } return (XN_STATUS_OK); }
XnStatus PlayerNode::HandleNodeAddedRecord(NodeAddedRecord record) { XnStatus nRetVal = XN_STATUS_OK; nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); DEBUG_LOG_RECORD(record, "NodeAdded"); nRetVal = HandleNodeAddedImpl( record.GetNodeID(), record.GetNodeType(), record.GetNodeName(), record.GetCompression(), record.GetNumberOfFrames(), record.GetMinTimestamp(), record.GetMaxTimestamp()); XN_IS_STATUS_OK(nRetVal); // get seek table (if exists) if (record.GetNumberOfFrames() > 0 && record.GetSeekTablePosition() != 0) { XnUInt32 nCurrPos = TellStream(); nRetVal = SeekStream(XN_OS_SEEK_SET, record.GetSeekTablePosition()); XN_IS_STATUS_OK(nRetVal); DataIndexRecordHeader seekTableHeader(m_pRecordBuffer, RECORD_MAX_SIZE); nRetVal = ReadRecord(seekTableHeader); XN_IS_STATUS_OK(nRetVal); nRetVal = HandleDataIndexRecord(seekTableHeader, TRUE); XN_IS_STATUS_OK(nRetVal); // and seek back nRetVal = SeekStream(XN_OS_SEEK_SET, nCurrPos); XN_IS_STATUS_OK(nRetVal); } return (XN_STATUS_OK); }
XnStatus PlayerNode::HandleGeneralPropRecord(GeneralPropRecord record) { XN_VALIDATE_INPUT_PTR(m_pNodeNotifications); XnStatus nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); DEBUG_LOG_RECORD(record, "GeneralProp"); PlayerNodeInfo* pPlayerNodeInfo = GetPlayerNodeInfo(record.GetNodeID()); XN_VALIDATE_PTR(pPlayerNodeInfo, XN_STATUS_CORRUPT_FILE); if (!pPlayerNodeInfo->bValid) { XN_ASSERT(FALSE); return XN_STATUS_CORRUPT_FILE; } // Fix backwards compatibility issues if (strcmp(record.GetPropName(), XN_PROP_REAL_WORLD_TRANSLATION_DATA) == 0) { // old recordings held the RealWorldTranslationData, but API has changed. Translate // it to Field Of View if (record.GetPropDataSize() != sizeof(XnRealWorldTranslationData)) { return XN_STATUS_CORRUPT_FILE; } const XnRealWorldTranslationData* pTransData = (const XnRealWorldTranslationData*)record.GetPropData(); // we also need resolution for the translation xn::DepthGenerator depthGen; nRetVal = m_context.GetProductionNodeByName(pPlayerNodeInfo->strName, depthGen); XN_IS_STATUS_OK(nRetVal); XnMapOutputMode outputMode; nRetVal = depthGen.GetMapOutputMode(outputMode); XN_IS_STATUS_OK(nRetVal); XnFieldOfView FOV; FOV.fHFOV = 2*atan(pTransData->dPixelSizeAtZeroPlane * pTransData->dSourceToDepthPixelRatio * outputMode.nXRes / 2 / pTransData->dZeroPlaneDistance); FOV.fVFOV = 2*atan(pTransData->dPixelSizeAtZeroPlane * pTransData->dSourceToDepthPixelRatio * outputMode.nYRes / 2 / pTransData->dZeroPlaneDistance); nRetVal = m_pNodeNotifications->OnNodeGeneralPropChanged(m_pNotificationsCookie, pPlayerNodeInfo->strName, XN_PROP_FIELD_OF_VIEW, sizeof(FOV), &FOV); XN_IS_STATUS_OK(nRetVal); } else { nRetVal = m_pNodeNotifications->OnNodeGeneralPropChanged(m_pNotificationsCookie, pPlayerNodeInfo->strName, record.GetPropName(), record.GetPropDataSize(), record.GetPropData()); XN_IS_STATUS_OK(nRetVal); } nRetVal = SaveRecordUndoInfo(pPlayerNodeInfo, record.GetPropName(), TellStream() - record.GetSize(), record.GetUndoRecordPos()); XN_IS_STATUS_OK(nRetVal); return XN_STATUS_OK; }
XnStatus PlayerNode::HandleNodeAdded_1_0_0_4_Record(NodeAdded_1_0_0_4_Record record) { XnStatus nRetVal = XN_STATUS_OK; nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); DEBUG_LOG_RECORD(record, "NodeAdded1_0_0_4"); /** BC issue **/ // NOTE: ONI files up to version 1.0.0.4 didn't had a different NodeAdded record. It did // not contain seek data (number of frames and min/max timestamp). Instead, this data was // in the DataBegin record. So we need to also find this record, and read these props from it. XnUInt32 nNodeID = record.GetNodeID(); XnChar strName[XN_MAX_NAME_LENGTH]; nRetVal = xnOSStrCopy(strName, record.GetNodeName(), XN_MAX_NAME_LENGTH); XN_IS_STATUS_OK(nRetVal); XnProductionNodeType type = record.GetNodeType(); XnCodecID compression = record.GetCompression(); XnUInt32 nNumFrames = 0; XnUInt64 nMinTimestamp = 0; XnUInt64 nMaxTimestamp = 0; if (xnIsTypeGenerator(type)) { // we need to look for the DataBegin record to have number of frames, etc. XnUInt32 nStartPos = TellStream(); // NOTE: this overwrites the current NodeAdded record buffer!!! nRetVal = SeekToRecordByType(nNodeID, RECORD_NODE_DATA_BEGIN); if (nRetVal == XN_STATUS_OK) { NodeDataBeginRecord dataBeginRecord(m_pRecordBuffer, RECORD_MAX_SIZE); nRetVal = ReadRecord(dataBeginRecord); XN_IS_STATUS_OK(nRetVal); nRetVal = dataBeginRecord.Decode(); XN_IS_STATUS_OK(nRetVal); nNumFrames = dataBeginRecord.GetNumFrames(); nMaxTimestamp = dataBeginRecord.GetMaxTimeStamp(); // also find data record for min timestamp nRetVal = SeekToRecordByType(record.GetNodeID(), RECORD_NEW_DATA); if (nRetVal == XN_STATUS_OK) { NewDataRecordHeader newDataRecord(m_pRecordBuffer, RECORD_MAX_SIZE); nRetVal = ReadRecord(newDataRecord); XN_IS_STATUS_OK(nRetVal); nRetVal = newDataRecord.Decode(); XN_IS_STATUS_OK(nRetVal); nMinTimestamp = newDataRecord.GetTimeStamp(); } // get back to start position nRetVal = SeekStream(XN_OS_SEEK_SET, nStartPos); XN_IS_STATUS_OK(nRetVal); } } nRetVal = HandleNodeAddedImpl(nNodeID, type, strName, compression, nNumFrames, nMinTimestamp, nMaxTimestamp); XN_IS_STATUS_OK(nRetVal); return XN_STATUS_OK; }
XnStatus PlayerNode::SeekToFrameAbsolute(XnUInt32 nNodeID, XnUInt32 nDestFrame) { XN_ASSERT((nNodeID != INVALID_NODE_ID) && (nNodeID < m_nMaxNodes)); PlayerNodeInfo* pPlayerNodeInfo = &m_pNodeInfoMap[nNodeID]; XN_ASSERT((nDestFrame > 0) && (nDestFrame <= pPlayerNodeInfo->nFrames)); XN_VALIDATE_INPUT_PTR(m_pNodeNotifications); XnUInt32 nStartPos = TellStream(); XnUInt32 nNextFrame = pPlayerNodeInfo->nCurFrame + 1; XnUInt32 nFrames = pPlayerNodeInfo->nFrames; XnStatus nRetVal = XN_STATUS_OK; if (nDestFrame == pPlayerNodeInfo->nCurFrame) { //Just go back to position of current frame nRetVal = SeekStream(XN_OS_SEEK_SET, pPlayerNodeInfo->nLastDataPos); XN_IS_STATUS_OK(nRetVal); } else if (nDestFrame < nNextFrame) { //Seek backwards XnUInt32 nDestRecordPos = pPlayerNodeInfo->newDataUndoInfo.nRecordPos; XnUInt32 nUndoRecordPos = pPlayerNodeInfo->newDataUndoInfo.nUndoRecordPos; NewDataRecordHeader record(m_pRecordBuffer, RECORD_MAX_SIZE); /*Scan back through the frames' undo positions until we get to a frame number that is smaller or equal to nDestFrame. We put the position of the frame we find in nDestRecordPos. */ do { if (nUndoRecordPos == 0) { /* The last frame we encountered doesn't have an undo frame. But this data frame can't be the first, so the file is corrupt */ XN_LOG_ERROR_RETURN(XN_STATUS_CORRUPT_FILE, XN_MASK_OPEN_NI, "Undo frame not found for frame in position %u", nDestRecordPos); } nRetVal = SeekStream(XN_OS_SEEK_SET, nUndoRecordPos); XN_IS_STATUS_OK(nRetVal); nDestRecordPos = nUndoRecordPos; record.ResetRead(); nRetVal = ReadRecordHeader(record); XN_IS_STATUS_OK(nRetVal); if (record.GetType() != RECORD_NEW_DATA) { XN_ASSERT(FALSE); XN_LOG_ERROR_RETURN(XN_STATUS_CORRUPT_FILE, XN_MASK_OPEN_NI, "Unexpected record type: %u", record.GetType()); } if (record.GetNodeID() != nNodeID) { XN_ASSERT(FALSE); XN_LOG_ERROR_RETURN(XN_STATUS_CORRUPT_FILE, XN_MASK_OPEN_NI, "Unexpected node id: %u", record.GetNodeID()); } nRetVal = ReadRecordFields(record); XN_IS_STATUS_OK(nRetVal); nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); nUndoRecordPos = record.GetUndoRecordPos(); } while (record.GetFrameNumber() > nDestFrame); //Now handle the frame nRetVal = HandleNewDataRecord(record, FALSE); XnBool bUndone = FALSE; for (XnUInt32 i = 0; i < m_nMaxNodes; i++) { //Rollback all properties to match the state the stream was in at position nDestRecordPos PlayerNodeInfo &pni = m_pNodeInfoMap[i]; for (RecordUndoInfoMap::Iterator it = pni.recordUndoInfoMap.begin(); it != pni.recordUndoInfoMap.end(); it++) { if ((it.Value().nRecordPos > nDestRecordPos) && (it.Value().nRecordPos < nStartPos)) { //This property was set between nDestRecordPos and our start position, so we need to undo it. nRetVal = UndoRecord(it.Value(), nDestRecordPos, bUndone); XN_IS_STATUS_OK(nRetVal); } } if ((i != nNodeID) && pni.bIsGenerator) { //Undo all other generator nodes' data RecordUndoInfo &undoInfo = pni.newDataUndoInfo; if ((undoInfo.nRecordPos > nDestRecordPos) && (undoInfo.nRecordPos < nStartPos)) { nRetVal = UndoRecord(undoInfo, nDestRecordPos, bUndone); XN_IS_STATUS_OK(nRetVal); if (!bUndone) { //We couldn't find a record that can undo this data record pni.nLastDataPos = 0; pni.newDataUndoInfo.Reset(); } } } } /*Now, for each node, go to the position of the last encountered data record, and process that record (including its payload).*/ /*TODO: Optimization: remember each node's last data pos, and later, see if it changes. Only process data frames of nodes whose last data pos actually changed.*/ nRetVal = ProcessEachNodeLastData(nNodeID); XN_IS_STATUS_OK(nRetVal); } else //(nDestFrame >= nNextFrame) { //Skip all frames until we get to our frame number, but handle any properties we run into. while (pPlayerNodeInfo->nCurFrame < nDestFrame) { nRetVal = ProcessRecord(FALSE); XN_IS_STATUS_OK(nRetVal); } /*Now, for each node, go to the position of the last encountered data record, and process that record (including its payload).*/ /*TODO: Optimization: remember each node's last data pos, and later, see if it changes. Only process data frames of nodes whose last data pos actually changed.*/ nRetVal = ProcessEachNodeLastData(nNodeID); XN_IS_STATUS_OK(nRetVal); } return XN_STATUS_OK; }
XnStatus PlayerNode::SeekToTimeStampAbsolute(XnUInt64 nDestTimeStamp) { XnStatus nRetVal = XN_STATUS_OK; XnUInt64 nRecordTimeStamp = 0LL; XnUInt32 nStartPos = TellStream(); //We'll revert to this in case nDestTimeStamp is beyond end of stream XN_IS_STATUS_OK(nRetVal); if (nDestTimeStamp < m_nTimeStamp) { nRetVal = Rewind(); } else if (nDestTimeStamp == m_nTimeStamp) { //Nothing to do return XN_STATUS_OK; } else if (nDestTimeStamp > m_nGlobalMaxTimeStamp) { nDestTimeStamp = m_nGlobalMaxTimeStamp; } Record record(m_pRecordBuffer, RECORD_MAX_SIZE); XnBool bEnd = FALSE; XnUInt32 nBytesRead = 0; while ((nRecordTimeStamp < nDestTimeStamp) && !bEnd) { nRetVal = ReadRecordHeader(record); XN_IS_STATUS_OK(nRetVal); switch (record.GetType()) { case RECORD_NEW_DATA: { //We already read Record::HEADER_SIZE, now read the rest of the new data record header nRetVal = Read(m_pRecordBuffer + Record::HEADER_SIZE, NewDataRecordHeader::MAX_SIZE - Record::HEADER_SIZE, nBytesRead); XN_IS_STATUS_OK(nRetVal); if (nBytesRead < NewDataRecordHeader::MAX_SIZE - Record::HEADER_SIZE) { return XN_STATUS_CORRUPT_FILE; } NewDataRecordHeader newDataRecordHeader(record); nRetVal = newDataRecordHeader.Decode(); XN_IS_STATUS_OK(nRetVal); //Save record time stamp nRecordTimeStamp = newDataRecordHeader.GetTimeStamp(); if (nRecordTimeStamp >= nDestTimeStamp) { //We're done - move back to beginning of record nRetVal = SeekStream(XN_OS_SEEK_CUR, -XnInt32(nBytesRead)); XN_IS_STATUS_OK(nRetVal); } else { //Skip to next record nRetVal = SeekStream(XN_OS_SEEK_CUR, newDataRecordHeader.GetSize() - NewDataRecordHeader::MAX_SIZE); XN_IS_STATUS_OK(nRetVal); } break; } case RECORD_END: { bEnd = TRUE; break; } case RECORD_NODE_ADDED_1_0_0_4: case RECORD_NODE_ADDED: case RECORD_INT_PROPERTY: case RECORD_REAL_PROPERTY: case RECORD_STRING_PROPERTY: case RECORD_GENERAL_PROPERTY: case RECORD_NODE_REMOVED: case RECORD_NODE_DATA_BEGIN: case RECORD_NODE_STATE_READY: { //Read rest of record and handle it normally nRetVal = Read(m_pRecordBuffer + Record::HEADER_SIZE, record.GetSize() - Record::HEADER_SIZE, nBytesRead); XN_IS_STATUS_OK(nRetVal); Record record(m_pRecordBuffer, RECORD_MAX_SIZE); nRetVal = HandleRecord(record, TRUE); XN_IS_STATUS_OK(nRetVal); break; } default: { XN_ASSERT(FALSE); return XN_STATUS_CORRUPT_FILE; } } //switch } //while if (bEnd) { SeekStream(XN_OS_SEEK_SET, nStartPos); return XN_STATUS_ILLEGAL_POSITION; } return XN_STATUS_OK; }//function
XnStatus PlayerNode::HandleNewDataRecord(NewDataRecordHeader record, XnBool bReadPayload) { XN_VALIDATE_INPUT_PTR(m_pNodeNotifications); XnStatus nRetVal = record.Decode(); XN_IS_STATUS_OK(nRetVal); DEBUG_LOG_RECORD(record, "NewData"); XN_ASSERT(record.GetNodeID() != INVALID_NODE_ID); PlayerNodeInfo* pPlayerNodeInfo = GetPlayerNodeInfo(record.GetNodeID()); XN_VALIDATE_PTR(pPlayerNodeInfo, XN_STATUS_CORRUPT_FILE); if (!pPlayerNodeInfo->bValid) { XN_ASSERT(FALSE); return XN_STATUS_CORRUPT_FILE; } XnUInt32 nRecordTotalSize = record.GetSize() + record.GetPayloadSize(); if (nRecordTotalSize > RECORD_MAX_SIZE) { XN_ASSERT(FALSE); XN_LOG_ERROR_RETURN(XN_STATUS_INTERNAL_BUFFER_TOO_SMALL, XN_MASK_OPEN_NI, "Record size %u is larger than player internal buffer", nRecordTotalSize); } pPlayerNodeInfo->nLastDataPos = TellStream() - record.GetSize(); pPlayerNodeInfo->newDataUndoInfo.nRecordPos = pPlayerNodeInfo->nLastDataPos; pPlayerNodeInfo->newDataUndoInfo.nUndoRecordPos = record.GetUndoRecordPos(); if (record.GetFrameNumber() > pPlayerNodeInfo->nFrames) { XN_ASSERT(FALSE); return XN_STATUS_CORRUPT_FILE; } pPlayerNodeInfo->nCurFrame = record.GetFrameNumber(); if (record.GetTimeStamp() > m_nGlobalMaxTimeStamp) { XN_ASSERT(FALSE); XN_LOG_ERROR_RETURN(XN_STATUS_CORRUPT_FILE, XN_MASK_OPEN_NI, "Record timestamp for record in position %u is larger than reported max timestamp", pPlayerNodeInfo->nLastDataPos); } m_nTimeStamp = record.GetTimeStamp(); if (bReadPayload) { //Now read the actual data XnUInt32 nBytesRead = 0; nRetVal = Read(record.GetPayload(), record.GetPayloadSize(), nBytesRead); XN_IS_STATUS_OK(nRetVal); if (nBytesRead < record.GetPayloadSize()) { XN_LOG_ERROR_RETURN(XN_STATUS_CORRUPT_FILE, XN_MASK_OPEN_NI, "Not enough bytes read"); } const XnUInt8* pCompressedData = record.GetPayload(); //The new (compressed) data is right at the end of the header XnUInt32 nCompressedDataSize = record.GetPayloadSize(); const XnUInt8* pUncompressedData = NULL; XnUInt32 nUncompressedDataSize = 0; XnCodecID compression = pPlayerNodeInfo->codec.GetCodecID(); if (compression == XN_CODEC_UNCOMPRESSED) { pUncompressedData = pCompressedData; nUncompressedDataSize = nCompressedDataSize; } else { //Decode data with codec nRetVal = pPlayerNodeInfo->codec.DecodeData(pCompressedData, nCompressedDataSize, m_pUncompressedData, DATA_MAX_SIZE, &nUncompressedDataSize); XN_IS_STATUS_OK(nRetVal); pUncompressedData = m_pUncompressedData; } nRetVal = m_pNodeNotifications->OnNodeNewData(m_pNotificationsCookie, pPlayerNodeInfo->strName, record.GetTimeStamp(), record.GetFrameNumber(), pUncompressedData, nUncompressedDataSize); XN_IS_STATUS_OK(nRetVal); } else { //Just skip the data nRetVal = SkipRecordPayload(record); XN_IS_STATUS_OK(nRetVal); } return XN_STATUS_OK; }