Commit | Line | Data |
---|---|---|
f6fa7814 DM |
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 | #else | |
74 | #define DECKLINK_STR const char * | |
75 | #define DECKLINK_STRDUP av_strdup | |
76 | /* free() is needed for a string returned by the DeckLink SDL. */ | |
77 | #define DECKLINK_FREE(s) free((void *) s) | |
78 | #endif | |
79 | ||
80 | HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName) | |
81 | { | |
82 | DECKLINK_STR tmpDisplayName; | |
83 | HRESULT hr = This->GetDisplayName(&tmpDisplayName); | |
84 | if (hr != S_OK) | |
85 | return hr; | |
86 | *displayName = DECKLINK_STRDUP(tmpDisplayName); | |
87 | DECKLINK_FREE(tmpDisplayName); | |
88 | return hr; | |
89 | } | |
90 | ||
91 | int ff_decklink_set_format(AVFormatContext *avctx, | |
92 | int width, int height, | |
93 | int tb_num, int tb_den, | |
94 | decklink_direction_t direction, int num) | |
95 | { | |
96 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
97 | struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; | |
98 | BMDDisplayModeSupport support; | |
99 | IDeckLinkDisplayModeIterator *itermode; | |
100 | IDeckLinkDisplayMode *mode; | |
101 | int i = 1; | |
102 | HRESULT res; | |
103 | ||
104 | if (direction == DIRECTION_IN) { | |
105 | res = ctx->dli->GetDisplayModeIterator (&itermode); | |
106 | } else { | |
107 | res = ctx->dlo->GetDisplayModeIterator (&itermode); | |
108 | } | |
109 | ||
110 | if (res!= S_OK) { | |
111 | av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); | |
112 | return AVERROR(EIO); | |
113 | } | |
114 | ||
115 | ||
116 | if (tb_num == 1) { | |
117 | tb_num *= 1000; | |
118 | tb_den *= 1000; | |
119 | } | |
120 | ctx->bmd_mode = bmdModeUnknown; | |
121 | while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) { | |
122 | BMDTimeValue bmd_tb_num, bmd_tb_den; | |
123 | int bmd_width = mode->GetWidth(); | |
124 | int bmd_height = mode->GetHeight(); | |
125 | ||
126 | mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den); | |
127 | ||
128 | if ((bmd_width == width && bmd_height == height && | |
129 | bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) { | |
130 | ctx->bmd_mode = mode->GetDisplayMode(); | |
131 | ctx->bmd_width = bmd_width; | |
132 | ctx->bmd_height = bmd_height; | |
133 | ctx->bmd_tb_den = bmd_tb_den; | |
134 | ctx->bmd_tb_num = bmd_tb_num; | |
135 | ctx->bmd_field_dominance = mode->GetFieldDominance(); | |
136 | av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n", | |
137 | bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num, | |
138 | (ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":""); | |
139 | } | |
140 | ||
141 | mode->Release(); | |
142 | i++; | |
143 | } | |
144 | ||
145 | itermode->Release(); | |
146 | ||
147 | if (ctx->bmd_mode == bmdModeUnknown) | |
148 | return -1; | |
149 | if (direction == DIRECTION_IN) { | |
150 | if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, | |
151 | bmdVideoOutputFlagDefault, | |
152 | &support, NULL) != S_OK) | |
153 | return -1; | |
154 | } else { | |
155 | if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, | |
156 | bmdVideoOutputFlagDefault, | |
157 | &support, NULL) != S_OK) | |
158 | return -1; | |
159 | } | |
160 | if (support == bmdDisplayModeSupported) | |
161 | return 0; | |
162 | ||
163 | return -1; | |
164 | } | |
165 | ||
166 | int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) { | |
167 | return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num); | |
168 | } | |
169 | ||
170 | int ff_decklink_list_devices(AVFormatContext *avctx) | |
171 | { | |
172 | IDeckLink *dl = NULL; | |
173 | IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); | |
174 | if (!iter) { | |
175 | av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); | |
176 | return AVERROR(EIO); | |
177 | } | |
178 | av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n"); | |
179 | while (iter->Next(&dl) == S_OK) { | |
180 | const char *displayName; | |
181 | ff_decklink_get_display_name(dl, &displayName); | |
182 | av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); | |
183 | av_free((void *) displayName); | |
184 | dl->Release(); | |
185 | } | |
186 | iter->Release(); | |
187 | return 0; | |
188 | } | |
189 | ||
190 | int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction) | |
191 | { | |
192 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
193 | struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; | |
194 | IDeckLinkDisplayModeIterator *itermode; | |
195 | IDeckLinkDisplayMode *mode; | |
196 | int i=0; | |
197 | HRESULT res; | |
198 | ||
199 | if (direction == DIRECTION_IN) { | |
200 | res = ctx->dli->GetDisplayModeIterator (&itermode); | |
201 | } else { | |
202 | res = ctx->dlo->GetDisplayModeIterator (&itermode); | |
203 | } | |
204 | ||
205 | if (res!= S_OK) { | |
206 | av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); | |
207 | return AVERROR(EIO); | |
208 | } | |
209 | ||
210 | av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n", | |
211 | avctx->filename); | |
212 | while (itermode->Next(&mode) == S_OK) { | |
213 | BMDTimeValue tb_num, tb_den; | |
214 | mode->GetFrameRate(&tb_num, &tb_den); | |
215 | av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps", | |
216 | ++i,mode->GetWidth(), mode->GetHeight(), | |
217 | (int) tb_den, (int) tb_num); | |
218 | switch (mode->GetFieldDominance()) { | |
219 | case bmdLowerFieldFirst: | |
220 | av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break; | |
221 | case bmdUpperFieldFirst: | |
222 | av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break; | |
223 | } | |
224 | av_log(avctx, AV_LOG_INFO, "\n"); | |
225 | mode->Release(); | |
226 | } | |
227 | ||
228 | itermode->Release(); | |
229 | ||
230 | return 0; | |
231 | } |