mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
FFmpeg : improvements to ffmpeg::list() functions (#2773)
* added a couple more audio examples * statically initialize all list_() functions where possible. --------- Co-authored-by: pf <pf@me>
This commit is contained in:
parent
b1fe026e06
commit
5f7026ab52
@ -296,55 +296,73 @@ namespace dlib
|
|||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
WHAT THIS OBJECT REPRESENTS
|
WHAT THIS OBJECT REPRESENTS
|
||||||
This object informs on available devices provided by the installation of ffmpeg dlib is linked against.
|
This object informs on available device types provided by the installation of ffmpeg dlib is linked against.
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
struct instance
|
std::string device_type;
|
||||||
|
bool is_audio_type{false};
|
||||||
|
bool is_video_type{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device_instance
|
||||||
{
|
{
|
||||||
|
/*!
|
||||||
|
WHAT THIS OBJECT REPRESENTS
|
||||||
|
This object informs on the currently available device instances readable by ffmpeg.
|
||||||
|
!*/
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string description;
|
std::string description;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string device_type;
|
const std::vector<std::string>& list_protocols();
|
||||||
std::vector<instance> devices;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> list_protocols();
|
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg protocols
|
- returns a list of all available ffmpeg protocols
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
std::vector<std::string> list_demuxers();
|
const std::vector<std::string>& list_demuxers();
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg demuxers
|
- returns a list of all available ffmpeg demuxers
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
std::vector<muxer_details> list_muxers();
|
const std::vector<muxer_details>& list_muxers();
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg muxers
|
- returns a list of all available ffmpeg muxers
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
std::vector<codec_details> list_codecs();
|
const std::vector<codec_details>& list_codecs();
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg codecs with information on whether decoding and/or encoding is supported.
|
- returns a list of all available ffmpeg codecs with information on whether decoding and/or encoding is supported.
|
||||||
Note that not all codecs support encoding, unless your installation of ffmpeg is built with third party library
|
Note that not all codecs support encoding, unless your installation of ffmpeg is built with third party library
|
||||||
dependencies like libx264, libx265, etc.
|
dependencies like libx264, libx265, etc.
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
std::vector<device_details> list_input_devices();
|
const std::vector<device_details>& list_input_device_types();
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg input devices and available instances of those devices
|
- returns a list of all available ffmpeg input device types (e.g. alsa, v4l2, etc)
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
std::vector<device_details> list_output_devices();
|
const std::vector<device_details>& list_output_device_types();
|
||||||
/*!
|
/*!
|
||||||
ensures
|
ensures
|
||||||
- returns a list of all registered ffmpeg output devices and available instances of those devices
|
- returns a list of all available ffmpeg output device types (e.g. alsa, v4l2, etc)
|
||||||
|
!*/
|
||||||
|
|
||||||
|
std::vector<device_instance> list_input_device_instances(const std::string& device_type);
|
||||||
|
/*!
|
||||||
|
ensures
|
||||||
|
- returns a list of all available ffmpeg input device instances for device type *device_type (e.g. hw:0,0, /dev/video0, etc)
|
||||||
|
!*/
|
||||||
|
|
||||||
|
std::vector<device_instance> list_output_device_instances(const std::string& device_type);
|
||||||
|
/*!
|
||||||
|
ensures
|
||||||
|
- returns a list of all available ffmpeg output device instances for device type *device_type (e.g. hw:0,0, /dev/video0, etc)
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
@ -662,8 +662,6 @@ namespace dlib
|
|||||||
if (!st.args_.enable_audio && !st.args_.enable_image)
|
if (!st.args_.enable_audio && !st.args_.enable_image)
|
||||||
return fail(*st.log, "You need to set at least one of `enable_audio` or `enable_image`");
|
return fail(*st.log, "You need to set at least one of `enable_audio` or `enable_image`");
|
||||||
|
|
||||||
static const auto all_codecs = list_codecs();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
st.connecting_time = system_clock::now();
|
st.connecting_time = system_clock::now();
|
||||||
st.connected_time = system_clock::time_point::max();
|
st.connected_time = system_clock::time_point::max();
|
||||||
@ -723,7 +721,7 @@ namespace dlib
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Before we create the encoder, check the codec is supported by this muxer
|
// Before we create the encoder, check the codec is supported by this muxer
|
||||||
const auto supported_codecs = list_codecs_for_muxer(st.pFormatCtx->oformat, all_codecs);
|
const auto supported_codecs = list_codecs_for_muxer(st.pFormatCtx->oformat);
|
||||||
|
|
||||||
if (std::find_if(begin(supported_codecs), end(supported_codecs), [&](const auto& supported) {
|
if (std::find_if(begin(supported_codecs), end(supported_codecs), [&](const auto& supported) {
|
||||||
return args.args_codec.codec != AV_CODEC_ID_NONE ?
|
return args.args_codec.codec != AV_CODEC_ID_NONE ?
|
||||||
|
@ -360,22 +360,25 @@ namespace dlib
|
|||||||
|
|
||||||
struct device_details
|
struct device_details
|
||||||
{
|
{
|
||||||
struct instance
|
std::string device_type;
|
||||||
|
bool is_audio_type{false};
|
||||||
|
bool is_video_type{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device_instance
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string description;
|
std::string description;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string device_type;
|
const std::vector<std::string>& list_protocols();
|
||||||
std::vector<instance> devices;
|
const std::vector<std::string>& list_demuxers();
|
||||||
};
|
const std::vector<muxer_details>& list_muxers();
|
||||||
|
const std::vector<codec_details>& list_codecs();
|
||||||
std::vector<std::string> list_protocols();
|
const std::vector<device_details>& list_input_device_types();
|
||||||
std::vector<std::string> list_demuxers();
|
const std::vector<device_details>& list_output_device_types();
|
||||||
std::vector<muxer_details> list_muxers();
|
std::vector<device_instance> list_input_device_instances(const std::string& device_type);
|
||||||
std::vector<codec_details> list_codecs();
|
std::vector<device_instance> list_output_device_instances(const std::string& device_type);
|
||||||
std::vector<device_details> list_input_devices();
|
|
||||||
std::vector<device_details> list_output_devices();
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -1185,7 +1188,9 @@ namespace dlib
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<std::string> list_protocols()
|
inline const std::vector<std::string>& list_protocols()
|
||||||
|
{
|
||||||
|
const static auto protocols = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
std::vector<std::string> protocols;
|
std::vector<std::string> protocols;
|
||||||
@ -1200,12 +1205,17 @@ namespace dlib
|
|||||||
while (init && (name = avio_enum_protocols(&opaque, 1)))
|
while (init && (name = avio_enum_protocols(&opaque, 1)))
|
||||||
protocols.emplace_back(name);
|
protocols.emplace_back(name);
|
||||||
|
|
||||||
|
return protocols;
|
||||||
|
}();
|
||||||
|
|
||||||
return protocols;
|
return protocols;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<std::string> list_demuxers()
|
inline const std::vector<std::string>& list_demuxers()
|
||||||
|
{
|
||||||
|
const static auto demuxers = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
std::vector<std::string> demuxers;
|
std::vector<std::string> demuxers;
|
||||||
@ -1220,19 +1230,21 @@ namespace dlib
|
|||||||
#endif
|
#endif
|
||||||
demuxers.push_back(demuxer->name);
|
demuxers.push_back(demuxer->name);
|
||||||
|
|
||||||
|
return demuxers;
|
||||||
|
}();
|
||||||
|
|
||||||
return demuxers;
|
return demuxers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<codec_details> list_codecs_for_muxer (
|
inline std::vector<codec_details> list_codecs_for_muxer (
|
||||||
const AVOutputFormat* oformat,
|
const AVOutputFormat* oformat
|
||||||
const std::vector<codec_details>& all_codecs = list_codecs()
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::vector<codec_details> supported_codecs;
|
std::vector<codec_details> supported_codecs;
|
||||||
|
|
||||||
for (const auto& codec : all_codecs)
|
for (const auto& codec : list_codecs())
|
||||||
if (avformat_query_codec(oformat, codec.codec_id, FF_COMPLIANCE_STRICT) == 1)
|
if (avformat_query_codec(oformat, codec.codec_id, FF_COMPLIANCE_STRICT) == 1)
|
||||||
supported_codecs.push_back(codec);
|
supported_codecs.push_back(codec);
|
||||||
|
|
||||||
@ -1241,12 +1253,12 @@ namespace dlib
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<muxer_details> list_muxers()
|
inline const std::vector<muxer_details>& list_muxers()
|
||||||
|
{
|
||||||
|
const static auto ret = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
|
|
||||||
const auto codecs = list_codecs();
|
|
||||||
|
|
||||||
std::vector<muxer_details> all_details;
|
std::vector<muxer_details> all_details;
|
||||||
const AVOutputFormat* muxer = nullptr;
|
const AVOutputFormat* muxer = nullptr;
|
||||||
|
|
||||||
@ -1260,16 +1272,21 @@ namespace dlib
|
|||||||
{
|
{
|
||||||
muxer_details details;
|
muxer_details details;
|
||||||
details.name = muxer->name;
|
details.name = muxer->name;
|
||||||
details.supported_codecs = list_codecs_for_muxer(muxer, codecs);
|
details.supported_codecs = list_codecs_for_muxer(muxer);
|
||||||
all_details.push_back(details);
|
all_details.push_back(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
return all_details;
|
return all_details;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<codec_details> list_codecs()
|
inline const std::vector<codec_details>& list_codecs()
|
||||||
|
{
|
||||||
|
const static auto ret = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
std::vector<codec_details> details;
|
std::vector<codec_details> details;
|
||||||
@ -1311,11 +1328,16 @@ namespace dlib
|
|||||||
details.erase(std::remove_if(details.begin(), details.end(), [](const auto& d) {return d.codec_name.empty();}), details.end());
|
details.erase(std::remove_if(details.begin(), details.end(), [](const auto& d) {return d.codec_name.empty();}), details.end());
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<device_details> list_input_devices()
|
inline const std::vector<device_details>& list_input_device_types()
|
||||||
|
{
|
||||||
|
const static auto ret = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
std::vector<device_details> devices;
|
std::vector<device_details> devices;
|
||||||
@ -1327,45 +1349,66 @@ namespace dlib
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
AVInputFormatPtr device{nullptr};
|
AVInputFormatPtr device{nullptr};
|
||||||
details::av_ptr<AVDeviceInfoList> managed;
|
|
||||||
|
|
||||||
const auto iter = [&](AVInputFormatPtr device)
|
while (init && (device = av_input_audio_device_next(device)))
|
||||||
{
|
{
|
||||||
device_details details;
|
device_details details;
|
||||||
details.device_type = std::string(device->name);
|
details.device_type = device->name;
|
||||||
|
details.is_audio_type = true;
|
||||||
|
devices.push_back(std::move(details));
|
||||||
|
}
|
||||||
|
|
||||||
|
device = nullptr;
|
||||||
|
|
||||||
|
while (init && (device = av_input_video_device_next(device)))
|
||||||
|
{
|
||||||
|
device_details details;
|
||||||
|
details.device_type = device->name;
|
||||||
|
details.is_video_type = true;
|
||||||
|
devices.push_back(std::move(details));
|
||||||
|
}
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
inline std::vector<device_instance> list_input_device_instances(const std::string& device_type)
|
||||||
|
{
|
||||||
|
const auto& types = list_input_device_types();
|
||||||
|
auto ret = std::find_if(types.begin(), types.end(), [&](const auto& type) {return type.device_type == device_type;});
|
||||||
|
if (ret == types.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<device_instance> instances;
|
||||||
|
|
||||||
|
details::av_ptr<AVDeviceInfoList> managed;
|
||||||
AVDeviceInfoList* device_list = nullptr;
|
AVDeviceInfoList* device_list = nullptr;
|
||||||
avdevice_list_input_sources(device, nullptr, nullptr, &device_list);
|
avdevice_list_input_sources(nullptr, ret->device_type.c_str(), nullptr, &device_list);
|
||||||
managed.reset(device_list);
|
managed.reset(device_list);
|
||||||
|
|
||||||
if (device_list)
|
if (device_list)
|
||||||
{
|
{
|
||||||
for (int i = 0 ; i < device_list->nb_devices ; ++i)
|
for (int i = 0 ; i < device_list->nb_devices ; ++i)
|
||||||
{
|
{
|
||||||
device_details::instance instance;
|
device_instance instance;
|
||||||
instance.name = std::string(device_list->devices[i]->device_name);
|
instance.name = std::string(device_list->devices[i]->device_name);
|
||||||
instance.description = std::string(device_list->devices[i]->device_description);
|
instance.description = std::string(device_list->devices[i]->device_description);
|
||||||
details.devices.push_back(std::move(instance));
|
instances.push_back(std::move(instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
devices.push_back(std::move(details));
|
return instances;
|
||||||
};
|
|
||||||
|
|
||||||
while (init && (device = av_input_audio_device_next(device)))
|
|
||||||
iter(device);
|
|
||||||
|
|
||||||
device = nullptr;
|
|
||||||
|
|
||||||
while (init && (device = av_input_video_device_next(device)))
|
|
||||||
iter(device);
|
|
||||||
|
|
||||||
return devices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline std::vector<device_details> list_output_devices()
|
inline const std::vector<device_details>& list_output_device_types()
|
||||||
|
{
|
||||||
|
const static auto ret = []
|
||||||
{
|
{
|
||||||
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
const bool init = details::register_ffmpeg::get(); // Don't let this get optimized away
|
||||||
std::vector<device_details> devices;
|
std::vector<device_details> devices;
|
||||||
@ -1378,40 +1421,58 @@ namespace dlib
|
|||||||
|
|
||||||
AVOutputFormatPtr device{nullptr};
|
AVOutputFormatPtr device{nullptr};
|
||||||
|
|
||||||
details::av_ptr<AVDeviceInfoList> managed;
|
while (init && (device = av_output_audio_device_next(device)))
|
||||||
|
|
||||||
const auto iter = [&](AVOutputFormatPtr device)
|
|
||||||
{
|
{
|
||||||
device_details details;
|
device_details details;
|
||||||
details.device_type = std::string(device->name);
|
details.device_type = std::string(device->name);
|
||||||
|
details.is_audio_type = true;
|
||||||
|
devices.push_back(std::move(details));
|
||||||
|
}
|
||||||
|
|
||||||
|
device = nullptr;
|
||||||
|
|
||||||
|
while (init && (device = av_output_video_device_next(device)))
|
||||||
|
{
|
||||||
|
device_details details;
|
||||||
|
details.device_type = std::string(device->name);
|
||||||
|
details.is_video_type = true;
|
||||||
|
devices.push_back(std::move(details));
|
||||||
|
}
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::vector<device_instance> list_output_device_instances(const std::string& device_type)
|
||||||
|
{
|
||||||
|
const auto& types = list_output_device_types();
|
||||||
|
auto ret = std::find_if(types.begin(), types.end(), [&](const auto& type) {return type.device_type == device_type;});
|
||||||
|
if (ret == types.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<device_instance> instances;
|
||||||
|
|
||||||
|
details::av_ptr<AVDeviceInfoList> managed;
|
||||||
AVDeviceInfoList* device_list = nullptr;
|
AVDeviceInfoList* device_list = nullptr;
|
||||||
avdevice_list_output_sinks(device, nullptr, nullptr, &device_list);
|
avdevice_list_output_sinks(nullptr, ret->device_type.c_str(), nullptr, &device_list);
|
||||||
managed.reset(device_list);
|
managed.reset(device_list);
|
||||||
|
|
||||||
if (device_list)
|
if (device_list)
|
||||||
{
|
{
|
||||||
for (int i = 0 ; i < device_list->nb_devices ; ++i)
|
for (int i = 0 ; i < device_list->nb_devices ; ++i)
|
||||||
{
|
{
|
||||||
device_details::instance instance;
|
device_instance instance;
|
||||||
instance.name = std::string(device_list->devices[i]->device_name);
|
instance.name = std::string(device_list->devices[i]->device_name);
|
||||||
instance.description = std::string(device_list->devices[i]->device_description);
|
instance.description = std::string(device_list->devices[i]->device_description);
|
||||||
details.devices.push_back(std::move(instance));
|
instances.push_back(std::move(instance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
devices.push_back(std::move(details));
|
return instances;
|
||||||
};
|
|
||||||
|
|
||||||
while (init && (device = av_output_audio_device_next(device)))
|
|
||||||
iter(device);
|
|
||||||
|
|
||||||
device = nullptr;
|
|
||||||
|
|
||||||
while (init && (device = av_output_video_device_next(device)))
|
|
||||||
iter(device);
|
|
||||||
|
|
||||||
return devices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------
|
||||||
|
@ -49,13 +49,15 @@ int main()
|
|||||||
|
|
||||||
// List all input devices supported by this installation of ffmpeg libraries
|
// List all input devices supported by this installation of ffmpeg libraries
|
||||||
cout << "Supported input devices:\n";
|
cout << "Supported input devices:\n";
|
||||||
for (const auto& device : ffmpeg::list_input_devices())
|
for (const auto& device : ffmpeg::list_input_device_types())
|
||||||
{
|
{
|
||||||
cout << " device type : " << device.device_type << '\n';
|
cout << " device type : `" << device.device_type << "` is audio " << device.is_audio_type << " is video " << device.is_video_type << '\n';
|
||||||
if (!device.devices.empty())
|
|
||||||
|
const auto instances = ffmpeg::list_input_device_instances(device.device_type);
|
||||||
|
if (!instances.empty())
|
||||||
{
|
{
|
||||||
cout << " instances :\n";
|
cout << " instances :\n";
|
||||||
for (const auto& instance : device.devices)
|
for (const auto& instance : instances)
|
||||||
cout << " name : " << left << setw(32) << instance.name << ", description : " << instance.description << '\n';
|
cout << " name : " << left << setw(32) << instance.name << ", description : " << instance.description << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,13 +66,15 @@ int main()
|
|||||||
|
|
||||||
// List all input devices supported by this installation of ffmpeg libraries
|
// List all input devices supported by this installation of ffmpeg libraries
|
||||||
cout << "Supported output devices:\n";
|
cout << "Supported output devices:\n";
|
||||||
for (const auto& device : ffmpeg::list_output_devices())
|
for (const auto& device : ffmpeg::list_output_device_types())
|
||||||
{
|
{
|
||||||
cout << " device type : " << device.device_type << '\n';
|
cout << " device type : `" << device.device_type << "` is audio " << device.is_audio_type << " is video " << device.is_video_type << '\n';
|
||||||
if (!device.devices.empty())
|
|
||||||
|
const auto instances = ffmpeg::list_output_device_instances(device.device_type);
|
||||||
|
if (!instances.empty())
|
||||||
{
|
{
|
||||||
cout << " instances :\n";
|
cout << " instances :\n";
|
||||||
for (const auto& instance : device.devices)
|
for (const auto& instance : instances)
|
||||||
cout << " name : " << left << setw(32) << instance.name << ", description : " << instance.description << '\n';
|
cout << " name : " << left << setw(32) << instance.name << ", description : " << instance.description << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user