Code Samples - C# (AdvRecorder Class)

Using the AdvRecorder class is the recommended method for creating ADV files. It has been created to let people that don't want to learn all low-level details of the ADV format to be able to easily create such files. People knowing the details of the format may find some small limitations when using the AdvRecorder. For a more involved process which however offers a complete control over the ADV file creation use the AdvLib Core Fuctions.

None of the code samples here are production ready. Please ensure to use error checking and general good coding practices in your sofware when you are using these code samples.

Creating an ADV file

The sample code below demonstrates the minimum code required to create a new ADV file using the AdvRecorder class. It saves 10 video frames as 16-bit uncompressed images and simulates an exposure of 0.5 sec. Please note that the timing accuracy, according to the standard, is provided in nanoseconds when passed to the StartRecordingNewFile() method.

Please note that the AdvRecorder class requires you to set the following file level metadata: RecorderSoftwareName, CameraModel and CameraSensorInfo. Even that the RecorderSoftwareVersion is not required to be set it is a good idea and the code sample below does it.

The UTC timestamps for the beginning and end of the the exposure of the video frame are passed to the AddVideoFrame() method. The AdvTimeStamp.FromDateTime() method is used to convert the .NET DateTime to the format used in the ADV file format.

	fileName = @"C:\hello-world.adv";

	const uint MILLI_TO_NANO = 1000000;
	const int WIDTH = 800;
	const int HEIGHT = 600;

	var rec = new AdvRecorder();
	rec.ImageConfig.SetImageParameters(WIDTH, HEIGHT, 16, 0);

	rec.FileMetaData.RecorderSoftwareName = "MyVideoRecorder";
	rec.FileMetaData.RecorderSoftwareVersion = "1.0b";
	rec.FileMetaData.CameraModel = "Flea3 FL3-FW-03S3M";
	rec.FileMetaData.CameraSensorInfo = "Sony ICX414AL (1/2\" 648x488 CCD)";

	rec.StartRecordingNewFile(fileName, 1 * MILLI_TO_NANO /* 1ms */);

	// TODO: Get the real actual timestamps and exposure 
	DateTime startTime = DateTime.UtcNow;
	double exposureSeconds = 0.5;
	
	for (int i = 0; i < 10; i++)
	{
		ushort[] pixels = new ushort[WIDTH * HEIGHT];

		rec.AddVideoFrame(
			pixels, false, null,
			AdvTimeStamp.FromDateTime(startTime.AddSeconds(exposureSeconds * i)),
			AdvTimeStamp.FromDateTime(startTime.AddSeconds(exposureSeconds * (i + 1))),
			null, AdvImageData.PixelDepth16Bit);
	}

	rec.FinishRecording();
}

Recording basic frame data with each frames such as Gain and Gamma

For accurate photometry it may be important to know the values of Gain and Gamma and they will be typically recorded in the file. As the gain and gamma settings of the camera could generally be modified during the recording they are saved for each frame, even if they don't change during the recording. The code sample below demonstrates how to do this.

Somewhere before the call to StartRecordingNewFile the relevent properties of StatusSectionConfig must be set to true. Then when the frame is saved the 6-th parameter of AddVideoFrame() will have to contain the values we want to save. Only the properties that have been turned on from the StatusSectionConfig will be saved in the frame, regardless of how many properties of the AdvStatusEntry instance are provided.


	var rec = new AdvRecorder();

	...
	
	rec.StatusSectionConfig.RecordGain = true;
	rec.StatusSectionConfig.RecordGamma = true;

	...
	
	rec.StartRecordingNewFile(fileName, 1 * MILLI_TO_NANO /* 1ms */);

	for (int i = 0; i < 10; i++)
	{
		ushort[] pixels = new ushort[WIDTH * HEIGHT];
	
		// TODO: Get the actual gain and gamma settings from the camera
		var statusEntry = new AdvRecorder.AdvStatusEntry()
		{
			Gain = 38.3f,
			Gamma = 1
		};

		rec.AddVideoFrame(
			pixels, false, null,
			AdvTimeStamp.FromDateTime(DateTime.Now),
			AdvTimeStamp.FromDateTime(DateTime.Now.AddSeconds(0.5 * i)),
			statusEntry, AdvImageData.PixelDepth16Bit);
	}

	rec.FinishRecording();

