Message ID | 20170926160623.1257-3-dheitmueller@ltnglobal.com |
---|---|
State | Superseded |
Headers | show |
On Tue, 26 Sep 2017, Devin Heitmueller wrote: > Add support for enumerating the sources/sinks via the ffmpeg > command line options, as opposed to having to create a real pipeline > and use the "-list_devices" option which does exit() after dumping > out the options. > > Note that this patch preserves the existing "-list_devices" option, > but now shares common code for the actual enumeration. > > Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com> > --- > libavdevice/decklink_common.cpp | 52 +++++++++++++++++++++++++++++++++++++---- > libavdevice/decklink_common.h | 2 +- > libavdevice/decklink_dec.cpp | 22 ++++++++++++++++- > libavdevice/decklink_dec.h | 1 + > libavdevice/decklink_dec_c.c | 1 + > libavdevice/decklink_enc.cpp | 22 ++++++++++++++++- > libavdevice/decklink_enc.h | 1 + > libavdevice/decklink_enc_c.c | 1 + > 8 files changed, 95 insertions(+), 7 deletions(-) > > diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp > index 7745575d0e..86d6fbb74b 100644 > --- a/libavdevice/decklink_common.cpp > +++ b/libavdevice/decklink_common.cpp > @@ -37,6 +37,7 @@ extern "C" { > #include "libavutil/imgutils.h" > #include "libavutil/intreadwrite.h" > #include "libavutil/bswap.h" > +#include "avdevice.h" > } > > #include "decklink_common.h" > @@ -261,24 +262,67 @@ int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t directio > return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num); > } > > -int ff_decklink_list_devices(AVFormatContext *avctx) > +int ff_decklink_list_devices(AVFormatContext *avctx, > + struct AVDeviceInfoList *device_list, > + int show_inputs, int show_outputs) > { > IDeckLink *dl = NULL; > IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); > + int ret = 0; > + > if (!iter) { > av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); > return AVERROR(EIO); > } > - av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n"); > + > while (iter->Next(&dl) == S_OK) { This probably needs an additional && ret == 0 condition, if there was an ENOMEM error, you want to return instantly instead of trying with the next device, and ignoring the ENOMEM. > + IDeckLinkOutput *output_config; > + IDeckLinkInput *input_config; > const char *displayName; > + AVDeviceInfo *new_device = NULL; > + int add = 0; > + > ff_decklink_get_display_name(dl, &displayName); > - av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); > + > + if (show_outputs) { > + if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { > + output_config->Release(); > + add = 1; > + } > + } > + > + if (show_inputs) { > + if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) == S_OK) { > + input_config->Release(); > + add = 1; > + } > + } > + > + if (add == 1) { > + new_device = (AVDeviceInfo *) av_mallocz(sizeof(AVDeviceInfo)); > + if (!new_device) { > + ret = AVERROR(ENOMEM); > + goto next; > + } > + new_device->device_name = av_strdup(displayName); > + new_device->device_description = av_strdup(displayName); > + if (!new_device->device_description || !new_device->device_name) { you might leak device_name here. > + ret = AVERROR(ENOMEM); > + goto next; > + } > + > + if ((ret = av_dynarray_add_nofree(&device_list->devices, > + &device_list->nb_devices, new_device)) < 0) { you should free the struct on error here I think > + goto next; > + } > + } > + > + next: > av_free((void *) displayName); av_freep > dl->Release(); > } > iter->Release(); > - return 0; > + return ret; > } > > int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) > diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h > index 749eb0f8b8..f81b33ada4 100644 > --- a/libavdevice/decklink_common.h > +++ b/libavdevice/decklink_common.h > @@ -135,7 +135,7 @@ static const BMDVideoConnection decklink_video_connection_map[] = { > HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); > int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); > int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); > -int ff_decklink_list_devices(AVFormatContext *avctx); > +int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list, int show_inputs, int show_outputs); > int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT); > void ff_decklink_cleanup(AVFormatContext *avctx); > int ff_decklink_init_device(AVFormatContext *avctx, const char* name); > diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp > index c271ff3639..cb282055c6 100644 > --- a/libavdevice/decklink_dec.cpp > +++ b/libavdevice/decklink_dec.cpp > @@ -38,6 +38,7 @@ extern "C" { > #include "libavutil/time.h" > #include "libavutil/mathematics.h" > #include "libavutil/reverse.h" > +#include "avdevice.h" > #if CONFIG_LIBZVBI > #include <libzvbi.h> > #endif > @@ -647,7 +648,21 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) > > /* List available devices. */ > if (ctx->list_devices) { > - ff_decklink_list_devices(avctx); > + struct AVDeviceInfoList *device_list = NULL; > + int ret; > + > + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); > + if (!device_list) > + return AVERROR(ENOMEM); > + > + ret = ff_decklink_list_devices(avctx, device_list, 1, 0); > + if (ret == 0) { > + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink input devices:\n"); > + for (int i = 0; i < device_list->nb_devices; i++) { > + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); > + } > + } > + avdevice_free_list_devices(&device_list); > return AVERROR_EXIT; > } > > @@ -810,4 +825,9 @@ int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt) > return 0; > } > > +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) > +{ > + return ff_decklink_list_devices(avctx, device_list, 1, 0); > +} > + > } /* extern "C" */ > diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h > index 9b71870deb..fbfbe6280e 100644 > --- a/libavdevice/decklink_dec.h > +++ b/libavdevice/decklink_dec.h > @@ -29,6 +29,7 @@ extern "C" { > int ff_decklink_read_header(AVFormatContext *avctx); > int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt); > int ff_decklink_read_close(AVFormatContext *avctx); > +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); > > #ifdef __cplusplus > } /* extern "C" */ > diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c > index e2118a619c..992c21a160 100644 > --- a/libavdevice/decklink_dec_c.c > +++ b/libavdevice/decklink_dec_c.c > @@ -83,6 +83,7 @@ AVInputFormat ff_decklink_demuxer = { > .flags = AVFMT_NOFILE, > .priv_class = &decklink_demuxer_class, > .priv_data_size = sizeof(struct decklink_cctx), > + .get_device_list = ff_decklink_list_input_devices, > .read_header = ff_decklink_read_header, > .read_packet = ff_decklink_read_packet, > .read_close = ff_decklink_read_close, > diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp > index 25ce7d026c..0f654faa19 100644 > --- a/libavdevice/decklink_enc.cpp > +++ b/libavdevice/decklink_enc.cpp > @@ -33,6 +33,7 @@ extern "C" { > extern "C" { > #include "libavformat/avformat.h" > #include "libavutil/imgutils.h" > +#include "avdevice.h" > } > > #include "decklink_common.h" > @@ -337,7 +338,21 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) > > /* List available devices. */ > if (ctx->list_devices) { > - ff_decklink_list_devices(avctx); > + struct AVDeviceInfoList *device_list = NULL; > + int ret; > + > + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); > + if (!device_list) > + return AVERROR(ENOMEM); > + > + ret = ff_decklink_list_devices(avctx, device_list, 0, 1); > + if (ret == 0) { > + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink output devices:\n"); > + for (int i = 0; i < device_list->nb_devices; i++) { > + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); > + } > + } > + avdevice_free_list_devices(&device_list); This code can be factorized among input and output. > return AVERROR_EXIT; > } > > @@ -400,4 +415,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) > return AVERROR(EIO); > } > > +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) > +{ > + return ff_decklink_list_devices(avctx, device_list, 0, 1); > +} > + > } /* extern "C" */ > diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h > index 5ffc05cd68..39237673b4 100644 > --- a/libavdevice/decklink_enc.h > +++ b/libavdevice/decklink_enc.h > @@ -29,6 +29,7 @@ extern "C" { > int ff_decklink_write_header(AVFormatContext *avctx); > int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt); > int ff_decklink_write_trailer(AVFormatContext *avctx); > +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); > > #ifdef __cplusplus > } /* extern "C" */ > diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c > index 03734f8507..360535cfda 100644 > --- a/libavdevice/decklink_enc_c.c > +++ b/libavdevice/decklink_enc_c.c > @@ -49,6 +49,7 @@ AVOutputFormat ff_decklink_muxer = { > .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, > .subtitle_codec = AV_CODEC_ID_NONE, > .flags = AVFMT_NOFILE, > + .get_device_list = ff_decklink_list_output_devices, > .priv_class = &decklink_muxer_class, > .priv_data_size = sizeof(struct decklink_cctx), > .write_header = ff_decklink_write_header, > -- > 2.13.2 > Regards, Marton
> On Sep 30, 2017, at 4:02 PM, Marton Balint <cus@passwd.hu> wrote: > > > > On Tue, 26 Sep 2017, Devin Heitmueller wrote: > >> Add support for enumerating the sources/sinks via the ffmpeg >> command line options, as opposed to having to create a real pipeline >> and use the "-list_devices" option which does exit() after dumping >> out the options. >> >> Note that this patch preserves the existing "-list_devices" option, >> but now shares common code for the actual enumeration. >> >> Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com> >> --- >> libavdevice/decklink_common.cpp | 52 +++++++++++++++++++++++++++++++++++++---- >> libavdevice/decklink_common.h | 2 +- >> libavdevice/decklink_dec.cpp | 22 ++++++++++++++++- >> libavdevice/decklink_dec.h | 1 + >> libavdevice/decklink_dec_c.c | 1 + >> libavdevice/decklink_enc.cpp | 22 ++++++++++++++++- >> libavdevice/decklink_enc.h | 1 + >> libavdevice/decklink_enc_c.c | 1 + >> 8 files changed, 95 insertions(+), 7 deletions(-) >> >> diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp >> index 7745575d0e..86d6fbb74b 100644 >> --- a/libavdevice/decklink_common.cpp >> +++ b/libavdevice/decklink_common.cpp >> @@ -37,6 +37,7 @@ extern "C" { >> #include "libavutil/imgutils.h" >> #include "libavutil/intreadwrite.h" >> #include "libavutil/bswap.h" >> +#include "avdevice.h" >> } >> #include "decklink_common.h" >> @@ -261,24 +262,67 @@ int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t directio >> return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num); >> } >> -int ff_decklink_list_devices(AVFormatContext *avctx) >> +int ff_decklink_list_devices(AVFormatContext *avctx, >> + struct AVDeviceInfoList *device_list, >> + int show_inputs, int show_outputs) >> { >> IDeckLink *dl = NULL; >> IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); >> + int ret = 0; >> + >> if (!iter) { >> av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); >> return AVERROR(EIO); >> } >> - av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n"); >> + >> while (iter->Next(&dl) == S_OK) { > > This probably needs an additional && ret == 0 condition, if there was an ENOMEM error, you want to return instantly instead of trying with the next device, and ignoring the ENOMEM. > >> + IDeckLinkOutput *output_config; >> + IDeckLinkInput *input_config; >> const char *displayName; >> + AVDeviceInfo *new_device = NULL; >> + int add = 0; >> + >> ff_decklink_get_display_name(dl, &displayName); >> - av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); >> + >> + if (show_outputs) { >> + if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { >> + output_config->Release(); >> + add = 1; >> + } >> + } >> + >> + if (show_inputs) { >> + if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) == S_OK) { >> + input_config->Release(); >> + add = 1; >> + } >> + } >> + >> + if (add == 1) { >> + new_device = (AVDeviceInfo *) av_mallocz(sizeof(AVDeviceInfo)); >> + if (!new_device) { >> + ret = AVERROR(ENOMEM); >> + goto next; >> + } >> + new_device->device_name = av_strdup(displayName); >> + new_device->device_description = av_strdup(displayName); >> + if (!new_device->device_description || !new_device->device_name) { > > you might leak device_name here. > >> + ret = AVERROR(ENOMEM); >> + goto next; >> + } >> + >> + if ((ret = av_dynarray_add_nofree(&device_list->devices, >> + &device_list->nb_devices, new_device)) < 0) { > > you should free the struct on error here I think > >> + goto next; >> + } >> + } >> + >> + next: >> av_free((void *) displayName); > > av_freep > >> dl->Release(); >> } >> iter->Release(); >> - return 0; >> + return ret; >> } >> int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) >> diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h >> index 749eb0f8b8..f81b33ada4 100644 >> --- a/libavdevice/decklink_common.h >> +++ b/libavdevice/decklink_common.h >> @@ -135,7 +135,7 @@ static const BMDVideoConnection decklink_video_connection_map[] = { >> HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); >> int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); >> int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); >> -int ff_decklink_list_devices(AVFormatContext *avctx); >> +int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list, int show_inputs, int show_outputs); >> int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT); >> void ff_decklink_cleanup(AVFormatContext *avctx); >> int ff_decklink_init_device(AVFormatContext *avctx, const char* name); >> diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp >> index c271ff3639..cb282055c6 100644 >> --- a/libavdevice/decklink_dec.cpp >> +++ b/libavdevice/decklink_dec.cpp >> @@ -38,6 +38,7 @@ extern "C" { >> #include "libavutil/time.h" >> #include "libavutil/mathematics.h" >> #include "libavutil/reverse.h" >> +#include "avdevice.h" >> #if CONFIG_LIBZVBI >> #include <libzvbi.h> >> #endif >> @@ -647,7 +648,21 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) >> >> /* List available devices. */ >> if (ctx->list_devices) { >> - ff_decklink_list_devices(avctx); >> + struct AVDeviceInfoList *device_list = NULL; >> + int ret; >> + >> + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); >> + if (!device_list) >> + return AVERROR(ENOMEM); >> + >> + ret = ff_decklink_list_devices(avctx, device_list, 1, 0); >> + if (ret == 0) { >> + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink input devices:\n"); >> + for (int i = 0; i < device_list->nb_devices; i++) { >> + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); >> + } >> + } >> + avdevice_free_list_devices(&device_list); >> return AVERROR_EXIT; >> } >> @@ -810,4 +825,9 @@ int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt) >> return 0; >> } >> +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) >> +{ >> + return ff_decklink_list_devices(avctx, device_list, 1, 0); >> +} >> + >> } /* extern "C" */ >> diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h >> index 9b71870deb..fbfbe6280e 100644 >> --- a/libavdevice/decklink_dec.h >> +++ b/libavdevice/decklink_dec.h >> @@ -29,6 +29,7 @@ extern "C" { >> int ff_decklink_read_header(AVFormatContext *avctx); >> int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt); >> int ff_decklink_read_close(AVFormatContext *avctx); >> +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); >> #ifdef __cplusplus >> } /* extern "C" */ >> diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c >> index e2118a619c..992c21a160 100644 >> --- a/libavdevice/decklink_dec_c.c >> +++ b/libavdevice/decklink_dec_c.c >> @@ -83,6 +83,7 @@ AVInputFormat ff_decklink_demuxer = { >> .flags = AVFMT_NOFILE, >> .priv_class = &decklink_demuxer_class, >> .priv_data_size = sizeof(struct decklink_cctx), >> + .get_device_list = ff_decklink_list_input_devices, >> .read_header = ff_decklink_read_header, >> .read_packet = ff_decklink_read_packet, >> .read_close = ff_decklink_read_close, >> diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp >> index 25ce7d026c..0f654faa19 100644 >> --- a/libavdevice/decklink_enc.cpp >> +++ b/libavdevice/decklink_enc.cpp >> @@ -33,6 +33,7 @@ extern "C" { >> extern "C" { >> #include "libavformat/avformat.h" >> #include "libavutil/imgutils.h" >> +#include "avdevice.h" >> } >> #include "decklink_common.h" >> @@ -337,7 +338,21 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) >> >> /* List available devices. */ >> if (ctx->list_devices) { >> - ff_decklink_list_devices(avctx); >> + struct AVDeviceInfoList *device_list = NULL; >> + int ret; >> + >> + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); >> + if (!device_list) >> + return AVERROR(ENOMEM); >> + >> + ret = ff_decklink_list_devices(avctx, device_list, 0, 1); >> + if (ret == 0) { >> + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink output devices:\n"); >> + for (int i = 0; i < device_list->nb_devices; i++) { >> + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); >> + } >> + } >> + avdevice_free_list_devices(&device_list); > > This code can be factorized among input and output. > >> return AVERROR_EXIT; >> } >> @@ -400,4 +415,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) >> return AVERROR(EIO); >> } >> +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) >> +{ >> + return ff_decklink_list_devices(avctx, device_list, 0, 1); >> +} >> + >> } /* extern "C" */ >> diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h >> index 5ffc05cd68..39237673b4 100644 >> --- a/libavdevice/decklink_enc.h >> +++ b/libavdevice/decklink_enc.h >> @@ -29,6 +29,7 @@ extern "C" { >> int ff_decklink_write_header(AVFormatContext *avctx); >> int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt); >> int ff_decklink_write_trailer(AVFormatContext *avctx); >> +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); >> #ifdef __cplusplus >> } /* extern "C" */ >> diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c >> index 03734f8507..360535cfda 100644 >> --- a/libavdevice/decklink_enc_c.c >> +++ b/libavdevice/decklink_enc_c.c >> @@ -49,6 +49,7 @@ AVOutputFormat ff_decklink_muxer = { >> .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, >> .subtitle_codec = AV_CODEC_ID_NONE, >> .flags = AVFMT_NOFILE, >> + .get_device_list = ff_decklink_list_output_devices, >> .priv_class = &decklink_muxer_class, >> .priv_data_size = sizeof(struct decklink_cctx), >> .write_header = ff_decklink_write_header, >> -- >> 2.13.2 >> > > Regards, > Marton Sorry for the delayed reply. I will submit updated patches this week that reflect the changes you have requested. Thanks, Devin
diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index 7745575d0e..86d6fbb74b 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -37,6 +37,7 @@ extern "C" { #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/bswap.h" +#include "avdevice.h" } #include "decklink_common.h" @@ -261,24 +262,67 @@ int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t directio return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num); } -int ff_decklink_list_devices(AVFormatContext *avctx) +int ff_decklink_list_devices(AVFormatContext *avctx, + struct AVDeviceInfoList *device_list, + int show_inputs, int show_outputs) { IDeckLink *dl = NULL; IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); + int ret = 0; + if (!iter) { av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); return AVERROR(EIO); } - av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n"); + while (iter->Next(&dl) == S_OK) { + IDeckLinkOutput *output_config; + IDeckLinkInput *input_config; const char *displayName; + AVDeviceInfo *new_device = NULL; + int add = 0; + ff_decklink_get_display_name(dl, &displayName); - av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); + + if (show_outputs) { + if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { + output_config->Release(); + add = 1; + } + } + + if (show_inputs) { + if (dl->QueryInterface(IID_IDeckLinkInput, (void **)&input_config) == S_OK) { + input_config->Release(); + add = 1; + } + } + + if (add == 1) { + new_device = (AVDeviceInfo *) av_mallocz(sizeof(AVDeviceInfo)); + if (!new_device) { + ret = AVERROR(ENOMEM); + goto next; + } + new_device->device_name = av_strdup(displayName); + new_device->device_description = av_strdup(displayName); + if (!new_device->device_description || !new_device->device_name) { + ret = AVERROR(ENOMEM); + goto next; + } + + if ((ret = av_dynarray_add_nofree(&device_list->devices, + &device_list->nb_devices, new_device)) < 0) { + goto next; + } + } + + next: av_free((void *) displayName); dl->Release(); } iter->Release(); - return 0; + return ret; } int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 749eb0f8b8..f81b33ada4 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -135,7 +135,7 @@ static const BMDVideoConnection decklink_video_connection_map[] = { HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); -int ff_decklink_list_devices(AVFormatContext *avctx); +int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list, int show_inputs, int show_outputs); int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT); void ff_decklink_cleanup(AVFormatContext *avctx); int ff_decklink_init_device(AVFormatContext *avctx, const char* name); diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index c271ff3639..cb282055c6 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -38,6 +38,7 @@ extern "C" { #include "libavutil/time.h" #include "libavutil/mathematics.h" #include "libavutil/reverse.h" +#include "avdevice.h" #if CONFIG_LIBZVBI #include <libzvbi.h> #endif @@ -647,7 +648,21 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) /* List available devices. */ if (ctx->list_devices) { - ff_decklink_list_devices(avctx); + struct AVDeviceInfoList *device_list = NULL; + int ret; + + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); + if (!device_list) + return AVERROR(ENOMEM); + + ret = ff_decklink_list_devices(avctx, device_list, 1, 0); + if (ret == 0) { + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink input devices:\n"); + for (int i = 0; i < device_list->nb_devices; i++) { + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); + } + } + avdevice_free_list_devices(&device_list); return AVERROR_EXIT; } @@ -810,4 +825,9 @@ int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt) return 0; } +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) +{ + return ff_decklink_list_devices(avctx, device_list, 1, 0); +} + } /* extern "C" */ diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h index 9b71870deb..fbfbe6280e 100644 --- a/libavdevice/decklink_dec.h +++ b/libavdevice/decklink_dec.h @@ -29,6 +29,7 @@ extern "C" { int ff_decklink_read_header(AVFormatContext *avctx); int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt); int ff_decklink_read_close(AVFormatContext *avctx); +int ff_decklink_list_input_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); #ifdef __cplusplus } /* extern "C" */ diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index e2118a619c..992c21a160 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -83,6 +83,7 @@ AVInputFormat ff_decklink_demuxer = { .flags = AVFMT_NOFILE, .priv_class = &decklink_demuxer_class, .priv_data_size = sizeof(struct decklink_cctx), + .get_device_list = ff_decklink_list_input_devices, .read_header = ff_decklink_read_header, .read_packet = ff_decklink_read_packet, .read_close = ff_decklink_read_close, diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index 25ce7d026c..0f654faa19 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -33,6 +33,7 @@ extern "C" { extern "C" { #include "libavformat/avformat.h" #include "libavutil/imgutils.h" +#include "avdevice.h" } #include "decklink_common.h" @@ -337,7 +338,21 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) /* List available devices. */ if (ctx->list_devices) { - ff_decklink_list_devices(avctx); + struct AVDeviceInfoList *device_list = NULL; + int ret; + + device_list = (struct AVDeviceInfoList *) av_mallocz(sizeof(AVDeviceInfoList)); + if (!device_list) + return AVERROR(ENOMEM); + + ret = ff_decklink_list_devices(avctx, device_list, 0, 1); + if (ret == 0) { + av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink output devices:\n"); + for (int i = 0; i < device_list->nb_devices; i++) { + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); + } + } + avdevice_free_list_devices(&device_list); return AVERROR_EXIT; } @@ -400,4 +415,9 @@ int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) return AVERROR(EIO); } +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list) +{ + return ff_decklink_list_devices(avctx, device_list, 0, 1); +} + } /* extern "C" */ diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h index 5ffc05cd68..39237673b4 100644 --- a/libavdevice/decklink_enc.h +++ b/libavdevice/decklink_enc.h @@ -29,6 +29,7 @@ extern "C" { int ff_decklink_write_header(AVFormatContext *avctx); int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt); int ff_decklink_write_trailer(AVFormatContext *avctx); +int ff_decklink_list_output_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list); #ifdef __cplusplus } /* extern "C" */ diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c index 03734f8507..360535cfda 100644 --- a/libavdevice/decklink_enc_c.c +++ b/libavdevice/decklink_enc_c.c @@ -49,6 +49,7 @@ AVOutputFormat ff_decklink_muxer = { .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME, .subtitle_codec = AV_CODEC_ID_NONE, .flags = AVFMT_NOFILE, + .get_device_list = ff_decklink_list_output_devices, .priv_class = &decklink_muxer_class, .priv_data_size = sizeof(struct decklink_cctx), .write_header = ff_decklink_write_header,
Add support for enumerating the sources/sinks via the ffmpeg command line options, as opposed to having to create a real pipeline and use the "-list_devices" option which does exit() after dumping out the options. Note that this patch preserves the existing "-list_devices" option, but now shares common code for the actual enumeration. Signed-off-by: Devin Heitmueller <dheitmueller@ltnglobal.com> --- libavdevice/decklink_common.cpp | 52 +++++++++++++++++++++++++++++++++++++---- libavdevice/decklink_common.h | 2 +- libavdevice/decklink_dec.cpp | 22 ++++++++++++++++- libavdevice/decklink_dec.h | 1 + libavdevice/decklink_dec_c.c | 1 + libavdevice/decklink_enc.cpp | 22 ++++++++++++++++- libavdevice/decklink_enc.h | 1 + libavdevice/decklink_enc_c.c | 1 + 8 files changed, 95 insertions(+), 7 deletions(-)