/* TIMECODE.hpp - grid aligned and fixed format time specifications Copyright (C) Lumiera.org 2010, Hermann Vosseler This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef LIB_TIME_TIMECODE_H #define LIB_TIME_TIMECODE_H #include "lib/time/timevalue.hpp" #include "lib/time/formats.hpp" #include "lib/time/digxel.hpp" #include "lib/symbol.hpp" //#include #include #include ///////////////TODO #include namespace lib { namespace time { using std::string; using lib::Literal; using boost::lexical_cast; /////////TODO /** * Interface: fixed format timecode specification. * @see time::format * @todo WIP-WIP-WIP */ class TCode { public: virtual ~TCode() { } operator string() const { return show(); } string describe() const { return string(tcID()); } Time getTime() const { return Time(value()); } protected: TCode (PQuant const& quant) : quantiser_(quant) { } virtual string show() const =0; virtual Literal tcID() const =0; virtual TimeValue value() const =0; protected: PQuant quantiser_; }; class QuTime; /** * A frame counting timecode value. * This is the hard-coded standard representation of * format::Frames, and is defined such as to make FrameNr * values interchangeable with integral numbers. * Like any concrete TCode subclass, it can be created * based on a QuTime value. This way, not only the (raw) TimeValue * is provided, but also the (frame)-Grid to base the frame count on. * But contrary to a QuTime value, a FrameNr value is \em materialised * (rounded) into a definite integral number, stripping the excess * precision contained in the original (raw) TimeValue. * As framecount values are implemented as single display field for an * integral value (time::Digxel), they allow for simple presentation. */ class FrameNr : public TCode , public CountVal { string show() const { return string(CountVal::show())+"#"; } Literal tcID() const { return "Framecount"; } TimeValue value() const { return Format::evaluate (*this, *quantiser_); } public: typedef format::Frames Format; FrameNr (QuTime const& quantisedTime); using TCode::operator string; // CountVal implicitly convertible to long ///////////TICKET #882 : outch! should be a 64bit type! }; /** * Classical Timecode value reminiscent to SMPTE format. * After quantisation, the resulting (materialised) time value is * decimated into a hours, a minutes, a seconds part and the remainder * is cast into a frame number relative to the seconds. Consequently, * a SmpteTC representation is always linked implicitly to a specific framerate. * * \par range extensions * Historically, SMPTE timecode format was focused mainly on how to encode a * unique timestamp in a way allowing to 'piggyback' these timestamps into an * existing (analogue) media data format. As a side effect, quite tight limits * had to be imposed on the possible component values in such a fixed-length format. * This whole concern is completely beyond the scope of a typical computer based video * implementation; thus we can consider ways to extend the value range to be represented * in this SMPTE-like timecode format: * - we can allow time values below the zero point * - we can allow time values beyond 24 hours. * Several different schemes how to do this extensions could be devised (and in addition, * we could also wrap around the hours field, jumping from 23:59:59:## to 0:0:0:0). * Currently, we implement an extension, where the timecode representation is symmetrical * to the zero point and the hours field is just extended beyond 23 hours. To give an * example: \c 0:0:0:0 minus 1 frame yields \c -0:0:0:1 * * @todo the range extension scheme could be a configurable strategy */ class SmpteTC : public TCode , boost::unit_steppable { uint effectiveFramerate_; virtual string show() const ; virtual Literal tcID() const { return "SMPTE"; } virtual TimeValue value() const { return Format::evaluate (*this, *quantiser_); } public: typedef format::Smpte Format; SmpteTC (QuTime const& quantisedTime); SmpteTC (SmpteTC const&); SmpteTC& operator= (SmpteTC const&); uint getFps() const; void clear(); void rebuild(); void invertOrientation(); HourDigit hours; SexaDigit mins; SexaDigit secs; SexaDigit frames; Signum sgn; SmpteTC& operator++(); SmpteTC& operator--(); }; /** * @warning missing implementation */ class HmsTC : public TCode { TimeVar tpoint_; virtual string show() const { return string(tpoint_); } virtual Literal tcID() const { return "Timecode"; } virtual TimeValue value() const { return tpoint_; } public: typedef format::Hms Format; HmsTC (QuTime const& quantisedTime); double getMillis () const; int getSecs () const; int getMins () const; int getHours () const; }; /** * @warning partially missing implementation */ class Secs : public TCode { FSecs sec_; virtual string show() const { return string(Time(sec_)); } virtual Literal tcID() const { return "Seconds"; } virtual TimeValue value() const { return Time(sec_); } public: typedef format::Seconds Format; Secs (QuTime const& quantisedTime); operator FSecs() const; }; /** writes time value, formatted as HH:MM:SS:mmm */ }} // lib::time #endif