void SensorFrameRecorderSink::Send()

in Shared/HoloLensForCV/SensorFrameRecorderSink.cpp [120:314]


	void SensorFrameRecorderSink::Send(
		SensorFrame^ sensorFrame)
	{
		dbg::TimerGuard timerGuard(
			L"SensorFrameRecorderSink::Send: synchrounous I/O",
			20.0 /* minimum_time_elapsed_in_milliseconds */);

		std::lock_guard<std::mutex> lockGuard(_sinkMutex);

		if (nullptr == _archiveSourceFolder)
		{
			return;
		}

		// Store a reference to the camera intrinsics.
		if (nullptr == _cameraIntrinsics)
		{
			_cameraIntrinsics = sensorFrame->SensorStreamingCameraIntrinsics;
		}

		// Avoid duplicate sensor frame recordings.
		if (_prevFrameTimestamp.Equals(sensorFrame->Timestamp)) {
			return;
		}

		_prevFrameTimestamp = sensorFrame->Timestamp;

		//
		// Write the sensor frame as a bitmap to the archive.
		//

#if DBG_ENABLE_VERBOSE_LOGGING
		dbg::trace(
			L"SensorFrameRecorderSink::Send: saving sensor frame to %s",
			bitmapPath);
#endif /* DBG_ENABLE_VERBOSE_LOGGING */

		Windows::Graphics::Imaging::SoftwareBitmap^ softwareBitmap =
			sensorFrame->SoftwareBitmap;

		// Determine metadata information about frame.

		int maxBitmapValue = 0;
		int actualBitmapWidth = softwareBitmap->PixelWidth;

		switch (softwareBitmap->BitmapPixelFormat)
		{

		case Windows::Graphics::Imaging::BitmapPixelFormat::Gray16:
			maxBitmapValue = 65535;
			break;

		case Windows::Graphics::Imaging::BitmapPixelFormat::Gray8:
			maxBitmapValue = 255;
			break;

		case Windows::Graphics::Imaging::BitmapPixelFormat::Bgra8:
			if ((_sensorType == SensorType::VisibleLightLeftFront) ||
				(_sensorType == SensorType::VisibleLightLeftLeft) ||
				(_sensorType == SensorType::VisibleLightRightFront) ||
				(_sensorType == SensorType::VisibleLightRightRight))
			{
				maxBitmapValue = 255;
				actualBitmapWidth = actualBitmapWidth * 4;
			}
            else if (_sensorType == SensorType::PhotoVideo)
            {
                maxBitmapValue = 255;
            }
			else
			{
				ASSERT(false);
			}

			break;

		default:
			// Unsupported by PGM format. Need to update save logic
#if DBG_ENABLE_INFORMATIONAL_LOGGING
			dbg::trace(
				L"SensorFrameRecorderSink::Send: unsupported bitmap pixel format for PGM");
#endif /* DBG_ENABLE_INFORMATIONAL_LOGGING */

			ASSERT(false);
			break;
		}

        // Determine which bitmap format to use.
        std::string bitmapFormat;
        std::wstring bitmapFileExtension;
        if (_sensorType == SensorType::PhotoVideo)
        {
            bitmapFormat = "P6";
            bitmapFileExtension = L"ppm";
        }
        else 
        {
            bitmapFormat = "P5";
            bitmapFileExtension = L"pgm";
        }

        // Compose the output file name.
        wchar_t bitmapPath[MAX_PATH];
        swprintf_s(
            bitmapPath, L"%s\\%020llu.%s",
            _sensorName->Data(),
            sensorFrame->Timestamp.UniversalTime,
            bitmapFileExtension.c_str());

		// Compose PGM header string.
		std::stringstream header;
		header << bitmapFormat << "\n"
			<< actualBitmapWidth << " "
			<< softwareBitmap->PixelHeight << "\n"
			<< maxBitmapValue << "\n";
		const std::string headerString = header.str();

		// Get bitmap buffer object of the frame.
		Windows::Graphics::Imaging::BitmapBuffer^ bitmapBuffer =
			softwareBitmap->LockBuffer(
				Windows::Graphics::Imaging::BitmapBufferAccessMode::Read);

		// Get raw pointer to the buffer object.
		uint32_t pixelBufferDataLength = 0;
		const uint8_t* pixelBufferData =
			Io::GetTypedPointerToMemoryBuffer<uint8_t>(
				bitmapBuffer->CreateReference(),
				pixelBufferDataLength);

        // Convert the software bitmap to raw bytes.
        std::vector<uint8_t> bitmapData;
        if (_sensorType == SensorType::PhotoVideo)
        {
            const uint32_t numPixels = softwareBitmap->PixelWidth * softwareBitmap->PixelHeight;

            // Allocate data for PGM bitmap file.
            bitmapData.reserve(headerString.size() + numPixels * 3);

            // Add PGM header data.
            bitmapData.insert(
                bitmapData.end(),
                headerString.c_str(), headerString.c_str() + headerString.size());

            for (uint32_t i = 0; i < numPixels; ++i)
            {
                for (uint32_t j = 0; j < 3; ++j)
                {
                    bitmapData.push_back(pixelBufferData[i * 4 + 2 - j]);
                }
            }
        }
        else
        {
            // Allocate data for PGM bitmap file.
            bitmapData.reserve(headerString.size() + pixelBufferDataLength);

            // Add PGM header data.
            bitmapData.insert(
                bitmapData.end(),
                headerString.c_str(), headerString.c_str() + headerString.size());

            // Add raw pixel data.
            bitmapData.insert(
                bitmapData.end(),
                pixelBufferData, pixelBufferData + pixelBufferDataLength);
        }

		// Add the bitmap to the tarball.
		_bitmapTarball->AddFile(bitmapPath, bitmapData.data(), bitmapData.size());

		//
		// Record the sensor frame meta data to the csv file.
		//

		bool writeComma = false;

		_csvWriter->WriteUInt64(
			sensorFrame->Timestamp.UniversalTime, &writeComma);

		{
			_csvWriter->WriteText(
				bitmapPath, &writeComma);
		}

		_csvWriter->WriteFloat4x4(
			sensorFrame->FrameToOrigin, &writeComma);

		_csvWriter->WriteFloat4x4(
			sensorFrame->CameraViewTransform, &writeComma);

		_csvWriter->WriteFloat4x4(
			sensorFrame->CameraProjectionTransform, &writeComma);

		_csvWriter->EndLine();
	}