[vlc-devel] help test decklink output plugin (video and audio)

Rémi Denis-Courmont remi at remlab.net
Tue Aug 16 17:49:56 CEST 2011


Please use unified diff, even for new files.

> /**************************************************************************
> *** * Preamble Decklink video and audio output
>  **************************************************************************
> ***/ //vlc -vvv file --aout decklinkoutput --vout decklinkoutput

License boiler plate is missing.

> #ifdef HAVE_CONFIG_H
> # include "config.h"
> #endif
> 
> //#include <stdint.h>
> 
> #include <vlc_common.h>
> #include <vlc_plugin.h>
> 
> #include <vlc_vout_display.h>
> #include <vlc_picture_pool.h>
> 
> #include <vlc_block.h>
> #include <vlc_atomic.h>
> #include <vlc_aout.h>
> #include <arpa/inet.h>
> 
> #include <DeckLinkAPI.h>
> #include <DeckLinkAPIDispatch.cpp>
> 
> # if __WORDSIZE == 64
> #  define INT64_C(c)	c ## L
> # else
> #  define INT64_C(c)	c ## LL
> # endif
> 
> #define CLOCK_FREQ INT64_C(1000000)

Please don't.

> #define DECKLINK_VIDEO_CODEC VLC_CODEC_UYVY
> #define DECKLINK_AUDIO_CODEC VLC_CODEC_S16N

I don't see the point in redefining these. If the plug-in ever gets support 
for more than once format, this scheme will fail anyway.

> #define FRAME_SIZE 1920
> #define CHANNELS_MAX 6
> 
> static const int pi_channels_maps[CHANNELS_MAX+1] =
> {
>     0,
>     AOUT_CHAN_CENTER,
>     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
>     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
>     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
> 
>      | AOUT_CHAN_REARRIGHT,
> 
>     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
> 
>      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
> 
>     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
> 
>      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
> 
> };

Where are those mappings coming from? Are you sure Decklink expects the same 
channels order as VLC (WG4)?

> #define CARD_INDEX_TEXT N_("Output card to use")
> #define CARD_INDEX_LONGTEXT N_( \
>     "DeckLink output card to use, if multiple exist. " \
>     "The cards are numbered from 0." )
> 
> #define MODE_TEXT N_("Desired output video mode")
> #define MODE_LONGTEXT N_( \
>     "Desired output video mode for DeckLink output. " \
>     "This value should be a FOURCC code in textual " \
>     "form, e.g. \"ntsc\"." )
> 
> #define AUDIO_CONNECTION_TEXT N_("Audio connection")
> #define AUDIO_CONNECTION_LONGTEXT N_( \
>     "Audio connection to use for DeckLink output. " \
>     "Valid choices: embedded, aesebu, analog. " \
>     "Leave blank for card default." )
> 
> 
> #define RATE_TEXT N_("Audio sampling rate in Hz")
> #define RATE_LONGTEXT N_( \
>     "Audio sampling rate (in hertz) for DeckLink output. " \
>     "0 disables audio output." )

Is there a rationale for this? Can't the incoming sample rate be used?

> #define CHANNELS_TEXT N_("Number of audio channels")
> #define CHANNELS_LONGTEXT N_( \
>     "Number of output audio channels for DeckLink output. " \
>     "Must be 2, 8 or 16. 0 disables audio output." )
> 
> #define VIDEO_CONNECTION_TEXT N_("Video connection")
> #define VIDEO_CONNECTION_LONGTEXT N_( \
>     "Video connection to use for DeckLink output. " \
>     "Valid choices: sdi, hdmi, opticalsdi, component, " \
>     "composite, svideo. " \
>     "Leave blank for card default." )
> 
> #define CFG_PREFIX "decklink-output-"
> #define VIDEO_CFG_PREFIX "decklink-vout-"
> #define AUDIO_CFG_PREFIX "decklink-aout-"
> 
> 
> 
> static const char *const ppsz_videoconns[] = {
>     "sdi", "hdmi", "opticalsdi", "component", "composite", "svideo"
> };
> static const char *const ppsz_videoconns_text[] = {
>     N_("SDI"), N_("HDMI"), N_("Optical SDI"), N_("Component"),
> N_("Composite"), N_("S-video")
> };

On the one hand, there should be an entry for the default value. On the other 
hand, you don't need to tell the user that default is empty in the help text.

> static const char *const ppsz_audioconns[] = {
>     "embedded", "aesebu", "analog"
> };
> static const char *const ppsz_audioconns_text[] = {
>     N_("Embedded"), N_("AES/EBU"), N_("Analog")
> };

