From 0e8b0c520e50f34671c0fa71c6848018a15a4360 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Sat, 30 Dec 2017 22:46:09 -0800
Subject: Use standard duration types for stream clocks

---
 examples/alffplay.cpp | 227 +++++++++++++++++++++++++++-----------------------
 1 file changed, 122 insertions(+), 105 deletions(-)

(limited to 'examples/alffplay.cpp')

diff --git a/examples/alffplay.cpp b/examples/alffplay.cpp
index 7c6b9f6e..021cdbaf 100644
--- a/examples/alffplay.cpp
+++ b/examples/alffplay.cpp
@@ -36,20 +36,19 @@ extern "C" {
 #include "AL/al.h"
 #include "AL/alext.h"
 
-namespace
-{
+namespace {
 
-static const std::string AppName("alffplay");
+const std::string AppName("alffplay");
 
-static bool do_direct_out = false;
-static bool has_latency_check = false;
-static LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
+bool do_direct_out = false;
+bool has_latency_check = false;
+LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
 
-#define AUDIO_BUFFER_TIME 100 /* In milliseconds, per-buffer */
+const std::chrono::duration<double> AVSyncThreshold(0.01);
+const std::chrono::seconds AVNoSyncThreshold(10);
+const std::chrono::milliseconds AudioBufferTime(100); /* Per-buffer */
 #define AUDIO_BUFFER_QUEUE_SIZE 8 /* Number of buffers to queue */
 #define MAX_QUEUE_SIZE (15 * 1024 * 1024) /* Bytes of compressed data to keep queued */
-#define AV_SYNC_THRESHOLD 0.01
-#define AV_NOSYNC_THRESHOLD 10.0
 #define SAMPLE_CORRECTION_MAX_DIFF 0.05
 #define AUDIO_DIFF_AVG_NB 20
 #define VIDEO_PICTURE_QUEUE_SIZE 16
@@ -60,12 +59,12 @@ enum {
     FF_MOVIE_DONE_EVENT
 };
 
-enum {
-    AV_SYNC_AUDIO_MASTER,
-    AV_SYNC_VIDEO_MASTER,
-    AV_SYNC_EXTERNAL_MASTER,
+enum class SyncMaster {
+    Audio,
+    Video,
+    External,
 
-    DEFAULT_AV_SYNC_TYPE = AV_SYNC_EXTERNAL_MASTER
+    Default = External
 };
 
 
@@ -123,7 +122,6 @@ struct AudioState {
 
     /* Used for clock difference average computation */
     struct {
-        std::atomic<int> Clocks; /* In microseconds */
         double Accum;
         double AvgCoeff;
         double Threshold;
@@ -131,7 +129,7 @@ struct AudioState {
     } mDiff;
 
     /* Time (in seconds) of the next sample to be buffered */
-    double mCurrentPts;
+    std::chrono::duration<double> mCurrentPts;
 
     /* Decompressed sample frame, and swresample context for conversion */
     AVFrame           *mDecodedFrame;
@@ -158,7 +156,7 @@ struct AudioState {
 
     AudioState(MovieState *movie)
       : mMovie(movie), mStream(nullptr), mCodecCtx(nullptr)
-      , mDiff{{0}, 0.0, 0.0, 0.0, 0}, mCurrentPts(0.0), mDecodedFrame(nullptr)
+      , mDiff{0.0, 0.0, 0.0, 0}, mCurrentPts(0.0), mDecodedFrame(nullptr)
       , mSwresCtx(nullptr), mDstChanLayout(0), mDstSampleFmt(AV_SAMPLE_FMT_NONE)
       , mSamples(nullptr), mSamplesLen(0), mSamplesPos(0), mSamplesMax(0)
       , mFormat(AL_NONE), mFrameSize(0), mSource(0), mBufferIdx(0)
@@ -180,7 +178,7 @@ struct AudioState {
         avcodec_free_context(&mCodecCtx);
     }
 
-    double getClock();
+    std::chrono::nanoseconds getClock();
 
     int getSync();
     int decodeFrame();
@@ -198,13 +196,13 @@ struct VideoState {
     std::mutex mQueueMtx;
     std::condition_variable mQueueCond;
 
-    double  mClock;
-    double  mFrameTimer;
-    double  mFrameLastPts;
-    double  mFrameLastDelay;
-    double  mCurrentPts;
+    std::chrono::nanoseconds mClock;
+    std::chrono::duration<double> mFrameTimer;
+    std::chrono::nanoseconds mFrameLastPts;
+    std::chrono::nanoseconds mFrameLastDelay;
+    std::chrono::nanoseconds mCurrentPts;
     /* time (av_gettime) at which we updated mCurrentPts - used to have running video pts */
-    int64_t mCurrentPtsTime;
+    std::chrono::microseconds mCurrentPtsTime;
 
     /* Decompressed video frame, and swscale context for conversion */
     AVFrame           *mDecodedFrame;
@@ -214,10 +212,10 @@ struct VideoState {
         SDL_Texture *mImage;
         int mWidth, mHeight; /* Logical image size (actual size may be larger) */
         std::atomic<bool> mUpdated;
-        double mPts;
+        std::chrono::nanoseconds mPts;
 
         Picture()
-          : mImage(nullptr), mWidth(0), mHeight(0), mUpdated(false), mPts(0.0)
+          : mImage(nullptr), mWidth(0), mHeight(0), mUpdated(false), mPts(0)
         { }
         ~Picture()
         {
@@ -235,9 +233,9 @@ struct VideoState {
     std::atomic<bool> mFinalUpdate;
 
     VideoState(MovieState *movie)
-      : mMovie(movie), mStream(nullptr), mCodecCtx(nullptr), mClock(0.0)
-      , mFrameTimer(0.0), mFrameLastPts(0.0), mFrameLastDelay(0.0)
-      , mCurrentPts(0.0), mCurrentPtsTime(0), mDecodedFrame(nullptr)
+      : mMovie(movie), mStream(nullptr), mCodecCtx(nullptr), mClock(0)
+      , mFrameTimer(0.0), mFrameLastPts(0), mFrameLastDelay(0)
+      , mCurrentPts(0), mCurrentPtsTime(0), mDecodedFrame(nullptr)
       , mSwscaleCtx(nullptr), mPictQSize(0), mPictQRead(0), mPictQWrite(0)
       , mFirstUpdate(true), mEOS(false), mFinalUpdate(false)
     { }
@@ -249,24 +247,24 @@ struct VideoState {
         avcodec_free_context(&mCodecCtx);
     }
 
-    double getClock();
+    std::chrono::nanoseconds getClock();
 
     static Uint32 SDLCALL sdl_refresh_timer_cb(Uint32 interval, void *opaque);
-    void schedRefresh(int delay);
+    void schedRefresh(std::chrono::milliseconds delay);
     void display(SDL_Window *screen, SDL_Renderer *renderer);
     void refreshTimer(SDL_Window *screen, SDL_Renderer *renderer);
     void updatePicture(SDL_Window *screen, SDL_Renderer *renderer);
-    int queuePicture(double pts);
-    double synchronize(double pts);
+    int queuePicture(std::chrono::nanoseconds pts);
+    std::chrono::nanoseconds synchronize(std::chrono::nanoseconds pts);
     int handler();
 };
 
 struct MovieState {
     AVFormatContext *mFormatCtx;
 
-    int mAVSyncType;
+    SyncMaster mAVSyncType;
 
-    int64_t mExternalClockBase;
+    std::chrono::microseconds mClockBase;
 
     std::atomic<bool> mQuit;
 
@@ -280,8 +278,8 @@ struct MovieState {
     std::string mFilename;
 
     MovieState(std::string fname)
-      : mFormatCtx(nullptr), mAVSyncType(DEFAULT_AV_SYNC_TYPE)
-      , mExternalClockBase(0), mQuit(false), mAudio(this), mVideo(this)
+      : mFormatCtx(nullptr), mAVSyncType(SyncMaster::Default)
+      , mClockBase(0), mQuit(false), mAudio(this), mVideo(this)
       , mFilename(std::move(fname))
     { }
     ~MovieState()
@@ -296,18 +294,19 @@ struct MovieState {
     bool prepare();
     void setTitle(SDL_Window *window);
 
-    double getClock();
+    std::chrono::nanoseconds getClock();
 
-    double getMasterClock();
+    std::chrono::nanoseconds getMasterClock();
 
     int streamComponentOpen(int stream_index);
     int parse_handler();
 };
 
 
-double AudioState::getClock()
+std::chrono::nanoseconds AudioState::getClock()
 {
-    double pts;
+    using fixed32 = std::chrono::duration<ALint64SOFT,std::ratio<1,(1ll<<32)>>;
+    using nanoseconds = std::chrono::nanoseconds;
 
     std::unique_lock<std::recursive_mutex> lock(mSrcMutex);
     /* The audio clock is the timestamp of the sample currently being heard.
@@ -325,10 +324,10 @@ double AudioState::getClock()
      * OpenAL's current position, and subtracting the source latency from that
      * gives the timestamp of the sample currently at the DAC.
      */
-    pts = mCurrentPts;
+    nanoseconds pts = std::chrono::duration_cast<nanoseconds>(mCurrentPts);
     if(mSource)
     {
-        ALdouble offset[2];
+        ALint64SOFT offset[2];
         ALint queue_size;
         ALint status;
 
@@ -337,7 +336,7 @@ double AudioState::getClock()
          * and getting the state. */
         if(has_latency_check)
         {
-            alGetSourcedvSOFT(mSource, AL_SEC_OFFSET_LATENCY_SOFT, offset);
+            alGetSourcei64vSOFT(mSource, AL_SEC_OFFSET_LATENCY_SOFT, offset);
             alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queue_size);
         }
         else
@@ -345,8 +344,8 @@ double AudioState::getClock()
             ALint ioffset;
             alGetSourcei(mSource, AL_SAMPLE_OFFSET, &ioffset);
             alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queue_size);
-            offset[0] = (double)ioffset / (double)mCodecCtx->sample_rate;
-            offset[1] = 0.0f;
+            offset[0] = (ALint64SOFT)ioffset << 32;
+            offset[1] = 0;
         }
         alGetSourcei(mSource, AL_SOURCE_STATE, &status);
 
@@ -355,26 +354,32 @@ double AudioState::getClock()
          * will put the source into an AL_INITIAL state and clear the queue
          * when it starts recovery. */
         if(status != AL_STOPPED)
-            pts -= queue_size*((double)AUDIO_BUFFER_TIME/1000.0) - offset[0];
+        {
+            pts -= AudioBufferTime*queue_size;
+            pts += std::chrono::duration_cast<nanoseconds>(
+                fixed32(offset[0] / mCodecCtx->sample_rate)
+            );
+        }
         if(status == AL_PLAYING)
-            pts -= offset[1];
+            pts -= nanoseconds(offset[1]);
     }
     lock.unlock();
 
-    return std::max(pts, 0.0);
+    return std::max(pts, std::chrono::nanoseconds::zero());
 }
 
 int AudioState::getSync()
 {
-    double diff, avg_diff, ref_clock;
+    using seconds = std::chrono::duration<double>;
+    double avg_diff;
 
-    if(mMovie->mAVSyncType == AV_SYNC_AUDIO_MASTER)
+    if(mMovie->mAVSyncType == SyncMaster::Audio)
         return 0;
 
-    ref_clock = mMovie->getMasterClock();
-    diff = ref_clock - getClock();
+    auto ref_clock = mMovie->getMasterClock();
+    auto diff = seconds(ref_clock - getClock());
 
-    if(!(fabs(diff) < AV_NOSYNC_THRESHOLD))
+    if(!(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold))
     {
         /* Difference is TOO big; reset diff stuff */
         mDiff.Accum = 0.0;
@@ -382,17 +387,17 @@ int AudioState::getSync()
     }
 
     /* Accumulate the diffs */
-    mDiff.Accum = mDiff.Accum*mDiff.AvgCoeff + diff;
+    mDiff.Accum = mDiff.Accum*mDiff.AvgCoeff + diff.count();
     avg_diff = mDiff.Accum*(1.0 - mDiff.AvgCoeff);
     if(fabs(avg_diff) < mDiff.Threshold)
         return 0;
 
     /* Constrain the per-update difference to avoid exceedingly large skips */
-    if(!(diff <= SAMPLE_CORRECTION_MAX_DIFF))
-        diff = SAMPLE_CORRECTION_MAX_DIFF;
-    else if(!(diff >= -SAMPLE_CORRECTION_MAX_DIFF))
-        diff = -SAMPLE_CORRECTION_MAX_DIFF;
-    return (int)(diff*mCodecCtx->sample_rate);
+    if(!(diff.count() < SAMPLE_CORRECTION_MAX_DIFF))
+        return (int)(SAMPLE_CORRECTION_MAX_DIFF * mCodecCtx->sample_rate);
+    if(!(diff.count() > -SAMPLE_CORRECTION_MAX_DIFF))
+        return (int)(-SAMPLE_CORRECTION_MAX_DIFF * mCodecCtx->sample_rate);
+    return (int)(diff.count()*mCodecCtx->sample_rate);
 }
 
 int AudioState::decodeFrame()
@@ -425,7 +430,9 @@ int AudioState::decodeFrame()
         /* If provided, update w/ pts */
         int64_t pts = av_frame_get_best_effort_timestamp(mDecodedFrame);
         if(pts != AV_NOPTS_VALUE)
-            mCurrentPts = av_q2d(mStream->time_base)*pts;
+            mCurrentPts = std::chrono::duration_cast<std::chrono::nanoseconds>(
+                std::chrono::duration<double>(av_q2d(mStream->time_base)*pts)
+            );
 
         if(mDecodedFrame->nb_samples > mSamplesMax)
         {
@@ -477,6 +484,9 @@ static void sample_dup(uint8_t *out, const uint8_t *in, int count, int frame_siz
 
 int AudioState::readAudio(uint8_t *samples, int length)
 {
+    using seconds = std::chrono::duration<int64_t>;
+    using nanoseconds = std::chrono::nanoseconds;
+
     int sample_skip = getSync();
     int audio_size = 0;
 
@@ -494,7 +504,7 @@ int AudioState::readAudio(uint8_t *samples, int length)
             mSamplesPos = std::min(mSamplesLen, sample_skip);
             sample_skip -= mSamplesPos;
 
-            mCurrentPts += (double)mSamplesPos / (double)mCodecCtx->sample_rate;
+            mCurrentPts += nanoseconds(seconds(mSamplesPos)) / mCodecCtx->sample_rate;
             continue;
         }
 
@@ -521,7 +531,7 @@ int AudioState::readAudio(uint8_t *samples, int length)
         }
 
         mSamplesPos += rem;
-        mCurrentPts += (double)rem / mCodecCtx->sample_rate;
+        mCurrentPts += nanoseconds(seconds(rem)) / mCodecCtx->sample_rate;
         samples += rem*mFrameSize;
         audio_size += rem;
     }
@@ -531,7 +541,7 @@ int AudioState::readAudio(uint8_t *samples, int length)
         int rem = length - audio_size;
         std::fill_n(samples, rem*mFrameSize,
                     (mDstSampleFmt == AV_SAMPLE_FMT_U8) ? 0x80 : 0x00);
-        mCurrentPts += (double)rem / mCodecCtx->sample_rate;
+        mCurrentPts += nanoseconds(seconds(rem)) / mCodecCtx->sample_rate;
         audio_size += rem;
     }
 
@@ -649,8 +659,8 @@ int AudioState::handler()
             mFormat = AL_FORMAT_STEREO16;
         }
     }
-    ALsizei buffer_len = mCodecCtx->sample_rate * AUDIO_BUFFER_TIME / 1000 *
-            mFrameSize;
+    ALsizei buffer_len = std::chrono::duration_cast<std::chrono::duration<int>>(
+        mCodecCtx->sample_rate * AudioBufferTime).count() * mFrameSize;
     void *samples = av_malloc(buffer_len);
 
     mSamples = NULL;
@@ -741,7 +751,7 @@ int AudioState::handler()
         /* (re)start the source if needed, and wait for a buffer to finish */
         if(state != AL_PLAYING && state != AL_PAUSED)
             alSourcePlay(mSource);
-        SDL_Delay(AUDIO_BUFFER_TIME / 3);
+        SDL_Delay((AudioBufferTime/3).count());
 
         lock.lock();
     }
@@ -759,9 +769,9 @@ finish:
 }
 
 
-double VideoState::getClock()
+std::chrono::nanoseconds VideoState::getClock()
 {
-    double delta = (av_gettime() - mCurrentPtsTime) / 1000000.0;
+    auto delta = std::chrono::microseconds(av_gettime()) - mCurrentPtsTime;
     return mCurrentPts + delta;
 }
 
@@ -775,9 +785,9 @@ Uint32 SDLCALL VideoState::sdl_refresh_timer_cb(Uint32 /*interval*/, void *opaqu
 }
 
 /* Schedules an FF_REFRESH_EVENT event to occur in 'delay' ms. */
-void VideoState::schedRefresh(int delay)
+void VideoState::schedRefresh(std::chrono::milliseconds delay)
 {
-    SDL_AddTimer(delay, sdl_refresh_timer_cb, this);
+    SDL_AddTimer(delay.count(), sdl_refresh_timer_cb, this);
 }
 
 /* Called by VideoState::refreshTimer to display the next video frame. */
@@ -834,7 +844,7 @@ void VideoState::refreshTimer(SDL_Window *screen, SDL_Renderer *renderer)
             mPictQCond.notify_all();
             return;
         }
-        schedRefresh(100);
+        schedRefresh(std::chrono::milliseconds(100));
         return;
     }
 
@@ -845,7 +855,7 @@ retry:
         if(mEOS)
             mFinalUpdate = true;
         else
-            schedRefresh(1);
+            schedRefresh(std::chrono::milliseconds(1));
         lock.unlock();
         mPictQCond.notify_all();
         return;
@@ -853,11 +863,11 @@ retry:
 
     Picture *vp = &mPictQ[mPictQRead];
     mCurrentPts = vp->mPts;
-    mCurrentPtsTime = av_gettime();
+    mCurrentPtsTime = std::chrono::microseconds(av_gettime());
 
     /* Get delay using the frame pts and the pts from last frame. */
-    double delay = vp->mPts - mFrameLastPts;
-    if(delay <= 0 || delay >= 1.0)
+    auto delay = vp->mPts - mFrameLastPts;
+    if(delay <= std::chrono::seconds::zero() || delay >= std::chrono::seconds(1))
     {
         /* If incorrect delay, use previous one. */
         delay = mFrameLastDelay;
@@ -867,33 +877,35 @@ retry:
     mFrameLastPts = vp->mPts;
 
     /* Update delay to sync to clock if not master source. */
-    if(mMovie->mAVSyncType != AV_SYNC_VIDEO_MASTER)
+    if(mMovie->mAVSyncType != SyncMaster::Video)
     {
-        double ref_clock = mMovie->getMasterClock();
-        double diff = vp->mPts - ref_clock;
+        using seconds = std::chrono::duration<double>;
+
+        auto ref_clock = mMovie->getMasterClock();
+        auto diff = seconds(vp->mPts - ref_clock);
 
         /* Skip or repeat the frame. Take delay into account. */
-        double sync_threshold = std::min(delay, AV_SYNC_THRESHOLD);
-        if(fabs(diff) < AV_NOSYNC_THRESHOLD)
+        auto sync_threshold = std::min(seconds(delay), AVSyncThreshold);
+        if(!(diff < AVNoSyncThreshold && diff > -AVNoSyncThreshold))
         {
             if(diff <= -sync_threshold)
-                delay = 0;
+                delay = std::chrono::nanoseconds::zero();
             else if(diff >= sync_threshold)
-                delay *= 2.0;
+                delay *= 2;
         }
     }
 
     mFrameTimer += delay;
     /* Compute the REAL delay. */
-    double actual_delay = mFrameTimer - (av_gettime() / 1000000.0);
-    if(!(actual_delay >= 0.010))
+    auto actual_delay = mFrameTimer - std::chrono::microseconds(av_gettime());
+    if(!(actual_delay >= AVSyncThreshold))
     {
         /* We don't have time to handle this picture, just skip to the next one. */
         mPictQRead = (mPictQRead+1)%mPictQ.size();
         mPictQSize--;
         goto retry;
     }
-    schedRefresh((int)(actual_delay*1000.0 + 0.5));
+    schedRefresh(std::chrono::duration_cast<std::chrono::milliseconds>(actual_delay));
 
     /* Show the picture! */
     display(screen, renderer);
@@ -1001,7 +1013,7 @@ void VideoState::updatePicture(SDL_Window *screen, SDL_Renderer *renderer)
     mPictQCond.notify_one();
 }
 
-int VideoState::queuePicture(double pts)
+int VideoState::queuePicture(std::chrono::nanoseconds pts)
 {
     /* Wait until we have space for a new pic */
     std::unique_lock<std::mutex> lock(mPictQMutex);
@@ -1036,20 +1048,20 @@ int VideoState::queuePicture(double pts)
     return 0;
 }
 
-double VideoState::synchronize(double pts)
+std::chrono::nanoseconds VideoState::synchronize(std::chrono::nanoseconds pts)
 {
-    double frame_delay;
-
-    if(pts == 0.0) /* if we aren't given a pts, set it to the clock */
+    if(pts == std::chrono::nanoseconds::zero()) /* if we aren't given a pts, set it to the clock */
         pts = mClock;
     else /* if we have pts, set video clock to it */
         mClock = pts;
 
     /* update the video clock */
-    frame_delay = av_q2d(mCodecCtx->time_base);
+    auto frame_delay = av_q2d(mCodecCtx->time_base);
     /* if we are repeating a frame, adjust clock accordingly */
     frame_delay += mDecodedFrame->repeat_pict * (frame_delay * 0.5);
-    mClock += frame_delay;
+
+    mClock += std::chrono::duration_cast<std::chrono::nanoseconds>(
+        std::chrono::duration<double>(frame_delay));
     return pts;
 }
 
@@ -1077,8 +1089,12 @@ int VideoState::handler()
             break;
         }
 
-        double pts = synchronize(
-            av_q2d(mStream->time_base) * av_frame_get_best_effort_timestamp(mDecodedFrame)
+        std::chrono::nanoseconds pts = synchronize(
+            std::chrono::duration_cast<std::chrono::nanoseconds>(
+                std::chrono::duration<double>(
+                    av_q2d(mStream->time_base) * av_frame_get_best_effort_timestamp(mDecodedFrame)
+                )
+            )
         );
         if(queuePicture(pts) < 0)
             break;
@@ -1132,7 +1148,7 @@ bool MovieState::prepare()
         return false;
     }
 
-    mVideo.schedRefresh(40);
+    mVideo.schedRefresh(std::chrono::milliseconds(40));
 
     mParseThread = std::thread(std::mem_fn(&MovieState::parse_handler), this);
     return true;
@@ -1148,16 +1164,17 @@ void MovieState::setTitle(SDL_Window *window)
     SDL_SetWindowTitle(window, (mFilename.substr(fpos)+" - "+AppName).c_str());
 }
 
