Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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