/***************************************************************************** * * * PrimeSense Sensor 5.x Alpha * * Copyright (C) 2012 PrimeSense Ltd. * * * * This file is part of PrimeSense Sensor * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * *****************************************************************************/ //--------------------------------------------------------------------------- // Includes //--------------------------------------------------------------------------- #include "XnDeviceFileReader.h" #include #include "XnDeviceFile.h" #include #include //--------------------------------------------------------------------------- // Types //--------------------------------------------------------------------------- typedef struct XnLastStreamData { XnUInt64 nPosition; XnUInt32 nFrameID; XnUInt64 nTimestamp; } XnLastStreamData; typedef XnStringsHashT XnLastStreamDataHash; //--------------------------------------------------------------------------- // Code //--------------------------------------------------------------------------- XnDeviceFileReader::XnDeviceFileReader() : XnStreamReaderDevice(XN_DEVICE_NAME, XN_DEVICE_FILE_MAX_INTERNAL_BUFFER), m_FrameDelay(XN_MODULE_PROPERTY_FRAME_DELAY, FALSE), m_pBCData(NULL), m_nFileVersion(0), m_nReferenceTime(0), m_nReferenceTimestamp(0), m_bFileHasData(FALSE), m_bStreamsCollectionChanged(FALSE), m_InstancePointer(XN_FILE_PROPERTY_INSTANCE_POINTER) { m_FrameDelay.UpdateSetCallbackToDefault(); m_InstancePointer.UpdateGetCallback(GetInstanceCallback, this); } XnDeviceFileReader::~XnDeviceFileReader() { } XnStatus XnDeviceFileReader::InitImpl(const XnDeviceConfig* pDeviceConfig) { XnStatus nRetVal = XN_STATUS_OK; nRetVal = XnStreamReaderDevice::InitImpl(pDeviceConfig); XN_IS_STATUS_OK(nRetVal); // register to events XnCallbackHandle hDummy = NULL; nRetVal = OnStreamCollectionChangedEvent().Register(StreamCollectionChangedCallback, this, hDummy); XN_IS_STATUS_OK(nRetVal); // TODO: remove this ReadWriteModeProperty().UnsafeUpdateValue(XN_DEVICE_MODE_READ); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::CreateDeviceModule(XnDeviceModuleHolder** ppModuleHolder) { XnStatus nRetVal = XN_STATUS_OK; nRetVal = XnStreamReaderDevice::CreateDeviceModule(ppModuleHolder); XN_IS_STATUS_OK(nRetVal); XnDeviceModule* pModule = (*ppModuleHolder)->GetModule(); // add sensor properties XnProperty* pProps[] = { &m_FrameDelay, &m_InstancePointer }; nRetVal = pModule->AddProperties(pProps, sizeof(pProps)/sizeof(XnProperty*)); if (nRetVal != XN_STATUS_OK) { DestroyModule(*ppModuleHolder); *ppModuleHolder = NULL; return (nRetVal); } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::CreateIOStreamImpl(const XnChar* strConnectionString, XnIOStream*& pStream) { XnStatus nRetVal = XN_STATUS_OK; // open file XN_VALIDATE_NEW_AND_INIT(pStream, XnIOFileStream, strConnectionString, XN_OS_FILE_READ); // read version nRetVal = ReadFileVersion(); if (nRetVal != XN_STATUS_OK) { XN_DELETE(pStream); pStream = NULL; return (nRetVal); } return (XN_STATUS_OK); } void XnDeviceFileReader::DestroyIOStreamImpl(XnIOStream* pStream) { XN_DELETE(pStream); } XnStatus XnDeviceFileReader::ReadFileVersion() { XnStatus nRetVal = XN_STATUS_OK; // read magic from file XnChar csFileMagic[XN_DEVICE_FILE_MAGIC_LEN]; nRetVal = GetIOStream()->ReadData((XnUChar*)csFileMagic, XN_DEVICE_FILE_MAGIC_LEN); XN_IS_STATUS_OK(nRetVal); if (strncmp(csFileMagic, XN_DEVICE_FILE_MAGIC_V4, XN_DEVICE_FILE_MAGIC_LEN) == 0) { m_nFileVersion = 4; } else if (strncmp(csFileMagic, XN_DEVICE_FILE_MAGIC_V3, XN_DEVICE_FILE_MAGIC_LEN) == 0) { m_nFileVersion = 3; } else if (strncmp(csFileMagic, XN_DEVICE_FILE_MAGIC_V2, XN_DEVICE_FILE_MAGIC_LEN) == 0) { m_nFileVersion = 2; } else if (strncmp(csFileMagic, XN_DEVICE_FILE_MAGIC_V1, XN_DEVICE_FILE_MAGIC_LEN) == 0) { m_nFileVersion = 1; } else { XN_LOG_ERROR_RETURN(XN_STATUS_DEVICE_FILE_CORRUPTED, XN_MASK_FILE, "Invalid file magic!"); } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::ReadInitialState(XnPropertySet *pSet) { XnStatus nRetVal = XN_STATUS_OK; if (m_nFileVersion < 4) { if (m_pBCData == NULL) { nRetVal = BCInit(); XN_IS_STATUS_OK(nRetVal); } return BCReadInitialState(pSet); } // first read first object - modules properties - using base nRetVal = XnStreamReaderDevice::ReadInitialState(pSet); XN_IS_STATUS_OK(nRetVal); // now continue reading until we get to first data XnPackedDataType nType; XnBool bStateEnd = FALSE; XnUInt64 nPositionBefore; while (!bStateEnd) { nRetVal = GetIOStream()->Tell(&nPositionBefore); XN_IS_STATUS_OK(nRetVal); nRetVal = GetDataPacker()->ReadNextObject(&nType); XN_IS_STATUS_OK(nRetVal); switch (nType) { case XN_PACKED_NEW_STREAM: { XnChar strType[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strName[XN_DEVICE_MAX_STRING_LENGTH]; XN_PROPERTY_SET_CREATE_ON_STACK(props); nRetVal = GetDataPacker()->ReadNewStream(strType, strName, &props); XN_IS_STATUS_OK(nRetVal); XnActualPropertiesHash* pStreamProps; nRetVal = XnPropertySetDataDetachModule(props.pData, strName, &pStreamProps); XN_IS_STATUS_OK(nRetVal); nRetVal = XnPropertySetDataAttachModule(pSet->pData, strName, pStreamProps); XN_IS_STATUS_OK(nRetVal); break; } case XN_PACKED_INT_PROPERTY: { XnChar strModule[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strProp[XN_DEVICE_MAX_STRING_LENGTH]; XnUInt64 nValue; nRetVal = GetDataPacker()->ReadProperty(strModule, strProp, &nValue); XN_IS_STATUS_OK(nRetVal); XnActualPropertiesHash* pModule = NULL; nRetVal = pSet->pData->Get(strModule, pModule); XN_IS_STATUS_OK(nRetVal); XnProperty* pProp = NULL; nRetVal = pModule->Get(strProp, pProp); XN_IS_STATUS_OK(nRetVal); XnActualIntProperty* pIntProp = (XnActualIntProperty*)pProp; nRetVal = pIntProp->UnsafeUpdateValue(nValue); XN_IS_STATUS_OK(nRetVal); break; } case XN_PACKED_REAL_PROPERTY: { XnChar strModule[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strProp[XN_DEVICE_MAX_STRING_LENGTH]; XnDouble dValue; nRetVal = GetDataPacker()->ReadProperty(strModule, strProp, &dValue); XN_IS_STATUS_OK(nRetVal); XnActualPropertiesHash* pModule; nRetVal = pSet->pData->Get(strModule, pModule); XN_IS_STATUS_OK(nRetVal); XnProperty* pProp; nRetVal = pModule->Get(strProp, pProp); XN_IS_STATUS_OK(nRetVal); XnActualRealProperty* pRealProp = (XnActualRealProperty*)pProp; nRetVal = pRealProp->UnsafeUpdateValue(dValue); XN_IS_STATUS_OK(nRetVal); break; } case XN_PACKED_STRING_PROPERTY: { XnChar strModule[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strProp[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strValue[XN_DEVICE_MAX_STRING_LENGTH]; nRetVal = GetDataPacker()->ReadProperty(strModule, strProp, strValue); XN_IS_STATUS_OK(nRetVal); XnActualPropertiesHash* pModule; nRetVal = pSet->pData->Get(strModule, pModule); XN_IS_STATUS_OK(nRetVal); XnProperty* pProp; nRetVal = pModule->Get(strProp, pProp); XN_IS_STATUS_OK(nRetVal); XnActualStringProperty* pStringProp = (XnActualStringProperty*)pProp; nRetVal = pStringProp->UnsafeUpdateValue(strValue); XN_IS_STATUS_OK(nRetVal); break; } case XN_PACKED_GENERAL_PROPERTY: { XnChar strModule[XN_DEVICE_MAX_STRING_LENGTH]; XnChar strProp[XN_DEVICE_MAX_STRING_LENGTH]; XnGeneralBuffer gbValue; nRetVal = GetDataPacker()->ReadProperty(strModule, strProp, &gbValue); XN_IS_STATUS_OK(nRetVal); XnActualPropertiesHash* pModule; nRetVal = pSet->pData->Get(strModule, pModule); XN_IS_STATUS_OK(nRetVal); XnProperty* pProp; nRetVal = pModule->Get(strProp, pProp); XN_IS_STATUS_OK(nRetVal); XnActualGeneralProperty* pIntProp = (XnActualGeneralProperty*)pProp; nRetVal = pIntProp->UnsafeUpdateValue(gbValue); XN_IS_STATUS_OK(nRetVal); break; } default: // reached end of initial state. go back to beginning of this object nRetVal = GetIOStream()->Seek(nPositionBefore); XN_IS_STATUS_OK(nRetVal); // stop reading bStateEnd = TRUE; } } // objects loop return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::HandleStreamRemoved(const XnChar* strName) { XnStatus nRetVal = XN_STATUS_OK; // check for specific case: all streams are removed and then end-of-file is reached. // in this case, we don't really want to destroy streams, just wrap around. XnStringsSet StreamsToRemove; nRetVal = StreamsToRemove.Set(strName); XN_IS_STATUS_OK(nRetVal); XnPackedDataType nType = XN_PACKED_STREAM_REMOVED; XnUInt64 nPositionBefore; for (;;) { nRetVal = GetIOStream()->Tell(&nPositionBefore); XN_IS_STATUS_OK(nRetVal); nRetVal = GetDataPacker()->ReadNextObject(&nType); XN_IS_STATUS_OK(nRetVal); if (nType == XN_PACKED_STREAM_REMOVED) { XnChar strTempName[XN_DEVICE_MAX_STRING_LENGTH]; nRetVal = GetDataPacker()->ReadStreamRemoved(strTempName); XN_IS_STATUS_OK(nRetVal); nRetVal = StreamsToRemove.Set(strTempName); XN_IS_STATUS_OK(nRetVal); } else { break; } } if (nType != XN_PACKED_END) { // Not the case we were looking for. Remove those streams. for (XnStringsSet::Iterator it = StreamsToRemove.Begin(); it != StreamsToRemove.End(); ++it) { nRetVal = XnStreamReaderDevice::HandleStreamRemoved(it->Key()); XN_IS_STATUS_OK(nRetVal); } } // in any case, the last object we read wasn't handled yet (end-of-stream or another event), so // seek back, so it will be handled. nRetVal = GetIOStream()->Seek(nPositionBefore); XN_IS_STATUS_OK(nRetVal); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::HandleIntProperty(const XnChar* strModule, const XnChar* strName, XnUInt64 nValue) { XnStatus nRetVal = XN_STATUS_OK; // ignore some properties if ((strcmp(strModule, XN_MODULE_NAME_DEVICE) == 0 && strcmp(strName, XN_MODULE_PROPERTY_READ_WRITE_MODE) == 0) || (strcmp(strModule, XN_MODULE_NAME_DEVICE) == 0 && strcmp(strName, XN_MODULE_PROPERTY_PRIMARY_STREAM) == 0) || (strcmp(strModule, XN_MODULE_NAME_DEVICE) == 0 && strcmp(strName, XN_MODULE_PROPERTY_FRAME_DELAY) == 0) || (strcmp(strModule, XN_MODULE_NAME_DEVICE) == 0 && strcmp(strName, XN_MODULE_PROPERTY_DEVICE_NAME) == 0)) { return (XN_STATUS_OK); } else { nRetVal = XnStreamReaderDevice::HandleIntProperty(strModule, strName, nValue); XN_IS_STATUS_OK(nRetVal); } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::HandleStreamData(XnStreamData* pDataProps, XnCompressionFormats nCompression, XnUInt32 nCompressedSize) { XnStatus nRetVal = XN_STATUS_OK; XnUInt64 nPosition; nRetVal = GetIOStream()->Tell(&nPosition); XN_IS_STATUS_OK(nRetVal); XnUIntHash::Iterator it = m_PositionsToIgnore.End(); if (XN_STATUS_OK == m_PositionsToIgnore.Find(nPosition, it)) { // ignore this one. Just update the frame ID XnStreamDeviceStreamHolder* pHolder; nRetVal = FindStream(pDataProps->StreamName, &pHolder); XN_IS_STATUS_OK(nRetVal); XnStreamReaderStream* pStream = (XnStreamReaderStream*)pHolder->GetStream(); pStream->NewDataAvailable(pDataProps->nTimestamp, pDataProps->nFrameID); // and remove it from list nRetVal = m_PositionsToIgnore.Remove(it); XN_IS_STATUS_OK(nRetVal); } else { // normal case. handle it nRetVal = XnStreamReaderDevice::HandleStreamData(pDataProps, nCompression, nCompressedSize); XN_IS_STATUS_OK(nRetVal); } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::Rewind() { XnStatus nRetVal = XN_STATUS_OK; // go back to start of stream nRetVal = GetIOStream()->Seek(XN_DEVICE_FILE_MAGIC_LEN); XN_IS_STATUS_OK(nRetVal); // read initial state XN_PROPERTY_SET_CREATE_ON_STACK(state); nRetVal = ReadInitialState(&state); XN_IS_STATUS_OK(nRetVal); // first handle current streams. remove or reset them XnDeviceModuleHolderList streams; nRetVal = GetStreamsList(streams); XN_IS_STATUS_OK(nRetVal); for (XnDeviceModuleHolderList::Iterator it = streams.Begin(); it != streams.End(); ++it) { XnDeviceModuleHolder* pHolder = *it; if (m_bStreamsCollectionChanged) { // we need to destroy all streams, and recreate them later nRetVal = DestroyStream(pHolder->GetModule()->GetName()); XN_IS_STATUS_OK(nRetVal); } else { // just reset frame ID XnStreamReaderStream* pStream = (XnStreamReaderStream*)pHolder->GetModule(); pStream->Reset(); } } // if we need, recreate streams if (m_bStreamsCollectionChanged) { nRetVal = CreateStreams(&state); XN_IS_STATUS_OK(nRetVal); } // now set state. for (XnPropertySetData::Iterator it = state.pData->Begin(); it != state.pData->End(); ++it) { const XnChar* strName = it->Key(); XnActualPropertiesHash* pHash = it->Value(); // fix it first if (strcmp(strName, XN_MODULE_NAME_DEVICE) == 0) { pHash->Remove(XN_MODULE_PROPERTY_READ_WRITE_MODE); pHash->Remove(XN_MODULE_PROPERTY_PRIMARY_STREAM); } XnDeviceModule* pModule; nRetVal = FindModule(strName, &pModule); XN_IS_STATUS_OK(nRetVal); nRetVal = pModule->UnsafeBatchConfig(*pHash); XN_IS_STATUS_OK(nRetVal); } ResetLastTimestampAndFrame(); m_nReferenceTimestamp = 0; m_nReferenceTime = 0; m_bStreamsCollectionChanged = FALSE; return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::HandleEndOfStream() { XnStatus nRetVal = XN_STATUS_OK; if (!m_bFileHasData) { XN_LOG_ERROR_RETURN(XN_STATUS_DEVICE_FILE_CORRUPTED, XN_MASK_FILE, "File does not contain any data..."); } nRetVal = Rewind(); XN_IS_STATUS_OK(nRetVal); return (XN_STATUS_OK); } void XnDeviceFileReader::FrameDelay(XnUInt64 nTimestamp) { if (m_FrameDelay.GetValue() != TRUE) return; if (!IsHighResTimestamps()) nTimestamp *= 1000; // first time if (m_nReferenceTime == 0) { xnOSQueryTimer(m_FrameDelayTimer, &m_nReferenceTime); m_nReferenceTimestamp = nTimestamp; return; } // delay XnUInt64 nNow; xnOSQueryTimer(m_FrameDelayTimer, &nNow); // check how much time has passed in the stream XnUInt64 nStreamDiff; if (nTimestamp < m_nReferenceTimestamp) { nStreamDiff = 0; } else { nStreamDiff = nTimestamp - m_nReferenceTimestamp; } // check how much time passed (for user) XnUInt64 nClockDiff = nNow - m_nReferenceTime; // update reference (so that frame delay will work with Pause / Resume) m_nReferenceTime = nNow; m_nReferenceTimestamp = nTimestamp; // check if we need to wait if (nClockDiff < nStreamDiff) { xnOSSleep(XnUInt32((nStreamDiff - nClockDiff) / 1000)); // take this time as a reference xnOSQueryTimer(m_FrameDelayTimer, &m_nReferenceTime); } } XnStatus XnDeviceFileReader::WaitForPrimaryStream(XN_EVENT_HANDLE /*hNewDataEvent*/, XnStreamDataSet* pSet) { XnStatus nRetVal = XN_STATUS_OK; // read until primary stream advanced while (!HasPrimaryStreamAdvanced(pSet)) { XnBool bWrap; nRetVal = ReadTillNextData(&bWrap); XN_IS_STATUS_OK(nRetVal); } FrameDelay(GetLastTimestamp()); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::WaitForStream(XN_EVENT_HANDLE /*hNewDataEvent*/, XnDeviceStream* pStream) { XnStatus nRetVal = XN_STATUS_OK; // play forward until we have new data in this stream while (!pStream->IsNewDataAvailable()) { XnBool bWrap; nRetVal = ReadTillNextData(&bWrap); XN_IS_STATUS_OK(nRetVal); } FrameDelay(pStream->GetLastTimestamp()); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::ReadTillNextData(XnBool* pbWrapOccurred) { XnStatus nRetVal = XN_STATUS_OK; *pbWrapOccurred = FALSE; if (m_nFileVersion < 4) { nRetVal = BCReadFrame(pbWrapOccurred); XN_IS_STATUS_OK(nRetVal); } else { XnPackedDataType nType = XN_PACKED_END; while (nType != XN_PACKED_STREAM_DATA) { nRetVal = ReadNextEventFromStream(&nType); XN_IS_STATUS_OK(nRetVal); if (nType == XN_PACKED_END) { *pbWrapOccurred = TRUE; } } m_bFileHasData = TRUE; } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::SeekTo(XnUInt64 nMinTimestamp, XnUInt32 nMinFrameID) { XnStatus nRetVal = XN_STATUS_OK; // first check if we need to seek forward or backwards (even if we're in the correct location, // we need to rewind, so that next read will return this frame again). if ((nMinTimestamp != 0 && nMinTimestamp <= GetLastTimestamp()) || (nMinFrameID != 0 && nMinFrameID <= GetLastFrameID())) { nRetVal = Rewind(); XN_IS_STATUS_OK(nRetVal); } XnBool bFoundNewData = FALSE; // Keep current position. XnUInt64 nStartingPosition; nRetVal = GetIOStream()->Tell(&nStartingPosition); XN_IS_STATUS_OK(nRetVal); // Take primary stream (it determines frame ID and timestamp) XnPackedDataType nType = (XnPackedDataType)-1; const XnChar* strPrimaryStream = GetPrimaryStream(); if (strcmp(strPrimaryStream, XN_PRIMARY_STREAM_ANY) == 0 || strcmp(strPrimaryStream, XN_PRIMARY_STREAM_NONE) == 0) { strPrimaryStream = NULL; } // start seeking forward until point is reached. XnUInt64 nFoundPosition; XnLastStreamDataHash StreamsHash; for (;;) { XnUInt64 nPositionBefore; nRetVal = GetIOStream()->Tell(&nPositionBefore); XN_IS_STATUS_OK(nRetVal); nRetVal = GetDataPacker()->ReadNextObject(&nType); XN_IS_STATUS_OK(nRetVal); XnUInt64 nPositionAfter; nRetVal = GetIOStream()->Tell(&nPositionAfter); XN_IS_STATUS_OK(nRetVal); if (nType == XN_PACKED_STREAM_DATA) { bFoundNewData = TRUE; XnStreamData props; XnCompressionFormats nCompression; XnUInt32 nCompressedSize; nRetVal = GetDataPacker()->ReadStreamDataProps(&props, &nCompression, &nCompressedSize); XN_IS_STATUS_OK(nRetVal); XnLastStreamData data; if (XN_STATUS_OK != StreamsHash.Get(props.StreamName, data)) { XnStreamDeviceStreamHolder* pHolder; nRetVal = FindStream(props.StreamName, &pHolder); XN_IS_STATUS_OK(nRetVal); data.nFrameID = pHolder->GetStream()->GetLastFrameID() + 1; } else { // if we had previous data from this stream, ignore it m_PositionsToIgnore.Set(data.nPosition, 0); ++data.nFrameID; } data.nPosition = nPositionAfter; data.nTimestamp = props.nTimestamp; nRetVal = StreamsHash.Set(props.StreamName, data); XN_IS_STATUS_OK(nRetVal); // now check if condition is met if (strPrimaryStream == NULL || strcmp(strPrimaryStream, props.StreamName) == 0) { if (data.nFrameID >= nMinFrameID && data.nTimestamp >= nMinTimestamp) { // we have everything we need // keep this position (we'll read up till here). nFoundPosition = nPositionAfter; break; } } } else if (nType == XN_PACKED_END) { // we'll read up to the last data of each stream nFoundPosition = nPositionBefore; break; } } // now seek back nRetVal = GetIOStream()->Seek(nStartingPosition); XN_IS_STATUS_OK(nRetVal); if (bFoundNewData) { // read everything up to position XnUInt64 nPositionAfter = nStartingPosition; while (nPositionAfter < nFoundPosition) { nRetVal = ReadNextEventFromStream(&nType); XN_IS_STATUS_OK(nRetVal); nRetVal = GetIOStream()->Tell(&nPositionAfter); XN_IS_STATUS_OK(nRetVal); } } else { // just remark the data as new (this is last frame, return it again to user) XnDeviceModuleHolderList streams; nRetVal = GetStreamsList(streams); XN_IS_STATUS_OK(nRetVal); for (XnDeviceModuleHolderList::Iterator it = streams.Begin(); it != streams.End(); ++it) { XnStreamReaderStream* pStream = (XnStreamReaderStream*)(*it)->GetModule(); pStream->ReMarkDataAsNew(); } } return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::Seek(XnUInt64 nTimestamp) { XnStatus nRetVal = XN_STATUS_OK; xnLogInfo(XN_MASK_FILE, "Seeking file to timestamp %llu...", nTimestamp); if (m_nFileVersion < 4) { return BCSeek(nTimestamp); } nRetVal = SeekTo(nTimestamp, 0); XN_IS_STATUS_OK(nRetVal); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::SeekFrame(XnUInt32 nFrameID) { XnStatus nRetVal = XN_STATUS_OK; // don't allow seeking to frame 0 nFrameID = XN_MAX(nFrameID, 1); xnLogInfo(XN_MASK_FILE, "Seeking file to frame %u...", nFrameID); if (m_nFileVersion < 4) { return BCSeekFrame(nFrameID); } nRetVal = SeekTo(0, nFrameID); XN_IS_STATUS_OK(nRetVal); return (XN_STATUS_OK); } XnStatus XnDeviceFileReader::OnStreamCollectionChanged(const XnChar* /*StreamName*/, XnStreamsChangeEventType /*EventType*/) { m_bStreamsCollectionChanged = TRUE; return XN_STATUS_OK; } void XnDeviceFileReader::StreamCollectionChangedCallback(const XnStreamCollectionChangedEventArgs& args, void* pCookie) { XnDeviceFileReader* pThis = (XnDeviceFileReader*)pCookie; pThis->OnStreamCollectionChanged(args.strStreamName, args.eventType); } XnStatus XnDeviceFileReader::ReadNextData() { XnBool bDummy; return ReadTillNextData(&bDummy); } XnStatus XN_CALLBACK_TYPE XnDeviceFileReader::GetInstanceCallback(const XnGeneralProperty* /*pSender*/, const XnGeneralBuffer& gbValue, void* pCookie) { if (gbValue.nDataSize != sizeof(void*)) { return XN_STATUS_DEVICE_PROPERTY_SIZE_DONT_MATCH; } *(void**)gbValue.pData = pCookie; return XN_STATUS_OK; }