213 lines
7.2 KiB
C++
213 lines
7.2 KiB
C++
/** \file matroska_common.h
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
* Kinect For Azure Record SDK.
|
|
*/
|
|
|
|
#ifndef RECORD_COMMON_H
|
|
#define RECORD_COMMON_H
|
|
|
|
#include <k4arecord/types.h>
|
|
#include <k4ainternal/handle.h>
|
|
#include <list>
|
|
#include <fstream>
|
|
#include <memory>
|
|
#include <thread>
|
|
|
|
#if defined(__clang__)
|
|
|
|
#pragma clang diagnostic push
|
|
// -Wheader-hygiene: using namespace directive in global context in header
|
|
// -Wconversion: implicit conversion loses integer precision: 'unsigned long' to 'uint8'
|
|
// -Wsign-conversion: implicit conversion changes signedness: 'int' to 'unsigned long'
|
|
// -Wfloat-equal: comparing floating point with == or != is unsafe
|
|
// -Wcast-qual: cast from 'const unsigned char *' to 'unsigned char *' drops const qualifier
|
|
#pragma clang diagnostic ignored "-Wheader-hygiene"
|
|
#pragma clang diagnostic ignored "-Wconversion"
|
|
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
#pragma clang diagnostic ignored "-Wfloat-equal"
|
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
#pragma warning(push)
|
|
// EBML header warnings
|
|
// 4267: 'return': conversion from 'size_t' to 'uint8', possible loss of data
|
|
// 4138: '*/' found outside of comment
|
|
// 4245: 'return': conversion from 'int' to 'uint64', signed/unsigned mismatch
|
|
#pragma warning(disable : 4267 4138 4245)
|
|
|
|
#endif
|
|
|
|
#include "ebml/EbmlHead.h"
|
|
#include "ebml/EbmlStream.h"
|
|
#include "ebml/EbmlSubHead.h"
|
|
#include "ebml/EbmlVoid.h"
|
|
#include "matroska/KaxSegment.h"
|
|
#include "matroska/KaxCluster.h"
|
|
#include "matroska/KaxSeekHead.h"
|
|
#include "matroska/KaxCuesData.h"
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#elif defined(_MSC_VER)
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
// Helpers to easily specify time in nanoseconds
|
|
constexpr uint64_t operator"" _us(unsigned long long x)
|
|
{
|
|
return x * 1000;
|
|
}
|
|
constexpr uint64_t operator"" _ms(unsigned long long x)
|
|
{
|
|
return x * 1000000;
|
|
}
|
|
constexpr uint64_t operator"" _s(unsigned long long x)
|
|
{
|
|
return x * 1000000000;
|
|
}
|
|
|
|
#ifndef MAX_CLUSTER_LENGTH_NS
|
|
#define MAX_CLUSTER_LENGTH_NS 32_ms
|
|
#endif
|
|
|
|
#ifndef MATROSKA_TIMESCALE_NS
|
|
// 1 unit = 1us
|
|
#define MATROSKA_TIMESCALE_NS 1_us
|
|
#endif
|
|
|
|
#ifndef CLUSTER_WRITE_DELAY_NS
|
|
#define CLUSTER_WRITE_DELAY_NS 2_s
|
|
#endif
|
|
|
|
#ifndef CLUSTER_WRITE_QUEUE_WARNING_NS
|
|
// If a cluster is in the qeuue too long, warn about disk write speed.
|
|
#define CLUSTER_WRITE_QUEUE_WARNING_NS CLUSTER_WRITE_DELAY_NS + 2_s
|
|
#endif
|
|
|
|
#ifndef CUE_ENTRY_GAP_NS
|
|
#define CUE_ENTRY_GAP_NS 1_s
|
|
#endif
|
|
|
|
#ifndef CLUSTER_READ_AHEAD_COUNT
|
|
#define CLUSTER_READ_AHEAD_COUNT 2
|
|
#endif
|
|
|
|
static_assert(MAX_CLUSTER_LENGTH_NS < INT16_MAX * MATROSKA_TIMESCALE_NS, "Cluster length must fit in a 16 bit int");
|
|
static_assert(CLUSTER_WRITE_DELAY_NS >= MAX_CLUSTER_LENGTH_NS * 2, "Cluster write delay is shorter than 2 clusters");
|
|
|
|
#define RETURN_IF_ERROR(_call_) \
|
|
{ \
|
|
k4a_result_t retval = TRACE_CALL(_call_); \
|
|
if (K4A_FAILED(retval)) \
|
|
{ \
|
|
return retval; \
|
|
} \
|
|
}
|
|
|
|
// make_unique is C++14 only
|
|
template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args &&... args)
|
|
{
|
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
}
|
|
|
|
// C++11 Cross-platform implementation of countof()
|
|
template<typename T, size_t N> constexpr size_t arraysize(T const (&)[N]) noexcept
|
|
{
|
|
return N;
|
|
}
|
|
|
|
// Function for switching between big and little-endian 16-bit ints
|
|
#ifndef __has_builtin
|
|
#define __has_builtin(x) 0
|
|
#endif
|
|
constexpr uint16_t swap_bytes_16(uint16_t input)
|
|
{
|
|
#if __has_builtin(__builtin_bswap16)
|
|
return __builtin_bswap16(input);
|
|
#else
|
|
return input >> 8 | input << 8;
|
|
#endif
|
|
}
|
|
|
|
namespace k4arecord
|
|
{
|
|
/**
|
|
* EBML IO handler compatible with file sizes larger than 32-bit
|
|
*/
|
|
class LargeFileIOCallback : public libebml::IOCallback
|
|
{
|
|
public:
|
|
LargeFileIOCallback(const char *path, const open_mode mode);
|
|
~LargeFileIOCallback() override;
|
|
|
|
uint32 read(void *buffer, size_t size) override;
|
|
void setFilePointer(int64 offset, libebml::seek_mode mode = libebml::seek_beginning) override;
|
|
size_t write(const void *buffer, size_t size) override;
|
|
uint64 getFilePointer() override;
|
|
void close() override;
|
|
void setOwnerThread();
|
|
|
|
private:
|
|
std::fstream m_stream;
|
|
std::thread::id m_owner;
|
|
};
|
|
|
|
// Struct matches https://docs.microsoft.com/en-us/windows/desktop/wmdm/-bitmapinfoheader
|
|
struct BITMAPINFOHEADER
|
|
{
|
|
uint32_t biSize = sizeof(BITMAPINFOHEADER);
|
|
uint32_t biWidth;
|
|
uint32_t biHeight;
|
|
uint16_t biPlanes = 1;
|
|
uint16_t biBitCount;
|
|
uint32_t biCompression;
|
|
uint32_t biSizeImage;
|
|
uint32_t biXPelsPerMeter = 0;
|
|
uint32_t biYPelsPerMeter = 0;
|
|
uint32_t biClrUsed = 0;
|
|
uint32_t biClrImportant = 0;
|
|
};
|
|
|
|
#pragma pack(push, 1)
|
|
// Used to serialize imu samples to disk. The struct padding and size must be exact.
|
|
struct matroska_imu_sample_t
|
|
{
|
|
uint64_t acc_timestamp_ns;
|
|
float acc_data[3];
|
|
uint64_t gyro_timestamp_ns;
|
|
float gyro_data[3];
|
|
};
|
|
#pragma pack(pop)
|
|
|
|
// Sample is stored as [acc_timestamp, acc_data[3], gyro_timestamp, gyro_data[3]]
|
|
static_assert(sizeof(matroska_imu_sample_t) == (sizeof(float) * 6 + sizeof(uint64_t) * 2),
|
|
"matroska_imu_sample_t size does not match expected padding.");
|
|
|
|
// If the size of an IMU sample changes in the SDK, the file format will need to be updated as well.
|
|
static_assert(sizeof(matroska_imu_sample_t) ==
|
|
sizeof(k4a_imu_sample_t().acc_sample.v) + sizeof(k4a_imu_sample_t().acc_timestamp_usec) +
|
|
sizeof(k4a_imu_sample_t().gyro_timestamp_usec) + sizeof(k4a_imu_sample_t().gyro_sample.v),
|
|
"Size of IMU data structure has changed from on-disk format.");
|
|
|
|
static const k4a_color_resolution_t color_resolutions[] = { K4A_COLOR_RESOLUTION_720P, K4A_COLOR_RESOLUTION_1080P,
|
|
K4A_COLOR_RESOLUTION_1440P, K4A_COLOR_RESOLUTION_1536P,
|
|
K4A_COLOR_RESOLUTION_2160P, K4A_COLOR_RESOLUTION_3072P };
|
|
|
|
static const std::pair<k4a_depth_mode_t, std::string> depth_modes[] =
|
|
{ { K4A_DEPTH_MODE_NFOV_2X2BINNED, "NFOV_2X2BINNED" },
|
|
{ K4A_DEPTH_MODE_NFOV_UNBINNED, "NFOV_UNBINNED" },
|
|
{ K4A_DEPTH_MODE_WFOV_2X2BINNED, "WFOV_2X2BINNED" },
|
|
{ K4A_DEPTH_MODE_WFOV_UNBINNED, "WFOV_UNBINNED" },
|
|
{ K4A_DEPTH_MODE_PASSIVE_IR, "PASSIVE_IR" } };
|
|
|
|
static const std::pair<k4a_wired_sync_mode_t, std::string> external_sync_modes[] =
|
|
{ { K4A_WIRED_SYNC_MODE_STANDALONE, "STANDALONE" },
|
|
{ K4A_WIRED_SYNC_MODE_MASTER, "MASTER" },
|
|
{ K4A_WIRED_SYNC_MODE_SUBORDINATE, "SUBORDINATE" } };
|
|
|
|
} // namespace k4arecord
|
|
|
|
#endif /* RECORD_COMMON_H */
|