blob: c9107c036a59c717f67abcb448e0e4e27b8f97f0
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 | |
148 | int ff_decklink_set_format(AVFormatContext *avctx, |
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 | |
258 | int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) { |
259 | return ff_decklink_set_format(avctx, 0, 0, 0, 0, AV_FIELD_UNKNOWN, direction, num); |
260 | } |
261 | |
262 | int ff_decklink_list_devices(AVFormatContext *avctx) |
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 | |
282 | int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) |
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 | |
333 | void ff_decklink_cleanup(AVFormatContext *avctx) |
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 | |
350 | int ff_decklink_init_device(AVFormatContext *avctx, const char* name) |
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 | } |
390 |