windows FFmpeg函数avdevice_list_devices导致C++运行时错误

vhmi4jdf  于 2023-05-30  发布在  Windows
关注(0)|答案(3)|浏览(343)

我使用Windows、C#、FFmpeg.AutoGen。我想获取设备列表。

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);

    }

}

函数avdevice_list_devices()导致错误:
Microsoft Visual C++运行时库。此应用程序请求运行时以一种不寻常的方式终止它。
我做错了什么?

更新

错误的另一个原因:

Assertion s->oformat || s->iformat failed at src/libavdevice/avdevice.c:192

如果我们在调试中查看上下文,我们将看到context.oformatcontext.iformat等于零。

更新2

如果设置一些非零值,则错误将消失。像这样:

AVInputFormat avformat = new AVInputFormat();

(*context).iformat = &avformat;

但无法获取设备列表。现在代码看起来像这样。最后一行抛出异常“Object reference not set to an instance of an object”。但是在调试中可以看到nb_devices的值是十(实际上根本没有设备)。

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;

    }

}
rmbxnbpk

rmbxnbpk1#

指针的用法是错误的。
private static unsafe AVDeviceInfoList** _devicesList;替换为:

private static unsafe AVDeviceInfoList* _devicesList; //Pointer to AVDeviceInfoList structure

ffmpeg.avdevice_list_devices(context, _devicesList);替换为:

ffmpeg.avdevice_list_devices(context, &_devicesList); //Pass the memory address of _devicesList.

avdevice_list_devices参数被定义为指向指针的指针,这并不意味着我们可以用**声明一个变量并将其作为参数传递。
**(指针到指针)的C语法非常混乱。
在我们的例子中,这意味着我们应该传递一个指针的地址,函数返回一个新指针。
返回的指针指向设备列表。
该函数动态地分配用于存储列表的内存,填充列表,并返回指向列表的指针。
要释放分配的内存,请执行:

avdevice_free_list_devices(&_devicesList)
nhhxz33t

nhhxz33t2#

很可能无法通过代码获取设备列表。证明。但毕竟应用程序应该使用任何功能获取设备列表!

tcbh2hod

tcbh2hod3#

找到解决方案。需要使用较新版本的FFmpeg和不同的方法(avdevice_list_input_sources)。此代码适用于以下条件:Windows 7、.NETFramework 4.5.2、FFmpeg.AutoGen 5.1.2.3、来自gyan.dev的FFmpeg库5.1.2。

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());

    }
}

相关问题