Skip to content
This repository has been archived by the owner on Aug 22, 2024. It is now read-only.

C# Record and Playback APIs #822

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 57 additions & 54 deletions docs/releasing.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion include/k4arecord/playback.h
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ K4ARECORD_EXPORT void k4a_playback_data_block_release(k4a_playback_data_block_t
*
* \remarks
* The first call to k4a_playback_get_next_imu_sample() after k4a_playback_seek_timestamp() will return the first imu
* sample with a timestamp greter than or equal to the seek time.
* sample with a timestamp greater than or equal to the seek time.
*
* \remarks
* The first call to k4a_playback_get_previous_imu_sample() after k4a_playback_seek_timestamp() will return the first
Expand Down
46 changes: 46 additions & 0 deletions include/k4arecord/record.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,52 @@ K4ARECORD_EXPORT k4a_result_t k4a_record_flush(k4a_record_t recording_handle);
*/
K4ARECORD_EXPORT void k4a_record_close(k4a_record_t recording_handle);

/** Sets and clears the callback function to receive debug messages from the Azure Kinect record and playback APIs.
*
* \param message_cb
* The callback function to receive messages from. Set to NULL to unregister the callback function.
*
* \param message_cb_context
* The callback functions context.
*
* \param min_level
* The least critical error the user wants to be notified about.
*
* \return ::K4A_RESULT_SUCCEEDED if the callback function was set or cleared successfully. ::K4A_RESULT_FAILED if an
* error is encountered or the callback function has already been set.
*
* \remarks
* Call this function to set or clear the callback function that is used to deliver debug messages to the caller. This
* callback may be called concurrently, it is up to the implementation of the callback function to ensure the
* parallelization is handled.
*
* \remarks
* Clearing the callback function will block until all pending calls to the callback function have completed.
*
* \remarks
* To update \p min_level, k4a_record_set_debug_message_handler() can be called with the same value \p message_cb and by
* specifying a new \p min_level.
*
* \remarks
* Logging provided via this API is independent of the logging controlled by the environmental variable controls \p
* K4A_ENABLE_LOG_TO_STDOUT, K4A_RECORD_ENABLE_LOG_TO_A_FILE, and K4A_LOG_LEVEL. However there is a slight change in
* default behavior when using this function. By default, when k4a_record_set_debug_message_handler() has not been used
* to register a message callback, the default for environmental variable controls is to send debug messages as if
* K4A_ENABLE_LOG_TO_STDOUT=1 were set. If k4a_record_set_debug_message_handler registers a callback function before
* k4a_record_create() or k4a_playback_create() is called, then the default for environmental controls is as if
* K4A_ENABLE_LOG_TO_STDOUT=0 was specified. Physically specifying the environmental control will override the default.
*
* \xmlonly
* <requirements>
* <requirement name="Header">k4a.h (include k4a/k4a.h)</requirement>
* <requirement name="Library">k4a.lib</requirement>
* <requirement name="DLL">k4a.dll</requirement>
* </requirements>
* \endxmlonly
*/
K4ARECORD_EXPORT k4a_result_t k4a_record_set_debug_message_handler(k4a_logging_message_cb_t *message_cb,
void *message_cb_context,
k4a_log_level_t min_level);
/**
* @}
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\k4a.props" />

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AssemblyName>dotnetrecording</AssemblyName>

<Platforms>x64;x86</Platforms>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRuleSet>..\..\AzureKinectSensorSDK.ruleset</CodeAnalysisRuleSet>
<OutputPath>$(BaseOutputPath)\$(AssemblyName)\</OutputPath>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Record\Microsoft.Azure.Kinect.Sensor.Record.csproj" />
<ProjectReference Include="..\..\SDK\Microsoft.Azure.Kinect.Sensor.csproj" />
</ItemGroup>

<ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json">
<Link>stylecop.json</Link>
</AdditionalFiles>
</ItemGroup>

<ItemGroup>
<Content Include="$(K4aBinaryDirectory)\k4a.dll">
<Link>k4a.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(K4aBinaryDirectory)\k4a.pdb">
<Link>k4a.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(K4aBinaryDirectory)\k4arecord.dll">
<Link>k4arecord.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(K4aBinaryDirectory)\k4arecord.pdb">
<Link>k4arecord.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

<!-- If the depth engine doesn't exist in the bin directory, it may be available in the PATH .
It isn't needed for compilation, but only required at runtime when reading data from a live device. -->
<Content Include="$(K4aBinaryDirectory)\depthengine_2_0.dll" Condition="Exists('$(K4aBinaryDirectory)\depthengine_2_0.dll')">
<Link>depthengine_2_0.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>
102 changes: 102 additions & 0 deletions src/csharp/Examples/Recording/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copyright header.

using System.Linq.Expressions;
using Microsoft.Azure.Kinect.Sensor;
using Microsoft.Azure.Kinect.Sensor.Record;

namespace Recording
{
class Program
{
static void Main(string[] args)
{
int frame = 0;

if (args.Length < 1)
{
Console.WriteLine("Please specify the name of an .mkv output file.");
return;
}

string path = args[0];

try
{
Console.WriteLine($"Recording from device to \"{path}\".");

DeviceConfiguration configuration = new DeviceConfiguration()
{
CameraFPS = FPS.FPS30,
ColorFormat = ImageFormat.ColorMJPG,
ColorResolution = ColorResolution.R720p,
DepthMode = DepthMode.NFOV_2x2Binned,
SynchronizedImagesOnly = true
};
using (Device device = Device.Open())
using (Recorder recorder = Recorder.Create(path, device, configuration))
{

device.StartCameras(configuration);
device.StartImu();

recorder.AddImuTrack();
recorder.WriteHeader();

for (frame = 0; frame < 100; frame++)
{
using (Capture capture = device.GetCapture())
{
recorder.WriteCapture(capture);
Console.WriteLine($"Wrote capture ({capture.Color.DeviceTimestamp})");
try
{
while (true)
{
// Throws TimeoutException when Imu sample is not available
ImuSample sample = device.GetImuSample(TimeSpan.Zero);

recorder.WriteImuSample(sample);
Console.WriteLine($"Wrote imu ({sample.AccelerometerTimestamp})");
}
}
catch (TimeoutException)
{

}
}
}
}

Console.WriteLine($"Wrote {frame} frames to output.mkv");

using (Playback playback = Playback.Open(@"output.mkv"))
{
Console.WriteLine($"Tracks = {playback.TrackCount}");
Console.WriteLine($"RecordingLength = {playback.RecordingLength}");

for (int i = 0; i < playback.TrackCount; i++)
{
string name = playback.GetTrackName(i);
string codecId = playback.GetTrackCodecId(name);

Console.WriteLine($" Track {i}: {name} ({codecId}) (builtin={playback.GetTrackIsBuiltin(name)})");
}
Capture capture;
while (null != (capture = playback.GetNextCapture()))
{
Console.WriteLine($"Color timestamp: {capture.Color.DeviceTimestamp} Depth timestamp: {capture.Depth.DeviceTimestamp}");
}
}

} catch (AzureKinectException exception)
{
Console.WriteLine(exception.ToString());
Console.WriteLine();
Console.WriteLine("Azure Kinect log messages:");
foreach (LogMessage m in exception.LogMessages)
{
Console.WriteLine(m.ToString());
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,9 @@
<Link>k4a.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(K4aBinaryDirectory)\depthengine_2_0.dll">
<!-- If the depth engine doesn't exist in the bin directory, it may be available in the PATH .
It isn't needed for compilation, but only required at runtime when reading data from a live device. -->
<Content Include="$(K4aBinaryDirectory)\depthengine_2_0.dll" Condition="Exists('$(K4aBinaryDirectory)\depthengine_2_0.dll')">
<Link>depthengine_2_0.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@
<Link>k4a.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(K4aBinaryDirectory)\depthengine_2_0.dll">
<!-- If the depth engine doesn't exist in the bin directory, it may be available in the PATH .
It isn't needed for compilation, but only required at runtime when reading data from a live device. -->
<Content Include="$(K4aBinaryDirectory)\depthengine_2_0.dll" Condition="Exists('$(K4aBinaryDirectory)\depthengine_2_0.dll')">
<Link>depthengine_2_0.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand Down
Loading