Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * Blackmagic DeckLink output | |
3 | * Copyright (c) 2013-2014 Ramiro Polla | |
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 | typedef unsigned long buffercount_type; | |
26 | #else | |
27 | #include <DeckLinkAPIDispatch.cpp> | |
28 | typedef uint32_t buffercount_type; | |
29 | #endif | |
30 | ||
31 | #include <pthread.h> | |
32 | #include <semaphore.h> | |
33 | ||
34 | extern "C" { | |
35 | #include "libavformat/avformat.h" | |
36 | #include "libavformat/internal.h" | |
37 | #include "libavutil/imgutils.h" | |
38 | } | |
39 | ||
40 | #include "decklink_enc.h" | |
41 | ||
42 | class decklink_callback; | |
43 | ||
44 | struct decklink_ctx { | |
45 | /* DeckLink SDK interfaces */ | |
46 | IDeckLink *dl; | |
47 | IDeckLinkOutput *dlo; | |
48 | decklink_callback *callback; | |
49 | ||
50 | /* DeckLink mode information */ | |
51 | IDeckLinkDisplayModeIterator *itermode; | |
52 | BMDTimeValue bmd_tb_den; | |
53 | BMDTimeValue bmd_tb_num; | |
54 | BMDDisplayMode bmd_mode; | |
55 | int bmd_width; | |
56 | int bmd_height; | |
57 | ||
58 | /* Streams present */ | |
59 | int audio; | |
60 | int video; | |
61 | ||
62 | /* Status */ | |
63 | int playback_started; | |
64 | int64_t last_pts; | |
65 | ||
66 | /* Options */ | |
67 | int list_devices; | |
68 | int list_formats; | |
69 | double preroll; | |
70 | ||
71 | int frames_preroll; | |
72 | int frames_buffer; | |
73 | ||
74 | sem_t semaphore; | |
75 | ||
76 | int channels; | |
77 | }; | |
78 | ||
79 | /* DeckLink callback class declaration */ | |
80 | class decklink_frame : public IDeckLinkVideoFrame | |
81 | { | |
82 | public: | |
83 | decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, long width, | |
84 | long height, void *buffer) : | |
85 | _ctx(ctx), _avframe(avframe), _width(width), | |
86 | _height(height), _buffer(buffer), _refs(0) { } | |
87 | ||
88 | virtual long STDMETHODCALLTYPE GetWidth (void) { return _width; } | |
89 | virtual long STDMETHODCALLTYPE GetHeight (void) { return _height; } | |
90 | virtual long STDMETHODCALLTYPE GetRowBytes (void) { return _width<<1; } | |
91 | virtual BMDPixelFormat STDMETHODCALLTYPE GetPixelFormat(void) { return bmdFormat8BitYUV; } | |
92 | virtual BMDFrameFlags STDMETHODCALLTYPE GetFlags (void) { return bmdVideoOutputFlagDefault; } | |
93 | virtual HRESULT STDMETHODCALLTYPE GetBytes (void **buffer) { *buffer = _buffer; return S_OK; } | |
94 | ||
95 | virtual HRESULT STDMETHODCALLTYPE GetTimecode (BMDTimecodeFormat format, IDeckLinkTimecode **timecode) { return S_FALSE; } | |
96 | virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) { return S_FALSE; } | |
97 | ||
98 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } | |
99 | virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } | |
100 | virtual ULONG STDMETHODCALLTYPE Release(void) { if (!--_refs) delete this; return _refs; } | |
101 | ||
102 | struct decklink_ctx *_ctx; | |
103 | AVFrame *_avframe; | |
104 | ||
105 | private: | |
106 | long _width; | |
107 | long _height; | |
108 | void *_buffer; | |
109 | int _refs; | |
110 | }; | |
111 | ||
112 | class decklink_callback : public IDeckLinkVideoOutputCallback | |
113 | { | |
114 | public: | |
115 | virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame *_frame, BMDOutputFrameCompletionResult result) | |
116 | { | |
117 | decklink_frame *frame = static_cast<decklink_frame *>(_frame); | |
118 | struct decklink_ctx *ctx = frame->_ctx; | |
119 | AVFrame *avframe = frame->_avframe; | |
120 | ||
121 | av_frame_free(&avframe); | |
122 | ||
123 | sem_post(&ctx->semaphore); | |
124 | ||
125 | return S_OK; | |
126 | } | |
127 | virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped(void) { return S_OK; } | |
128 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } | |
129 | virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1; } | |
130 | virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; } | |
131 | }; | |
132 | ||
133 | #ifdef _WIN32 | |
134 | static IDeckLinkIterator *CreateDeckLinkIteratorInstance(void) | |
135 | { | |
136 | IDeckLinkIterator *iter; | |
137 | ||
138 | if (CoInitialize(NULL) != S_OK) { | |
139 | av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n"); | |
140 | return NULL; | |
141 | } | |
142 | ||
143 | if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, | |
144 | IID_IDeckLinkIterator, (void**) &iter) != S_OK) { | |
145 | av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n"); | |
146 | return NULL; | |
147 | } | |
148 | ||
149 | return iter; | |
150 | } | |
151 | #endif | |
152 | ||
153 | /* free() is needed for a string returned by the DeckLink SDL. */ | |
154 | #undef free | |
155 | ||
156 | #ifdef _WIN32 | |
157 | static char *dup_wchar_to_utf8(wchar_t *w) | |
158 | { | |
159 | char *s = NULL; | |
160 | int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0); | |
161 | s = (char *) av_malloc(l); | |
162 | if (s) | |
163 | WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0); | |
164 | return s; | |
165 | } | |
166 | #define DECKLINK_STR OLECHAR * | |
167 | #define DECKLINK_STRDUP dup_wchar_to_utf8 | |
168 | #else | |
169 | #define DECKLINK_STR const char * | |
170 | #define DECKLINK_STRDUP av_strdup | |
171 | #endif | |
172 | ||
173 | static HRESULT IDeckLink_GetDisplayName(IDeckLink *This, const char **displayName) | |
174 | { | |
175 | DECKLINK_STR tmpDisplayName; | |
176 | HRESULT hr = This->GetDisplayName(&tmpDisplayName); | |
177 | if (hr != S_OK) | |
178 | return hr; | |
179 | *displayName = DECKLINK_STRDUP(tmpDisplayName); | |
180 | free((void *) tmpDisplayName); | |
181 | return hr; | |
182 | } | |
183 | ||
184 | static int decklink_set_format(struct decklink_ctx *ctx, | |
185 | int width, int height, | |
186 | int tb_num, int tb_den) | |
187 | { | |
188 | BMDDisplayModeSupport support; | |
189 | IDeckLinkDisplayMode *mode; | |
190 | ||
191 | if (tb_num == 1) { | |
192 | tb_num *= 1000; | |
193 | tb_den *= 1000; | |
194 | } | |
195 | ctx->bmd_mode = bmdModeUnknown; | |
196 | while ((ctx->bmd_mode == bmdModeUnknown) && ctx->itermode->Next(&mode) == S_OK) { | |
197 | BMDTimeValue bmd_tb_num, bmd_tb_den; | |
198 | int bmd_width = mode->GetWidth(); | |
199 | int bmd_height = mode->GetHeight(); | |
200 | ||
201 | mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den); | |
202 | ||
203 | if (bmd_width == width && bmd_height == height && | |
204 | bmd_tb_num == tb_num && bmd_tb_den == tb_den) { | |
205 | ctx->bmd_mode = mode->GetDisplayMode(); | |
206 | ctx->bmd_width = bmd_width; | |
207 | ctx->bmd_height = bmd_height; | |
208 | ctx->bmd_tb_den = bmd_tb_den; | |
209 | ctx->bmd_tb_num = bmd_tb_num; | |
210 | } | |
211 | ||
212 | mode->Release(); | |
213 | } | |
214 | if (ctx->bmd_mode == bmdModeUnknown) | |
215 | return -1; | |
216 | if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, | |
217 | bmdVideoOutputFlagDefault, | |
218 | &support, NULL) != S_OK) | |
219 | return -1; | |
220 | if (support == bmdDisplayModeSupported) | |
221 | return 0; | |
222 | ||
223 | return -1; | |
224 | } | |
225 | ||
226 | static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) | |
227 | { | |
228 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
229 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
230 | AVCodecContext *c = st->codec; | |
231 | ||
232 | if (ctx->video) { | |
233 | av_log(avctx, AV_LOG_ERROR, "Only one video stream is supported!\n"); | |
234 | return -1; | |
235 | } | |
236 | ||
237 | if (c->pix_fmt != AV_PIX_FMT_UYVY422) { | |
238 | av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!" | |
239 | " Only AV_PIX_FMT_UYVY422 is supported.\n"); | |
240 | return -1; | |
241 | } | |
242 | if (decklink_set_format(ctx, c->width, c->height, | |
243 | c->time_base.num, c->time_base.den)) { | |
244 | av_log(avctx, AV_LOG_ERROR, "Unsupported video size or framerate!" | |
245 | " Check available formats with -list_formats 1.\n"); | |
246 | return -1; | |
247 | } | |
248 | if (ctx->dlo->EnableVideoOutput(ctx->bmd_mode, | |
249 | bmdVideoOutputFlagDefault) != S_OK) { | |
250 | av_log(avctx, AV_LOG_ERROR, "Could not enable video output!\n"); | |
251 | return -1; | |
252 | } | |
253 | ||
254 | /* Set callback. */ | |
255 | ctx->callback = new decklink_callback(); | |
256 | ctx->dlo->SetScheduledFrameCompletionCallback(ctx->callback); | |
257 | ||
258 | /* Start video semaphore. */ | |
259 | ctx->frames_preroll = c->time_base.den * ctx->preroll; | |
260 | if (c->time_base.den > 1000) | |
261 | ctx->frames_preroll /= 1000; | |
262 | ||
263 | /* Buffer twice as many frames as the preroll. */ | |
264 | ctx->frames_buffer = ctx->frames_preroll * 2; | |
265 | ctx->frames_buffer = FFMIN(ctx->frames_buffer, 60); | |
266 | sem_init(&ctx->semaphore, 0, ctx->frames_buffer); | |
267 | ||
268 | /* The device expects the framerate to be fixed. */ | |
269 | avpriv_set_pts_info(st, 64, c->time_base.num, c->time_base.den); | |
270 | ||
271 | ctx->video = 1; | |
272 | ||
273 | return 0; | |
274 | } | |
275 | ||
276 | static int decklink_setup_audio(AVFormatContext *avctx, AVStream *st) | |
277 | { | |
278 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
279 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
280 | AVCodecContext *c = st->codec; | |
281 | ||
282 | if (ctx->audio) { | |
283 | av_log(avctx, AV_LOG_ERROR, "Only one audio stream is supported!\n"); | |
284 | return -1; | |
285 | } | |
286 | if (c->sample_rate != 48000) { | |
287 | av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate!" | |
288 | " Only 48kHz is supported.\n"); | |
289 | return -1; | |
290 | } | |
291 | if (c->channels != 2 && c->channels != 8) { | |
292 | av_log(avctx, AV_LOG_ERROR, "Unsupported number of channels!" | |
293 | " Only stereo and 7.1 are supported.\n"); | |
294 | return -1; | |
295 | } | |
296 | if (ctx->dlo->EnableAudioOutput(bmdAudioSampleRate48kHz, | |
297 | bmdAudioSampleType16bitInteger, | |
298 | c->channels, | |
299 | bmdAudioOutputStreamTimestamped) != S_OK) { | |
300 | av_log(avctx, AV_LOG_ERROR, "Could not enable audio output!\n"); | |
301 | return -1; | |
302 | } | |
303 | if (ctx->dlo->BeginAudioPreroll() != S_OK) { | |
304 | av_log(avctx, AV_LOG_ERROR, "Could not begin audio preroll!\n"); | |
305 | return -1; | |
306 | } | |
307 | ||
308 | /* The device expects the sample rate to be fixed. */ | |
309 | avpriv_set_pts_info(st, 64, 1, c->sample_rate); | |
310 | ctx->channels = c->channels; | |
311 | ||
312 | ctx->audio = 1; | |
313 | ||
314 | return 0; | |
315 | } | |
316 | ||
317 | av_cold int ff_decklink_write_trailer(AVFormatContext *avctx) | |
318 | { | |
319 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
320 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
321 | ||
322 | if (ctx->playback_started) { | |
323 | BMDTimeValue actual; | |
324 | ctx->dlo->StopScheduledPlayback(ctx->last_pts * ctx->bmd_tb_num, | |
325 | &actual, ctx->bmd_tb_den); | |
326 | ctx->dlo->DisableVideoOutput(); | |
327 | if (ctx->audio) | |
328 | ctx->dlo->DisableAudioOutput(); | |
329 | } | |
330 | ||
331 | if (ctx->dlo) | |
332 | ctx->dlo->Release(); | |
333 | if (ctx->dl) | |
334 | ctx->dl->Release(); | |
335 | ||
336 | if (ctx->callback) | |
337 | delete ctx->callback; | |
338 | ||
339 | sem_destroy(&ctx->semaphore); | |
340 | ||
341 | av_freep(&cctx->ctx); | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
346 | static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) | |
347 | { | |
348 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
349 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
350 | AVPicture *avpicture = (AVPicture *) pkt->data; | |
351 | AVFrame *avframe, *tmp; | |
352 | decklink_frame *frame; | |
353 | buffercount_type buffered; | |
354 | HRESULT hr; | |
355 | ||
356 | /* HACK while av_uncoded_frame() isn't implemented */ | |
357 | int ret; | |
358 | ||
359 | tmp = av_frame_alloc(); | |
360 | if (!tmp) | |
361 | return AVERROR(ENOMEM); | |
362 | tmp->format = AV_PIX_FMT_UYVY422; | |
363 | tmp->width = ctx->bmd_width; | |
364 | tmp->height = ctx->bmd_height; | |
365 | ret = av_frame_get_buffer(tmp, 32); | |
366 | if (ret < 0) { | |
367 | av_frame_free(&tmp); | |
368 | return ret; | |
369 | } | |
370 | av_image_copy(tmp->data, tmp->linesize, (const uint8_t **) avpicture->data, | |
371 | avpicture->linesize, (AVPixelFormat) tmp->format, tmp->width, | |
372 | tmp->height); | |
373 | avframe = av_frame_clone(tmp); | |
374 | av_frame_free(&tmp); | |
375 | if (!avframe) { | |
376 | av_log(avctx, AV_LOG_ERROR, "Could not clone video frame.\n"); | |
377 | return AVERROR(EIO); | |
378 | } | |
379 | /* end HACK */ | |
380 | ||
381 | frame = new decklink_frame(ctx, avframe, ctx->bmd_width, ctx->bmd_height, | |
382 | (void *) avframe->data[0]); | |
383 | if (!frame) { | |
384 | av_log(avctx, AV_LOG_ERROR, "Could not create new frame.\n"); | |
385 | return AVERROR(EIO); | |
386 | } | |
387 | ||
388 | /* Always keep at most one second of frames buffered. */ | |
389 | sem_wait(&ctx->semaphore); | |
390 | ||
391 | /* Schedule frame for playback. */ | |
392 | hr = ctx->dlo->ScheduleVideoFrame((struct IDeckLinkVideoFrame *) frame, | |
393 | pkt->pts * ctx->bmd_tb_num, | |
394 | ctx->bmd_tb_num, ctx->bmd_tb_den); | |
395 | if (hr != S_OK) { | |
396 | av_log(avctx, AV_LOG_ERROR, "Could not schedule video frame." | |
397 | " error %08x.\n", (uint32_t) hr); | |
398 | frame->Release(); | |
399 | return AVERROR(EIO); | |
400 | } | |
401 | ||
402 | ctx->dlo->GetBufferedVideoFrameCount(&buffered); | |
403 | av_log(avctx, AV_LOG_DEBUG, "Buffered video frames: %d.\n", (int) buffered); | |
404 | if (pkt->pts > 2 && buffered <= 2) | |
405 | av_log(avctx, AV_LOG_WARNING, "There are not enough buffered video frames." | |
406 | " Video may misbehave!\n"); | |
407 | ||
408 | /* Preroll video frames. */ | |
409 | if (!ctx->playback_started && pkt->pts > ctx->frames_preroll) { | |
410 | av_log(avctx, AV_LOG_DEBUG, "Ending audio preroll.\n"); | |
411 | if (ctx->audio && ctx->dlo->EndAudioPreroll() != S_OK) { | |
412 | av_log(avctx, AV_LOG_ERROR, "Could not end audio preroll!\n"); | |
413 | return AVERROR(EIO); | |
414 | } | |
415 | av_log(avctx, AV_LOG_DEBUG, "Starting scheduled playback.\n"); | |
416 | if (ctx->dlo->StartScheduledPlayback(0, ctx->bmd_tb_den, 1.0) != S_OK) { | |
417 | av_log(avctx, AV_LOG_ERROR, "Could not start scheduled playback!\n"); | |
418 | return AVERROR(EIO); | |
419 | } | |
420 | ctx->playback_started = 1; | |
421 | } | |
422 | ||
423 | return 0; | |
424 | } | |
425 | ||
426 | static int decklink_write_audio_packet(AVFormatContext *avctx, AVPacket *pkt) | |
427 | { | |
428 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
429 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
430 | int sample_count = pkt->size / (ctx->channels << 1); | |
431 | buffercount_type buffered; | |
432 | ||
433 | ctx->dlo->GetBufferedAudioSampleFrameCount(&buffered); | |
434 | if (pkt->pts > 1 && !buffered) | |
435 | av_log(avctx, AV_LOG_WARNING, "There's no buffered audio." | |
436 | " Audio will misbehave!\n"); | |
437 | ||
438 | if (ctx->dlo->ScheduleAudioSamples(pkt->data, sample_count, pkt->pts, | |
439 | bmdAudioSampleRate48kHz, NULL) != S_OK) { | |
440 | av_log(avctx, AV_LOG_ERROR, "Could not schedule audio samples.\n"); | |
441 | return AVERROR(EIO); | |
442 | } | |
443 | ||
444 | return 0; | |
445 | } | |
446 | ||
447 | extern "C" { | |
448 | ||
449 | av_cold int ff_decklink_write_header(AVFormatContext *avctx) | |
450 | { | |
451 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
452 | struct decklink_ctx *ctx; | |
453 | IDeckLinkIterator *iter; | |
454 | IDeckLink *dl = NULL; | |
455 | unsigned int n; | |
456 | ||
457 | ctx = (struct decklink_ctx *) av_mallocz(sizeof(struct decklink_ctx)); | |
458 | if (!ctx) | |
459 | return AVERROR(ENOMEM); | |
460 | ctx->list_devices = cctx->list_devices; | |
461 | ctx->list_formats = cctx->list_formats; | |
462 | ctx->preroll = cctx->preroll; | |
463 | cctx->ctx = ctx; | |
464 | ||
465 | iter = CreateDeckLinkIteratorInstance(); | |
466 | if (!iter) { | |
467 | av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); | |
468 | return AVERROR(EIO); | |
469 | } | |
470 | ||
471 | /* List available devices. */ | |
472 | if (ctx->list_devices) { | |
473 | av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n"); | |
474 | while (iter->Next(&dl) == S_OK) { | |
475 | const char *displayName; | |
476 | IDeckLink_GetDisplayName(dl, &displayName); | |
477 | av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); | |
478 | av_free((void *) displayName); | |
479 | dl->Release(); | |
480 | } | |
481 | iter->Release(); | |
482 | return AVERROR_EXIT; | |
483 | } | |
484 | ||
485 | /* Open device. */ | |
486 | while (iter->Next(&dl) == S_OK) { | |
487 | const char *displayName; | |
488 | IDeckLink_GetDisplayName(dl, &displayName); | |
489 | if (!strcmp(avctx->filename, displayName)) { | |
490 | av_free((void *) displayName); | |
491 | ctx->dl = dl; | |
492 | break; | |
493 | } | |
494 | av_free((void *) displayName); | |
495 | dl->Release(); | |
496 | } | |
497 | iter->Release(); | |
498 | if (!ctx->dl) { | |
499 | av_log(avctx, AV_LOG_ERROR, "Could not open '%s'\n", avctx->filename); | |
500 | return AVERROR(EIO); | |
501 | } | |
502 | ||
503 | /* Get output device. */ | |
504 | if (ctx->dl->QueryInterface(IID_IDeckLinkOutput, (void **) &ctx->dlo) != S_OK) { | |
505 | av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n", | |
506 | avctx->filename); | |
507 | ctx->dl->Release(); | |
508 | return AVERROR(EIO); | |
509 | } | |
510 | ||
511 | if (ctx->dlo->GetDisplayModeIterator(&ctx->itermode) != S_OK) { | |
512 | av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); | |
513 | ctx->dl->Release(); | |
514 | return AVERROR(EIO); | |
515 | } | |
516 | ||
517 | /* List supported formats. */ | |
518 | if (ctx->list_formats) { | |
519 | IDeckLinkDisplayMode *mode; | |
520 | ||
521 | av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n", | |
522 | avctx->filename); | |
523 | while (ctx->itermode->Next(&mode) == S_OK) { | |
524 | BMDTimeValue tb_num, tb_den; | |
525 | mode->GetFrameRate(&tb_num, &tb_den); | |
526 | av_log(avctx, AV_LOG_INFO, "\t%ldx%ld at %d/%d fps", | |
527 | mode->GetWidth(), mode->GetHeight(), | |
528 | (int) tb_den, (int) tb_num); | |
529 | switch (mode->GetFieldDominance()) { | |
530 | case bmdLowerFieldFirst: | |
531 | av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break; | |
532 | case bmdUpperFieldFirst: | |
533 | av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break; | |
534 | } | |
535 | av_log(avctx, AV_LOG_INFO, "\n"); | |
536 | mode->Release(); | |
537 | } | |
538 | ||
539 | ctx->itermode->Release(); | |
540 | ctx->dlo->Release(); | |
541 | ctx->dl->Release(); | |
542 | return AVERROR_EXIT; | |
543 | } | |
544 | ||
545 | /* Setup streams. */ | |
546 | for (n = 0; n < avctx->nb_streams; n++) { | |
547 | AVStream *st = avctx->streams[n]; | |
548 | AVCodecContext *c = st->codec; | |
549 | if (c->codec_type == AVMEDIA_TYPE_AUDIO) { | |
550 | if (decklink_setup_audio(avctx, st)) | |
551 | goto error; | |
552 | } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) { | |
553 | if (decklink_setup_video(avctx, st)) | |
554 | goto error; | |
555 | } else { | |
556 | av_log(avctx, AV_LOG_ERROR, "Unsupported stream type.\n"); | |
557 | goto error; | |
558 | } | |
559 | } | |
560 | ctx->itermode->Release(); | |
561 | ||
562 | return 0; | |
563 | ||
564 | error: | |
565 | ||
566 | ctx->dlo->Release(); | |
567 | ctx->dl->Release(); | |
568 | ||
569 | return AVERROR(EIO); | |
570 | } | |
571 | ||
572 | int ff_decklink_write_packet(AVFormatContext *avctx, AVPacket *pkt) | |
573 | { | |
574 | struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; | |
575 | struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; | |
576 | AVStream *st = avctx->streams[pkt->stream_index]; | |
577 | ||
578 | ctx->last_pts = FFMAX(ctx->last_pts, pkt->pts); | |
579 | ||
580 | if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) | |
581 | return decklink_write_video_packet(avctx, pkt); | |
582 | else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) | |
583 | return decklink_write_audio_packet(avctx, pkt); | |
584 | ||
585 | return AVERROR(EIO); | |
586 | } | |
587 | ||
588 | } /* extern "C" */ |