2011-01-02 01:21:39 +01:00
|
|
|
|
/*
|
|
|
|
|
|
FORMATS.hpp - formats for displaying and specifying time
|
|
|
|
|
|
|
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
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2010, 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.
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-11-03 18:22:31 +01:00
|
|
|
|
/** @file formats.hpp
|
2016-11-07 16:22:04 +01:00
|
|
|
|
** Definition of time code formats
|
|
|
|
|
|
** This header is part of the Lumiera time and timecode handling library
|
|
|
|
|
|
** and defines the interfaces and types to deal with the common set of
|
|
|
|
|
|
** time code formats encountered in video editing. The generic handling
|
|
|
|
|
|
** of _quantised time_ can be parametrised to support and comply to these
|
|
|
|
|
|
** specific time code formats.
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
|
#ifndef LIB_TIME_FORMATS_H
|
|
|
|
|
|
#define LIB_TIME_FORMATS_H
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/time/timevalue.hpp"
|
2011-01-16 15:41:34 +01:00
|
|
|
|
#include "lib/meta/no-instance.hpp"
|
|
|
|
|
|
#include "lib/meta/typelist.hpp"
|
|
|
|
|
|
#include "lib/meta/generator.hpp"
|
2011-01-16 19:50:42 +01:00
|
|
|
|
#include "lib/typed-counter.hpp"
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
2014-04-03 22:42:48 +02:00
|
|
|
|
#include <memory>
|
2011-05-13 06:28:55 +02:00
|
|
|
|
#include <string>
|
2011-01-16 19:50:42 +01:00
|
|
|
|
#include <bitset>
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
2024-03-16 02:04:47 +01:00
|
|
|
|
namespace lumiera {
|
|
|
|
|
|
namespace error {
|
|
|
|
|
|
LUMIERA_ERROR_DECLARE (INVALID_TIMECODE); ///< timecode format error, illegal value encountered.
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace time {
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-13 23:56:52 +01:00
|
|
|
|
// ====== forward declarations of concrete Timecode types
|
|
|
|
|
|
|
|
|
|
|
|
class FrameNr;
|
|
|
|
|
|
class SmpteTC;
|
|
|
|
|
|
class HmsTC;
|
|
|
|
|
|
class Secs;
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-15 00:52:02 +01:00
|
|
|
|
class Quantiser; // API for grid aligning
|
2022-10-30 23:12:34 +01:00
|
|
|
|
using QuantR = Quantiser const&;
|
|
|
|
|
|
using PQuant = std::shared_ptr<const Quantiser>;
|
2011-01-13 23:56:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
|
namespace format {
|
|
|
|
|
|
|
2011-05-13 06:28:55 +02:00
|
|
|
|
using std::string;
|
2011-01-16 15:41:34 +01:00
|
|
|
|
using lib::meta::NoInstance; // the following types are for metaprogramming only...
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-03-16 02:04:47 +01:00
|
|
|
|
/**
|
2011-01-02 01:21:39 +01:00
|
|
|
|
* Frame count as timecode format.
|
|
|
|
|
|
* An integral number used to count frames
|
|
|
|
|
|
* can be used as a simple from of time code.
|
2018-11-15 21:13:52 +01:00
|
|
|
|
* Indeed the Lumiera vault layer mostly relies
|
|
|
|
|
|
* on these frame counts. As with any timecode, the
|
2011-01-02 01:21:39 +01:00
|
|
|
|
* underlying framerate/quantisation remains implicit.
|
|
|
|
|
|
*/
|
2011-01-14 05:33:50 +01:00
|
|
|
|
struct Frames
|
2011-01-16 15:41:34 +01:00
|
|
|
|
: NoInstance<Frames>
|
2011-01-02 01:21:39 +01:00
|
|
|
|
{
|
2011-05-13 06:28:55 +02:00
|
|
|
|
static TimeValue parse (string const&, QuantR);
|
2011-01-15 00:52:02 +01:00
|
|
|
|
static void rebuild (FrameNr&, QuantR, TimeValue const&);
|
|
|
|
|
|
static TimeValue evaluate (FrameNr const&, QuantR);
|
2011-01-02 01:21:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Widely used standard media timecode format.
|
|
|
|
|
|
* A SMPTE timestamp addresses individual frames,
|
|
|
|
|
|
* by specifying time as hour-minute-second plus the
|
|
|
|
|
|
* frame number within the actual second.
|
|
|
|
|
|
*/
|
2011-01-14 05:33:50 +01:00
|
|
|
|
struct Smpte
|
2011-01-16 15:41:34 +01:00
|
|
|
|
: NoInstance<Smpte>
|
2011-01-02 01:21:39 +01:00
|
|
|
|
{
|
2011-05-13 06:28:55 +02:00
|
|
|
|
static TimeValue parse (string const&, QuantR);
|
2011-01-18 05:01:25 +01:00
|
|
|
|
static void rebuild (SmpteTC&, QuantR, TimeValue const&);
|
2011-01-15 00:52:02 +01:00
|
|
|
|
static TimeValue evaluate (SmpteTC const&, QuantR);
|
2011-01-21 11:42:29 +01:00
|
|
|
|
static uint getFramerate (QuantR, TimeValue const&);
|
2011-04-29 04:04:48 +02:00
|
|
|
|
static void applyRangeLimitStrategy (SmpteTC&);
|
2011-01-02 01:21:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* The informal hours-minutes-seconds-millisecond timecode.
|
|
|
|
|
|
* As such, this timecode is quantisation agnostic, but usually
|
|
|
|
|
|
* it is used to address some frame or block or otherwise quantised
|
|
|
|
|
|
* entity in time. HMS-Timecode is similar to SMPTE, but uses a
|
|
|
|
|
|
* floating point milliseconds value instead of the frame count
|
|
|
|
|
|
*/
|
2011-01-14 05:33:50 +01:00
|
|
|
|
struct Hms
|
2011-01-16 15:41:34 +01:00
|
|
|
|
: NoInstance<Hms>
|
2011-01-02 01:21:39 +01:00
|
|
|
|
{
|
2011-05-13 06:28:55 +02:00
|
|
|
|
static TimeValue parse (string const&, QuantR);
|
2011-01-18 05:01:25 +01:00
|
|
|
|
static void rebuild (HmsTC&, QuantR, TimeValue const&);
|
2011-01-15 00:52:02 +01:00
|
|
|
|
static TimeValue evaluate (HmsTC const&, QuantR);
|
2011-01-02 01:21:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Simple timecode specification as fractional seconds.
|
|
|
|
|
|
* Similar to HMS, a specification of seconds is quantisation agnostic,
|
|
|
|
|
|
* but usually some implicit quantisation is used anyway, be it on actual
|
|
|
|
|
|
* data frames, audio frames, or just on some smaller time interval, e.g.
|
|
|
|
|
|
* full milliseconds.
|
|
|
|
|
|
* @note Seconds is implemented as rational number and thus uses
|
|
|
|
|
|
* decimal format, not the usual sexagesimal time format
|
|
|
|
|
|
*/
|
2011-01-14 05:33:50 +01:00
|
|
|
|
struct Seconds
|
2011-01-16 15:41:34 +01:00
|
|
|
|
: NoInstance<Seconds>
|
2011-01-02 01:21:39 +01:00
|
|
|
|
{
|
2011-05-13 06:28:55 +02:00
|
|
|
|
static TimeValue parse (string const&, QuantR);
|
2011-01-18 05:01:25 +01:00
|
|
|
|
static void rebuild (Secs&, QuantR, TimeValue const&);
|
2011-01-15 00:52:02 +01:00
|
|
|
|
static TimeValue evaluate (Secs const&, QuantR);
|
2011-01-02 01:21:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-05 02:43:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class FMT>
|
|
|
|
|
|
struct Traits;
|
|
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct Traits<Frames>
|
|
|
|
|
|
{
|
2022-10-30 23:12:34 +01:00
|
|
|
|
using TimeCode = FrameNr;
|
2011-01-05 02:43:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct Traits<Smpte>
|
|
|
|
|
|
{
|
2022-10-30 23:12:34 +01:00
|
|
|
|
using TimeCode = SmpteTC;
|
2011-01-05 02:43:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct Traits<Hms>
|
|
|
|
|
|
{
|
2022-10-30 23:12:34 +01:00
|
|
|
|
using TimeCode = HmsTC;
|
2011-01-05 02:43:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct Traits<Seconds>
|
|
|
|
|
|
{
|
2022-10-30 23:12:34 +01:00
|
|
|
|
using TimeCode = Secs;
|
2011-01-05 02:43:29 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-16 19:50:42 +01:00
|
|
|
|
/* == Descriptor to define Support for specific formats == */
|
|
|
|
|
|
|
2025-06-02 02:24:09 +02:00
|
|
|
|
using lib::meta::TyOLD;
|
2011-12-03 02:56:50 +01:00
|
|
|
|
using lib::meta::Node;
|
|
|
|
|
|
using lib::meta::NullType;
|
2011-01-16 19:50:42 +01:00
|
|
|
|
|
2011-01-16 15:41:34 +01:00
|
|
|
|
/**
|
2011-01-16 19:50:42 +01:00
|
|
|
|
* Descriptor to denote support for a specific (timecode) format.
|
2011-01-16 15:41:34 +01:00
|
|
|
|
* This helper can be used to configure a selection of specific
|
|
|
|
|
|
* timecode formats to be or not to be supported by some facility.
|
|
|
|
|
|
* Formats are described by the format descriptor types defined in
|
|
|
|
|
|
* this header (or elsewhere for additional formats). This helper
|
|
|
|
|
|
* establishes an numeric ID at runtime and uses a bitset to keep
|
|
|
|
|
|
* track of the support for a given format.
|
|
|
|
|
|
*
|
2011-01-16 19:50:42 +01:00
|
|
|
|
* @note preconfigured limit #MAXID on the absolute number of
|
|
|
|
|
|
* different Format types; maybe needs to be increased accordingly.
|
|
|
|
|
|
* @warning the actual numeric IDs might vary on each run
|
|
|
|
|
|
* @see TypedContext
|
2011-01-16 15:41:34 +01:00
|
|
|
|
*/
|
|
|
|
|
|
class Supported
|
|
|
|
|
|
{
|
2024-03-16 02:04:47 +01:00
|
|
|
|
enum { MAXID = 8 };
|
2011-01-16 19:50:42 +01:00
|
|
|
|
|
|
|
|
|
|
std::bitset<MAXID> flags_;
|
|
|
|
|
|
|
|
|
|
|
|
template<class F>
|
2011-12-02 17:50:44 +01:00
|
|
|
|
IxID
|
2011-01-16 22:19:48 +01:00
|
|
|
|
typeID() const
|
2011-01-16 19:50:42 +01:00
|
|
|
|
{
|
|
|
|
|
|
return TypedContext<Supported>::ID<F>::get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class F, class FS>
|
|
|
|
|
|
Supported
|
|
|
|
|
|
define(Node<F,FS>) ///< @internal set the flag for one Format in the typelist
|
|
|
|
|
|
{
|
|
|
|
|
|
flags_.set (typeID<F>());
|
|
|
|
|
|
return define(FS());
|
|
|
|
|
|
}
|
2011-04-26 06:11:31 +02:00
|
|
|
|
Supported define(NullType) { return *this;} ///< @internal recursion end
|
2011-01-16 19:50:42 +01:00
|
|
|
|
|
|
|
|
|
|
Supported() { } ///< @note use #formats to set up a new descriptor
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-16 15:41:34 +01:00
|
|
|
|
public:
|
2011-01-16 19:50:42 +01:00
|
|
|
|
/** build a new Descriptor to denote support for all the Formats,
|
|
|
|
|
|
* @param TY typelist holding all the Format types to support
|
|
|
|
|
|
*/
|
2011-01-16 15:41:34 +01:00
|
|
|
|
template<typename TY>
|
|
|
|
|
|
static Supported
|
2011-01-16 19:50:42 +01:00
|
|
|
|
formats()
|
|
|
|
|
|
{
|
|
|
|
|
|
typedef typename TY::List SupportedFormats;
|
|
|
|
|
|
return Supported().define(SupportedFormats());
|
|
|
|
|
|
}
|
2011-01-16 15:41:34 +01:00
|
|
|
|
|
2011-01-16 19:50:42 +01:00
|
|
|
|
/** check if a specific Format is supported */
|
2011-01-16 15:41:34 +01:00
|
|
|
|
template<class F>
|
|
|
|
|
|
bool
|
2011-01-16 22:19:48 +01:00
|
|
|
|
check() const
|
2011-01-16 19:50:42 +01:00
|
|
|
|
{
|
|
|
|
|
|
return flags_[typeID<F>()];
|
|
|
|
|
|
}
|
2011-01-16 15:41:34 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2011-01-16 19:50:42 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* predefined standard configuration:
|
|
|
|
|
|
* Descriptor for supporting all the classical timecode formats
|
|
|
|
|
|
*/
|
2011-01-16 15:41:34 +01:00
|
|
|
|
struct SupportStandardTimecode
|
|
|
|
|
|
: Supported
|
|
|
|
|
|
{
|
|
|
|
|
|
SupportStandardTimecode()
|
2025-06-02 02:24:09 +02:00
|
|
|
|
: Supported(formats< TyOLD<Hms,Smpte,Frames,Seconds> >())
|
2011-01-16 15:41:34 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-01-02 01:21:39 +01:00
|
|
|
|
}}} // lib::time::format
|
|
|
|
|
|
#endif
|