TCaptureDeviceManager 获取多个网络摄像头的视频捕获设备

问题描述 投票:0回答:1

我有一个用 C++Builder 11.1.5 编写的应用程序,我正在尝试从 2 个网络摄像头捕获实时视频。

有一个优秀的教程,它描述了如何使用 1 个网络摄像头在以下 URL 上执行此操作,我已经完美地工作了:Video Capturing.

按照那个例子,我在窗体的

OnCreate
事件上使用下面的代码,它存储了计算机上所有可用的视频捕获设备的信息:

NumbAvailableCameras = 0;

DeviceList = TCaptureDeviceManager::Current->GetDevicesByMediaType(TMediaType::Video);
for (i = 0; i < DeviceList->Count; i++) {
    UniqueID = DeviceList->Items[i]->UniqueID;
    UniqueDescription = DeviceList->Items[i]->Description;
    UniqueName = DeviceList->Items[i]->Name;
    ComboBox1->Items->Add(DeviceList->Items[i]->Name);
    AvailableCameraIndices[NumbAvailableCameras] = i;
    AvailableCameraNames[NumbAvailableCameras] = DeviceList->Items[i]->Name;
    AvailableCameraDescriptions[NumbAvailableCameras] = UniqueDescription;
    AvailableCameraIdentifiers[NumbAvailableCameras] = UniqueID;
    CameraIndex[i] = i;
    NumbAvailableCameras++;
    }

然后,有一个按钮,它的

OnClick
事件允许启动捕获:

CAM1VideoCamera = dynamic_cast<TVideoCaptureDevice*>
        (TCaptureDeviceManager::Current->GetDevicesByName(ComboBox1->Selected->Text));

现在,我有 2 个名称相同的网络摄像头,因此

GetDevicesByName()
例程不起作用,因为它会选择它找到的具有所选名称的第一个摄像头。

作为替代方案,我尝试了以下代码,但它为捕获设备返回

NULL

CAM1VideoCamera = dynamic_cast<TVideoCaptureDevice*>
        (TCaptureDeviceManager::Current->Devices[CameraIndex[0]]);

关于如何正确执行此操作的任何想法?

c++ firemonkey c++builder video-capture
1个回答
0
投票

我有 2 个名称相同的网络摄像头,因此 GetDevicesByName 例程无法正常工作,因为它会选择使用所选名称找到的first 摄像头

实际上,它返回具有所选名称(错误?)的last设备。

我觉得奇怪的是,该方法被命名为plural但它只返回一个single设备。

我现在已经向Embarcadero报告了这些问题:

RSP-41707:TCaptureDeviceManager.GetDevicesByName() 问题

我尝试了以下代码,但它为 CaptureDevice 返回 NULL

那是因为你使用了错误的索引。

您正在检索视频设备的

TCaptureDeviceList
,但是在访问主
TCaptureDeviceList
列表时,您正在使用与该
TCaptureDeviceManager::Devices[]
相关的索引。因此,如果视频设备前面的
Devices[]
列表中存在任何音频设备,那么您的
CameraIndex[]
索引将无法正确匹配,因此您最终可以将
TAudioCaptureDevice
对象传递给
dynamic_cast
,这就是为什么它会返回
NULL
.

要做你正在尝试的事情,你将不得不忘记使用

GetDevicesByMediaType()
而是直接迭代
Devices[]
列表,例如:

NumbAvailableCameras = 0;

int DeviceCount = TCaptureDeviceManager::Current->Count;

for (int DeviceIndex = 0; DeviceIndex < DeviceCount; ++DeviceIndex) {
    TCaptureDevice *Device = TCaptureDeviceManager::Current->Devices[DeviceIndex];
    if (Device->MediaType != TMediaType::Video) continue;

    UniqueName = Device->Name;
    ComboBox1->Items->Add(UniqueName);

    AvailableCameraIndices[NumbAvailableCameras] = NumbAvailableCameras; // should this be DeviceIndex instead?
    AvailableCameraNames[NumbAvailableCameras] = UniqueName;
    AvailableCameraDescriptions[NumbAvailableCameras] = Device->Description;
    AvailableCameraIdentifiers[NumbAvailableCameras] = Device->UniqueID;

    CameraIndex[NumbAvailableCameras] = DeviceIndex; // <-- absolute index, not relative index!

    ++NumbAvailableCameras;
}

现在,访问

TCaptureDeviceManager::Current->Devices[CameraIndex[...]]
应该只返回
TVideoCaptureDevice
对象,正如预期的那样。在这种情况下,由于您知道所有索引仅适用于视频设备,因此您可以(并且应该)使用
static_cast
而不是
dynamic_cast


话虽这么说,看来

AvailableCameraIndices[]
CameraIndex[]
可能在做同样的工作,所以你可以考虑去掉其中一个。

更好的是,考虑改变

AvailableCameraIndices[]
/
CameraIndex[]
来存储(指向)实际的
TVideoCaptureDevice
对象本身,而不是存储它的索引,因为设备和索引在
TCaptureDeviceManager
的生命周期中永远不会改变,例如:

NumbAvailableCameras = 0;

int DeviceCount = TCaptureDeviceManager::Current->Count;

for (int i = 0; i < DeviceCount; ++i) {
    TCaptureDevice *Device = TCaptureDeviceManager::Current->Devices[i];
    if (Device->MediaType != TMediaType::Video) continue;
    AvailableCameras[NumbAvailableCameras] = static_cast<TVideoCaptureDevice*>(Device);
    ++NumbAvailableCameras;
    ComboBox1->Items->Add(Device->Name);
}

在这种情况下,您可以删除所有单独的

AvailableCamera...[]
数组并单独使用
GetDevicesByMdiaType()
,例如:

AvailableCameras = TCaptureDeviceManager::Current->GetDevicesByMediaType(TMediaType::Video);

for (auto Device : AvailableCameras) {
    ComboBox1->Items->Add(Device->Name);
}
© www.soinside.com 2019 - 2024. All rights reserved.