61#define STDMETHODCALLTYPE
65class PlaybackDelegate;
68#define DECKLINK_MAGIC 0x415f46d0
69#define MOD_NAME "[DeckLink audio play.] "
92class PlaybackDelegate :
public IDeckLinkVideoOutputCallback
103 virtual HRESULT
STDMETHODCALLTYPE QueryInterface (REFIID, LPVOID *) {
return E_NOINTERFACE;}
107 virtual HRESULT
STDMETHODCALLTYPE ScheduledFrameCompleted (IDeckLinkVideoFrame *, BMDOutputFrameCompletionResult) {
113 virtual HRESULT
STDMETHODCALLTYPE ScheduledPlaybackHasStopped () {
return S_OK; }
117static void audio_play_decklink_probe(
struct device_info **available_devices,
int *
count,
void (**
deleter)(
void *))
121 strcpy((*available_devices)[0].dev,
"");
122 strcpy((*available_devices)[0].
name,
"Audio-only output through DeckLink device");
126static void audio_play_decklink_help()
128 IDeckLinkIterator* deckLinkIterator;
133 printf(
"Audio-only DeckLink output. For simultaneous audio and video use the DeckLink display "
134 "with analog/embedded audio playback module.\n");
136 col() <<
SBOLD(
SRED(
"\t-r decklink")) <<
"[:<index>][:audioConsumerLevels={true|false}]\n";
138 col() <<
SBOLD(
"audioConsumerLevels")
"\n";
139 printf(
"\tIf set true the analog audio levels are set to maximum gain on audio input.\n");
140 printf(
"\tIf set false the selected analog input gain levels are used.\n");
143 bool com_initialized =
false;
145 if (deckLinkIterator == NULL)
150 printf(
"Available Blackmagic audio playback devices:\n");
153 while (deckLinkIterator->Next(&deckLink) == S_OK)
155 BMD_STR deviceNameString = NULL;
158 result = deckLink->GetModelName(&deviceNameString);
162 printf(
"\tdecklink:%d : Blackmagic %s\n",numDevices, deviceNameCString);
164 free(deviceNameCString);
174 deckLinkIterator->Release();
180 printf(
"\nNo Blackmagic Design devices were found.\n");
185static void *audio_play_decklink_init(
const char *cfg)
188 IDeckLinkIterator* deckLinkIterator;
190 IDeckLinkConfiguration* deckLinkConfiguration = NULL;
196 IDeckLinkDisplayModeIterator *displayModeIterator = NULL;
197 IDeckLinkDisplayMode *deckLinkDisplayMode = NULL;
205 if (strlen(cfg) == 0) {
207 fprintf(stderr,
"Card number unset, using first found (see -r decklink:help)!\n");
208 }
else if (strcmp(cfg,
"help") == 0) {
209 audio_play_decklink_help();
213 char *tmp = strdup(cfg);
214 char *
item, *save_ptr;
215 item = strtok_r(tmp,
":", &save_ptr);
217 if(strncasecmp(
item,
"audioConsumerLevels=",
218 strlen(
"audioConsumerLevels=")) == 0) {
219 char *levels =
item + strlen(
"audioConsumerLevels=");
220 if (strcasecmp(levels,
"false") == 0) {
225 item = strtok_r(NULL,
":", &save_ptr);
242 "\"-d decklink -r analog\" instead.\n");
246 if (!deckLinkIterator) {
251 while (deckLinkIterator->Next(&deckLink) == S_OK)
253 if (dnum == cardIdx){
262 fprintf(stderr,
"No DeckLink PCI card #%d found\n", cardIdx);
272 result = s->
deckLink->QueryInterface(IID_IDeckLinkConfiguration, (
void**)&deckLinkConfiguration);
275 printf(
"Could not obtain the IDeckLinkConfiguration interface: %08x\n", (
int) result);
280 result = deckLinkConfiguration->SetFlag(bmdDeckLinkConfigAnalogAudioConsumerLevels,
283 fprintf(stderr,
"[DeckLink capture] Unable set input audio consumer levels.\n");
286 deckLinkConfiguration->Release();
287 deckLinkConfiguration = NULL;
292 fprintf(stderr,
"Fatal: cannot create display mode iterator [decklink].\n");
297 if(displayModeIterator->Next(&deckLinkDisplayMode) == S_OK)
299 width = deckLinkDisplayMode->GetWidth();
300 height = deckLinkDisplayMode->GetHeight();
303 fprintf(stderr,
"[decklink] Fatal: cannot get any display mode.\n");
311 s->
delegate =
new PlaybackDelegate(s);
316 s->
deckLinkOutput->EnableVideoOutput(deckLinkDisplayMode->GetDisplayMode(), bmdVideoOutputFlagDefault);
318 displayModeIterator->Release();
319 displayModeIterator = NULL;
320 deckLinkDisplayMode->Release();
321 deckLinkDisplayMode = NULL;
327 if (displayModeIterator)
328 displayModeIterator->Release();
329 if (deckLinkDisplayMode)
330 deckLinkDisplayMode->Release();
331 if (deckLinkConfiguration)
332 deckLinkConfiguration->Release();
344 unsigned int sampleFrameCount =
frame->data_len /
346 uint32_t sampleFramesWritten;
347 char *data =
frame->data;
350 tmp_frame.
data = NULL;
355 memcpy(&tmp_frame,
frame,
sizeof(tmp_frame));
359 tmp_frame.data = (
char *) malloc(tmp_frame.max_size);
360 memcpy(tmp_frame.data,
frame->data,
frame->data_len);
365 data = tmp_frame.data;
368 s->
deckLinkOutput->ScheduleAudioSamples (data, sampleFrameCount, 0,
369 0, &sampleFramesWritten);
370 if(sampleFramesWritten != sampleFrameCount)
371 LOG(
LOG_LEVEL_ERROR) <<
"[decklink] audio buffer overflow! (" << sampleFramesWritten <<
" written, " << sampleFrameCount - sampleFramesWritten <<
"\n";
373 free(tmp_frame.data);
377static bool audio_play_decklink_ctl(
void *
state [[gnu::unused]],
int request,
void *data,
size_t *
len)
399 BMDAudioSampleType sample_type;
408 fprintf(stderr,
"[decklink] requested channel count isn't supported: "
418 if((
desc.bps != 2 &&
desc.bps != 4) ||
419 desc.sample_rate != 48000) {
426 sample_type = bmdAudioSampleType16bitInteger;
429 sample_type = bmdAudioSampleType32bitInteger;
438 bmdAudioOutputStreamContinuous);
444static void audio_play_decklink_done(
void *
state)
458 audio_play_decklink_probe,
459 audio_play_decklink_init,
460 audio_play_decklink_put_frame,
461 audio_play_decklink_ctl,
462 audio_play_decklink_reconfigure,
463 audio_play_decklink_done
struct video_frame * frame
int void(** deleter)(void *))
#define STDMETHODCALLTYPE
This file contains definition of some common audio types.
#define AUDIO_PLAYBACK_CTL_QUERY_FORMAT
#define AUDIO_PLAYBACK_ABI_VERSION
bool blackmagic_api_version_check()
IDeckLinkIterator * create_decklink_iterator(bool *com_initialized, bool verbose)
void release_bmd_api_str(BMD_STR string)
void decklink_uninitialize(bool *com_initialized)
char * get_cstr_from_bmd_api_str(BMD_STR bmd_string)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_WARNING
less severe errors
@ LIBRARY_CLASS_AUDIO_PLAYBACK
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
struct used to comunicate with audio capture/playback device
int audio_consumer_levels
0 false, 1 true, -1 default
BMDTimeValue frameRateDuration
PlaybackDelegate * delegate
struct audio_desc audio_desc
IDeckLinkMutableVideoFrame * deckLinkFrame
int output_audio_channel_count
BMDTimeScale frameRateScale
IDeckLinkOutput * deckLinkOutput
void audio_frame_multiply_channel(struct audio_frame *frame, int new_channel_count)