lumiera_/src/steam/play/timings.cpp
2025-06-07 23:59:57 +02:00

222 lines
6.5 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Timings - timing specifications for a frame quantised data stream
Copyright (C)
2012, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file timings.cpp
** Implementation of a data tuple for timing specification.
** A Timings record represents a constraint on playback, and will be
** used to organise and the calculations necessary to generate the data.
** Especially, a Timings record serves to establish a relation to an externally
** fixed time grid or time source.
*/
#include "steam/play/timings.hpp"
#include "lib/time/formats.hpp"
#include "lib/time/timequant.hpp"
#include "lib/rational.hpp"
namespace steam {
namespace play {
using lib::time::PQuant;
using lib::time::Time;
using lib::time::TimeVar;
using lib::time::FrameCnt;
using lib::time::FSecs;
namespace { // Hard wired placeholder settings...
const Duration DEFAULT_ENGINE_LATENCY = Duration{Time{10,0}}; ///////////////////////////////////////TICKET #802 : shouldn't be hard wired
const Duration DEFAULT_JOB_PLANNING_TURNOVER(FSecs(3,2));
}//(End)hard wired settings
namespace { // hidden local details of the service implementation....
inline PQuant
buildStandardGridForFramerate (FrameRate fps)
{
return PQuant (new lib::time::FixedFrameQuantiser (fps));
} //////TODO maybe caching these quantisers? they are immutable and threadsafe
} // (End) hidden service impl details
/** Create a default initialised Timing constraint record.
* Using the standard optimistic settings for most values,
* no latency, no special requirements. The frame grid is
* rooted at the "natural" time origin; it is not related
* in any way to the current session.
* @remarks this ctor is intended rather for testing purposes!
* Usually, when creating a play/render process,
* the actual timings _are related to the timeline_
* and the latency/speed requirements of the output.
*/
Timings::Timings (FrameRate fps)
: grid_{buildStandardGridForFramerate(fps)}
, playbackUrgency {ASAP}
, playbackSpeed {1}
, scheduledDelivery{Time::NEVER}
, outputLatency{Duration::NIL}
, engineLatency{DEFAULT_ENGINE_LATENCY} //////////////////////////////////////////////////////////////TICKET #802 : derive from engine state -- but make it adjustable for unit tests!!!
{
ENSURE (grid_);
}
Timings::Timings (FrameRate fps, Time realTimeAnchor)
: grid_{buildStandardGridForFramerate(fps)}
, playbackUrgency {TIMEBOUND}
, playbackSpeed {1}
, scheduledDelivery{realTimeAnchor}
, outputLatency {Duration::NIL}
, engineLatency{DEFAULT_ENGINE_LATENCY}
{
ENSURE (grid_);
}
//////////////////////////////////////////////////////////////////TODO ctors for use in the real player/engine?
/** a special marker Timings record,
* indicating disabled or halted output */
Timings Timings::DISABLED(FrameRate::HALTED);
/** @internal typically invoked from assertions */
bool
Timings::isValid() const
{
return bool(grid_)
and (( (ASAP == playbackUrgency or NICE == playbackUrgency)
and Time::NEVER == scheduledDelivery)
or
( TIMEBOUND == playbackUrgency
and Time::MIN < scheduledDelivery and scheduledDelivery < Time::MAX)
);
}
Time
Timings::getOrigin() const
{
return Time(grid_->timeOf(0));
}
Time
Timings::getFrameStartAt (FrameCnt frameNr) const
{
return Time(grid_->timeOf(frameNr));
}
Duration
Timings::getFrameDurationAt (TimeValue refPoint) const
{
FrameCnt frameNr = grid_->gridPoint (refPoint);
return getFrameDurationAt(frameNr);
}
Duration
Timings::getFrameDurationAt (FrameCnt refFrameNr) const
{
return Offset (grid_->timeOf(refFrameNr), grid_->timeOf(refFrameNr + 1));
}
FrameCnt
Timings::getBreakPointAfter (TimeValue refPoint) const
{
FrameCnt frameNr = grid_->gridPoint (refPoint);
return grid_->timeOf(frameNr) == refPoint? frameNr
: frameNr+1;
}
/** @remarks the purpose of this function is to support scheduling
* and frame handling even in case the frame rate isn't constant.
* To indicate the case the frame rate is changing right now,
* this function might return Duration::NIL
* @todo implement real support for variable frame rates
*/ ////////////////////////////////////////////////////////TICKET #236
Duration
Timings::constantFrameTimingsInterval (TimeValue) const
{
return Duration (Time::MAX);
}
Time
Timings::getTimeDue(FrameCnt frameOffset) const
{
if (TIMEBOUND == playbackUrgency)
{
REQUIRE (scheduledDelivery != Time::NEVER);
return scheduledDelivery
+ getRealOffset (frameOffset);
}
else
return Time::NEVER;
}
Offset
Timings::getRealOffset (FrameCnt frameOffset) const
{
Offset nominalOffset (grid_->timeOf(0), grid_->timeOf(frameOffset));
return isOriginalSpeed()? nominalOffset
: nominalOffset * playbackSpeed;
////////////////////////TICKET #902 for full-featured variable speed playback, we need to integrate (sum up step wise) instead of just using a fixed factor
}
Duration
Timings::getPlanningChunkDuration() const
{
UNIMPLEMENTED ("controlling the job planning rhythm");
}
FrameCnt
Timings::establishNextPlanningChunkStart(FrameCnt anchorFrame) const
{
TimeVar breakingPoint = grid_->timeOf(anchorFrame);
breakingPoint += getPlanningChunkDuration();
FrameCnt nextFrame = grid_->gridPoint (breakingPoint);
ASSERT (breakingPoint <= grid_->timeOf(nextFrame));
ASSERT (breakingPoint > grid_->timeOf(nextFrame-1));
if (grid_->timeOf(nextFrame) == breakingPoint)
return nextFrame;
else
return nextFrame+1;
}
Timings
Timings::constrainedBy (Timings additionalConditions)
{
UNIMPLEMENTED ("how to combine timing constraints");
}
}} // namespace steam::play