Rebased commits to have all changes in one patch. Hopefully it's complete now.
Deti On 18.08.14 19:48, Deti Fliegl wrote: > On 18.08.14 19:23, Carl Eugen Hoyos wrote: >> Deti Fliegl <deti <at> fliegl.de> writes: >> >>> +/* free() is needed for a string returned by the DeckLink SDL. */ >>> +#undef free >> >> I believe this is not needed anymore but ... > removed it - but this has been part of the existing code which I simply > moved to a new file. > >> >>> + free((void *) tmpDisplayName); >> >> ... please move the comment here. > Done. > >> Is the cast necessary? > Yes. > >> >>> + av_log(NULL, AV_LOG_ERROR, >> >> Context should not be NULL. > Can hardly be done in this file unless you supply avctx as argument in > every function only for av_log purposes. > >> >>> + av_log(NULL, 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)":""); >> >> Please split this line. > done. > >> Isn't your patch missing a configure check and >> a change to Makefile? > Must have missed some files to commit. Fixing patch attached to this mail. > >> (What is the license of the decklink libraries?) > There is no DeckLink library code in my patch. The already existing > decklink encoder support covers how to build ffmpeg with the DeckLink SDK. > > Deti > > > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel >
commit missing files use avctx as context as often as possible Signed-off-by: Deti fliegl <fli...@baycom.de> --- configure | 4 +- doc/indevs.texi | 54 +++++ libavdevice/Makefile | 5 +- libavdevice/alldevices.c | 2 +- libavdevice/decklink_common.cpp | 229 ++++++++++++++++++ libavdevice/decklink_common.h | 98 ++++++++ libavdevice/decklink_common_c.h | 32 +++ libavdevice/decklink_dec.cpp | 520 ++++++++++++++++++++++++++++++++++++++++ libavdevice/decklink_dec.h | 32 +++ libavdevice/decklink_dec_c.c | 54 +++++ libavdevice/decklink_enc.cpp | 196 ++------------- libavdevice/decklink_enc.h | 11 - libavdevice/decklink_enc_c.c | 1 + 13 files changed, 1044 insertions(+), 194 deletions(-) create mode 100644 libavdevice/decklink_common.cpp create mode 100644 libavdevice/decklink_common.h create mode 100644 libavdevice/decklink_common_c.h create mode 100644 libavdevice/decklink_dec.cpp create mode 100644 libavdevice/decklink_dec.h create mode 100644 libavdevice/decklink_dec_c.c diff --git a/configure b/configure index f355dad..189542f 100755 --- a/configure +++ b/configure @@ -253,7 +253,7 @@ External library support: native MPEG-4/Xvid encoder exists [no] --enable-libzmq enable message passing via libzmq [no] --enable-libzvbi enable teletext support via libzvbi [no] - --enable-decklink enable Blackmagick DeckLink output [no] + --enable-decklink enable Blackmagick DeckLink I/O support [no] --enable-openal enable OpenAL 1.1 capture support [no] --enable-opencl enable OpenCL code --enable-opengl enable OpenGL rendering [no] @@ -2441,6 +2441,8 @@ bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr caca_outdev_deps="libcaca" decklink_outdev_deps="decklink pthreads" decklink_outdev_extralibs="-lstdc++" +decklink_indev_deps="decklink pthreads" +decklink_indev_extralibs="-lstdc++" dshow_indev_deps="IBaseFilter" dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid" dv1394_indev_deps="dv1394" diff --git a/doc/indevs.texi b/doc/indevs.texi index ce409b9..ddf4c44 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -922,4 +922,58 @@ Use the MIT-SHM extension for shared memory. Default value is @code{1}. It may be necessary to disable it for remote displays. @end table +@section decklink + +The decklink input device provides capture capabilities for Blackmagic +DeckLink devices. + +To enable this input device, you need the Blackmagic DeckLink SDK and you +need to configure with the appropriate @code{--extra-cflags} +and @code{--extra-ldflags}. +On Windows, you need to run the IDL files through @command{widl}. + +DeckLink is very picky about the formats it supports. Pixel format is always +uyvy422, framerate and video size must be determined for your device with +@command{-list_formats 1}. Audio sample rate is always 48 kHz and the number +of channels currently is limited to 2 (stereo). + +@subsection Options + +@table @option + +@item list_devices +If set to @option{true}, print a list of devices and exit. +Defaults to @option{false}. + +@item list_formats +If set to @option{true}, print a list of supported formats and exit. +Defaults to @option{false}. + +@end table + +@subsection Examples + +@itemize + +@item +List input devices: +@example +ffmpeg -f decklink -list_devices 1 -i dummy +@end example + +@item +List supported formats: +@example +ffmpeg -f decklink -list_formats 1 -i 'Intensity Pro' +@end example + +@item +Capture video clip at 1080i50 (format 11): +@example +ffmpeg -f decklink -r 25 -i 'Intensity Pro@@11' -acodec copy -vcodec copy output.avi +@end example + +@end itemize + + @c man end INPUT DEVICES diff --git a/libavdevice/Makefile b/libavdevice/Makefile index db301e7..8cf98f0 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -16,7 +16,8 @@ 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_DECKLINK_INDEV) += decklink_dec.o decklink_dec_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 +58,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_dec.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 diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index ca34959..b8e7854 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -50,7 +50,7 @@ void avdevice_register_all(void) REGISTER_INDEV (AVFOUNDATION, avfoundation); REGISTER_INDEV (BKTR, bktr); REGISTER_OUTDEV (CACA, caca); - REGISTER_OUTDEV (DECKLINK, decklink); + REGISTER_INOUTDEV(DECKLINK, decklink); REGISTER_INDEV (DSHOW, dshow); REGISTER_INDEV (DV1394, dv1394); REGISTER_INOUTDEV(FBDEV, fbdev); diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp new file mode 100644 index 0000000..8309983 --- /dev/null +++ b/libavdevice/decklink_common.cpp @@ -0,0 +1,229 @@ +/* + * 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 +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 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() is needed for a string returned by the DeckLink SDL. */ + free((void *) tmpDisplayName); + return hr; +} + +int 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 decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num) { + return decklink_set_format(avctx, 0, 0, 0, 0, direction, num); +} + +int 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; + IDeckLink_GetDisplayName(dl, &displayName); + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", displayName); + av_free((void *) displayName); + dl->Release(); + } + iter->Release(); + return 0; +} + +int 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; +} diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h new file mode 100644 index 0000000..588097f --- /dev/null +++ b/libavdevice/decklink_common.h @@ -0,0 +1,98 @@ +/* + * 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 IDeckLink_GetDisplayName(IDeckLink *This, const char **displayName); +int 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 decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); +int decklink_list_devices(AVFormatContext *avctx); +int decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direction = DIRECTION_OUT); + diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h new file mode 100644 index 0000000..861a51a --- /dev/null +++ b/libavdevice/decklink_common_c.h @@ -0,0 +1,32 @@ +/* + * 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; +}; + diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp new file mode 100644 index 0000000..b066adb --- /dev/null +++ b/libavdevice/decklink_dec.cpp @@ -0,0 +1,520 @@ +/* + * Blackmagic DeckLink output + * Copyright (c) 2013-2014 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> + +#include <pthread.h> +#include <semaphore.h> + +extern "C" { +#include "libavformat/avformat.h" +#include "libavformat/internal.h" +#include "libavutil/imgutils.h" +} + +#include "decklink_common.h" +#include "decklink_dec.h" + +static void avpacket_queue_init(AVFormatContext *avctx, AVPacketQueue *q) +{ + memset(q, 0, sizeof(AVPacketQueue)); + pthread_mutex_init(&q->mutex, NULL); + pthread_cond_init(&q->cond, NULL); + q->avctx = avctx; +} + +static void avpacket_queue_flush(AVPacketQueue *q) +{ + AVPacketList *pkt, *pkt1; + + pthread_mutex_lock(&q->mutex); + for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) { + pkt1 = pkt->next; + av_free_packet(&pkt->pkt); + av_freep(&pkt); + } + q->last_pkt = NULL; + q->first_pkt = NULL; + q->nb_packets = 0; + q->size = 0; + pthread_mutex_unlock(&q->mutex); +} + +static void avpacket_queue_end(AVPacketQueue *q) +{ + avpacket_queue_flush(q); + pthread_mutex_destroy(&q->mutex); + pthread_cond_destroy(&q->cond); +} + +static unsigned long long avpacket_queue_size(AVPacketQueue *q) +{ + unsigned long long size; + pthread_mutex_lock(&q->mutex); + size = q->size; + pthread_mutex_unlock(&q->mutex); + return size; +} + +static int avpacket_queue_put(AVPacketQueue *q, AVPacket *pkt) +{ + AVPacketList *pkt1; + + // Drop Packet if queue size is > 1GB + if (avpacket_queue_size(q) > 1024 * 1024 * 1024 ) { + av_log(q->avctx, AV_LOG_WARNING, "Decklink input buffer overrun!\n"); + return -1; + } + /* duplicate the packet */ + if (av_dup_packet(pkt) < 0) { + return -1; + } + + pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList)); + if (!pkt1) { + return -1; + } + pkt1->pkt = *pkt; + pkt1->next = NULL; + + pthread_mutex_lock(&q->mutex); + + if (!q->last_pkt) { + q->first_pkt = pkt1; + } else { + q->last_pkt->next = pkt1; + } + + q->last_pkt = pkt1; + q->nb_packets++; + q->size += pkt1->pkt.size + sizeof(*pkt1); + + pthread_cond_signal(&q->cond); + + pthread_mutex_unlock(&q->mutex); + return 0; +} + +static int avpacket_queue_get(AVPacketQueue *q, AVPacket *pkt, int block) +{ + AVPacketList *pkt1; + int ret; + + pthread_mutex_lock(&q->mutex); + + for (;; ) { + pkt1 = q->first_pkt; + if (pkt1) { + q->first_pkt = pkt1->next; + if (!q->first_pkt) { + q->last_pkt = NULL; + } + q->nb_packets--; + q->size -= pkt1->pkt.size + sizeof(*pkt1); + *pkt = pkt1->pkt; + av_free(pkt1); + ret = 1; + break; + } else if (!block) { + ret = 0; + break; + } else { + pthread_cond_wait(&q->cond, &q->mutex); + } + } + pthread_mutex_unlock(&q->mutex); + return ret; +} + +class decklink_input_callback : public IDeckLinkInputCallback +{ +public: + decklink_input_callback(AVFormatContext *_avctx); + ~decklink_input_callback(); + + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual ULONG STDMETHODCALLTYPE AddRef(void); + virtual ULONG STDMETHODCALLTYPE Release(void); + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags); + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); + +private: + ULONG m_refCount; + pthread_mutex_t m_mutex; + AVFormatContext *avctx; + decklink_ctx *ctx; + int no_video; + int64_t initial_video_pts; + int64_t initial_audio_pts; +}; + +decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : m_refCount(0) +{ + avctx = _avctx; + decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + ctx = (struct decklink_ctx *) cctx->ctx; + initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE; + pthread_mutex_init(&m_mutex, NULL); +} + +decklink_input_callback::~decklink_input_callback() +{ + pthread_mutex_destroy(&m_mutex); +} + +ULONG decklink_input_callback::AddRef(void) +{ + pthread_mutex_lock(&m_mutex); + m_refCount++; + pthread_mutex_unlock(&m_mutex); + + return (ULONG)m_refCount; +} + +ULONG decklink_input_callback::Release(void) +{ + pthread_mutex_lock(&m_mutex); + m_refCount--; + pthread_mutex_unlock(&m_mutex); + + if (m_refCount == 0) { + delete this; + return 0; + } + + return (ULONG)m_refCount; +} + +HRESULT decklink_input_callback::VideoInputFrameArrived( + IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame) +{ + void *frameBytes; + void *audioFrameBytes; + BMDTimeValue frameTime; + BMDTimeValue frameDuration; + + ctx->frameCount++; + + // Handle Video Frame + if (videoFrame) { + AVPacket pkt; + AVCodecContext *c; + av_init_packet(&pkt); + c = ctx->video_st->codec; + if (ctx->frameCount % 25 == 0) { + unsigned long long qsize = avpacket_queue_size(&ctx->queue); + av_log(avctx, AV_LOG_DEBUG, + "Frame received (#%lu) - Valid (%liB) - QSize %fMB\n", + ctx->frameCount, + videoFrame->GetRowBytes() * videoFrame->GetHeight(), + (double)qsize / 1024 / 1024); + } + + videoFrame->GetBytes(&frameBytes); + videoFrame->GetStreamTime(&frameTime, &frameDuration, + ctx->video_st->time_base.den); + + if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) { + unsigned bars[8] = { + 0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035, + 0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 }; + int width = videoFrame->GetWidth(); + int height = videoFrame->GetHeight(); + unsigned *p = (unsigned *)frameBytes; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x += 2) + *p++ = bars[(x * 8) / width]; + } + + if (!no_video) { + av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - No input signal detected " + "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped); + } + no_video = 1; + } else { + if (no_video) { + av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned " + "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped); + } + no_video = 0; + } + + pkt.pts = frameTime / ctx->video_st->time_base.num; + + if (initial_video_pts == AV_NOPTS_VALUE) { + initial_video_pts = pkt.pts; + } + + pkt.pts -= initial_video_pts; + pkt.dts = pkt.pts; + + pkt.duration = frameDuration; + //To be made sure it still applies + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.stream_index = ctx->video_st->index; + pkt.data = (uint8_t *)frameBytes; + pkt.size = videoFrame->GetRowBytes() * + videoFrame->GetHeight(); + //fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts); + c->frame_number++; + if (avpacket_queue_put(&ctx->queue, &pkt) < 0) { + ++ctx->dropped; + } + } + + // Handle Audio Frame + if (audioFrame) { + AVCodecContext *c; + AVPacket pkt; + BMDTimeValue audio_pts; + av_init_packet(&pkt); + + c = ctx->audio_st->codec; + //hack among hacks + pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codec->channels * (16 / 8); + audioFrame->GetBytes(&audioFrameBytes); + audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den); + pkt.pts = audio_pts / ctx->audio_st->time_base.num; + + if (initial_audio_pts == AV_NOPTS_VALUE) { + initial_audio_pts = pkt.pts; + } + + pkt.pts -= initial_audio_pts; + pkt.dts = pkt.pts; + + //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts); + pkt.flags |= AV_PKT_FLAG_KEY; + pkt.stream_index = ctx->audio_st->index; + pkt.data = (uint8_t *)audioFrameBytes; + + c->frame_number++; + if (avpacket_queue_put(&ctx->queue, &pkt) < 0) { + ++ctx->dropped; + } + } + + return S_OK; +} + +HRESULT decklink_input_callback::VideoInputFormatChanged( + BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, + BMDDetectedVideoInputFormatFlags) +{ + return S_OK; +} + +static HRESULT decklink_start_input(AVFormatContext *avctx) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; + + ctx->input_callback = new decklink_input_callback(avctx); + ctx->dli->SetCallback(ctx->input_callback); + return ctx->dli->StartStreams(); +} + +extern "C" { + +av_cold int ff_decklink_read_close(AVFormatContext *avctx) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; + + if (ctx->capture_started) { + ctx->dli->StopStreams(); + ctx->dli->DisableVideoInput(); + ctx->dli->DisableAudioInput(); + } + + if (ctx->dli) + ctx->dli->Release(); + if (ctx->dl) + ctx->dl->Release(); + + avpacket_queue_end(&ctx->queue); + + av_freep(&cctx->ctx); + + return 0; +} + +av_cold int ff_decklink_read_header(AVFormatContext *avctx) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx; + IDeckLinkDisplayModeIterator *itermode; + IDeckLinkIterator *iter; + IDeckLink *dl = NULL; + AVStream *st; + HRESULT result; + char fname[1024]; + char *tmp; + int mode_num = 0; + + ctx = (struct decklink_ctx *) av_mallocz(sizeof(struct decklink_ctx)); + if (!ctx) + return AVERROR(ENOMEM); + ctx->list_devices = cctx->list_devices; + ctx->list_formats = cctx->list_formats; + ctx->preroll = cctx->preroll; + cctx->ctx = ctx; + + iter = CreateDeckLinkIteratorInstance(); + if (!iter) { + av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); + return AVERROR(EIO); + } + + /* List available devices. */ + if (ctx->list_devices) { + decklink_list_devices(avctx); + return AVERROR_EXIT; + } + + strcpy (fname, avctx->filename); + tmp=strchr (fname, '@'); + if (tmp != NULL) { + mode_num = atoi (tmp+1); + *tmp = 0; + } + + /* Open device. */ + while (iter->Next(&dl) == S_OK) { + const char *displayName; + IDeckLink_GetDisplayName(dl, &displayName); + if (!strcmp(fname, displayName)) { + av_free((void *) displayName); + ctx->dl = dl; + break; + } + av_free((void *) displayName); + dl->Release(); + } + iter->Release(); + if (!ctx->dl) { + av_log(avctx, AV_LOG_ERROR, "Could not open '%s'\n", fname); + return AVERROR(EIO); + } + + /* Get input device. */ + if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n", + avctx->filename); + ctx->dl->Release(); + return AVERROR(EIO); + } + + /* List supported formats. */ + if (ctx->list_formats) { + decklink_list_formats(avctx, DIRECTION_IN); + ctx->dli->Release(); + ctx->dl->Release(); + return AVERROR_EXIT; + } + + if (ctx->dli->GetDisplayModeIterator(&itermode) != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Could not get Display Mode Iterator\n"); + ctx->dl->Release(); + return AVERROR(EIO); + } + + if (mode_num > 0) { + if (decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set mode %d for %s\n", mode_num, fname); + goto error; + } + } + + itermode->Release(); + + /* Setup streams. */ + st = avformat_new_stream(avctx, NULL); + if (!st) { + av_log(avctx, AV_LOG_ERROR, "Cannot add stream\n"); + goto error; + } + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codec->sample_rate = bmdAudioSampleRate48kHz; + st->codec->channels = 2; + avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ + ctx->audio_st=st; + + st = avformat_new_stream(avctx, NULL); + if (!st) { + av_log(avctx, AV_LOG_ERROR, "Cannot add stream\n"); + goto error; + } + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + st->codec->width = 1920; + st->codec->height = 1080; + + st->codec->pix_fmt = AV_PIX_FMT_UYVY422; + st->codec->bit_rate = avpicture_get_size(st->codec->pix_fmt, 1920, 1080) * /*av_q2d(25)*/ 25 * 8; + st->codec->codec_tag = MKTAG('U', 'Y', 'V', 'Y'); + avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ + ctx->video_st=st; + + result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, 2); + + if (result != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Cannot enable audio input\n"); + goto error; + } + + result = ctx->dli->EnableVideoInput(ctx->bmd_mode, bmdFormat8BitYUV, bmdVideoInputFlagDefault); + + if (result != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Cannot enable video input\n"); + goto error; + } + + avpacket_queue_init (avctx, &ctx->queue); + + if (decklink_start_input (avctx) != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n"); + goto error; + } + + return 0; + +error: + + ctx->dli->Release(); + ctx->dl->Release(); + + return AVERROR(EIO); +} + +int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *) cctx->ctx; + + avpacket_queue_get(&ctx->queue, pkt, 1); + + return 0; +} + +} /* extern "C" */ diff --git a/libavdevice/decklink_dec.h b/libavdevice/decklink_dec.h new file mode 100644 index 0000000..6bd9226 --- /dev/null +++ b/libavdevice/decklink_dec.h @@ -0,0 +1,32 @@ +/* + * Blackmagic DeckLink output + * 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 + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int ff_decklink_read_header(AVFormatContext *avctx); +int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt); +int ff_decklink_read_close(AVFormatContext *avctx); + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c new file mode 100644 index 0000000..2aea277 --- /dev/null +++ b/libavdevice/decklink_dec_c.c @@ -0,0 +1,54 @@ +/* + * Blackmagic DeckLink output + * Copyright (c) 2014 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 "libavformat/avformat.h" +#include "libavutil/opt.h" + +#include "decklink_common_c.h" +#include "decklink_dec.h" + +#define OFFSET(x) offsetof(struct decklink_cctx, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { + { "list_devices", "list available devices" , OFFSET(list_devices), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, DEC }, + { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, DEC }, + { NULL }, +}; + +static const AVClass decklink_demuxer_class = { + .class_name = "Blackmagic DeckLink demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, +}; + +AVInputFormat ff_decklink_demuxer = { + .name = "decklink", + .long_name = NULL_IF_CONFIG_SMALL("Blackmagic DeckLink input"), + .flags = AVFMT_NOFILE | AVFMT_RAWPICTURE, + .priv_class = &decklink_demuxer_class, + .priv_data_size = sizeof(struct decklink_cctx), + .read_header = ff_decklink_read_header, + .read_packet = ff_decklink_read_packet, + .read_close = ff_decklink_read_close, +}; diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index 3d7cbe2..dda4a05 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -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 (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,15 +336,7 @@ 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(); + decklink_list_devices(avctx); return AVERROR_EXIT; } @@ -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(); + 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; diff --git a/libavdevice/decklink_enc.h b/libavdevice/decklink_enc.h index 0b9ad8f..6086947 100644 --- a/libavdevice/decklink_enc.h +++ b/libavdevice/decklink_enc.h @@ -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 diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c index 7c18043..c3c9018 100644 --- a/libavdevice/decklink_enc_c.c +++ b/libavdevice/decklink_enc_c.c @@ -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) -- 1.9.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel