#include "libavutil/avutil.h"
#include "libavutil/common.h"
#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
#include "libavutil/time.h"
#include "libavutil/mathematics.h"
#include "libavutil/reverse.h"
#include "decklink_dec.h"
#define MAX_WIDTH_VANC 1920
+const BMDDisplayMode AUTODETECT_DEFAULT_MODE = bmdModeNTSC;
typedef struct VANCLineNumber {
BMDDisplayMode mode;
static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame,
IDeckLinkAudioInputPacket *audioFrame,
int64_t wallclock,
+ int64_t abs_wallclock,
DecklinkPtsSource pts_src,
- AVRational time_base, int64_t *initial_pts)
+ AVRational time_base, int64_t *initial_pts,
+ int copyts)
{
int64_t pts = AV_NOPTS_VALUE;
BMDTimeValue bmd_pts;
res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, &bmd_pts, &bmd_duration);
break;
case PTS_SRC_WALLCLOCK:
+ /* fall through */
+ case PTS_SRC_ABS_WALLCLOCK:
{
/* MSVC does not support compound literals like AV_TIME_BASE_Q
* in C++ code (compiler error C4576) */
AVRational timebase;
timebase.num = 1;
timebase.den = AV_TIME_BASE;
- pts = av_rescale_q(wallclock, timebase, time_base);
+ if (pts_src == PTS_SRC_WALLCLOCK)
+ pts = av_rescale_q(wallclock, timebase, time_base);
+ else
+ pts = av_rescale_q(abs_wallclock, timebase, time_base);
break;
}
}
if (res == S_OK)
pts = bmd_pts / time_base.num;
- if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
- *initial_pts = pts;
- if (*initial_pts != AV_NOPTS_VALUE)
- pts -= *initial_pts;
+ if (!copyts) {
+ if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
+ *initial_pts = pts;
+ if (*initial_pts != AV_NOPTS_VALUE)
+ pts -= *initial_pts;
+ }
return pts;
}
void *audioFrameBytes;
BMDTimeValue frameTime;
BMDTimeValue frameDuration;
- int64_t wallclock = 0;
+ int64_t wallclock = 0, abs_wallclock = 0;
+ struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+
+ if (ctx->autodetect) {
+ if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) &&
+ ctx->bmd_mode == bmdModeUnknown)
+ {
+ ctx->bmd_mode = AUTODETECT_DEFAULT_MODE;
+ }
+ return S_OK;
+ }
ctx->frameCount++;
if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK)
wallclock = av_gettime_relative();
+ if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)
+ abs_wallclock = av_gettime();
// Handle Video Frame
if (videoFrame) {
no_video = 0;
}
- pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts);
+ pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts);
pkt.dts = pkt.pts;
pkt.duration = frameDuration;
pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8);
audioFrame->GetBytes(&audioFrameBytes);
audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den);
- pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts);
+ pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts);
pkt.dts = pkt.pts;
//fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode,
BMDDetectedVideoInputFormatFlags)
{
+ ctx->bmd_mode = mode->GetDisplayMode();
return S_OK;
}
-static HRESULT decklink_start_input(AVFormatContext *avctx)
-{
- struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data;
+static int decklink_autodetect(struct decklink_cctx *cctx) {
struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;
+ DECKLINK_BOOL autodetect_supported = false;
+ int i;
+
+ if (ctx->attr->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &autodetect_supported) != S_OK)
+ return -1;
+ if (autodetect_supported == false)
+ return -1;
+
+ ctx->autodetect = 1;
+ ctx->bmd_mode = bmdModeUnknown;
+ if (ctx->dli->EnableVideoInput(AUTODETECT_DEFAULT_MODE,
+ bmdFormat8BitYUV,
+ bmdVideoInputEnableFormatDetection) != S_OK) {
+ return -1;
+ }
+
+ if (ctx->dli->StartStreams() != S_OK) {
+ return -1;
+ }
+
+ // 1 second timeout
+ for (i = 0; i < 10; i++) {
+ av_usleep(100000);
+ /* Sometimes VideoInputFrameArrived is called without the
+ * bmdFrameHasNoInputSource flag before VideoInputFormatChanged.
+ * So don't break for bmd_mode == AUTODETECT_DEFAULT_MODE. */
+ if (ctx->bmd_mode != bmdModeUnknown &&
+ ctx->bmd_mode != AUTODETECT_DEFAULT_MODE)
+ break;
+ }
+
+ ctx->dli->PauseStreams();
+ ctx->dli->FlushStreams();
+ ctx->autodetect = 0;
+ if (ctx->bmd_mode != bmdModeUnknown) {
+ cctx->format_code = (char *)av_mallocz(5);
+ if (!cctx->format_code)
+ return -1;
+ AV_WB32(cctx->format_code, ctx->bmd_mode);
+ return 0;
+ } else {
+ return -1;
+ }
- ctx->input_callback = new decklink_input_callback(avctx);
- ctx->dli->SetCallback(ctx->input_callback);
- return ctx->dli->StartStreams();
}
extern "C" {
goto error;
}
- if (mode_num > 0 || cctx->format_code) {
- if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) {
- av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n",
- mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname);
+ if (ff_decklink_set_configs(avctx, DIRECTION_IN) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not set input configuration\n");
+ ret = AVERROR(EIO);
+ goto error;
+ }
+
+ ctx->input_callback = new decklink_input_callback(avctx);
+ ctx->dli->SetCallback(ctx->input_callback);
+
+ if (mode_num == 0 && !cctx->format_code) {
+ if (decklink_autodetect(cctx) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Cannot Autodetect input stream or No signal\n");
ret = AVERROR(EIO);
goto error;
}
+ av_log(avctx, AV_LOG_INFO, "Autodetected the input mode\n");
+ }
+ if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) {
+ av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n",
+ mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname);
+ ret = AVERROR(EIO);
+ goto error;
}
#if !CONFIG_LIBZVBI
avpacket_queue_init (avctx, &ctx->queue);
- if (decklink_start_input (avctx) != S_OK) {
+ if (ctx->dli->StartStreams() != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n");
ret = AVERROR(EIO);
goto error;