decklink: Header cleanup
[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 extern "C" {
30 #include "libavformat/internal.h"
31 #include "libavutil/imgutils.h"
32 }
33
34 #include "decklink_common.h"
35
36 #ifdef _WIN32
37 IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
38 {
39     IDeckLinkIterator *iter;
40
41     if (CoInitialize(NULL) < 0) {
42         av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
43         return NULL;
44     }
45
46     if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
47                          IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
48         av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
49         return NULL;
50     }
51
52     return iter;
53 }
54 #endif
55
56 #ifdef _WIN32
57 static char *dup_wchar_to_utf8(wchar_t *w)
58 {
59     char *s = NULL;
60     int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
61     s = (char *) av_malloc(l);
62     if (s)
63         WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
64     return s;
65 }
66 #define DECKLINK_STR    OLECHAR *
67 #define DECKLINK_STRDUP dup_wchar_to_utf8
68 #define DECKLINK_FREE(s) SysFreeString(s)
69 #elif defined(__APPLE__)
70 static char *dup_cfstring_to_utf8(CFStringRef w)
71 {
72     char s[256];
73     CFStringGetCString(w, s, 255, kCFStringEncodingUTF8);
74     return av_strdup(s);
75 }
76 #define DECKLINK_STR    const __CFString *
77 #define DECKLINK_STRDUP dup_cfstring_to_utf8
78 #define DECKLINK_FREE(s) free((void *) s)
79 #else
80 #define DECKLINK_STR    const char *
81 #define DECKLINK_STRDUP av_strdup
82 /* free() is needed for a string returned by the DeckLink SDL. */
83 #define DECKLINK_FREE(s) free((void *) s)
84 #endif
85
86 HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
87 {
88     DECKLINK_STR tmpDisplayName;
89     HRESULT hr = This->GetDisplayName(&tmpDisplayName);
90     if (hr != S_OK)
91         return hr;
92     *displayName = DECKLINK_STRDUP(tmpDisplayName);
93     DECKLINK_FREE(tmpDisplayName);
94     return hr;
95 }
96
97 int ff_decklink_set_format(AVFormatContext *avctx,
98                                int width, int height,
99                                int tb_num, int tb_den,
100                                decklink_direction_t direction, int num)
101 {
102     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
103     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
104     BMDDisplayModeSupport support;
105     IDeckLinkDisplayModeIterator *itermode;
106     IDeckLinkDisplayMode *mode;
107     int i = 1;
108     HRESULT res;
109
110     if (direction == DIRECTION_IN) {
111         res = ctx->dli->GetDisplayModeIterator (&itermode);
112     } else {
113         res = ctx->dlo->GetDisplayModeIterator (&itermode);
114     }
115
116     if (res!= S_OK) {
117             av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
118             return AVERROR(EIO);
119     }
120
121
122     if (tb_num == 1) {
123         tb_num *= 1000;
124         tb_den *= 1000;
125     }
126     ctx->bmd_mode = bmdModeUnknown;
127     while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
128         BMDTimeValue bmd_tb_num, bmd_tb_den;
129         int bmd_width  = mode->GetWidth();
130         int bmd_height = mode->GetHeight();
131
132         mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
133
134         if ((bmd_width == width && bmd_height == height &&
135             bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) {
136             ctx->bmd_mode   = mode->GetDisplayMode();
137             ctx->bmd_width  = bmd_width;
138             ctx->bmd_height = bmd_height;
139             ctx->bmd_tb_den = bmd_tb_den;
140             ctx->bmd_tb_num = bmd_tb_num;
141             ctx->bmd_field_dominance = mode->GetFieldDominance();
142             av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
143                 bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num,
144                 (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
145         }
146
147         mode->Release();
148         i++;
149     }
150
151     itermode->Release();
152
153     if (ctx->bmd_mode == bmdModeUnknown)
154         return -1;
155     if (direction == DIRECTION_IN) {
156         if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
157                                            bmdVideoOutputFlagDefault,
158                                            &support, NULL) != S_OK)
159             return -1;
160     } else {
161         if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
162                                            bmdVideoOutputFlagDefault,
163                                            &support, NULL) != S_OK)
164         return -1;
165     }
166     if (support == bmdDisplayModeSupported)
167         return 0;
168
169     return -1;
170 }
171
172 int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
173     return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num);
174 }
175
176 int ff_decklink_list_devices(AVFormatContext *avctx)
177 {
178     IDeckLink *dl = NULL;
179     IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
180     if (!iter) {
181         av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
182         return AVERROR(EIO);
183     }
184     av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
185     while (iter->Next(&dl) == S_OK) {
186         const char *displayName;
187         ff_decklink_get_display_name(dl, &displayName);
188         av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
189         av_free((void *) displayName);
190         dl->Release();
191     }
192     iter->Release();
193     return 0;
194 }
195
196 int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction)
197 {
198     struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
199     struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
200     IDeckLinkDisplayModeIterator *itermode;
201     IDeckLinkDisplayMode *mode;
202     int i=0;
203     HRESULT res;
204
205     if (direction == DIRECTION_IN) {
206         res = ctx->dli->GetDisplayModeIterator (&itermode);
207     } else {
208         res = ctx->dlo->GetDisplayModeIterator (&itermode);
209     }
210
211     if (res!= S_OK) {
212             av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
213             return AVERROR(EIO);
214     }
215
216     av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
217                avctx->filename);
218     while (itermode->Next(&mode) == S_OK) {
219         BMDTimeValue tb_num, tb_den;
220         mode->GetFrameRate(&tb_num, &tb_den);
221         av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps",
222                 ++i,mode->GetWidth(), mode->GetHeight(),
223                 (int) tb_den, (int) tb_num);
224         switch (mode->GetFieldDominance()) {
225         case bmdLowerFieldFirst:
226         av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
227         case bmdUpperFieldFirst:
228         av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
229         }
230         av_log(avctx, AV_LOG_INFO, "\n");
231         mode->Release();
232     }
233
234     itermode->Release();
235
236     return 0;
237 }