FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
decklink_common.cpp
Go to the documentation of this file.
1 /*
2  * Blackmagic DeckLink output
3  * Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <DeckLinkAPI.h>
23 #ifdef _WIN32
24 #include <DeckLinkAPI_i.c>
25 #else
26 #include <DeckLinkAPIDispatch.cpp>
27 #endif
28 
29 #include <pthread.h>
30 #include <semaphore.h>
31 
32 extern "C" {
33 #include "libavformat/avformat.h"
34 #include "libavformat/internal.h"
35 #include "libavutil/imgutils.h"
36 #include "libavutil/intreadwrite.h"
37 #include "libavutil/bswap.h"
38 }
39 
40 #include "decklink_common.h"
41 
42 #ifdef _WIN32
43 IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
44 {
45  IDeckLinkIterator *iter;
46 
47  if (CoInitialize(NULL) < 0) {
48  av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
49  return NULL;
50  }
51 
52  if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
53  IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
54  av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
55  return NULL;
56  }
57 
58  return iter;
59 }
60 #endif
61 
62 #ifdef _WIN32
63 static char *dup_wchar_to_utf8(wchar_t *w)
64 {
65  char *s = NULL;
66  int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
67  s = (char *) av_malloc(l);
68  if (s)
69  WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
70  return s;
71 }
72 #define DECKLINK_STR OLECHAR *
73 #define DECKLINK_STRDUP dup_wchar_to_utf8
74 #define DECKLINK_FREE(s) SysFreeString(s)
75 #define DECKLINK_BOOL BOOL
76 #elif defined(__APPLE__)
77 static char *dup_cfstring_to_utf8(CFStringRef w)
78 {
79  char s[256];
80  CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
81  return av_strdup(s);
82 }
83 #define DECKLINK_STR const __CFString *
84 #define DECKLINK_STRDUP dup_cfstring_to_utf8
85 #define DECKLINK_FREE(s) free((void *) s)
86 #define DECKLINK_BOOL bool
87 #else
88 #define DECKLINK_STR const char *
89 #define DECKLINK_STRDUP av_strdup
90 /* free() is needed for a string returned by the DeckLink SDL. */
91 #define DECKLINK_FREE(s) free((void *) s)
92 #define DECKLINK_BOOL bool
93 #endif
94 
95 HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
96 {
97  DECKLINK_STR tmpDisplayName;
98  HRESULT hr = This->GetDisplayName(&tmpDisplayName);
99  if (hr != S_OK)
100  return hr;
101  *displayName = DECKLINK_STRDUP(tmpDisplayName);
102  DECKLINK_FREE(tmpDisplayName);
103  return hr;
104 }
105 
106 static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id)
107 {
108  struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
109  struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
110  BMDDeckLinkAttributeID attr_id = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? BMDDeckLinkAudioInputConnections : BMDDeckLinkVideoInputConnections;
111  int64_t bmd_input = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? (int64_t)ctx->audio_input : (int64_t)ctx->video_input;
112  const char *type_name = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? "audio" : "video";
113  int64_t supported_connections = 0;
114  HRESULT res;
115 
116  if (bmd_input) {
117  res = ctx->attr->GetInt(attr_id, &supported_connections);
118  if (res != S_OK) {
119  av_log(avctx, AV_LOG_ERROR, "Failed to query supported %s inputs.\n", type_name);
120  return AVERROR_EXTERNAL;
121  }
122  if ((supported_connections & bmd_input) != bmd_input) {
123  av_log(avctx, AV_LOG_ERROR, "Device does not support selected %s input.\n", type_name);
124  return AVERROR(ENOSYS);
125  }
126  res = ctx->cfg->SetInt(cfg_id, bmd_input);
127  if (res != S_OK) {
128  av_log(avctx, AV_LOG_ERROR, "Failed to select %s input.\n", type_name);
129  return AVERROR_EXTERNAL;
130  }
131  }
132  return 0;
133 }
134 
135 static DECKLINK_BOOL field_order_eq(enum AVFieldOrder field_order, BMDFieldDominance bmd_field_order)
136 {
137  if (field_order == AV_FIELD_UNKNOWN)
138  return true;
139  if ((field_order == AV_FIELD_TT || field_order == AV_FIELD_TB) && bmd_field_order == bmdUpperFieldFirst)
140  return true;
141  if ((field_order == AV_FIELD_BB || field_order == AV_FIELD_BT) && bmd_field_order == bmdLowerFieldFirst)
142  return true;
143  if (field_order == AV_FIELD_PROGRESSIVE && (bmd_field_order == bmdProgressiveFrame || bmd_field_order == bmdProgressiveSegmentedFrame))
144  return true;
145  return false;
146 }
147 
149  int width, int height,
150  int tb_num, int tb_den,
151  enum AVFieldOrder field_order,
152  decklink_direction_t direction, int num)
153 {
154  struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
155  struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
156  BMDDisplayModeSupport support;
157  IDeckLinkDisplayModeIterator *itermode;
158  IDeckLinkDisplayMode *mode;
159  int i = 1;
160  HRESULT res;
161 
162  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",
163  width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)");
164 
165  if (ctx->duplex_mode) {
166  DECKLINK_BOOL duplex_supported = false;
167 
168  if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK)
169  duplex_supported = false;
170 
171  if (duplex_supported) {
172  res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf);
173  if (res != S_OK)
174  av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n");
175  else
176  av_log(avctx, AV_LOG_VERBOSE, "Successfully set duplex mode to %s duplex.\n", ctx->duplex_mode == 2 ? "full" : "half");
177  } else {
178  av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n");
179  }
180  }
181 
182  if (direction == DIRECTION_IN) {
183  int ret;
184  ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection);
185  if (ret < 0)
186  return ret;
187  ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection);
188  if (ret < 0)
189  return ret;
190  res = ctx->dli->GetDisplayModeIterator (&itermode);
191  } else {
192  res = ctx->dlo->GetDisplayModeIterator (&itermode);
193  }
194 
195  if (res!= S_OK) {
196  av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
197  return AVERROR(EIO);
198  }
199 
200  char format_buf[] = " ";
201  if (cctx->format_code)
202  memcpy(format_buf, cctx->format_code, FFMIN(strlen(cctx->format_code), sizeof(format_buf)));
203  BMDDisplayMode target_mode = (BMDDisplayMode)AV_RB32(format_buf);
204  AVRational target_tb = av_make_q(tb_num, tb_den);
205  ctx->bmd_mode = bmdModeUnknown;
206  while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
207  BMDTimeValue bmd_tb_num, bmd_tb_den;
208  int bmd_width = mode->GetWidth();
209  int bmd_height = mode->GetHeight();
210  BMDDisplayMode bmd_mode = mode->GetDisplayMode();
211  BMDFieldDominance bmd_field_dominance = mode->GetFieldDominance();
212 
213  mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
214  AVRational mode_tb = av_make_q(bmd_tb_num, bmd_tb_den);
215 
216  if ((bmd_width == width &&
217  bmd_height == height &&
218  !av_cmp_q(mode_tb, target_tb) &&
219  field_order_eq(field_order, bmd_field_dominance))
220  || i == num
221  || target_mode == bmd_mode) {
222  ctx->bmd_mode = bmd_mode;
223  ctx->bmd_width = bmd_width;
224  ctx->bmd_height = bmd_height;
225  ctx->bmd_tb_den = bmd_tb_den;
226  ctx->bmd_tb_num = bmd_tb_num;
227  ctx->bmd_field_dominance = bmd_field_dominance;
228  av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
229  bmd_width, bmd_height, 1/av_q2d(mode_tb),
230  (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
231  }
232 
233  mode->Release();
234  i++;
235  }
236 
237  itermode->Release();
238 
239  if (ctx->bmd_mode == bmdModeUnknown)
240  return -1;
241  if (direction == DIRECTION_IN) {
242  if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
243  bmdVideoOutputFlagDefault,
244  &support, NULL) != S_OK)
245  return -1;
246  } else {
247  if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
248  bmdVideoOutputFlagDefault,
249  &support, NULL) != S_OK)
250  return -1;
251  }
252  if (support == bmdDisplayModeSupported)
253  return 0;
254 
255  return -1;
256 }
257 
259  return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num);
260 }
261 
263 {
264  IDeckLink *dl = NULL;
265  IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
266  if (!iter) {
267  av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
268  return AVERROR(EIO);
269  }
270  av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
271  while (iter->Next(&dl) == S_OK) {
272  const char *displayName;
273  ff_decklink_get_display_name(dl, &displayName);
274  av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
275  av_free((void *) displayName);
276  dl->Release();
277  }
278  iter->Release();
279  return 0;
280 }
281 
283 {
284  struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
285  struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
286  IDeckLinkDisplayModeIterator *itermode;
287  IDeckLinkDisplayMode *mode;
288  uint32_t format_code;
289  HRESULT res;
290 
291  if (direction == DIRECTION_IN) {
292  int ret;
293  ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection);
294  if (ret < 0)
295  return ret;
296  ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection);
297  if (ret < 0)
298  return ret;
299  res = ctx->dli->GetDisplayModeIterator (&itermode);
300  } else {
301  res = ctx->dlo->GetDisplayModeIterator (&itermode);
302  }
303 
304  if (res!= S_OK) {
305  av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
306  return AVERROR(EIO);
307  }
308 
309  av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n\tformat_code\tdescription",
310  avctx->filename);
311  while (itermode->Next(&mode) == S_OK) {
312  BMDTimeValue tb_num, tb_den;
313  mode->GetFrameRate(&tb_num, &tb_den);
314  format_code = av_bswap32(mode->GetDisplayMode());
315  av_log(avctx, AV_LOG_INFO, "\n\t%.4s\t\t%ldx%ld at %d/%d fps",
316  (char*) &format_code, mode->GetWidth(), mode->GetHeight(),
317  (int) tb_den, (int) tb_num);
318  switch (mode->GetFieldDominance()) {
319  case bmdLowerFieldFirst:
320  av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
321  case bmdUpperFieldFirst:
322  av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
323  }
324  mode->Release();
325  }
326  av_log(avctx, AV_LOG_INFO, "\n");
327 
328  itermode->Release();
329 
330  return 0;
331 }
332 
334 {
335  struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
336  struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
337 
338  if (ctx->dli)
339  ctx->dli->Release();
340  if (ctx->dlo)
341  ctx->dlo->Release();
342  if (ctx->attr)
343  ctx->attr->Release();
344  if (ctx->cfg)
345  ctx->cfg->Release();
346  if (ctx->dl)
347  ctx->dl->Release();
348 }
349 
351 {
352  struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
353  struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
354  IDeckLink *dl = NULL;
355  IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
356  if (!iter) {
357  av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
358  return AVERROR_EXTERNAL;
359  }
360 
361  while (iter->Next(&dl) == S_OK) {
362  const char *displayName;
363  ff_decklink_get_display_name(dl, &displayName);
364  if (!strcmp(name, displayName)) {
365  av_free((void *)displayName);
366  ctx->dl = dl;
367  break;
368  }
369  av_free((void *)displayName);
370  dl->Release();
371  }
372  iter->Release();
373  if (!ctx->dl)
374  return AVERROR(ENXIO);
375 
376  if (ctx->dl->QueryInterface(IID_IDeckLinkConfiguration, (void **)&ctx->cfg) != S_OK) {
377  av_log(avctx, AV_LOG_ERROR, "Could not get configuration interface for '%s'\n", name);
378  ff_decklink_cleanup(avctx);
379  return AVERROR_EXTERNAL;
380  }
381 
382  if (ctx->dl->QueryInterface(IID_IDeckLinkAttributes, (void **)&ctx->attr) != S_OK) {
383  av_log(avctx, AV_LOG_ERROR, "Could not get attributes interface for '%s'\n", name);
384  ff_decklink_cleanup(avctx);
385  return AVERROR_EXTERNAL;
386  }
387 
388  return 0;
389 }
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
#define S_OK
Definition: windows2linux.h:40
misc image utilities
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Format I/O context.
Definition: avformat.h:1349
#define av_malloc(s)
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:87
#define height
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define av_log(a,...)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
static char * dup_wchar_to_utf8(wchar_t *w)
Definition: dshow.c:132
char filename[1024]
input or output filename
Definition: avformat.h:1425
#define FFMIN(a, b)
Definition: common.h:96
#define width
AVFormatContext * ctx
Definition: movenc.c:48
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
#define av_bswap32
Definition: bswap.h:33
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:237
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVFieldOrder
Definition: avcodec.h:1710
byte swapping routines
DWORD HRESULT
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
Main libavformat public API header.
int
#define av_free(p)
void * priv_data
Format private data.
Definition: avformat.h:1377
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
mode
Use these values in ebur128_init (or'ed).
Definition: ebur128.h:83
const char * name
Definition: opengl_enc.c:103