I use Windows, C#, FFmpeg.AutoGen. I want to get list of devices.
public static class Helpers
{
private static unsafe AVDeviceInfoList** _devicesList;
public static unsafe void GetMediaSourceNames()
{
ffmpeg.avdevice_register_all();
AVFormatContext* context = ffmpeg.avformat_alloc_context();
ffmpeg.avdevice_list_devices(context, _devicesList);
}
}
Function avdevice_list_devices() causes error:
Microsoft Visual C++ Runtime Library. This application has requested the Runtime to terminate it in an unusual way.
What am I doing wrong?
UPDATE
Another reason for the error:
Assertion s->oformat || s->iformat failed at src/libavdevice/avdevice.c:192
If we look at the context in debugging, we will see that context.oformat
and context.iformat
are equal to zero.
UPDATE 2
If set some non-zero value, then the error will disappear. Like this:
AVInputFormat avformat = new AVInputFormat();
(*context).iformat = &avformat;
But can't get list of devices.
Now the code looks like this. The last line throws an exception "Object reference not set to an instance of an object". But in debugging can see the value of nb_devices
is ten (in fact, there are no devices at all).
public static class Helpers
{
private static unsafe AVDeviceInfoList* _devicesList;
public static unsafe void GetMediaSourcesNames()
{
ffmpeg.avdevice_register_all();
AVFormatContext* context = ffmpeg.avformat_alloc_context();
AVInputFormat avformat = new AVInputFormat();
(*context).iformat = &avformat;
fixed (AVDeviceInfoList** devicesListPointer = &_devicesList)
{
ffmpeg.avdevice_list_devices(context, devicesListPointer);
}
int devicesQuantity = (*_devicesList).nb_devices;
}
}
Solution is found. Need to use newer version of FFmpeg and different method (avdevice_list_input_sources). This code works in the following conditions: Windows 7, .NETFramework 4.5.2, FFmpeg.AutoGen 5.1.2.3, FFmpeg libraries 5.1.2 from gyan.dev.
internal static class Program
{
private static unsafe void Main()
{
DynamicallyLoadedBindings.Initialize();
ffmpeg.avdevice_register_all();
AVInputFormat* iformat = ffmpeg.av_find_input_format("dshow");
AVDeviceInfoList* deviceListPointer = null;
int result = ffmpeg.avdevice_list_input_sources(iformat, null, null, &deviceListPointer);
if (result < 0)
{
Console.WriteLine($"ERROR: {result} / 0x{result:X8} / {GetErrorDescription(result)}");
if (result == -5)
{
Console.WriteLine("No devices");
}
Console.ReadLine();
return;
}
else
{
Console.WriteLine($"{result} devices");
}
AVDeviceInfoList deviceList = *deviceListPointer;
for (int i = 0; i < deviceList.nb_devices; i++)
{
AVDeviceInfo deviceInfo = *deviceList.devices[i];
for (int j = 0; j < deviceInfo.nb_media_types; j++)
{
Console.WriteLine((deviceInfo.media_types)[j]);
}
Console.WriteLine(BytePtrToStringUtf8(deviceInfo.device_name));
Console.WriteLine(BytePtrToStringUtf8(deviceInfo.device_description));
}
Console.ReadLine();
}
private static unsafe string GetErrorDescription(int errorNumber)
{
byte[] chars = new byte[1000];
fixed (byte* charsPointer = &chars[0])
{
ffmpeg.av_strerror(errorNumber, charsPointer, (ulong)chars.Length);
return BytePtrToStringUtf8(charsPointer);
}
}
private static unsafe string BytePtrToStringUtf8(byte* bytePtr)
{
if (bytePtr == null) return null;
if (*bytePtr == 0) return string.Empty;
List<byte> byteBuffer = new List<byte>();
while (true)
{
byte currentByte = *bytePtr;
if (currentByte == 0)
break;
byteBuffer.Add(currentByte);
bytePtr++;
}
return Encoding.UTF8.GetString(byteBuffer.ToArray());
}
}