2014-09-22 01:39:50 +02:00
/*
* Blackmagic DeckLink output
* Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2017-05-05 17:59:21 -07:00
/* Include internal.h first to avoid conflict between winsock.h (used by
* DeckLink headers) and winsock2.h (used by libavformat) in MSVC++ builds */
extern "C" {
#include "libavformat/internal.h"
}
2014-09-22 01:39:50 +02:00
#include <DeckLinkAPI.h>
#ifdef _WIN32
#include <DeckLinkAPI_i.c>
#else
2018-01-08 20:16:58 -05:00
/* The file provided by the SDK is known to be missing prototypes, which doesn't
cause issues with GCC since the warning doesn't apply to C++ files. However
Clang does complain (and warnings are treated as errors), so suppress the
warning just for this one file */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#endif
2014-09-22 01:39:50 +02:00
#include <DeckLinkAPIDispatch.cpp>
2018-01-08 20:16:58 -05:00
#ifdef __clang__
#pragma clang diagnostic pop
#endif
2014-09-22 01:39:50 +02:00
#endif
extern "C" {
2016-01-24 12:42:39 -08:00
#include "libavformat/avformat.h"
2014-09-22 01:39:50 +02:00
#include "libavutil/imgutils.h"
2017-03-20 00:16:37 +01:00
#include "libavutil/intreadwrite.h"
2017-03-20 00:16:36 +01:00
#include "libavutil/bswap.h"
2017-10-06 08:55:43 -04:00
#include "avdevice.h"
2014-09-22 01:39:50 +02:00
}
#include "decklink_common.h"
2018-04-15 00:06:59 +02:00
static IDeckLinkIterator * decklink_create_iterator ( AVFormatContext * avctx )
2014-09-22 01:39:50 +02:00
{
IDeckLinkIterator * iter ;
2018-04-15 00:06:59 +02:00
#ifdef _WIN32
2014-12-03 16:41:41 +01:00
if ( CoInitialize ( NULL ) < 0 ) {
2018-04-15 00:06:59 +02:00
av_log ( avctx , AV_LOG_ERROR , "COM initialization failed. \n " );
2014-09-22 01:39:50 +02:00
return NULL ;
}
if ( CoCreateInstance ( CLSID_CDeckLinkIterator , NULL , CLSCTX_ALL ,
IID_IDeckLinkIterator , ( void ** ) & iter ) != S_OK ) {
2018-04-15 00:06:59 +02:00
iter = NULL ;
2014-09-22 01:39:50 +02:00
}
2018-04-15 00:06:59 +02:00
#else
iter = CreateDeckLinkIteratorInstance ();
#endif
if ( ! iter )
av_log ( avctx , AV_LOG_ERROR , "Could not create DeckLink iterator. "
"Make sure you have DeckLink drivers " BLACKMAGIC_DECKLINK_API_VERSION_STRING " or newer installed. \n " );
2014-09-22 01:39:50 +02:00
return iter ;
}
2018-10-19 15:35:48 -04:00
static int decklink_get_attr_string ( IDeckLink * dl , BMDDeckLinkAttributeID cfg_id , const char ** s )
2014-09-22 01:39:50 +02:00
{
2018-09-20 23:56:00 +02:00
DECKLINK_STR tmp ;
HRESULT hr ;
2019-03-14 01:37:11 +01:00
IDeckLinkProfileAttributes * attr ;
2018-09-20 23:56:00 +02:00
* s = NULL ;
2019-03-14 01:37:11 +01:00
if ( dl -> QueryInterface ( IID_IDeckLinkProfileAttributes , ( void ** ) & attr ) != S_OK )
2018-09-20 23:56:00 +02:00
return AVERROR_EXTERNAL ;
hr = attr -> GetString ( cfg_id , & tmp );
attr -> Release ();
if ( hr == S_OK ) {
* s = DECKLINK_STRDUP ( tmp );
DECKLINK_FREE ( tmp );
if ( !* s )
return AVERROR ( ENOMEM );
} else if ( hr == E_FAIL ) {
return AVERROR_EXTERNAL ;
}
return 0 ;
2014-09-22 01:39:50 +02:00
}
2016-06-18 12:04:15 +02:00
static int decklink_select_input ( AVFormatContext * avctx , BMDDeckLinkConfigurationID cfg_id )
{
2016-08-02 22:46:28 -07:00
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
2016-06-18 12:04:15 +02:00
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
BMDDeckLinkAttributeID attr_id = ( cfg_id == bmdDeckLinkConfigAudioInputConnection ) ? BMDDeckLinkAudioInputConnections : BMDDeckLinkVideoInputConnections ;
2016-06-27 01:11:50 +02:00
int64_t bmd_input = ( cfg_id == bmdDeckLinkConfigAudioInputConnection ) ? ( int64_t ) ctx -> audio_input : ( int64_t ) ctx -> video_input ;
2016-06-18 12:04:15 +02:00
const char * type_name = ( cfg_id == bmdDeckLinkConfigAudioInputConnection ) ? "audio" : "video" ;
int64_t supported_connections = 0 ;
HRESULT res ;
if ( bmd_input ) {
res = ctx -> attr -> GetInt ( attr_id , & supported_connections );
if ( res != S_OK ) {
av_log ( avctx , AV_LOG_ERROR , "Failed to query supported %s inputs. \n " , type_name );
return AVERROR_EXTERNAL ;
}
if (( supported_connections & bmd_input ) != bmd_input ) {
av_log ( avctx , AV_LOG_ERROR , "Device does not support selected %s input. \n " , type_name );
return AVERROR ( ENOSYS );
}
res = ctx -> cfg -> SetInt ( cfg_id , bmd_input );
if ( res != S_OK ) {
av_log ( avctx , AV_LOG_ERROR , "Failed to select %s input. \n " , type_name );
return AVERROR_EXTERNAL ;
}
}
return 0 ;
}
2017-02-18 02:33:05 +01:00
static DECKLINK_BOOL field_order_eq ( enum AVFieldOrder field_order , BMDFieldDominance bmd_field_order )
{
if ( field_order == AV_FIELD_UNKNOWN )
return true ;
if (( field_order == AV_FIELD_TT || field_order == AV_FIELD_TB ) && bmd_field_order == bmdUpperFieldFirst )
return true ;
if (( field_order == AV_FIELD_BB || field_order == AV_FIELD_BT ) && bmd_field_order == bmdLowerFieldFirst )
return true ;
if ( field_order == AV_FIELD_PROGRESSIVE && ( bmd_field_order == bmdProgressiveFrame || bmd_field_order == bmdProgressiveSegmentedFrame ))
return true ;
return false ;
}
2017-11-07 09:32:23 +05:30
int ff_decklink_set_configs ( AVFormatContext * avctx ,
decklink_direction_t direction ) {
2016-08-02 22:46:28 -07:00
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
2014-09-22 01:39:50 +02:00
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
HRESULT res ;
2016-06-11 13:41:29 +02:00
if ( ctx -> duplex_mode ) {
2016-06-27 01:11:50 +02:00
DECKLINK_BOOL duplex_supported = false ;
2016-06-11 13:41:29 +02:00
2019-03-14 01:37:11 +01:00
#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
IDeckLinkProfileManager * manager = NULL ;
if ( ctx -> dl -> QueryInterface ( IID_IDeckLinkProfileManager , ( void ** ) & manager ) == S_OK )
duplex_supported = true ;
#else
2016-06-11 13:41:29 +02:00
if ( ctx -> attr -> GetFlag ( BMDDeckLinkSupportsDuplexModeConfiguration , & duplex_supported ) != S_OK )
duplex_supported = false ;
2019-03-14 01:37:11 +01:00
#endif
2016-06-11 13:41:29 +02:00
if ( duplex_supported ) {
2019-03-14 01:37:11 +01:00
#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
IDeckLinkProfile * profile = NULL ;
BMDProfileID bmd_profile_id = ctx -> duplex_mode == 2 ? bmdProfileOneSubDeviceFullDuplex : bmdProfileTwoSubDevicesHalfDuplex ;
res = manager -> GetProfile ( bmd_profile_id , & profile );
if ( res == S_OK ) {
res = profile -> SetActive ();
profile -> Release ();
}
manager -> Release ();
#else
2016-06-11 13:41:29 +02:00
res = ctx -> cfg -> SetInt ( bmdDeckLinkConfigDuplexMode , ctx -> duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf );
2019-03-14 01:37:11 +01:00
#endif
2016-06-11 13:41:29 +02:00
if ( res != S_OK )
av_log ( avctx , AV_LOG_WARNING , "Setting duplex mode failed. \n " );
else
2016-06-28 03:06:25 +02:00
av_log ( avctx , AV_LOG_VERBOSE , "Successfully set duplex mode to %s duplex. \n " , ctx -> duplex_mode == 2 ? "full" : "half" );
2016-06-11 13:41:29 +02:00
} else {
av_log ( avctx , AV_LOG_WARNING , "Unable to set duplex mode, because it is not supported. \n " );
}
}
2014-09-22 01:39:50 +02:00
if ( direction == DIRECTION_IN ) {
2016-06-18 12:04:15 +02:00
int ret ;
ret = decklink_select_input ( avctx , bmdDeckLinkConfigAudioInputConnection );
if ( ret < 0 )
return ret ;
ret = decklink_select_input ( avctx , bmdDeckLinkConfigVideoInputConnection );
if ( ret < 0 )
return ret ;
2017-11-07 09:32:23 +05:30
}
2018-11-25 01:38:05 +01:00
if ( direction == DIRECTION_OUT && cctx -> timing_offset != INT_MIN ) {
res = ctx -> cfg -> SetInt ( bmdDeckLinkConfigReferenceInputTimingOffset , cctx -> timing_offset );
if ( res != S_OK )
av_log ( avctx , AV_LOG_WARNING , "Setting timing offset failed. \n " );
}
2017-11-07 09:32:23 +05:30
return 0 ;
}
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 , int num )
{
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
2019-03-14 01:37:11 +01:00
#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
DECKLINK_BOOL support ;
#else
2017-11-07 09:32:23 +05:30
BMDDisplayModeSupport support ;
2019-03-14 01:37:11 +01:00
#endif
2017-11-07 09:32:23 +05:30
IDeckLinkDisplayModeIterator * itermode ;
IDeckLinkDisplayMode * mode ;
int i = 1 ;
HRESULT res ;
av_log ( avctx , AV_LOG_DEBUG , "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s \n " ,
width , height , tb_num , tb_den , field_order , direction , num , ( cctx -> format_code ) ? cctx -> format_code : "(unset)" );
if ( direction == DIRECTION_IN ) {
2014-09-22 01:39:50 +02:00
res = ctx -> dli -> GetDisplayModeIterator ( & itermode );
} else {
res = ctx -> dlo -> GetDisplayModeIterator ( & itermode );
}
if ( res != S_OK ) {
av_log ( avctx , AV_LOG_ERROR , "Could not get Display Mode Iterator \n " );
return AVERROR ( EIO );
}
2017-03-20 00:16:37 +01:00
char format_buf [] = " " ;
if ( cctx -> format_code )
memcpy ( format_buf , cctx -> format_code , FFMIN ( strlen ( cctx -> format_code ), sizeof ( format_buf )));
BMDDisplayMode target_mode = ( BMDDisplayMode ) AV_RB32 ( format_buf );
2016-07-10 13:02:37 +02:00
AVRational target_tb = av_make_q ( tb_num , tb_den );
2014-09-22 01:39:50 +02:00
ctx -> bmd_mode = bmdModeUnknown ;
while (( ctx -> bmd_mode == bmdModeUnknown ) && itermode -> Next ( & mode ) == S_OK ) {
BMDTimeValue bmd_tb_num , bmd_tb_den ;
int bmd_width = mode -> GetWidth ();
int bmd_height = mode -> GetHeight ();
2017-03-20 00:16:37 +01:00
BMDDisplayMode bmd_mode = mode -> GetDisplayMode ();
2017-02-18 02:33:05 +01:00
BMDFieldDominance bmd_field_dominance = mode -> GetFieldDominance ();
2014-09-22 01:39:50 +02:00
mode -> GetFrameRate ( & bmd_tb_num , & bmd_tb_den );
2016-07-10 13:02:37 +02:00
AVRational mode_tb = av_make_q ( bmd_tb_num , bmd_tb_den );
2014-09-22 01:39:50 +02:00
2017-02-18 02:33:05 +01:00
if (( bmd_width == width &&
bmd_height == height &&
! av_cmp_q ( mode_tb , target_tb ) &&
2017-03-20 00:16:37 +01:00
field_order_eq ( field_order , bmd_field_dominance ))
|| i == num
|| target_mode == bmd_mode ) {
ctx -> bmd_mode = bmd_mode ;
2014-09-22 01:39:50 +02:00
ctx -> bmd_width = bmd_width ;
ctx -> bmd_height = bmd_height ;
ctx -> bmd_tb_den = bmd_tb_den ;
ctx -> bmd_tb_num = bmd_tb_num ;
2017-02-18 02:33:05 +01:00
ctx -> bmd_field_dominance = bmd_field_dominance ;
2014-09-22 01:39:50 +02:00
av_log ( avctx , AV_LOG_INFO , "Found Decklink mode %d x %d with rate %.2f%s \n " ,
2016-07-10 13:02:37 +02:00
bmd_width , bmd_height , 1 / av_q2d ( mode_tb ),
2014-09-22 01:39:50 +02:00
( ctx -> bmd_field_dominance == bmdLowerFieldFirst || ctx -> bmd_field_dominance == bmdUpperFieldFirst ) ? "(i)" : "" );
}
mode -> Release ();
i ++ ;
}
itermode -> Release ();
if ( ctx -> bmd_mode == bmdModeUnknown )
return - 1 ;
2019-03-14 01:37:11 +01:00
#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000
if ( direction == DIRECTION_IN ) {
if ( ctx -> dli -> DoesSupportVideoMode ( ctx -> video_input , ctx -> bmd_mode , ( BMDPixelFormat ) cctx -> raw_format ,
2019-05-01 12:47:43 +02:00
bmdSupportedVideoModeDefault ,
2019-03-14 01:37:11 +01:00
& support ) != S_OK )
return - 1 ;
} else {
BMDDisplayMode actualMode = ctx -> bmd_mode ;
2019-05-01 12:47:43 +02:00
if ( ctx -> dlo -> DoesSupportVideoMode ( bmdVideoConnectionUnspecified , ctx -> bmd_mode , ctx -> raw_format ,
bmdSupportedVideoModeDefault ,
& actualMode , & support ) != S_OK || ! support || ctx -> bmd_mode != actualMode ) {
return - 1 ;
2019-03-14 01:37:11 +01:00
}
}
if ( support )
return 0 ;
#else
2014-09-22 01:39:50 +02:00
if ( direction == DIRECTION_IN ) {
2017-09-07 14:46:31 +02:00
if ( ctx -> dli -> DoesSupportVideoMode ( ctx -> bmd_mode , ( BMDPixelFormat ) cctx -> raw_format ,
2014-09-22 01:39:50 +02:00
bmdVideoOutputFlagDefault ,
& support , NULL ) != S_OK )
return - 1 ;
} else {
2018-09-07 15:40:25 -04:00
if ( ! ctx -> supports_vanc || ctx -> dlo -> DoesSupportVideoMode ( ctx -> bmd_mode , ctx -> raw_format ,
bmdVideoOutputVANC ,
2019-03-14 02:13:56 +01:00
& support , NULL ) != S_OK || support != bmdDisplayModeSupported ) {
2018-09-07 15:40:25 -04:00
/* Try without VANC enabled */
if ( ctx -> dlo -> DoesSupportVideoMode ( ctx -> bmd_mode , ctx -> raw_format ,
bmdVideoOutputFlagDefault ,
& support , NULL ) != S_OK ) {
return - 1 ;
}
ctx -> supports_vanc = 0 ;
}
2014-09-22 01:39:50 +02:00
}
if ( support == bmdDisplayModeSupported )
return 0 ;
2019-03-14 01:37:11 +01:00
#endif
2014-09-22 01:39:50 +02:00
return - 1 ;
}
int ff_decklink_set_format ( AVFormatContext * avctx , decklink_direction_t direction , int num ) {
2017-02-18 02:33:05 +01:00
return ff_decklink_set_format ( avctx , 0 , 0 , 0 , 0 , AV_FIELD_UNKNOWN , direction , num );
2014-09-22 01:39:50 +02:00
}
2017-10-06 08:55:43 -04:00
int ff_decklink_list_devices ( AVFormatContext * avctx ,
struct AVDeviceInfoList * device_list ,
int show_inputs , int show_outputs )
2014-09-22 01:39:50 +02:00
{
IDeckLink * dl = NULL ;
2018-04-15 00:06:59 +02:00
IDeckLinkIterator * iter = decklink_create_iterator ( avctx );
2017-10-06 08:55:43 -04:00
int ret = 0 ;
2018-04-15 00:06:59 +02:00
if ( ! iter )
2014-09-22 01:39:50 +02:00
return AVERROR ( EIO );
2017-10-06 08:55:43 -04:00
while ( ret == 0 && iter -> Next ( & dl ) == S_OK ) {
IDeckLinkOutput * output_config ;
IDeckLinkInput * input_config ;
2018-09-20 23:56:00 +02:00
const char * display_name = NULL ;
const char * unique_name = NULL ;
2017-10-06 08:55:43 -04:00
AVDeviceInfo * new_device = NULL ;
int add = 0 ;
2018-09-20 23:56:00 +02:00
ret = decklink_get_attr_string ( dl , BMDDeckLinkDisplayName , & display_name );
if ( ret < 0 )
goto next ;
ret = decklink_get_attr_string ( dl , BMDDeckLinkDeviceHandle , & unique_name );
if ( ret < 0 )
goto next ;
2017-10-06 08:55:43 -04:00
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 ;
}
2018-03-17 12:41:15 +01:00
2018-09-20 23:56:00 +02:00
new_device -> device_name = av_strdup ( unique_name ? unique_name : display_name );
new_device -> device_description = av_strdup ( display_name );
2017-10-06 08:55:43 -04:00
2018-03-17 12:41:15 +01:00
if ( ! new_device -> device_name ||
! new_device -> device_description ||
av_dynarray_add_nofree ( & device_list -> devices , & device_list -> nb_devices , new_device ) < 0 ) {
ret = AVERROR ( ENOMEM );
2017-10-06 08:55:43 -04:00
av_freep ( & new_device -> device_name );
av_freep ( & new_device -> device_description );
av_freep ( & new_device );
goto next ;
}
}
next :
2018-09-20 23:56:00 +02:00
av_freep ( & display_name );
av_freep ( & unique_name );
2014-09-22 01:39:50 +02:00
dl -> Release ();
}
iter -> Release ();
2017-10-06 08:55:43 -04:00
return ret ;
}
/* This is a wrapper around the ff_decklink_list_devices() which dumps the
output to av_log() and exits (for backward compatibility with the
"-list_devices" argument). */
void ff_decklink_list_devices_legacy ( AVFormatContext * avctx ,
int show_inputs , int show_outputs )
{
struct AVDeviceInfoList * device_list = NULL ;
int ret ;
device_list = ( struct AVDeviceInfoList * ) av_mallocz ( sizeof ( AVDeviceInfoList ));
if ( ! device_list )
return ;
ret = ff_decklink_list_devices ( avctx , device_list , show_inputs , show_outputs );
if ( ret == 0 ) {
av_log ( avctx , AV_LOG_INFO , "Blackmagic DeckLink %s devices: \n " ,
show_inputs ? "input" : "output" );
for ( int i = 0 ; i < device_list -> nb_devices ; i ++ ) {
2018-09-20 23:56:00 +02:00
av_log ( avctx , AV_LOG_INFO , " \t '%s' \n " , device_list -> devices [ i ] -> device_description );
2017-10-06 08:55:43 -04:00
}
}
avdevice_free_list_devices ( & device_list );
2014-09-22 01:39:50 +02:00
}
int ff_decklink_list_formats ( AVFormatContext * avctx , decklink_direction_t direction )
{
2016-08-02 22:46:28 -07:00
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
2014-09-22 01:39:50 +02:00
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
IDeckLinkDisplayModeIterator * itermode ;
IDeckLinkDisplayMode * mode ;
2017-03-20 00:16:36 +01:00
uint32_t format_code ;
2014-09-22 01:39:50 +02:00
HRESULT res ;
if ( direction == DIRECTION_IN ) {
2016-06-18 12:04:15 +02:00
int ret ;
ret = decklink_select_input ( avctx , bmdDeckLinkConfigAudioInputConnection );
if ( ret < 0 )
return ret ;
ret = decklink_select_input ( avctx , bmdDeckLinkConfigVideoInputConnection );
if ( ret < 0 )
return ret ;
2014-09-22 01:39:50 +02:00
res = ctx -> dli -> GetDisplayModeIterator ( & itermode );
} else {
res = ctx -> dlo -> GetDisplayModeIterator ( & itermode );
}
if ( res != S_OK ) {
av_log ( avctx , AV_LOG_ERROR , "Could not get Display Mode Iterator \n " );
return AVERROR ( EIO );
}
2017-03-25 17:52:11 +01:00
av_log ( avctx , AV_LOG_INFO , "Supported formats for '%s': \n\t format_code \t description" ,
2017-12-29 23:29:52 +01:00
avctx -> url );
2014-09-22 01:39:50 +02:00
while ( itermode -> Next ( & mode ) == S_OK ) {
BMDTimeValue tb_num , tb_den ;
mode -> GetFrameRate ( & tb_num , & tb_den );
2017-03-20 00:16:36 +01:00
format_code = av_bswap32 ( mode -> GetDisplayMode ());
2017-03-25 17:52:11 +01:00
av_log ( avctx , AV_LOG_INFO , " \n\t %.4s \t\t %ldx%ld at %d/%d fps" ,
( char * ) & format_code , mode -> GetWidth (), mode -> GetHeight (),
2014-09-22 01:39:50 +02:00
( int ) tb_den , ( int ) tb_num );
switch ( mode -> GetFieldDominance ()) {
case bmdLowerFieldFirst :
av_log ( avctx , AV_LOG_INFO , " (interlaced, lower field first)" ); break ;
case bmdUpperFieldFirst :
av_log ( avctx , AV_LOG_INFO , " (interlaced, upper field first)" ); break ;
}
mode -> Release ();
}
2017-03-20 00:16:36 +01:00
av_log ( avctx , AV_LOG_INFO , " \n " );
2014-09-22 01:39:50 +02:00
itermode -> Release ();
return 0 ;
}
2016-06-18 15:49:01 +02:00
void ff_decklink_cleanup ( AVFormatContext * avctx )
{
2016-08-02 22:46:28 -07:00
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
2016-06-18 15:49:01 +02:00
if ( ctx -> dli )
ctx -> dli -> Release ();
if ( ctx -> dlo )
ctx -> dlo -> Release ();
2016-06-11 13:41:29 +02:00
if ( ctx -> attr )
ctx -> attr -> Release ();
if ( ctx -> cfg )
ctx -> cfg -> Release ();
2016-06-18 15:49:01 +02:00
if ( ctx -> dl )
ctx -> dl -> Release ();
}
2016-06-18 16:55:47 +02:00
int ff_decklink_init_device ( AVFormatContext * avctx , const char * name )
{
struct decklink_cctx * cctx = ( struct decklink_cctx * ) avctx -> priv_data ;
struct decklink_ctx * ctx = ( struct decklink_ctx * ) cctx -> ctx ;
IDeckLink * dl = NULL ;
2018-04-15 00:06:59 +02:00
IDeckLinkIterator * iter = decklink_create_iterator ( avctx );
if ( ! iter )
2016-06-18 16:55:47 +02:00
return AVERROR_EXTERNAL ;
while ( iter -> Next ( & dl ) == S_OK ) {
2018-09-20 23:56:00 +02:00
const char * display_name = NULL ;
const char * unique_name = NULL ;
decklink_get_attr_string ( dl , BMDDeckLinkDisplayName , & display_name );
decklink_get_attr_string ( dl , BMDDeckLinkDeviceHandle , & unique_name );
if ( display_name && ! strcmp ( name , display_name ) || unique_name && ! strcmp ( name , unique_name )) {
av_free (( void * ) unique_name );
av_free (( void * ) display_name );
2016-06-18 16:55:47 +02:00
ctx -> dl = dl ;
break ;
}
2018-09-20 23:56:00 +02:00
av_free (( void * ) display_name );
av_free (( void * ) unique_name );
2016-06-18 16:55:47 +02:00
dl -> Release ();
}
iter -> Release ();
if ( ! ctx -> dl )
return AVERROR ( ENXIO );
2016-06-11 13:41:29 +02:00
if ( ctx -> dl -> QueryInterface ( IID_IDeckLinkConfiguration , ( void ** ) & ctx -> cfg ) != S_OK ) {
av_log ( avctx , AV_LOG_ERROR , "Could not get configuration interface for '%s' \n " , name );
ff_decklink_cleanup ( avctx );
return AVERROR_EXTERNAL ;
}
2019-03-14 01:37:11 +01:00
if ( ctx -> dl -> QueryInterface ( IID_IDeckLinkProfileAttributes , ( void ** ) & ctx -> attr ) != S_OK ) {
2016-06-11 13:41:29 +02:00
av_log ( avctx , AV_LOG_ERROR , "Could not get attributes interface for '%s' \n " , name );
ff_decklink_cleanup ( avctx );
return AVERROR_EXTERNAL ;
}
2016-06-18 16:55:47 +02:00
return 0 ;
}