lumiera_/src/steam/play/timings.cpp
Ichthyostega 806db414dd Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
 * there is no entity "Lumiera.org" which holds any copyrights
 * Lumiera source code is provided under the GPL Version 2+

== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''

The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!

The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01: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_)
&& (( (ASAP == playbackUrgency || NICE == playbackUrgency)
&& Time::NEVER == scheduledDelivery)
||
(TIMEBOUND == playbackUrgency
&& Time::MIN < scheduledDelivery && 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