Same comments apply.

> struct aout_sys_t
> {
>     uint64_t aoutTotalAudioPackages;
> };
> 
> 
> 
> struct vout_display_sys_t
> {
>     picture_pool_t *pool;
>     uint64_t vdTotalFrames;
>     vlc_mutex_t pts_lock;
> };
> 
> typedef struct
> {
>     IDeckLink *p_card;
>     IDeckLinkOutput *p_output;
>     IDeckLinkConfiguration *p_config;
>     IDeckLinkDisplayModeIterator *p_display_iterator;
>     IDeckLinkIterator *decklink_iterator;
>     int         i_card_index;
>     char        *psz_video_connection;
>     BMDDisplayMode        display_mode;
>     BMDVideoOutputFlags		videoOutputFlags;
>     char        *psz_audio_connection;
>     int i_channels;
>     int i_rate;
>     uint32_t i_dominance_flags;
>     int i_width;
>     int i_height;
>     BMDTimeScale i_timescale;
>     BMDTimeValue i_frameduration;
>     vlc_mutex_t m_lock;
>     vlc_atomic_t m_ref;
> } decklink_sys_t;
> 
> 
> static decklink_sys_t decklink_sys = {NULL,NULL,NULL,NULL,NULL,
>                                      -1,NULL,0,0,NULL,-1,-1,
>                                       0,-1,-1,0,0,
>                                       NULL,NULL};

Use VLC_ATOMIC_INIT(0) for the atomic variable.

> /**************************************************************************
> *** * Local prototypes.
> ***************************************************************************
> **/
> 
> static int  OpenDecklink        ( vlc_object_t *);
> static void CloseDecklink       ( vlc_object_t *);
> 
> static int  OpenVideo           ( vlc_object_t * );
> static void CloseVideo          ( vlc_object_t * );
> static picture_pool_t 	*PoolVideo  (vout_display_t *, unsigned);
> static void DisplayVideo(vout_display_t *, picture_t *, subpicture_t
> *subpicture);
> static int  ControlVideo(vout_display_t *, int, va_list);
> 
> static int  OpenAudio           ( vlc_object_t * );
> static void CloseAudio          ( vlc_object_t * );
> static void PlayAudio           ( audio_output_t *, block_t * );
> 
> 
> 
> 
> /**************************************************************************
> *** * Module descriptor
>  **************************************************************************
> ***/
> 
> vlc_module_begin()
>     set_shortname( N_("DecklinkOutput") )
>     set_description( N_("Decklink Output plug-in") )
>     set_section( N_("Decklink General Options"), NULL )
>     add_integer( CFG_PREFIX "card-index", 0,
>                 CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true )
> 
>     add_submodule ()

You only need one sub-module. You can use the primary module for the video 
output capability.

