avdevice/decklink: add support for audio and video input selection
[ffmpeg.git] / libavdevice / decklink_common.cpp
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 }
37
38 #include "decklink_common.h"
39
40 #ifdef _WIN32
41 IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
42 {
43     IDeckLinkIterator *iter;
44
45     if (CoInitialize(NULL) < 0) {
46         av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
47         return NULL;
48     }
49
50     if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
51                          IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
52         av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
53         return NULL;
54     }
55
56     return iter;
57 }
58 #endif
59
60 #ifdef _WIN32
61 static char *dup_wchar_to_utf8(wchar_t *w)
62 {
63     char *s = NULL;
64     int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
65     s = (char *) av_malloc(l);
66     if (s)
67         WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
68     return s;
69 }
70 #define DECKLINK_STR    OLECHAR *
71 #define DECKLINK_STRDUP dup_wchar_to_utf8
72 #define DECKLINK_FREE(s) SysFreeString(s)
73 #elif defined(__APPLE__)
74 static char *dup_cfstring_to_utf8(CFStringRef w)
75 {
76     char s[256];
77     CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
78     return av_strdup(s);
79 }
80 #define DECKLINK_STR    const __CFString *
81 #define DECKLINK_STRDUP dup_cfstring_to_utf8
82 #define DECKLINK_FREE(s) free((void *) s)
83 #else
84 #define DECKLINK_STR    const char *
85 #define DECKLINK_STRDUP av_strdup
86 /* free() is needed for a string returned by the DeckLink SDL. */
87 #define DECKLINK_FREE(s) free((void *) s)
88 #endif
89
90 HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
91 {
92     DECKLINK_STR tmpDisplayName;
93     HRESULT hr = This->GetDisplayName(&tmpDisplayName);
94     if (hr != S_OK)
95         return hr;
96     *displayName = DECKLINK_STRDUP(tmpDisplayName);
97     DECKLINK_FREE(tmpDisplayName);
98     return hr;
99 }
100
101 static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id)
102 {
103     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
104     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
105     BMDDeckLinkAttributeID attr_id = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? BMDDeckLinkAudioInputConnections : BMDDeckLinkVideoInputConnections;
106     int64_t bmd_input              = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? ctx->audio_input : ctx->video_input;
107     const char *type_name          = (cfg_id == bmdDeckLinkConfigAudioInputConnection) ? "audio" : "video";
108     int64_t supported_connections = 0;
109     HRESULT res;
110
111     if (bmd_input) {
112         res = ctx->attr->GetInt(attr_id, &supported_connections);
113         if (res != S_OK) {
114             av_log(avctx, AV_LOG_ERROR, "Failed to query supported %s inputs.\n", type_name);
115             return AVERROR_EXTERNAL;
116         }
117         if ((supported_connections & bmd_input) != bmd_input) {
118             av_log(avctx, AV_LOG_ERROR, "Device does not support selected %s input.\n", type_name);
119             return AVERROR(ENOSYS);
120         }
121         res = ctx->cfg->SetInt(cfg_id, bmd_input);
122         if (res != S_OK) {
123             av_log(avctx, AV_LOG_ERROR, "Failed to select %s input.\n", type_name);
124             return AVERROR_EXTERNAL;
125         }
126     }
127     return 0;
128 }
129
130 int ff_decklink_set_format(AVFormatContext *avctx,
131                                int width, int height,
132                                int tb_num, int tb_den,
133                                decklink_direction_t direction, int num)
134 {
135     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
136     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
137     BMDDisplayModeSupport support;
138     IDeckLinkDisplayModeIterator *itermode;
139     IDeckLinkDisplayMode *mode;
140     int i = 1;
141     HRESULT res;
142
143     if (ctx->duplex_mode) {
144         bool duplex_supported = false;
145
146         if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK)
147             duplex_supported = false;
148
149         if (duplex_supported) {
150             res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf);
151             if (res != S_OK)
152                 av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n");
153             else
154                 av_log(avctx, AV_LOG_VERBOSE, "Succesfully set duplex mode to %s duplex.\n", ctx->duplex_mode == 2 ? "full" : "half");
155         } else {
156             av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n");
157         }
158     }
159
160     if (direction == DIRECTION_IN) {
161         int ret;
162         ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection);
163         if (ret < 0)
164             return ret;
165         ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection);
166         if (ret < 0)
167             return ret;
168         res = ctx->dli->GetDisplayModeIterator (&itermode);
169     } else {
170         res = ctx->dlo->GetDisplayModeIterator (&itermode);
171     }
172
173     if (res!= S_OK) {
174             av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
175             return AVERROR(EIO);
176     }
177
178
179     if (tb_num == 1) {
180         tb_num *= 1000;
181         tb_den *= 1000;
182     }
183     ctx->bmd_mode = bmdModeUnknown;
184     while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
185         BMDTimeValue bmd_tb_num, bmd_tb_den;
186         int bmd_width  = mode->GetWidth();
187         int bmd_height = mode->GetHeight();
188
189         mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
190
191         if ((bmd_width == width && bmd_height == height &&
192             bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) {
193             ctx->bmd_mode   = mode->GetDisplayMode();
194             ctx->bmd_width  = bmd_width;
195             ctx->bmd_height = bmd_height;
196             ctx->bmd_tb_den = bmd_tb_den;
197             ctx->bmd_tb_num = bmd_tb_num;
198             ctx->bmd_field_dominance = mode->GetFieldDominance();
199             av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
200                 bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num,
201                 (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
202         }
203
204         mode->Release();
205         i++;
206     }
207
208     itermode->Release();
209
210     if (ctx->bmd_mode == bmdModeUnknown)
211         return -1;
212     if (direction == DIRECTION_IN) {
213         if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
214                                            bmdVideoOutputFlagDefault,
215                                            &support, NULL) != S_OK)
216             return -1;
217     } else {
218         if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
219                                            bmdVideoOutputFlagDefault,
220                                            &support, NULL) != S_OK)
221         return -1;
222     }
223     if (support == bmdDisplayModeSupported)
224         return 0;
225
226     return -1;
227 }
228
229 int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
230     return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num);
231 }
232
233 int ff_decklink_list_devices(AVFormatContext *avctx)
234 {
235     IDeckLink *dl = NULL;
236     IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
237     if (!iter) {
238         av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
239         return AVERROR(EIO);
240     }
241     av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
242     while (iter->Next(&dl) == S_OK) {
243         const char *displayName;
244         ff_decklink_get_display_name(dl, &displayName);
245         av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
246         av_free((void *) displayName);
247         dl->Release();
248     }
249     iter->Release();
250     return 0;
251 }
252
253 int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction)
254 {
255     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
256     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
257     IDeckLinkDisplayModeIterator *itermode;
258     IDeckLinkDisplayMode *mode;
259     int i=0;
260     HRESULT res;
261
262     if (direction == DIRECTION_IN) {
263         int ret;
264         ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection);
265         if (ret < 0)
266             return ret;
267         ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection);
268         if (ret < 0)
269             return ret;
270         res = ctx->dli->GetDisplayModeIterator (&itermode);
271     } else {
272         res = ctx->dlo->GetDisplayModeIterator (&itermode);
273     }
274
275     if (res!= S_OK) {
276             av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
277             return AVERROR(EIO);
278     }
279
280     av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
281                avctx->filename);
282     while (itermode->Next(&mode) == S_OK) {
283         BMDTimeValue tb_num, tb_den;
284         mode->GetFrameRate(&tb_num, &tb_den);
285         av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps",
286                 ++i,mode->GetWidth(), mode->GetHeight(),
287                 (int) tb_den, (int) tb_num);
288         switch (mode->GetFieldDominance()) {
289         case bmdLowerFieldFirst:
290         av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
291         case bmdUpperFieldFirst:
292         av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
293         }
294         av_log(avctx, AV_LOG_INFO, "\n");
295         mode->Release();
296     }
297
298     itermode->Release();
299
300     return 0;
301 }
302
303 void ff_decklink_cleanup(AVFormatContext *avctx)
304 {
305     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
306     struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx;
307
308     if (ctx->dli)
309         ctx->dli->Release();
310     if (ctx->dlo)
311         ctx->dlo->Release();
312     if (ctx->attr)
313         ctx->attr->Release();
314     if (ctx->cfg)
315         ctx->cfg->Release();
316     if (ctx->dl)
317         ctx->dl->Release();
318 }
319
320 int ff_decklink_init_device(AVFormatContext *avctx, const char* name)
321 {
322     struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
323     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
324     IDeckLink *dl = NULL;
325     IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
326     if (!iter) {
327         av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
328         return AVERROR_EXTERNAL;
329     }
330
331     while (iter->Next(&dl) == S_OK) {
332         const char *displayName;
333         ff_decklink_get_display_name(dl, &displayName);
334         if (!strcmp(name, displayName)) {
335             av_free((void *)displayName);
336             ctx->dl = dl;
337             break;
338         }
339         av_free((void *)displayName);
340         dl->Release();
341     }
342     iter->Release();
343     if (!ctx->dl)
344         return AVERROR(ENXIO);
345
346     if (ctx->dl->QueryInterface(IID_IDeckLinkConfiguration, (void **)&ctx->cfg) != S_OK) {
347         av_log(avctx, AV_LOG_ERROR, "Could not get configuration interface for '%s'\n", name);
348         ff_decklink_cleanup(avctx);
349         return AVERROR_EXTERNAL;
350     }
351
352     if (ctx->dl->QueryInterface(IID_IDeckLinkAttributes, (void **)&ctx->attr) != S_OK) {
353         av_log(avctx, AV_LOG_ERROR, "Could not get attributes interface for '%s'\n", name);
354         ff_decklink_cleanup(avctx);
355         return AVERROR_EXTERNAL;
356     }
357
358     return 0;
359 }