Recording user defined frame data with each frame

An example of recording user defined frame data is given below. The custom frame data tags can be defined by calling StatusSectionConfig.AddDefineTag. One of the 6 fixed data types must be selected for the defined tag. They are Int8, Int16, Int32, Long64, Real and UTF8String. The actual custom tag values are provided in the AdvStatusEntry.AdditionalStatusTags property as an array of objects. The primitive type in the object array must match that of the defined tag and the tags must appear in the array in the same order as they have been defined.

	var rec = new AdvRecorder();

	...
	
	rec.StatusSectionConfig.AddDefineTag("ErrorFlag", Adv2TagType.Int8);
	rec.StatusSectionConfig.AddDefineTag("Temperature", Adv2TagType.Real);

	rec.StartRecordingNewFile(fileName, 1 * MILLI_TO_NANO /* 1ms */);

	for (int i = 0; i < 10; i++)
	{
		ushort[] pixels = new ushort[WIDTH * HEIGHT];

		var statusEntry = new AdvRecorder.AdvStatusEntry()
		{
			// Set actual values. Order and type of values is important.
			AdditionalStatusTags = new object[]{ (byte)1, 15.3f }
		};

		rec.AddVideoFrame(
			pixels, false, null,
			AdvTimeStamp.FromDateTime(startTime.AddSeconds(exposureSeconds * i)),
			AdvTimeStamp.FromDateTime(startTime.AddSeconds(exposureSeconds * (i + 1))),
			statusEntry, AdvImageData.PixelDepth16Bit);
	}

	rec.FinishRecording();

Providing more details such as Observer, Object, etc

This is an example of some of the metatags that you should consider setting when recording an ADV file plus an example of how to add a custom defined tag, which was called Timing Hardware in this instance.

	rec.FileMetaData.Telescope = "14\" LX-200 ACF (Tangra Observatory)";
	rec.FileMetaData.Observer = "Hristo Pavlov";
	rec.FileMetaData.ObjectName = "Chariklo";
	rec.FileMetaData.Comment = "Full moon only 20 deg away from the target.";

	rec.FileMetaData.AddUserTag("Timing Hardware", "IOTA-VTI v3");

Creating an ADV file using a custom clock tick source

The ADV format uses two different time references for two different reasons. As shown in the example above the UTC timestamps for each frame are provided during the recording and are used for the absolute timing of events in UTC. Those timestamps can be specified with an accuracy of a nanosecond however more realistically they will be probably accurate to a millisecond or a fraction of a millisecond. Note that the claimed accuracy is provided in the StartRecordingNewFile() method and the value should correspond to the verified accuracy of your system.

At the same time the AdvRecorder will also assign a time reference to each recorded frame in the form of number of ticks ellapsed since some arbitrary moment in the past. By default those ticks saved automatically and are provided by the CPU clock which frequency could change overtime for example with temperature. The purpose of this time reference is to provide a more precise timestamp but with smaller absolute accuracy. It is allowed the tick count to overflow i.e. to start again from zero when reaching its maximum value. This time reference can be very useful for cameras with extreamly high frame rates and can provide timing resolution down to a pico-second.

In some cases the used camera hardware may be able to provide tick values from its own internal clock and in other cases such ticks may be available from other hardware components which are part of the acquisition chain - for example the FireWire clock when the camera is connected via a FireWire port. It may be a good idea in those cases to override the CPU clock time reference ticks saved in the ADV file and use the native camera or acquisition chain ticks. In fact this may be the only way to get an accurate relative frame timestamps for very fast cameras.

The code sample below demonstrates how to define a custom tickcount clock and use it for relative time. It is done simply by calling DefineCustomClock() before StartRecordingNewFile() and passings the frequency of the clock in Hz, the resolution of the reading and a method that returns the reading (in out case called GetCustomClockTickCount). This method will be called by AdvRecorder when saving the frame i.e. some time after the end of the frame acquisition.

	var rec = new AdvRecorder();

	...
	
	rec.DefineCustomClock(
			AdvRecorder.AdvStream.MainStream, 
			98304000 /* 98.304MHz */, 
			100, /* 100 ticks resolution */ 
			GetCustomClockTickCount);
	...
	
	rec.StartRecordingNewFile(fileName, 1 * MILLI_TO_NANO /* 1ms */);

Language