>     set_description (N_("Decklink Video Output module"))
>     set_category(CAT_VIDEO)
>     set_subcategory(SUBCAT_VIDEO_VOUT)
>     set_capability("vout display", 0)
>     set_callbacks (OpenVideo, CloseVideo)
>     set_section( N_("Decklink Video Options"), NULL )
>     add_string( VIDEO_CFG_PREFIX "video-connection", 0,
>                 VIDEO_CONNECTION_TEXT, VIDEO_CONNECTION_LONGTEXT, true )
>                 change_string_list( ppsz_videoconns, ppsz_videoconns_text,
> 0 ) add_string( VIDEO_CFG_PREFIX "mode", "pal ",
>                 MODE_TEXT, MODE_LONGTEXT, true )
> 
>     add_submodule ()
>     set_description (N_("Decklink Audio Output module"))
>     set_category( CAT_AUDIO )
>     set_subcategory( SUBCAT_AUDIO_AOUT )
>     set_capability( "audio output", 0 )
>     set_callbacks (OpenAudio, CloseAudio)
>     set_section( N_("Decklink Audio Options"), NULL )
>     add_string( AUDIO_CFG_PREFIX "audio-connection", 0,
>                 AUDIO_CONNECTION_TEXT, AUDIO_CONNECTION_LONGTEXT, true )
>                 change_string_list( ppsz_audioconns, ppsz_audioconns_text,
> 0 ) add_integer( AUDIO_CFG_PREFIX "audio-rate", 48000,
>                 RATE_TEXT, RATE_LONGTEXT, true )
>     add_integer( AUDIO_CFG_PREFIX "audio-channels", 2,
>                 CHANNELS_TEXT, CHANNELS_LONGTEXT, true )
> vlc_module_end ()
> 
> /**************************************************************************
> *** * Open: initialize interface
>  **************************************************************************
> ***/
> 
> static int OpenDecklink( vlc_object_t *p_this )
> {
>     if(!(vlc_atomic_get( &decklink_sys.m_ref ))){
>         vlc_mutex_init(&decklink_sys.m_lock);

This should probably be initialized statically instead with VLC_STATIC_MUTEX.

>         vlc_mutex_lock(&decklink_sys.m_lock);

You could use vlc_mutex_locker(). which should simplify the code.

>         vlc_atomic_set( &(decklink_sys.m_ref), 0 );

As far as concurrency is concerned, this is logically flawed.

>         int i_rate;
>         int i_card_index;
>         int i_channels;
>         BMDVideoOutputFlags    videoOutputFlags = 0;
>         bool    b_found_mode;
> 
>         i_card_index = var_InheritInteger( p_this, CFG_PREFIX "card-index"
> );
> 
> 		//IDeckLinkDisplayModeIterator *p_display_iterator = NULL;
> 
>         decklink_sys.decklink_iterator = CreateDeckLinkIteratorInstance();
>         if( !decklink_sys.decklink_iterator )
>         {
>             msg_Err( p_this, "DeckLink drivers not found." );
>            	if( decklink_sys.p_display_iterator )
>            		decklink_sys.p_display_iterator->Release();
>            	vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
>         }
>         HRESULT result;
>         if( i_card_index < 0 )
>         {
>             msg_Err( p_this, "Invalid card index %d", i_card_index );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();

As JB noted, you could factor these error cases with a goto statement.

>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
>         for( int i = 0; i <= i_card_index; ++i )
>         {
>             if( decklink_sys.p_card ){
> 
> 	        	//decklink_sys.p_card->Release();
>             msg_Dbg( p_this, "Error here %d Cannot Release Pcard dc", i);
>         }
>         result = decklink_sys.decklink_iterator->Next( &decklink_sys.p_card
> ); if( result != S_OK )
>             break;
>         }
>         if( result != S_OK )
>         {
>             msg_Err( p_this, "DeckLink PCI card %d not found", i_card_index
> ); if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
>         const char *psz_model_name;
>         result = decklink_sys.p_card->GetModelName( &psz_model_name );
> 
>         if( result != S_OK )
>         {
>             msg_Err( p_this, "Could not get model name" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
>         msg_Dbg( p_this, "Opened DeckLink PCI card %d (%s)", i_card_index,
> psz_model_name );
> 
>         if( decklink_sys.p_card->QueryInterface( IID_IDeckLinkOutput,
> (void**)&decklink_sys.p_output) != S_OK )
>         {
>             msg_Err( p_this, "Card has no outputs" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
>         if( decklink_sys.p_card->QueryInterface(
> IID_IDeckLinkConfiguration, (void**)&decklink_sys.p_config) != S_OK )
>         {
>             msg_Err( p_this, "Failed to get configuration interface" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
>         decklink_sys.i_card_index = i_card_index ;
> 
> 	    //Setting up Video Connection
>         char* psz_video_connection;
>         psz_video_connection = var_InheritString( p_this, VIDEO_CFG_PREFIX
> "video-connection" );
>         if( psz_video_connection )
>         {
>             BMDVideoConnection conn;
>             if ( !strcmp( psz_video_connection, "sdi" ) )
>                 conn = bmdVideoConnectionSDI;
>             else if ( !strcmp( psz_video_connection, "hdmi" ) )
>                 conn = bmdVideoConnectionHDMI;
>             else if ( !strcmp( psz_video_connection, "opticalsdi" ) )
>                 conn = bmdVideoConnectionOpticalSDI;
>             else if ( !strcmp( psz_video_connection, "component" ) )
>                 conn = bmdVideoConnectionComponent;
>             else if ( !strcmp( psz_video_connection, "composite" ) )
>                 conn = bmdVideoConnectionComposite;
>             else if ( !strcmp( psz_video_connection, "svideo" ) )
>                 conn = bmdVideoConnectionSVideo;
>             else
>             {
>                 msg_Err( p_this, "Invalid video-connection specified;
> choose one of " \
>                                     "sdi, hdmi, opticalsdi, component,
> composite, or svideo." );
>                 if( decklink_sys.decklink_iterator )
>                     decklink_sys.decklink_iterator->Release();
>                 free( psz_video_connection );
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
>             }
>             msg_Dbg( p_this, "Setting video output connection to 0x%x",
> conn); result = decklink_sys.p_config->SetInt(
> bmdDeckLinkConfigVideoOutputConnection, conn );
>             if( result != S_OK )
>             {
>                 msg_Err( p_this, "Failed to set video output connection" );
>                 if( decklink_sys.decklink_iterator )
>                     decklink_sys.decklink_iterator->Release();
>                 free( psz_video_connection );
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>             }
> 
>             decklink_sys.psz_video_connection = psz_video_connection;
>             free( psz_video_connection );
>         }
> 
> 	    //End of Setting up Video Connection
> 
> 
> 	    // Setting up Audio Connection
>         char *psz_audio_connection;
>         psz_audio_connection = var_CreateGetNonEmptyString( p_this,
> AUDIO_CFG_PREFIX "audio-connection" );
>         if( psz_audio_connection )
>         {
>             BMDAudioConnection conn;
>             if ( !strcmp( psz_audio_connection, "embedded" ) )
>                 conn = bmdAudioConnectionEmbedded;
>             else if ( !strcmp( psz_audio_connection, "aesebu" ) )
>                 conn = bmdAudioConnectionAESEBU;
>             else if ( !strcmp( psz_audio_connection, "analog" ) )
>                 conn = bmdAudioConnectionAnalog;
>             else
>             {
>                 msg_Err( p_this, "Invalid audio-connection specified;
> choose one of " \
>                     "embedded, aesebu, or analog." );
>                 if( decklink_sys.decklink_iterator )
>                     decklink_sys.decklink_iterator->Release();
>                 free( psz_audio_connection );
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
>             }
> 
>             msg_Dbg( p_this, "Setting audio output format to 0x%x", conn);
>             result = decklink_sys.p_config->SetInt(
> bmdDeckLinkConfigAudioInputConnection, conn );
>             if( result != S_OK )
>             {
>                 msg_Err( p_this, "Failed to set audio output connection" );
>                 if( decklink_sys.decklink_iterator )
>                     decklink_sys.decklink_iterator->Release();
>                 free( psz_audio_connection );
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
>             }
> 
>             decklink_sys.psz_audio_connection = psz_audio_connection;
>             free( psz_audio_connection );
>         }
> 	    // End of Setting up Audio Connection
> 
> 	    //Find Display Mode
> 
>         result = decklink_sys.p_output->GetDisplayModeIterator(
> &decklink_sys.p_display_iterator );
>         if( result != S_OK )
>         {
>             msg_Err( p_this, "Failed to enumerate display modes" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
>         char        *psz_display_mode;
>         psz_display_mode = var_CreateGetNonEmptyString( p_this,
> VIDEO_CFG_PREFIX "mode" );
>         if( !psz_display_mode || strlen( psz_display_mode ) > 4 )
>         {
>             msg_Err( p_this, "Missing or invalid mode string" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
> 	    /*
> 	     * Pad the --decklink-mode string to four characters, so the user can
> specify e.g. "pal"
> 	     * without having to add the trailing space.
> 	     */
>         char sz_display_mode_padded[5];
>         strcpy(sz_display_mode_padded, "    ");
>         for( int i = 0; i < strlen( psz_display_mode ); ++i )
>             sz_display_mode_padded[i] = psz_display_mode[i];

You could probably use sprintf() or snprintf() with a fixed width format 
modifier.

>         BMDDisplayMode wanted_mode_id;
>         memcpy( &wanted_mode_id, &sz_display_mode_padded,
> sizeof(wanted_mode_id) );
> 
>         b_found_mode = false;
> 
>         for (;;)
> 	    {
> 	        IDeckLinkDisplayMode *p_display_mode;
> 	        result = decklink_sys.p_display_iterator->Next( &p_display_mode
> );
> 	        if( result != S_OK || !p_display_mode )
> 	            break;
> 
> 	        char sz_mode_id_text[5] = {0};
> 	        BMDDisplayMode mode_id = ntohl( p_display_mode->GetDisplayMode()
> );
> 	        memcpy( sz_mode_id_text, &mode_id, sizeof(mode_id) );
> 
> 	        const char *psz_mode_name;
> 	        result = p_display_mode->GetName( &psz_mode_name );
> 	        if( result != S_OK )
> 	        {
> 	            msg_Err( p_this, "Failed to get display mode name" );
> 	            p_display_mode->Release();
> 
> 	            if( decklink_sys.decklink_iterator )
> 	            	decklink_sys.decklink_iterator->Release();
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
> 	        }
> 
> 	        BMDTimeValue frame_duration, time_scale;
> 
> 	        result = p_display_mode->GetFrameRate( &frame_duration,
> &time_scale );
> 	        if( result != S_OK )
> 	        {
> 	            msg_Err( p_this, "Failed to get frame rate" );
> 	            p_display_mode->Release();
> 	            if( decklink_sys.decklink_iterator )
> 	            	decklink_sys.decklink_iterator->Release();
>                 if( decklink_sys.p_display_iterator )
>                     decklink_sys.p_display_iterator->Release();
>                 vlc_mutex_unlock(&decklink_sys.m_lock);
>                 return VLC_EGENERIC;
>             }
> 
> 	        const char *psz_field_dominance;
> 	        uint32_t i_dominance_flags = 0;
> 	        switch( p_display_mode->GetFieldDominance() )
> 	        {
> 	        case bmdProgressiveFrame:
> 	            psz_field_dominance = "";
> 	            break;
> 	        case bmdProgressiveSegmentedFrame:
> 	            psz_field_dominance = ", segmented";
> 	            break;
> 	        case bmdLowerFieldFirst:
> 	            psz_field_dominance = ", interlaced [BFF]";
> 	            i_dominance_flags = BLOCK_FLAG_BOTTOM_FIELD_FIRST;
> 	            break;
> 	        case bmdUpperFieldFirst:
> 	            psz_field_dominance = ", interlaced [TFF]";
> 	            i_dominance_flags = BLOCK_FLAG_TOP_FIELD_FIRST;
> 	            break;
> 	        case bmdUnknownFieldDominance:
> 	        default:
> 	            psz_field_dominance = ", unknown field dominance";
> 	            break;
> 	        }
> 
> 	        msg_Dbg( p_this, "Found mode '%s': %s (%dx%d, %.3f fps%s)",
>                     sz_mode_id_text, psz_mode_name,
>                     p_display_mode->GetWidth(),
> p_display_mode->GetHeight(), double(time_scale) / frame_duration,
> psz_field_dominance );
> 
> 	        if( wanted_mode_id == mode_id )
> 	        {
> 	            b_found_mode = true;
> 	            decklink_sys.i_width = p_display_mode->GetWidth();
> 	            decklink_sys.i_height = p_display_mode->GetHeight();
> 	            decklink_sys.i_timescale = time_scale;
> 	            decklink_sys.i_frameduration = frame_duration;
> 	            decklink_sys.i_dominance_flags = i_dominance_flags;
> 	            decklink_sys.display_mode =  wanted_mode_id;
> 
> 	            if (p_display_mode->GetDisplayMode() == bmdModeNTSC ||
> 	            	p_display_mode->GetDisplayMode() == bmdModeNTSC2398 ||
> 	            	p_display_mode->GetDisplayMode() == bmdModePAL)
> 	            {
> 	            	//timeCodeFormat = bmdTimecodeVITC;
> 	            	videoOutputFlags |= bmdVideoOutputVITC;
> 	            }
> 	            else
> 	            {
> 	            	//timeCodeFormat = bmdTimecodeRP188;
> 	            	videoOutputFlags |= bmdVideoOutputRP188;
> 	            }
> 	            decklink_sys.videoOutputFlags = videoOutputFlags;
> 	        }
> 
> 	        p_display_mode->Release();
> 	    }
> 	    if( !b_found_mode )
> 	    {
> 	        msg_Err( p_this, "Unknown video mode specified." );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 	    //End of Find Display Mode
> 
> 	    // Get Audio rate and Audio Channels
>         i_channels = var_InheritInteger( p_this, AUDIO_CFG_PREFIX "audio-
> channels" );
>         i_rate = var_InheritInteger( p_this, AUDIO_CFG_PREFIX "audio-rate"
> );
> 
>         if( !(i_rate > 0 && i_channels > 0) )
>         {
>         msg_Err( p_this, "Invalid audio rate or audio channels" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 	    decklink_sys.i_channels = i_channels;
> 	    decklink_sys.i_rate = i_rate;
> 	    // End of Get Audio rate and Audio Channels
> 
> 
> 	    //vlc_mutex_lock(&decklink_sys.m_lock);
> 
> 
> 	    result = decklink_sys.p_output->EnableVideoOutput( htonl(
> decklink_sys.display_mode ), decklink_sys.videoOutputFlags );
>         if( result != S_OK )
>         {
>             msg_Err( p_this, "Failed to Enable Video Output" );
> 	        //p_display_mode->Release();
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
>         result = decklink_sys.p_output->EnableAudioOutput(
> decklink_sys.i_rate, bmdAudioSampleType16bitInteger,
> decklink_sys.i_channels,bmdAudioOutputStreamContinuous );
> 
>         if( result != S_OK )
>         {
>             msg_Err( p_this, "Failed to Enable Audio Output" );
>             if( decklink_sys.decklink_iterator )
>                 decklink_sys.decklink_iterator->Release();
>             if( decklink_sys.p_display_iterator )
>                 decklink_sys.p_display_iterator->Release();
>             vlc_mutex_unlock(&decklink_sys.m_lock);
>             return VLC_EGENERIC;
>         }
> 
> 
> 	    //decklink_sys.p_output-
> 
> >StartScheduledPlayback(0,decklink_sys.i_timescale,1.0);
> 
>         decklink_sys.p_output->StartScheduledPlayback(0,100,1.0);
> 
>         vlc_mutex_unlock(&decklink_sys.m_lock);
>         msg_Dbg(p_this,"Finish Open Decklink, Decklink ref = %d",
> (int)vlc_atomic_get( &decklink_sys.m_ref ));
>         return VLC_SUCCESS;
>     }
>     else
>     {
>         msg_Dbg(p_this,"Finish Open Decklink, Decklink ref = %d",
> (int)vlc_atomic_get( &decklink_sys.m_ref ));
>         return VLC_SUCCESS;
>     }
> }
> 
> /**************************************************************************
> *** * Close: destroy interface
>  **************************************************************************
> ***/ static void CloseDecklink(vlc_object_t *p_this){
> 
>     int result;
>     uintptr_t _ref = vlc_atomic_get( &decklink_sys.m_ref );
> 
>     if ( _ref == 0 ){
>         vlc_mutex_lock(&decklink_sys.m_lock);
> 
>         decklink_sys.p_output->StopScheduledPlayback(0, NULL, 0);
>         result = decklink_sys.p_output->DisableVideoOutput();
>         result = decklink_sys.p_output->DisableAudioOutput();
> 
>         if( decklink_sys.decklink_iterator )
>             decklink_sys.decklink_iterator->Release();
> 
>     	if( decklink_sys.p_display_iterator )
>             decklink_sys.p_display_iterator->Release();
> 
>         if( decklink_sys.p_config )
>             decklink_sys.p_config->Release();
> 
>         if( decklink_sys.p_output )
>         {
>             decklink_sys.p_output->Release();
>         }
> 
>         if( decklink_sys.p_card )
>             decklink_sys.p_card->Release();
> 
>         vlc_mutex_unlock(&decklink_sys.m_lock);
>         vlc_mutex_destroy(&decklink_sys.m_lock);
>         msg_Dbg(p_this,"Finish destroy Decklink, Decklink ref = %d", _ref);
>     }
>     return;
> }
> 
> static int OpenVideo( vlc_object_t *p_this )
> {
>     int result;
>     result = OpenDecklink( p_this );
>     if( result != VLC_SUCCESS ){
>         CloseVideo(p_this);

This error path will probably crash as is.

>         return VLC_EGENERIC;
>     }
> 
>     vout_display_t *vd = (vout_display_t *)p_this;
>     vout_display_sys_t *sys;
> 
> 	    /* Allocate instance and initialize some members */
>     vd->sys = sys = (vout_display_sys_t*)malloc(sizeof(*sys));
>     if (!sys)

This error path will probably leak.

>         return VLC_ENOMEM;
> 
>     vlc_mutex_init( &sys->pts_lock );
>     sys->pool = NULL;
>     sys->vdTotalFrames = 1;
> 
>     vd->fmt.i_chroma = DECKLINK_VIDEO_CODEC;
>     video_format_FixRgb(&(vd->fmt));
>     vd->info.has_hide_mouse = true;
>     vd->pool    = PoolVideo;
>     vd->prepare = NULL;
>     vd->display = DisplayVideo;
>     vd->control = ControlVideo;
>     vd->manage  = NULL;
>     vout_display_SendEventFullscreen(vd, false);
>     vlc_mutex_lock(&decklink_sys.m_lock);
>     uintptr_t new_ref = vlc_atomic_inc( &decklink_sys.m_ref );
>     vlc_mutex_unlock(&decklink_sys.m_lock);
> 
>     msg_Dbg(vd,"Open Decklink Video, Decklink ref = %d",
> (int)vlc_atomic_get( &decklink_sys.m_ref ));
>     return VLC_SUCCESS;
> }
> 
> /**************************************************************************
> *** * Close: destroy interface
>  **************************************************************************
> ***/
> 
> static void CloseVideo( vlc_object_t *p_this )
> {
>     vout_display_t *vd = (vout_display_t *)p_this;
>     vout_display_sys_t *sys = vd->sys;
> 
>     sys->vdTotalFrames = 0;
> 
>     if (sys->pool)
>         picture_pool_Delete(sys->pool);
> 
>     vlc_mutex_destroy( &sys->pts_lock );
> 
>     free(sys);
> 
>     //If ref = 0
>     vlc_mutex_lock(&decklink_sys.m_lock);
>     uintptr_t new_ref = vlc_atomic_dec( &decklink_sys.m_ref );
>     vlc_mutex_unlock(&decklink_sys.m_lock);
>     msg_Dbg(vd,"Close Decklink Video, Decklink ref = %d",
> (int)vlc_atomic_get( &decklink_sys.m_ref ));
>     CloseDecklink((vlc_object_t *)vd);
> }
> 
> 
> static picture_pool_t *PoolVideo(vout_display_t *vd, unsigned
> requested_count) {
>     vout_display_sys_t *sys = vd->sys;
>     if (!sys->pool)
>         sys->pool = picture_pool_NewFromFormat(&vd->fmt, requested_count);
>     return sys->pool;
> 
> }
> 
> static void DisplayVideo(vout_display_t *vd, picture_t *picture,
> subpicture_t *subpicture)
> {
> 
>     vout_display_sys_t *sys = vd->sys;
> 
> 	/*picture_t* to IDeckLinkMutableVideoFrame* */
> 
>     if(picture)
>     {
>         int i_width = decklink_sys.i_width;
>         int i_height = decklink_sys.i_height;
>         BMDTimeScale i_timescale = decklink_sys.i_timescale;
>         BMDTimeValue i_frameduration = decklink_sys.i_frameduration;
> 
> 		//Export picture to block_t
>         block_t *_vdblock ;
>         size_t result;
>         video_format_t *_fmt;
>         _fmt = (video_format_t *)malloc(sizeof(*_fmt));
>         video_format_Setup(_fmt,DECKLINK_VIDEO_CODEC,picture-
> 
> >format.i_width,picture->format.i_height,1,1 );
> 
>         video_format_FixRgb(_fmt);
> 
>         picture_Export(VLC_OBJECT(vd), &_vdblock, _fmt
> ,picture,DECKLINK_VIDEO_CODEC, i_width, i_height);

This is going to be very slow and very useless.

>         free(_fmt);
> 	    //End of export picture to block_t
> 
> 	    //Render to Decklink
>         IDeckLinkMutableVideoFrame *pDLVideoFrame;
>         if (decklink_sys.p_output->CreateVideoFrame(i_width, i_height,
> i_width*2,bmdFormat8BitYUV , bmdFrameFlagDefault, &pDLVideoFrame) != S_OK){
>             msg_Dbg( vd, "Failed to create video frame");
>             block_Release( _vdblock );
>             pDLVideoFrame->Release();
>             return;
>         }
> 
>         void *_frame_bytes;
>         pDLVideoFrame->GetBytes( (void**)&_frame_bytes );
>         int i_stride = pDLVideoFrame->GetRowBytes();
>         int i_bpp = 2;
> 
>         for( int y = 0; y < i_height; ++y )
>         {
>             uint8_t *dst = (uint8_t *)_frame_bytes + i_stride * y;
>             const uint8_t *src = (const uint8_t *)_vdblock->p_buffer +
> i_width * i_bpp * y;
>             memcpy( dst, src, i_width * i_bpp );
>         }

If you're going to copy the raw frames anyway, then you really should not 
convert to block as an intermediary step.

> 		//end of block_t to Decklink Frame
>         if (decklink_sys.p_output->ScheduleVideoFrame(pDLVideoFrame, (sys-
> 
> >vdTotalFrames * i_frameduration)+VLC_TS_0, i_frameduration, i_timescale)
> >!=
> 
> S_OK)
>         {
>             block_Release( _vdblock );
>             pDLVideoFrame->Release();
>             return ;
>         }
>         sys->vdTotalFrames ++;
>         pDLVideoFrame->Release();
>         block_Release( _vdblock );
>     }
> 
> 	/* End of picture_t* to IDeckLinkMutableVideoFrame* */
>     picture_Release(picture);
>     VLC_UNUSED(subpicture);
>     return;
> }
> 
> static int ControlVideo(vout_display_t *vd, int query, va_list args)
> {
>     VLC_UNUSED(vd);
>     switch (query) {
>     case VOUT_DISPLAY_CHANGE_FULLSCREEN: {
>         const vout_display_cfg_t *cfg = va_arg(args, const
> vout_display_cfg_t *);
>         if (cfg->is_fullscreen)
>             return VLC_EGENERIC;
>         return VLC_SUCCESS;
>     }
>     default:
>         return VLC_EGENERIC;
>     }
> }
> 
> 
> static int OpenAudio( vlc_object_t *p_this )
> {
>     int result;
>     result = OpenDecklink( p_this );
>     if( result != VLC_SUCCESS ){
>         CloseAudio(p_this);

This is going to crash.

>         return VLC_EGENERIC;
>     }
>     audio_output_t * aout = (audio_output_t *)p_this;
> 
>     struct aout_sys_t *a_sys = NULL;
>     a_sys = ( aout_sys_t *)calloc( 1, sizeof( aout_sys_t ) );
>     if( !(a_sys))
>     {
>         return VLC_ENOMEM;

This will leak.

>     }
>     aout->sys = a_sys;
> 
>     //Audio preferences go here
>     a_sys->aoutTotalAudioPackages = 1;
>     aout->pf_play = PlayAudio;
>     aout->pf_pause = NULL;
>     aout->pf_flush = NULL;
>     aout->format.i_format = DECKLINK_AUDIO_CODEC;
>     aout->format.i_channels = decklink_sys.i_channels;
>     aout->format.i_physical_channels = pi_channels_maps[aout-
> 
> >format.i_channels];
> 
>     aout->format.i_rate = decklink_sys.i_rate;
>     aout->format.i_bitspersample = 16;
>     aout->format.i_blockalign = aout->format.i_channels * aout-
> 
> >format.i_bitspersample /8 ;
> 
>     aout->format.i_frame_length  = FRAME_SIZE;
>     aout_VolumeSoftInit( aout );
> 
> 
>     //End of Audio preferences go here
> 
>     vlc_mutex_lock(&decklink_sys.m_lock);
>     uintptr_t new_ref = vlc_atomic_inc( &decklink_sys.m_ref );
>     msg_Dbg( aout, "Open Audio Decklink ref = %d", (int)new_ref);
>     vlc_mutex_unlock(&decklink_sys.m_lock);
> 
>     return VLC_SUCCESS;
> 
> 
> }
> 
> /**************************************************************************
> *** * Close: destroy interface
>  **************************************************************************
> ***/
> 
> static void CloseAudio( vlc_object_t *p_this )
> {
>     audio_output_t * aout = (audio_output_t *)p_this;
>     aout_sys_t *a_sys = aout->sys;
> 
>     HRESULT result;
>     a_sys->aoutTotalAudioPackages = 0;
>     free(a_sys);
> 
>     //If ref = 0
>     vlc_mutex_lock(&decklink_sys.m_lock);
>     uintptr_t new_ref = vlc_atomic_dec( &decklink_sys.m_ref );
>     vlc_mutex_unlock(&decklink_sys.m_lock);
>     msg_Dbg(aout,"Close Decklink Video, Decklink ref = %d",
> (int)vlc_atomic_get( &decklink_sys.m_ref ));
>     CloseDecklink((vlc_object_t *)aout);
> }
> 
> static void PlayAudio( audio_output_t * aout, block_t *p_buffer)
> {
>     aout_sys_t *a_sys = aout->sys;
> 
>     uint32_t sampleFrameCount = p_buffer->i_buffer / (sizeof(int16_t) *
> aout-
> 
> >format.i_channels);
> 
>     BMDTimeValue streamLength =  p_buffer->i_length;
> 
>     if ((decklink_sys.p_output->ScheduleAudioSamples (p_buffer->p_buffer,
> sampleFrameCount,a_sys->aoutTotalAudioPackages * streamLength, CLOCK_FREQ,
> NULL)) != S_OK)
>     {
>         msg_Dbg( aout, "Failed to schedule audio sample");
>     }
> 
>     a_sys->aoutTotalAudioPackages++;
>     aout_BufferFree( p_buffer );
> }

-- 
Rémi Denis-Courmont
http://www.remlab.net/
http://fi.linkedin.com/in/remidenis



More information about the vlc-devel mailing list