[vlc-commits] sout: sdi: fix with 4.0 non abs clock timestamps
Francois Cartegnie
git at videolan.org
Sun May 5 15:26:49 CEST 2019
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Fri May 3 17:07:21 2019 +0200| [f6f98c83b30857e049ba39af0157a4aefc791b7d] | committer: Francois Cartegnie
sout: sdi: fix with 4.0 non abs clock timestamps
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f6f98c83b30857e049ba39af0157a4aefc791b7d
---
modules/stream_out/sdi/DBMSDIOutput.cpp | 103 ++++++++++++++++++++------------
modules/stream_out/sdi/DBMSDIOutput.hpp | 11 +++-
2 files changed, 74 insertions(+), 40 deletions(-)
diff --git a/modules/stream_out/sdi/DBMSDIOutput.cpp b/modules/stream_out/sdi/DBMSDIOutput.cpp
index d54d2ce688..5cb007c34a 100644
--- a/modules/stream_out/sdi/DBMSDIOutput.cpp
+++ b/modules/stream_out/sdi/DBMSDIOutput.cpp
@@ -44,15 +44,14 @@ DBMSDIOutput::DBMSDIOutput(sout_stream_t *p_stream) :
{
p_card = NULL;
p_output = NULL;
- offset = 0;
+ clock.system_reference = VLC_TICK_INVALID;
+ clock.offset = 0;
lasttimestamp = 0;
b_running = false;
}
DBMSDIOutput::~DBMSDIOutput()
{
- if(video.pic_nosignal)
- picture_Release(video.pic_nosignal);
es_format_Clean(&video.configuredfmt);
if(p_output)
{
@@ -73,8 +72,6 @@ AbstractStream *DBMSDIOutput::Add(const es_format_t *fmt)
{
msg_Dbg(p_stream, "accepted %s %4.4s",
s->getID().toString().c_str(), (const char *) &fmt->i_codec);
- if( videoStream && (!audioStreams.empty() || audio.i_channels == 0) )
- Start();
}
else
{
@@ -85,6 +82,16 @@ AbstractStream *DBMSDIOutput::Add(const es_format_t *fmt)
return s;
}
+int DBMSDIOutput::Send(AbstractStream *s, block_t *b)
+{
+ if(!b_running && b->i_dts != VLC_TICK_INVALID)
+ {
+ if( videoStream && (!audioStreams.empty() || audio.i_channels == 0) )
+ Start(b->i_dts);
+ }
+ return SDIOutput::Send(s, b);
+}
+
IDeckLinkDisplayMode * DBMSDIOutput::MatchDisplayMode(const video_format_t *fmt, BMDDisplayMode forcedmode)
{
HRESULT result;
@@ -502,7 +509,7 @@ error:
return VLC_EGENERIC;
}
-int DBMSDIOutput::Start()
+int DBMSDIOutput::Start(vlc_tick_t startTime)
{
HRESULT result;
if(FAKE_DRIVER && !b_running)
@@ -512,8 +519,8 @@ int DBMSDIOutput::Start()
}
if(b_running)
return VLC_EGENERIC;
- result = p_output->StartScheduledPlayback(
- samples_from_vlc_tick(vlc_tick_now(), timescale), timescale, 1.0);
+
+ result = p_output->StartScheduledPlayback(startTime, CLOCK_FREQ, 1.0);
CHECK("Could not start playback");
b_running = true;
return VLC_SUCCESS;
@@ -575,12 +582,14 @@ int DBMSDIOutput::ProcessAudio(block_t *p_block)
return VLC_EGENERIC;
}
- p_block->i_pts -= offset;
+ p_block->i_pts -= clock.offset;
uint32_t sampleFrameCount = p_block->i_nb_samples;
uint32_t written;
HRESULT result = p_output->ScheduleAudioSamples(
- p_block->p_buffer, p_block->i_nb_samples, p_block->i_pts, CLOCK_FREQ, &written);
+ p_block->p_buffer, p_block->i_nb_samples,
+ p_block->i_pts + CLOCK_FREQ,
+ CLOCK_FREQ, &written);
if (result != S_OK)
msg_Err(p_stream, "Failed to schedule audio sample: 0x%X", result);
@@ -598,22 +607,26 @@ int DBMSDIOutput::ProcessAudio(block_t *p_block)
int DBMSDIOutput::ProcessVideo(picture_t *picture, block_t *p_cc)
{
- mtime_t now = vlc_tick_now();
-
if (!picture)
return VLC_EGENERIC;
- if(picture->date - now > 5000)
- vlc_msleep_i11e(picture->date - now);
+ checkClockDrift();
- if (video.pic_nosignal &&
- now - picture->date > vlc_tick_from_sec(video.nosignal_delay))
+ if(video.pic_nosignal)
{
- msg_Dbg(p_stream, "no signal");
-
- picture_Hold(video.pic_nosignal);
- video.pic_nosignal->date = now;
- doProcessVideo(picture, NULL);
+ BMDTimeValue streamTime;
+ double playbackSpeed;
+ if(S_OK == p_output->GetScheduledStreamTime(CLOCK_FREQ, &streamTime, &playbackSpeed))
+ {
+ if(picture->date + CLOCK_FREQ - streamTime >
+ VLC_TICK_FROM_SEC(video.nosignal_delay))
+ {
+ msg_Info(p_stream, "no signal");
+ picture_Hold(video.pic_nosignal);
+ video.pic_nosignal->date = streamTime + VLC_TICK_FROM_MS(30);
+ doProcessVideo(video.pic_nosignal, NULL);
+ }
+ }
}
return doProcessVideo(picture, p_cc);
@@ -623,7 +636,6 @@ int DBMSDIOutput::doProcessVideo(picture_t *picture, block_t *p_cc)
{
HRESULT result;
int w, h, stride, length, ret = VLC_EGENERIC;
- mtime_t now;
IDeckLinkMutableVideoFrame *pDLVideoFrame = NULL;
w = video.configuredfmt.video.i_visible_width;
h = video.configuredfmt.video.i_visible_height;
@@ -634,7 +646,7 @@ int DBMSDIOutput::doProcessVideo(picture_t *picture, block_t *p_cc)
result = p_output->CreateVideoFrame(w, h, w*3,
video.tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
bmdFrameFlagDefault, &pDLVideoFrame);
- if (result != S_OK) {
+ if(result != S_OK) {
msg_Err(p_stream, "Failed to create video frame: 0x%X", result);
goto error;
}
@@ -693,10 +705,10 @@ int DBMSDIOutput::doProcessVideo(picture_t *picture, block_t *p_cc)
// compute frame duration in CLOCK_FREQ units
length = (frameduration * CLOCK_FREQ) / timescale;
-
- picture->date -= offset;
+ picture->date -= clock.offset;
result = p_output->ScheduleVideoFrame(pDLVideoFrame,
- picture->date, length, CLOCK_FREQ);
+ picture->date + CLOCK_FREQ,
+ length, CLOCK_FREQ);
if (result != S_OK) {
msg_Err(p_stream, "Dropped Video frame %" PRId64 ": 0x%x",
picture->date, result);
@@ -704,18 +716,6 @@ int DBMSDIOutput::doProcessVideo(picture_t *picture, block_t *p_cc)
}
lasttimestamp = __MAX(picture->date, lasttimestamp);
- now = vlc_tick_now() - offset;
-
- BMDTimeValue decklink_now;
- double speed;
- p_output->GetScheduledStreamTime (CLOCK_FREQ, &decklink_now, &speed);
-
- if ((now - decklink_now) > 400000) {
- /* XXX: workaround card clock drift */
- offset += 50000;
- msg_Err(p_stream, "Delaying: offset now %" PRId64, offset);
- }
-
end:
ret = VLC_SUCCESS;
@@ -729,6 +729,33 @@ error:
return ret;
}
+void DBMSDIOutput::checkClockDrift()
+{
+ BMDTimeValue hardwareTime, timeInFrame, ticksPerFrame;
+ if(S_OK == p_output->GetHardwareReferenceClock(CLOCK_FREQ,
+ &hardwareTime,
+ &timeInFrame,
+ &ticksPerFrame))
+ {
+ if(clock.system_reference == VLC_TICK_INVALID)
+ {
+ clock.system_reference = vlc_tick_now();
+ clock.hardware_reference = hardwareTime;
+ }
+ else
+ {
+ vlc_tick_t elapsed_system = vlc_tick_now() - clock.system_reference;
+ BMDTimeValue elapsed_hardware = hardwareTime - clock.hardware_reference;
+ if(std::abs(elapsed_system - elapsed_hardware) >
+ std::abs(clock.offset) + VLC_TICK_FROM_MS(15))
+ {
+ clock.offset = elapsed_system - elapsed_hardware;
+ msg_Info(p_stream, "offset now %" PRId64 " ms", clock.offset / 1000);
+ }
+ }
+ }
+}
+
picture_t * DBMSDIOutput::CreateNoSignalPicture(const char *psz_file, const video_format_t *fmt)
{
picture_t *p_pic = NULL;
diff --git a/modules/stream_out/sdi/DBMSDIOutput.hpp b/modules/stream_out/sdi/DBMSDIOutput.hpp
index 95fe8bf9ce..60fca102ef 100644
--- a/modules/stream_out/sdi/DBMSDIOutput.hpp
+++ b/modules/stream_out/sdi/DBMSDIOutput.hpp
@@ -36,6 +36,7 @@ namespace sdi_sout
virtual AbstractStream *Add(const es_format_t *); /* reimpl */
virtual int Open(); /* impl */
virtual int Process(); /* impl */
+ virtual int Send(AbstractStream *, block_t *); /* reimpl */
protected:
int ProcessVideo(picture_t *, block_t *);
@@ -51,14 +52,20 @@ namespace sdi_sout
BMDTimeValue frameduration;
vlc_tick_t lasttimestamp;
/* XXX: workaround card clock drift */
- vlc_tick_t offset;
+ struct
+ {
+ vlc_tick_t offset; /* > 0 if clock card is slower */
+ vlc_tick_t system_reference;
+ BMDTimeValue hardware_reference;
+ } clock;
bool b_running;
- int Start();
+ int Start(vlc_tick_t);
const char *ErrorToString(long i_code);
IDeckLinkDisplayMode * MatchDisplayMode(const video_format_t *,
BMDDisplayMode = bmdDisplayModeNotSupported);
int doProcessVideo(picture_t *, block_t *);
picture_t * CreateNoSignalPicture(const char*, const video_format_t *);
+ void checkClockDrift();
};
}
More information about the vlc-commits
mailing list