-double MovieState::getClock()
+std::chrono::nanoseconds MovieState::getClock()
 {
-    return (av_gettime()-mExternalClockBase) / 1000000.0;
+    using microseconds = std::chrono::microseconds;
+    return microseconds(av_gettime()) - mClockBase;
 }
 
-double MovieState::getMasterClock()
+std::chrono::nanoseconds MovieState::getMasterClock()
 {
-    if(mAVSyncType == AV_SYNC_VIDEO_MASTER)
+    if(mAVSyncType == SyncMaster::Video)
         return mVideo.getClock();
-    if(mAVSyncType == AV_SYNC_AUDIO_MASTER)
+    if(mAVSyncType == SyncMaster::Audio)
         return mAudio.getClock();
     return getClock();
 }
@@ -1207,9 +1224,9 @@ int MovieState::streamComponentOpen(int stream_index)
             mVideo.mStream = mFormatCtx->streams[stream_index];
             mVideo.mCodecCtx = avctx;
 
-            mVideo.mCurrentPtsTime = av_gettime();
-            mVideo.mFrameTimer = (double)mVideo.mCurrentPtsTime / 1000000.0;
-            mVideo.mFrameLastDelay = 40e-3;
+            mVideo.mCurrentPtsTime = std::chrono::microseconds(av_gettime());
+            mVideo.mFrameTimer = mVideo.mCurrentPtsTime;
+            mVideo.mFrameLastDelay = std::chrono::milliseconds(40);
 
             mVideoThread = std::thread(std::mem_fn(&VideoState::handler), &mVideo);
             break;
@@ -1241,7 +1258,7 @@ int MovieState::parse_handler()
     /* Start the external clock in 50ms, to give the audio and video
      * components time to start without needing to skip ahead.
      */
-    mExternalClockBase = av_gettime() + 50000;
+    mClockBase = std::chrono::microseconds(av_gettime() + 50000);
     if(audio_index >= 0) audio_index = streamComponentOpen(audio_index);
     if(video_index >= 0) video_index = streamComponentOpen(video_index);
 
-- 
cgit v1.2.3