diff mbox

[FFmpeg-devel,2/4] libavdevice/decklink: add support for -sources and -sinks arguments

Message ID 20170926160623.1257-3-dheitmueller@ltnglobal.com
State Superseded
Headers show

Commit Message

Devin Heitmueller Sept. 26, 2017, 4:06 p.m. UTC
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(-)

Comments

Marton Balint Sept. 30, 2017, 8:02 p.m. UTC | #1
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
Devin Heitmueller Oct. 4, 2017, 8:56 p.m. UTC | #2
> 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 mbox

Patch

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,