Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
9c389165
Commit
9c389165
authored
Jan 22, 2013
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Decklink output
parent
88ed3dba
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
814 additions
and
1 deletion
+814
-1
NEWS
NEWS
+1
-0
configure.ac
configure.ac
+1
-1
modules/LIST
modules/LIST
+1
-0
modules/video_output/Modules.am
modules/video_output/Modules.am
+7
-0
modules/video_output/decklink.cpp
modules/video_output/decklink.cpp
+803
-0
po/POTFILES.in
po/POTFILES.in
+1
-0
No files found.
NEWS
View file @
9c389165
...
...
@@ -64,6 +64,7 @@ Audio Filters:
* new VSXu visualization plugin
Video Outputs:
* DecklinkOutput: New module using Blackmagic cards
* OpenGL: use glsl instead of ARB to do the YUV->RGB conversions
* Fix the power management issue on Windows for standby management
...
...
configure.ac
View file @
9c389165
...
...
@@ -1764,7 +1764,7 @@ if test "${enable_decklink}" != "no"
then
if test "${with_decklink_sdk}" != "no" -a -n "${with_decklink_sdk}"
then
VLC_ADD_CXXFLAGS([decklink],[-I${with_decklink_sdk}/include])
VLC_ADD_CXXFLAGS([decklink
decklinkoutput
],[-I${with_decklink_sdk}/include])
fi
VLC_SAVE_FLAGS
CXXFLAGS="${CXXFLAGS} ${CXXFLAGS_decklink}"
...
...
modules/LIST
View file @
9c389165
...
...
@@ -85,6 +85,7 @@ $Id$
* dc1394: IIDC (DCAM) FireWire input module
* ddummy: dummy decoder
* decklink: input module to read from a Blackmagic SDI card
* decklinkoutput: output module to write to Blackmagic SDI card
* decomp: Decompression module
* deinterlace: naive deinterlacing filter
* demux_cdg: Demuxer for CD-G files (Karaoke)
...
...
modules/video_output/Modules.am
View file @
9c389165
...
...
@@ -10,6 +10,13 @@ SOURCES_vout_macosx = macosx.m opengl.h opengl.c
SOURCES_vout_ios = ios.m opengl.h opengl.c
SOURCES_android_surface = androidsurface.c
if HAVE_DECKLINK
libdecklinkoutput_plugin_la_SOURCES = decklink.cpp
libdecklinkoutput_plugin_la_CXXFLAGS = $(AM_CFLAGS) $(CXXFLAGS_decklinkoutput)
libdecklinkoutput_plugin_la_LIBADD = $(AM_LIBADD) $(LIBS_decklink) $(LIBDL)
libvlc_LTLIBRARIES += libdecklinkoutput_plugin.la
endif
### OpenGL ###
# TODO: merge all three source files (?)
libgles2_plugin_la_SOURCES = opengl.c opengl.h gl.c
...
...
modules/video_output/decklink.cpp
0 → 100644
View file @
9c389165
/*****************************************************************************
* decklink.cpp: BlackMagic DeckLink SDI output module
*****************************************************************************
* Copyright (C) 2012-2013 Rafaël Carré
* Copyright (C) 2009 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
*
* Authors: Rafaël Carré <funman@videolan.org>
*
* This program 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.
*
* This library 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*
* TODO:
* - test non stereo audio
* - inherit aout/vout settings from corresponding module
* (allow to change settings between successive runs per instance)
* - allow several instances per process
* - get rid of process-wide destructor
*/
#define __STDC_FORMAT_MACROS
#define __STDC_CONSTANT_MACROS
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdint.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_threads.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>
#define FRAME_SIZE 1920
#define CHANNELS_MAX 6
#if 0
static const int pi_channels_maps[CHANNELS_MAX+1] =
{
0,
AOUT_CHAN_CENTER,
AOUT_CHANS_STEREO,
AOUT_CHANS_3_0,
AOUT_CHANS_4_0,
AOUT_CHANS_5_0,
AOUT_CHANS_5_1,
};
#endif
#define CARD_INDEX_TEXT N_("Output card")
#define CARD_INDEX_LONGTEXT N_(\
"DeckLink output card, if multiple exist. " \
"The cards are numbered from 0.")
#define MODE_TEXT N_("Desired output mode")
#define MODE_LONGTEXT N_(\
"Desired output 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 for DeckLink output.")
#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.")
#define CHANNELS_TEXT N_("Number of audio channels")
#define CHANNELS_LONGTEXT N_(\
"Number of output 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 for DeckLink output.")
#define VIDEO_TENBITS_TEXT N_("10 bits")
#define VIDEO_TENBITS_LONGTEXT N_(\
"Use 10 bits per pixel for video frames.")
#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"
)
};
static
const
char
*
const
ppsz_audioconns
[]
=
{
"embedded"
,
"aesebu"
,
"analog"
};
static
const
char
*
const
ppsz_audioconns_text
[]
=
{
N_
(
"Embedded"
),
N_
(
"AES/EBU"
),
N_
(
"Analog"
)
};
struct
vout_display_sys_t
{
picture_pool_t
*
pool
;
bool
tenbits
;
};
/* Only one audio output module and one video output module
* can be used per process.
* We use a static mutex in audio/video submodules entry points. */
static
struct
{
IDeckLink
*
p_card
;
IDeckLinkOutput
*
p_output
;
IDeckLinkConfiguration
*
p_config
;
IDeckLinkDisplayModeIterator
*
p_display_iterator
;
IDeckLinkIterator
*
decklink_iterator
;
//int i_channels;
int
i_rate
;
int
i_width
;
int
i_height
;
BMDTimeScale
timescale
;
BMDTimeValue
frameduration
;
/* XXX: workaround card clock drift */
mtime_t
offset
;
}
decklink_sys
=
{
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
,
0
,
-
1
,
-
1
,
0
,
0
,
0
,
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static
int
OpenVideo
(
vlc_object_t
*
);
static
void
CloseVideo
(
vlc_object_t
*
);
static
int
OpenAudio
(
vlc_object_t
*
);
static
void
CloseAudio
(
vlc_object_t
*
);
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin
()
set_shortname
(
N_
(
"DecklinkOutput"
))
set_description
(
N_
(
"output module to write to Blackmagic SDI card"
))
set_section
(
N_
(
"Decklink General Options"
),
NULL
)
add_integer
(
CFG_PREFIX
"card-index"
,
0
,
CARD_INDEX_TEXT
,
CARD_INDEX_LONGTEXT
,
true
)
add_submodule
()
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"
,
"sdi"
,
VIDEO_CONNECTION_TEXT
,
VIDEO_CONNECTION_LONGTEXT
,
true
)
change_string_list
(
ppsz_videoconns
,
ppsz_videoconns_text
)
add_string
(
VIDEO_CFG_PREFIX
"mode"
,
"pal "
,
MODE_TEXT
,
MODE_LONGTEXT
,
true
)
add_bool
(
VIDEO_CFG_PREFIX
"tenbits"
,
false
,
VIDEO_TENBITS_TEXT
,
VIDEO_TENBITS_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"
,
"embedded"
,
AUDIO_CONNECTION_TEXT
,
AUDIO_CONNECTION_LONGTEXT
,
true
)
change_string_list
(
ppsz_audioconns
,
ppsz_audioconns_text
)
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
()
// Connection mode
static
BMDAudioConnection
getAConn
(
vlc_object_t
*
p_this
)
{
BMDAudioConnection
conn
=
bmdAudioConnectionEmbedded
;
char
*
psz
=
var_InheritString
(
p_this
,
AUDIO_CFG_PREFIX
"audio-connection"
);
if
(
!
psz
)
goto
end
;
if
(
!
strcmp
(
psz
,
"embedded"
))
conn
=
bmdAudioConnectionEmbedded
;
else
if
(
!
strcmp
(
psz
,
"aesebu"
))
conn
=
bmdAudioConnectionAESEBU
;
else
if
(
!
strcmp
(
psz
,
"analog"
))
conn
=
bmdAudioConnectionAnalog
;
end:
free
(
psz
);
return
conn
;
}
static
BMDVideoConnection
getVConn
(
vlc_object_t
*
p_this
)
{
BMDVideoConnection
conn
=
bmdVideoConnectionSDI
;
char
*
psz
=
var_InheritString
(
p_this
,
VIDEO_CFG_PREFIX
"video-connection"
);
if
(
!
psz
)
goto
end
;
if
(
!
strcmp
(
psz
,
"sdi"
))
conn
=
bmdVideoConnectionSDI
;
else
if
(
!
strcmp
(
psz
,
"hdmi"
))
conn
=
bmdVideoConnectionHDMI
;
else
if
(
!
strcmp
(
psz
,
"opticalsdi"
))
conn
=
bmdVideoConnectionOpticalSDI
;
else
if
(
!
strcmp
(
psz
,
"component"
))
conn
=
bmdVideoConnectionComponent
;
else
if
(
!
strcmp
(
psz
,
"composite"
))
conn
=
bmdVideoConnectionComposite
;
else
if
(
!
strcmp
(
psz
,
"svideo"
))
conn
=
bmdVideoConnectionSVideo
;
end:
free
(
psz
);
return
conn
;
}
/*****************************************************************************
*
*****************************************************************************/
static
atomic_uint
initialized
=
ATOMIC_VAR_INIT
(
0
);
static
void
CloseDecklink
(
void
)
__attribute__
((
destructor
));
static
void
CloseDecklink
(
void
)
{
if
(
!
atomic_load
(
&
initialized
))
return
;
decklink_sys
.
p_output
->
StopScheduledPlayback
(
0
,
NULL
,
0
);
decklink_sys
.
p_output
->
DisableVideoOutput
();
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
();
}
static
int
OpenDecklink
(
vlc_object_t
*
p_this
)
{
vout_display_t
*
vd
=
(
vout_display_t
*
)
p_this
;
vout_display_sys_t
*
sys
=
vd
->
sys
;
#define CHECK(message) do { \
if (result != S_OK) \
{ \
msg_Err(p_this, message ": 0x%X", result); \
goto error; \
} \
} while(0)
HRESULT
result
;
IDeckLinkDisplayMode
*
p_display_mode
=
NULL
;
static
vlc_mutex_t
lock
=
VLC_STATIC_MUTEX
;
vlc_mutex_lock
(
&
lock
);
if
(
atomic_load
(
&
initialized
))
{
/* already initialized */
vlc_mutex_unlock
(
&
lock
);
return
VLC_SUCCESS
;
}
//decklink_sys.i_channels = var_InheritInteger(p_this, AUDIO_CFG_PREFIX "audio-channels");
decklink_sys
.
i_rate
=
var_InheritInteger
(
p_this
,
AUDIO_CFG_PREFIX
"audio-rate"
);
int
i_card_index
=
var_InheritInteger
(
p_this
,
CFG_PREFIX
"card-index"
);
BMDVideoConnection
vconn
=
getVConn
(
p_this
);
BMDAudioConnection
aconn
=
getAConn
(
p_this
);
char
*
mode
=
var_InheritString
(
p_this
,
VIDEO_CFG_PREFIX
"mode"
);
size_t
len
=
mode
?
strlen
(
mode
)
:
0
;
if
(
!
mode
||
len
>
4
)
{
free
(
mode
);
msg_Err
(
p_this
,
"Missing or invalid mode"
);
goto
error
;
}
BMDDisplayMode
wanted_mode_id
;
memset
(
&
wanted_mode_id
,
' '
,
4
);
strncpy
((
char
*
)
&
wanted_mode_id
,
mode
,
4
);
free
(
mode
);
if
(
i_card_index
<
0
)
{
msg_Err
(
p_this
,
"Invalid card index %d"
,
i_card_index
);
goto
error
;
}
decklink_sys
.
decklink_iterator
=
CreateDeckLinkIteratorInstance
();
if
(
!
decklink_sys
.
decklink_iterator
)
{
msg_Err
(
p_this
,
"DeckLink drivers not found."
);
goto
error
;
}
for
(
int
i
=
0
;
i
<=
i_card_index
;
++
i
)
{
if
(
decklink_sys
.
p_card
)
decklink_sys
.
p_card
->
Release
();
result
=
decklink_sys
.
decklink_iterator
->
Next
(
&
decklink_sys
.
p_card
);
CHECK
(
"Card not found"
);
}
const
char
*
psz_model_name
;
result
=
decklink_sys
.
p_card
->
GetModelName
(
&
psz_model_name
);
CHECK
(
"Unknown model name"
);
msg_Dbg
(
p_this
,
"Opened DeckLink PCI card %s"
,
psz_model_name
);
result
=
decklink_sys
.
p_card
->
QueryInterface
(
IID_IDeckLinkOutput
,
(
void
**
)
&
decklink_sys
.
p_output
);
CHECK
(
"No outputs"
);
result
=
decklink_sys
.
p_card
->
QueryInterface
(
IID_IDeckLinkConfiguration
,
(
void
**
)
&
decklink_sys
.
p_config
);
CHECK
(
"Could not get config interface"
);
if
(
vconn
)
{
result
=
decklink_sys
.
p_config
->
SetInt
(
bmdDeckLinkConfigVideoOutputConnection
,
vconn
);
CHECK
(
"Could not set video output connection"
);
}
if
(
aconn
)
{
result
=
decklink_sys
.
p_config
->
SetInt
(
bmdDeckLinkConfigAudioInputConnection
,
aconn
);
CHECK
(
"Could not set audio output connection"
);
}
result
=
decklink_sys
.
p_output
->
GetDisplayModeIterator
(
&
decklink_sys
.
p_display_iterator
);
CHECK
(
"Could not enumerate display modes"
);
for
(;
;
p_display_mode
->
Release
())
{
int
w
,
h
;
result
=
decklink_sys
.
p_display_iterator
->
Next
(
&
p_display_mode
);
if
(
result
!=
S_OK
)
break
;
BMDDisplayMode
mode_id
=
ntohl
(
p_display_mode
->
GetDisplayMode
());
const
char
*
psz_mode_name
;
result
=
p_display_mode
->
GetName
(
&
psz_mode_name
);
CHECK
(
"Could not get display mode name"
);
result
=
p_display_mode
->
GetFrameRate
(
&
decklink_sys
.
frameduration
,
&
decklink_sys
.
timescale
);
CHECK
(
"Could not get frame rate"
);
w
=
p_display_mode
->
GetWidth
();
h
=
p_display_mode
->
GetHeight
();
msg_Dbg
(
p_this
,
"Found mode '%4.4s': %s (%dx%d, %.3f fps)"
,
(
char
*
)
&
mode_id
,
psz_mode_name
,
w
,
h
,
double
(
decklink_sys
.
timescale
)
/
decklink_sys
.
frameduration
);
msg_Dbg
(
p_this
,
"scale %d dur %d"
,
(
int
)
decklink_sys
.
timescale
,
(
int
)
decklink_sys
.
frameduration
);
if
(
wanted_mode_id
!=
mode_id
)
continue
;
decklink_sys
.
i_width
=
w
;
decklink_sys
.
i_height
=
h
;
p_display_mode
->
Release
();
p_display_mode
=
NULL
;
mode_id
=
htonl
(
mode_id
);
BMDVideoOutputFlags
flags
=
bmdVideoOutputVANC
;
if
(
mode_id
==
bmdModeNTSC
||
mode_id
==
bmdModeNTSC2398
||
mode_id
==
bmdModePAL
)
{
flags
=
bmdVideoOutputVITC
;
}
BMDDisplayModeSupport
support
;
IDeckLinkDisplayMode
*
resultMode
;
result
=
decklink_sys
.
p_output
->
DoesSupportVideoMode
(
mode_id
,
sys
->
tenbits
?
bmdFormat10BitYUV
:
bmdFormat8BitYUV
,
flags
,
&
support
,
&
resultMode
);
CHECK
(
"Does not support video mode"
);
if
(
support
==
bmdDisplayModeNotSupported
)
{
msg_Err
(
p_this
,
"Video mode not supported"
);
goto
error
;
}
result
=
decklink_sys
.
p_output
->
EnableVideoOutput
(
mode_id
,
flags
);
CHECK
(
"Could not enable video output"
);
break
;
}
if
(
decklink_sys
.
i_width
<
0
)
{
msg_Err
(
p_this
,
"Unknown video mode specified."
);
goto
error
;
}
/* audio */
if
(
/*decklink_sys.i_channels > 0 &&*/
decklink_sys
.
i_rate
>
0
)
{
result
=
decklink_sys
.
p_output
->
EnableAudioOutput
(
decklink_sys
.
i_rate
,
bmdAudioSampleType16bitInteger
,
/*decklink_sys.i_channels*/
2
,
bmdAudioOutputStreamTimestamped
);
}
else
{
result
=
decklink_sys
.
p_output
->
DisableAudioOutput
();
}
CHECK
(
"Could not enable audio output"
);
/* start */
result
=
decklink_sys
.
p_output
->
StartScheduledPlayback
(
(
mdate
()
*
decklink_sys
.
timescale
)
/
CLOCK_FREQ
,
decklink_sys
.
timescale
,
1.0
);
CHECK
(
"Could not start playback"
);
atomic_store
(
&
initialized
,
1
);
vlc_mutex_unlock
(
&
lock
);
return
VLC_SUCCESS
;
error:
if
(
decklink_sys
.
decklink_iterator
)
decklink_sys
.
decklink_iterator
->
Release
();
if
(
decklink_sys
.
p_display_iterator
)
decklink_sys
.
p_display_iterator
->
Release
();
if
(
p_display_mode
)
p_display_mode
->
Release
();
vlc_mutex_unlock
(
&
lock
);
return
VLC_EGENERIC
;
#undef CHECK
}
/*****************************************************************************
* Video
*****************************************************************************/
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
inline
void
put_le32
(
uint8_t
**
p
,
uint32_t
d
)
{
SetDWLE
(
*
p
,
d
);
(
*
p
)
+=
4
;
}
static
inline
int
clip
(
int
a
)
{
if
(
a
<
4
)
return
4
;
else
if
(
a
>
1019
)
return
1019
;
else
return
a
;
}
static
void
v210_convert
(
void
*
frame_bytes
,
picture_t
*
pic
,
int
dst_stride
)
{
int
width
=
pic
->
format
.
i_width
;
int
height
=
pic
->
format
.
i_height
;
int
line_padding
=
dst_stride
-
((
width
*
8
+
11
)
/
12
)
*
4
;
int
h
,
w
;
uint8_t
*
data
=
(
uint8_t
*
)
frame_bytes
;
const
uint16_t
*
y
=
(
const
uint16_t
*
)
pic
->
p
[
0
].
p_pixels
;
const
uint16_t
*
u
=
(
const
uint16_t
*
)
pic
->
p
[
1
].
p_pixels
;
const
uint16_t
*
v
=
(
const
uint16_t
*
)
pic
->
p
[
2
].
p_pixels
;
#define WRITE_PIXELS(a, b, c) \
do { \
val = clip(*a++); \
val |= (clip(*b++) << 10) | \
(clip(*c++) << 20); \
put_le32(&data, val); \
} while (0)
for
(
h
=
0
;
h
<
height
;
h
++
)
{
uint32_t
val
=
0
;
for
(
w
=
0
;
w
<
width
-
5
;
w
+=
6
)
{
WRITE_PIXELS
(
u
,
y
,
v
);
WRITE_PIXELS
(
y
,
u
,
y
);
WRITE_PIXELS
(
v
,
y
,
u
);
WRITE_PIXELS
(
y
,
v
,
y
);
}
if
(
w
<
width
-
1
)
{
WRITE_PIXELS
(
u
,
y
,
v
);
val
=
clip
(
*
y
++
);
if
(
w
==
width
-
2
)
put_le32
(
&
data
,
val
);
#undef WRITE_PIXELS
}
if
(
w
<
width
-
3
)
{
val
|=
(
clip
(
*
u
++
)
<<
10
)
|
(
clip
(
*
y
++
)
<<
20
);
put_le32
(
&
data
,
val
);
val
=
clip
(
*
v
++
)
|
(
clip
(
*
y
++
)
<<
10
);
put_le32
(
&
data
,
val
);
}
memset
(
data
,
0
,
line_padding
);
data
+=
line_padding
;
y
+=
pic
->
p
[
0
].
i_pitch
/
2
-
width
;
u
+=
pic
->
p
[
1
].
i_pitch
/
2
-
width
/
2
;
v
+=
pic
->
p
[
2
].
i_pitch
/
2
-
width
/
2
;
}
}
static
void
DisplayVideo
(
vout_display_t
*
vd
,
picture_t
*
picture
,
subpicture_t
*
)
{
vout_display_sys_t
*
sys
=
vd
->
sys
;
if
(
!
picture
)
return
;
HRESULT
result
;
int
w
,
h
,
stride
,
length
;
mtime_t
now
;
w
=
decklink_sys
.
i_width
;
h
=
decklink_sys
.
i_height
;
IDeckLinkMutableVideoFrame
*
pDLVideoFrame
;
result
=
decklink_sys
.
p_output
->
CreateVideoFrame
(
w
,
h
,
w
*
3
,
sys
->
tenbits
?
bmdFormat10BitYUV
:
bmdFormat8BitYUV
,
bmdFrameFlagDefault
,
&
pDLVideoFrame
);
if
(
result
!=
S_OK
)
{
msg_Err
(
vd
,
"Failed to create video frame: 0x%X"
,
result
);
pDLVideoFrame
=
NULL
;
goto
end
;
}
void
*
frame_bytes
;
pDLVideoFrame
->
GetBytes
((
void
**
)
&
frame_bytes
);
stride
=
pDLVideoFrame
->
GetRowBytes
();
if
(
sys
->
tenbits
)
v210_convert
(
frame_bytes
,
picture
,
stride
);
else
for
(
int
y
=
0
;
y
<
h
;
++
y
)
{
uint8_t
*
dst
=
(
uint8_t
*
)
frame_bytes
+
stride
*
y
;
const
uint8_t
*
src
=
(
const
uint8_t
*
)
picture
->
p
[
0
].
p_pixels
+
picture
->
p
[
0
].
i_pitch
*
y
;
memcpy
(
dst
,
src
,
w
*
2
/* bpp */
);
}
// compute frame duration in CLOCK_FREQ units
length
=
(
decklink_sys
.
frameduration
*
CLOCK_FREQ
)
/
decklink_sys
.
timescale
;
picture
->
date
-=
decklink_sys
.
offset
;
result
=
decklink_sys
.
p_output
->
ScheduleVideoFrame
(
pDLVideoFrame
,
picture
->
date
,
length
,
CLOCK_FREQ
);
if
(
result
!=
S_OK
)
{
msg_Err
(
vd
,
"Dropped Video frame %"
PRId64
": 0x%x"
,
picture
->
date
,
result
);
goto
end
;
}
now
=
mdate
()
-
decklink_sys
.
offset
;
BMDTimeValue
decklink_now
;
double
speed
;
decklink_sys
.
p_output
->
GetScheduledStreamTime
(
CLOCK_FREQ
,
&
decklink_now
,
&
speed
);
if
((
now
-
decklink_now
)
>
400000
)
{
/* XXX: workaround card clock drift */
decklink_sys
.
offset
+=
50000
;
msg_Err
(
vd
,
"Delaying: offset now %"
PRId64
""
,
decklink_sys
.
offset
);
}
end:
if
(
pDLVideoFrame
)
pDLVideoFrame
->
Release
();
picture_Release
(
picture
);
}
static
int
ControlVideo
(
vout_display_t
*
vd
,
int
query
,
va_list
args
)
{
VLC_UNUSED
(
vd
);
const
vout_display_cfg_t
*
cfg
;
switch
(
query
)
{
case
VOUT_DISPLAY_CHANGE_FULLSCREEN
:
cfg
=
va_arg
(
args
,
const
vout_display_cfg_t
*
);
return
cfg
->
is_fullscreen
?
VLC_EGENERIC
:
VLC_SUCCESS
;
default:
return
VLC_EGENERIC
;
}
}
static
atomic_uint
video_lock
=
ATOMIC_VAR_INIT
(
0
);
static
int
OpenVideo
(
vlc_object_t
*
p_this
)
{
vout_display_t
*
vd
=
(
vout_display_t
*
)
p_this
;
vout_display_sys_t
*
sys
;
if
(
atomic_exchange
(
&
video_lock
,
1
))
{
msg_Err
(
vd
,
"Decklink video module already busy"
);
return
VLC_EGENERIC
;
}
vd
->
sys
=
sys
=
(
vout_display_sys_t
*
)
malloc
(
sizeof
(
*
sys
));
if
(
!
sys
)
return
VLC_ENOMEM
;
if
(
OpenDecklink
(
p_this
)
!=
VLC_SUCCESS
)
goto
error
;
if
(
decklink_sys
.
i_width
&
1
)
{
msg_Err
(
vd
,
"Invalid width %d"
,
decklink_sys
.
i_width
);
goto
error
;
}
sys
->
pool
=
NULL
;
sys
->
tenbits
=
var_InheritBool
(
p_this
,
VIDEO_CFG_PREFIX
"tenbits"
);
vd
->
fmt
.
i_chroma
=
sys
->
tenbits
?
VLC_CODEC_I422_10L
/* we will convert to v210 */
:
VLC_CODEC_UYVY
;
//video_format_FixRgb(&(vd->fmt));
vd
->
fmt
.
i_width
=
decklink_sys
.
i_width
;
vd
->
fmt
.
i_height
=
decklink_sys
.
i_height
;
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
);
return
VLC_SUCCESS
;
error:
free
(
sys
);
return
VLC_EGENERIC
;
}
static
void
CloseVideo
(
vlc_object_t
*
p_this
)
{
vout_display_t
*
vd
=
(
vout_display_t
*
)
p_this
;
vout_display_sys_t
*
sys
=
vd
->
sys
;
if
(
sys
->
pool
)
picture_pool_Delete
(
sys
->
pool
);
free
(
sys
);
atomic_fetch_sub
(
&
video_lock
,
1
);
}
/*****************************************************************************
* Audio
*****************************************************************************/
static
void
Flush
(
audio_output_t
*
aout
,
bool
drain
)
{
if
(
!
atomic_load
(
&
initialized
))
return
;
if
(
drain
)
{
uint32_t
samples
;
decklink_sys
.
p_output
->
GetBufferedAudioSampleFrameCount
(
&
samples
);
msleep
(
CLOCK_FREQ
*
samples
/
decklink_sys
.
i_rate
);
}
else
if
(
decklink_sys
.
p_output
->
FlushBufferedAudioSamples
()
==
E_FAIL
)
msg_Err
(
aout
,
"Flush failed"
);
}
static
int
TimeGet
(
audio_output_t
*
,
mtime_t
*
restrict
)
{
/* synchronization is handled by the card */
return
-
1
;
}
static
int
Start
(
audio_output_t
*
,
audio_sample_format_t
*
restrict
fmt
)
{
fmt
->
i_format
=
VLC_CODEC_S16N
;
fmt
->
i_channels
=
2
;
//decklink_sys.i_channels;
fmt
->
i_physical_channels
=
AOUT_CHANS_STEREO
;
//pi_channels_maps[fmt->i_channels];
fmt
->
i_rate
=
decklink_sys
.
i_rate
;
fmt
->
i_bitspersample
=
16
;
fmt
->
i_blockalign
=
fmt
->
i_channels
*
fmt
->
i_bitspersample
/
8
;
fmt
->
i_frame_length
=
FRAME_SIZE
;
return
VLC_SUCCESS
;
}
static
void
PlayAudio
(
audio_output_t
*
aout
,
block_t
*
audio
)
{
if
(
!
atomic_load
(
&
initialized
))
return
;
audio
->
i_pts
-=
decklink_sys
.
offset
;
uint32_t
sampleFrameCount
=
audio
->
i_buffer
/
(
2
*
2
/*decklink_sys.i_channels*/
);
uint32_t
written
;
HRESULT
result
=
decklink_sys
.
p_output
->
ScheduleAudioSamples
(
audio
->
p_buffer
,
sampleFrameCount
,
audio
->
i_pts
,
CLOCK_FREQ
,
&
written
);
if
(
result
!=
S_OK
)
msg_Err
(
aout
,
"Failed to schedule audio sample: 0x%X"
,
result
);
else
if
(
sampleFrameCount
!=
written
)
msg_Err
(
aout
,
"Written only %d samples out of %d"
,
written
,
sampleFrameCount
);
block_Release
(
audio
);
}
static
atomic_uint
audio_lock
=
ATOMIC_VAR_INIT
(
0
);
static
int
OpenAudio
(
vlc_object_t
*
p_this
)
{
audio_output_t
*
aout
=
(
audio_output_t
*
)
p_this
;
if
(
atomic_exchange
(
&
audio_lock
,
1
))
{
msg_Err
(
aout
,
"Decklink audio module already busy"
);
return
VLC_EGENERIC
;
}
aout
->
play
=
PlayAudio
;
aout
->
start
=
Start
;
aout
->
flush
=
Flush
;
aout
->
time_get
=
TimeGet
;
aout
->
pause
=
NULL
;
aout
->
stop
=
NULL
;
aout
->
mute_set
=
NULL
;
aout
->
volume_set
=
NULL
;
return
VLC_SUCCESS
;
}
static
void
CloseAudio
(
vlc_object_t
*
)
{
atomic_fetch_sub
(
&
audio_lock
,
1
);
}
po/POTFILES.in
View file @
9c389165
...
...
@@ -1141,6 +1141,7 @@ modules/video_filter/yuvp.c
modules/video_output/aa.c
modules/video_output/androidsurface.c
modules/video_output/caca.c
modules/video_output/decklink.cpp
modules/video_output/directfb.c
modules/video_output/drawable.c
modules/video_output/egl.c
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment