Commit a5e040ee authored by Deti Fliegl's avatar Deti Fliegl Committed by Michael Niedermayer

avdevice/decklink: move general code of decklink encoder to common file

Signed-off-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parent 56b8d106
......@@ -16,7 +16,7 @@ OBJS-$(CONFIG_ALSA_OUTDEV) += alsa-audio-common.o \
OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o
OBJS-$(CONFIG_BKTR_INDEV) += bktr.o
OBJS-$(CONFIG_CACA_OUTDEV) += caca.o
OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o
OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o
OBJS-$(CONFIG_DSHOW_INDEV) += dshow.o dshow_enummediatypes.o \
dshow_enumpins.o dshow_filter.o \
dshow_pin.o dshow_common.o
......@@ -57,7 +57,7 @@ OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o
# Windows resource file
SLIBOBJS-$(HAVE_GNU_WINDRES) += avdeviceres.o
SKIPHEADERS-$(CONFIG_DECKLINK) += decklink_enc.h
SKIPHEADERS-$(CONFIG_DECKLINK) += decklink_enc.h decklink_common.h
SKIPHEADERS-$(CONFIG_DSHOW_INDEV) += dshow_capture.h
SKIPHEADERS-$(CONFIG_FBDEV_INDEV) += fbdev_common.h
SKIPHEADERS-$(CONFIG_FBDEV_OUTDEV) += fbdev_common.h
......
/*
* Blackmagic DeckLink output
* Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <DeckLinkAPI.h>
#ifdef _WIN32
#include <DeckLinkAPI_i.c>
#else
#include <DeckLinkAPIDispatch.cpp>
#endif
#include <pthread.h>
#include <semaphore.h>
extern "C" {
#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/imgutils.h"
}
#include "decklink_common.h"
#ifdef _WIN32
IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
{
IDeckLinkIterator *iter;
if (CoInitialize(NULL) != S_OK) {
av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
return NULL;
}
if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
return NULL;
}
return iter;
}
#endif
#ifdef _WIN32
static char *dup_wchar_to_utf8(wchar_t *w)
{
char *s = NULL;
int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
s = (char *) av_malloc(l);
if (s)
WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
return s;
}
#define DECKLINK_STR OLECHAR *
#define DECKLINK_STRDUP dup_wchar_to_utf8
#else
#define DECKLINK_STR const char *
#define DECKLINK_STRDUP av_strdup
#endif
HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName)
{
DECKLINK_STR tmpDisplayName;
HRESULT hr = This->GetDisplayName(&tmpDisplayName);
if (hr != S_OK)
return hr;
*displayName = DECKLINK_STRDUP(tmpDisplayName);
/* free() is needed for a string returned by the DeckLink SDL. */
free((void *) tmpDisplayName);
return hr;
}
int ff_decklink_set_format(AVFormatContext *avctx,
int width, int height,
int tb_num, int tb_den,
decklink_direction_t direction, int num)
{
struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
BMDDisplayModeSupport support;
IDeckLinkDisplayModeIterator *itermode;
IDeckLinkDisplayMode *mode;
int i = 1;
HRESULT res;
if (direction == DIRECTION_IN) {
res = ctx->dli->GetDisplayModeIterator (&itermode);
} else {
res = ctx->dlo->GetDisplayModeIterator (&itermode);
}
if (res!= S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
return AVERROR(EIO);
}
if (tb_num == 1) {
tb_num *= 1000;
tb_den *= 1000;
}
ctx->bmd_mode = bmdModeUnknown;
while ((ctx->bmd_mode == bmdModeUnknown) && itermode->Next(&mode) == S_OK) {
BMDTimeValue bmd_tb_num, bmd_tb_den;
int bmd_width = mode->GetWidth();
int bmd_height = mode->GetHeight();
mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
if ((bmd_width == width && bmd_height == height &&
bmd_tb_num == tb_num && bmd_tb_den == tb_den) || i == num) {
ctx->bmd_mode = mode->GetDisplayMode();
ctx->bmd_width = bmd_width;
ctx->bmd_height = bmd_height;
ctx->bmd_tb_den = bmd_tb_den;
ctx->bmd_tb_num = bmd_tb_num;
ctx->bmd_field_dominance = mode->GetFieldDominance();
av_log(avctx, AV_LOG_INFO, "Found Decklink mode %d x %d with rate %.2f%s\n",
bmd_width, bmd_height, (float)bmd_tb_den/(float)bmd_tb_num,
(ctx->bmd_field_dominance==bmdLowerFieldFirst || ctx->bmd_field_dominance==bmdUpperFieldFirst)?"(i)":"");
}
mode->Release();
i++;
}
itermode->Release();
if (ctx->bmd_mode == bmdModeUnknown)
return -1;
if (direction == DIRECTION_IN) {
if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
bmdVideoOutputFlagDefault,
&support, NULL) != S_OK)
return -1;
} else {
if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
bmdVideoOutputFlagDefault,
&support, NULL) != S_OK)
return -1;
}
if (support == bmdDisplayModeSupported)
return 0;
return -1;
}
int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) {
return ff_decklink_set_format(avctx, 0, 0, 0, 0, direction, num);
}
int ff_decklink_list_devices(AVFormatContext *avctx)
{
IDeckLink *dl = NULL;
IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance();
if (!iter) {
av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n");
return AVERROR(EIO);
}
av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
while (iter->Next(&dl) == S_OK) {
const char *displayName;
ff_decklink_get_display_name(dl, &displayName);
av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
av_free((void *) displayName);
dl->Release();
}
iter->Release();
return 0;
}
int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction)
{
struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
IDeckLinkDisplayModeIterator *itermode;
IDeckLinkDisplayMode *mode;
int i=0;
HRESULT res;
if (direction == DIRECTION_IN) {
res = ctx->dli->GetDisplayModeIterator (&itermode);
} else {
res = ctx->dlo->GetDisplayModeIterator (&itermode);
}
if (res!= S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
return AVERROR(EIO);
}
av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
avctx->filename);
while (itermode->Next(&mode) == S_OK) {
BMDTimeValue tb_num, tb_den;
mode->GetFrameRate(&tb_num, &tb_den);
av_log(avctx, AV_LOG_INFO, "\t%d\t%ldx%ld at %d/%d fps",
++i,mode->GetWidth(), mode->GetHeight(),
(int) tb_den, (int) tb_num);
switch (mode->GetFieldDominance()) {
case bmdLowerFieldFirst:
av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
case bmdUpperFieldFirst:
av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
}
av_log(avctx, AV_LOG_INFO, "\n");
mode->Release();
}
itermode->Release();
return 0;
}
/*
* Blackmagic DeckLink common code
* Copyright (c) 2013-2014 Ramiro Polla, Luca Barbato, Deti Fliegl
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "decklink_common_c.h"
class decklink_output_callback;
class decklink_input_callback;
typedef struct AVPacketQueue {
AVPacketList *first_pkt, *last_pkt;
int nb_packets;
unsigned long long size;
int abort_request;
pthread_mutex_t mutex;
pthread_cond_t cond;
AVFormatContext *avctx;
} AVPacketQueue;
struct decklink_ctx {
/* DeckLink SDK interfaces */
IDeckLink *dl;
IDeckLinkOutput *dlo;
IDeckLinkInput *dli;
decklink_output_callback *output_callback;
decklink_input_callback *input_callback;
/* DeckLink mode information */
BMDTimeValue bmd_tb_den;
BMDTimeValue bmd_tb_num;
BMDDisplayMode bmd_mode;
int bmd_width;
int bmd_height;
int bmd_field_dominance;
/* Capture buffer queue */
AVPacketQueue queue;
/* Streams present */
int audio;
int video;
/* Status */
int playback_started;
int capture_started;
int64_t last_pts;
unsigned long frameCount;
unsigned int dropped;
AVStream *audio_st;
AVStream *video_st;
/* Options */
int list_devices;
int list_formats;
double preroll;
int frames_preroll;
int frames_buffer;
sem_t semaphore;
int channels;
};
typedef enum { DIRECTION_IN, DIRECTION_OUT} decklink_direction_t;
#ifdef _WIN32
typedef unsigned long buffercount_type;
IDeckLinkIterator *CreateDeckLinkIteratorInstance(void);
char *dup_wchar_to_utf8(wchar_t *w);
#else
typedef uint32_t buffercount_type;
#endif
HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName);
int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, decklink_direction_t direction = DIRECTION_OUT, int num = 0);
int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num);
int ff_decklink_list_devices(AVFormatContext *avctx);
int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT);
/*
* Blackmagic DeckLink common code
* Copyright (c) 2013-2014 Ramiro Polla
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
struct decklink_cctx {
const AVClass *cclass;
void *ctx;
/* Options */
int list_devices;
int list_formats;
double preroll;
};
......@@ -20,13 +20,6 @@
*/
#include <DeckLinkAPI.h>
#ifdef _WIN32
#include <DeckLinkAPI_i.c>
typedef unsigned long buffercount_type;
#else
#include <DeckLinkAPIDispatch.cpp>
typedef uint32_t buffercount_type;
#endif
#include <pthread.h>
#include <semaphore.h>
......@@ -37,44 +30,9 @@ extern "C" {
#include "libavutil/imgutils.h"
}
#include "decklink_common.h"
#include "decklink_enc.h"
class decklink_callback;
struct decklink_ctx {
/* DeckLink SDK interfaces */
IDeckLink *dl;
IDeckLinkOutput *dlo;
decklink_callback *callback;
/* DeckLink mode information */
IDeckLinkDisplayModeIterator *itermode;
BMDTimeValue bmd_tb_den;
BMDTimeValue bmd_tb_num;
BMDDisplayMode bmd_mode;
int bmd_width;
int bmd_height;
/* Streams present */
int audio;
int video;
/* Status */
int playback_started;
int64_t last_pts;
/* Options */
int list_devices;
int list_formats;
double preroll;
int frames_preroll;
int frames_buffer;
sem_t semaphore;
int channels;
};
/* DeckLink callback class declaration */
class decklink_frame : public IDeckLinkVideoFrame
......@@ -109,7 +67,7 @@ private:
int _refs;
};
class decklink_callback : public IDeckLinkVideoOutputCallback
class decklink_output_callback : public IDeckLinkVideoOutputCallback
{
public:
virtual HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame *_frame, BMDOutputFrameCompletionResult result)
......@@ -130,99 +88,6 @@ public:
virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; }
};
#ifdef _WIN32
static IDeckLinkIterator *CreateDeckLinkIteratorInstance(void)
{
IDeckLinkIterator *iter;
if (CoInitialize(NULL) != S_OK) {
av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n");
return NULL;
}
if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL,
IID_IDeckLinkIterator, (void**) &iter) != S_OK) {
av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n");
return NULL;
}
return iter;
}
#endif
/* free() is needed for a string returned by the DeckLink SDL. */
#undef free
#ifdef _WIN32
static char *dup_wchar_to_utf8(wchar_t *w)
{
char *s = NULL;
int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
s = (char *) av_malloc(l);
if (s)
WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
return s;
}
#define DECKLINK_STR OLECHAR *
#define DECKLINK_STRDUP dup_wchar_to_utf8
#else
#define DECKLINK_STR const char *
#define DECKLINK_STRDUP av_strdup
#endif
static HRESULT IDeckLink_GetDisplayName(IDeckLink *This, const char **displayName)
{
DECKLINK_STR tmpDisplayName;
HRESULT hr = This->GetDisplayName(&tmpDisplayName);
if (hr != S_OK)
return hr;
*displayName = DECKLINK_STRDUP(tmpDisplayName);
free((void *) tmpDisplayName);
return hr;
}
static int decklink_set_format(struct decklink_ctx *ctx,
int width, int height,
int tb_num, int tb_den)
{
BMDDisplayModeSupport support;
IDeckLinkDisplayMode *mode;
if (tb_num == 1) {
tb_num *= 1000;
tb_den *= 1000;
}
ctx->bmd_mode = bmdModeUnknown;
while ((ctx->bmd_mode == bmdModeUnknown) && ctx->itermode->Next(&mode) == S_OK) {
BMDTimeValue bmd_tb_num, bmd_tb_den;
int bmd_width = mode->GetWidth();
int bmd_height = mode->GetHeight();
mode->GetFrameRate(&bmd_tb_num, &bmd_tb_den);
if (bmd_width == width && bmd_height == height &&
bmd_tb_num == tb_num && bmd_tb_den == tb_den) {
ctx->bmd_mode = mode->GetDisplayMode();
ctx->bmd_width = bmd_width;
ctx->bmd_height = bmd_height;
ctx->bmd_tb_den = bmd_tb_den;
ctx->bmd_tb_num = bmd_tb_num;
}
mode->Release();
}
if (ctx->bmd_mode == bmdModeUnknown)
return -1;
if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV,
bmdVideoOutputFlagDefault,
&support, NULL) != S_OK)
return -1;
if (support == bmdDisplayModeSupported)
return 0;
return -1;
}
static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
{
struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
......@@ -239,7 +104,7 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
" Only AV_PIX_FMT_UYVY422 is supported.\n");
return -1;
}
if (decklink_set_format(ctx, c->width, c->height,
if (ff_decklink_set_format(avctx, c->width, c->height,
c->time_base.num, c->time_base.den)) {
av_log(avctx, AV_LOG_ERROR, "Unsupported video size or framerate!"
" Check available formats with -list_formats 1.\n");
......@@ -252,8 +117,8 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st)
}
/* Set callback. */
ctx->callback = new decklink_callback();
ctx->dlo->SetScheduledFrameCompletionCallback(ctx->callback);
ctx->output_callback = new decklink_output_callback();
ctx->dlo->SetScheduledFrameCompletionCallback(ctx->output_callback);
/* Start video semaphore. */
ctx->frames_preroll = c->time_base.den * ctx->preroll;
......@@ -333,8 +198,8 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx)
if (ctx->dl)
ctx->dl->Release();
if (ctx->callback)
delete ctx->callback;
if (ctx->output_callback)
delete ctx->output_callback;
sem_destroy(&ctx->semaphore);
......@@ -450,6 +315,7 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
{
struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
struct decklink_ctx *ctx;
IDeckLinkDisplayModeIterator *itermode;
IDeckLinkIterator *iter;
IDeckLink *dl = NULL;
unsigned int n;
......@@ -470,22 +336,14 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
/* List available devices. */
if (ctx->list_devices) {
av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink devices:\n");
while (iter->Next(&dl) == S_OK) {
const char *displayName;
IDeckLink_GetDisplayName(dl, &displayName);
av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName);
av_free((void *) displayName);
dl->Release();
}
iter->Release();
ff_decklink_list_devices(avctx);
return AVERROR_EXIT;
}
/* Open device. */
while (iter->Next(&dl) == S_OK) {
const char *displayName;
IDeckLink_GetDisplayName(dl, &displayName);
ff_decklink_get_display_name(dl, &displayName);
if (!strcmp(avctx->filename, displayName)) {
av_free((void *) displayName);
ctx->dl = dl;
......@@ -508,40 +366,20 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
return AVERROR(EIO);
}
if (ctx->dlo->GetDisplayModeIterator(&ctx->itermode) != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
ctx->dl->Release();
return AVERROR(EIO);
}
/* List supported formats. */
if (ctx->list_formats) {
IDeckLinkDisplayMode *mode;
av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n",
avctx->filename);
while (ctx->itermode->Next(&mode) == S_OK) {
BMDTimeValue tb_num, tb_den;
mode->GetFrameRate(&tb_num, &tb_den);
av_log(avctx, AV_LOG_INFO, "\t%ldx%ld at %d/%d fps",
mode->GetWidth(), mode->GetHeight(),
(int) tb_den, (int) tb_num);
switch (mode->GetFieldDominance()) {
case bmdLowerFieldFirst:
av_log(avctx, AV_LOG_INFO, " (interlaced, lower field first)"); break;
case bmdUpperFieldFirst:
av_log(avctx, AV_LOG_INFO, " (interlaced, upper field first)"); break;
}
av_log(avctx, AV_LOG_INFO, "\n");
mode->Release();
}
ctx->itermode->Release();
ff_decklink_list_formats(avctx);
ctx->dlo->Release();
ctx->dl->Release();
return AVERROR_EXIT;
}
if (ctx->dlo->GetDisplayModeIterator(&itermode) != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n");
ctx->dl->Release();
return AVERROR(EIO);
}
/* Setup streams. */
for (n = 0; n < avctx->nb_streams; n++) {
AVStream *st = avctx->streams[n];
......@@ -557,7 +395,7 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx)
goto error;
}
}
ctx->itermode->Release();
itermode->Release();
return 0;
......
......@@ -19,17 +19,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
struct decklink_cctx {
const AVClass *cclass;
void *ctx;
/* Options */
int list_devices;
int list_formats;
double preroll;
};
#ifdef __cplusplus
extern "C" {
#endif
......
......@@ -22,6 +22,7 @@
#include "libavformat/avformat.h"
#include "libavutil/opt.h"
#include "decklink_common_c.h"
#include "decklink_enc.h"
#define OFFSET(x) offsetof(struct decklink_cctx, x)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment