X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Ftimecode.cpp;h=8303c59c740a8faf58508fb83af75c14e23399ad;hb=405ebfa31dec2209eca7031b7ee781f5ca7be10d;hp=1b25df21f13adaf5a5de50bd488ab890d36c4cab;hpb=f1f6ca90ed44361ea1d2122a772cb7d5bdd1e8ed;p=kdenlive diff --git a/src/timecode.cpp b/src/timecode.cpp index 1b25df21..8303c59c 100644 --- a/src/timecode.cpp +++ b/src/timecode.cpp @@ -4,6 +4,7 @@ begin : Wed Dec 17 2003 copyright : (C) 2003 by Jason Wood email : jasonwood@blueyonder.co.uk + * Copyright (C) 2010 by Jean-Baptiste Mardelle (jb@kdenlive.org) * ***************************************************************************/ /*************************************************************************** @@ -14,28 +15,127 @@ * (at your option) any later version. * * * ***************************************************************************/ -#include "timecode.h" -#include -#include +/* + + Timecode calculation code for reference + If we ever use Quicktime timecode with 50.94 Drop frame, keep in mind that there is a bug inthe Quicktime code + +//CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE +//Code by David Heidelberger, adapted from Andrew Duncan +//Given an int called framenumber and a double called framerate +//Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off. + +int d; +int m; + +int dropFrames = round(framerate * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate +int framesPerHour = round(framerate*60*60); //Number of frames in an hour +int framesPer24Hours = framesPerHour*24; //Number of frames in a day - timecode rolls over after 24 hours +int framesPer10Minutes = round(framerate * 60 * 10); //Number of frames per ten minutes +int framesPerMinute = round(framerate)*60)- dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames + +if (framenumber<0) //Negative time. Add 24 hours. +{ + framenumber=framesPer24Hours+framenumber; +} + +//If framenumber is greater than 24 hrs, next operation will rollover clock +framenumber = framenumber % framesPer24Hours; //% is the modulus operator, which returns a remainder. a % b = the remainder of a/b + +d = framenumber\framesPer10Minutes; // \ means integer division, which is a/b without a remainder. Some languages you could use floor(a/b) +m = framenumber % framesPer10Minutes; + +if (m>1) +{ + framenumber=framenumber + (dropFrames*9*d) + dropFrames*((m-dropFrames)\framesPerMinute); +} +else +{ + framenumber = framenumber + dropFrames*9*d; +} + +int frRound = round(framerate); +int frames = framenumber % frRound; +int seconds = (framenumber \ frRound) % 60; +int minutes = ((framenumber \ frRound) \ 60) % 60; +int hours = (((framenumber \ frRound) \ 60) \ 60); + + +------------------------------------------------------------------------------------ + +//CONVERT DROP FRAME TIMECODE TO A FRAME NUMBER +//Code by David Heidelberger, adapted from Andrew Duncan +//Given ints called hours, minutes, seconds, frames, and a double called framerate + +int dropFrames = round(framerate*.066666); //Number of drop frames is 6% of framerate rounded to nearest integer +int timeBase = round(framerate); //We don’t need the exact framerate anymore, we just need it rounded to nearest integer + +int hourFrames = timeBase*60*60; //Number of frames per hour (non-drop) +int minuteFrames = timeBase*60; //Number of frames per minute (non-drop) +int totalMinutes = (60*hours) + minutes; //Total number of minuts +int frameNumber = ((hourFrames * hours) + (minuteFrames * minutes) + (timeBase * seconds) + frames) - (dropFrames * (totalMinutes - (totalMinutes \ 10))); +return frameNumber; -Timecode::Timecode(Formats format, double framesPerSecond, bool dropFrame) : - m_format(format), - m_dropFrame(dropFrame), - m_displayedFramesPerSecond(framesPerSecond + 0.5), - m_realFps(framesPerSecond) +*/ + + +#include + +#include +#include + +#include "timecode.h" + +Timecode::Timecode(Formats format, double framesPerSecond) { + m_validator = new QRegExpValidator(0); + setFormat(framesPerSecond, format); } Timecode::~Timecode() { } +void Timecode::setFormat(double framesPerSecond, Formats format) +{ + m_displayedFramesPerSecond = (int)(framesPerSecond + 0.5); + m_dropFrameTimecode = (framesPerSecond / 1.00 != (int)framesPerSecond) ; + m_format = format; + m_realFps = framesPerSecond; + if (m_dropFrameTimecode) { + m_dropFrames = round(m_realFps * .066666); //Number of frames to drop on the minute marks is the nearest integer to 6% of the framerate + m_framesPer10Minutes = round(m_realFps * 600); //Number of frames per ten minutes + } + QRegExp regExp; + if (m_dropFrameTimecode) + regExp.setPattern("^\\d{2}:\\d{2}:\\d{2};\\d{2}$"); + else + regExp.setPattern("^\\d{2}:\\d{2}:\\d{2}:\\d{2}$"); + m_validator->setRegExp(regExp); +} + double Timecode::fps() const { - return m_realFps; //m_displayedFramesPerSecond; + return m_realFps; +} + +bool Timecode::df() const +{ + return m_dropFrameTimecode; +} + +const QValidator *Timecode::validator() const +{ + return m_validator; } +QString Timecode::reformatSeparators(QString duration) const +{ + if (m_dropFrameTimecode) + return duration.replace(8, 1, ';'); + return duration.replace(8, 1, ':'); +} int Timecode::getDisplayFrameCount(const QString duration, bool frameDisplay) const { @@ -45,32 +145,29 @@ int Timecode::getDisplayFrameCount(const QString duration, bool frameDisplay) co int Timecode::getFrameCount(const QString duration) const { - if (m_dropFrame) { - // calculate how many frames need to be dropped every minute. - int frames; - int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - m_realFps) + 0.5); - - int perMinute = toDrop / 9; - int tenthMinute = toDrop % 9; - - // calculate how many frames are in a normal minute, and how many are in a tenth minute. - int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute; - int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;; - - // Number of actual frames in a 10 minute interval : - int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames; - frames = 6 * duration.section(':', 0, 0).toInt() * tenMinutes; - int minutes = duration.section(':', 1, 1).toInt(); - frames += ((int) minutes / 10) * tenMinutes; - int mins = minutes % 10; - if (mins > 0) { - frames += tenthMinuteFrames; - mins--; - if (mins > 0) frames += mins * normalMinuteFrames; + if (m_dropFrameTimecode) { + + //CONVERT DROP FRAME TIMECODE TO A FRAME NUMBER + //Code by David Heidelberger, adapted from Andrew Duncan + //Given ints called hours, minutes, seconds, frames, and a double called framerate + + //Get Hours, Minutes, Seconds, Frames from timecode + int hours, minutes, seconds, frames; + + hours = duration.section(':', 0, 0).toInt(); + minutes = duration.section(':', 1, 1).toInt(); + if (duration.contains(';')) { + seconds = duration.section(';', 0, 0).section(':', 2, 2).toInt(); + frames = duration.section(';', 1, 1).toInt(); + } else { + //Handle Drop Frame timecode frame calculations, even if the timecode supplied uses incorrect "99:99:99:99" format instead of "99:99:99;99" + seconds = duration.section(':', 2, 2).toInt(); + frames = duration.section(':', 3, 3).toInt(); } - if (minutes % 10 > 0) frames -= perMinute; - frames += duration.section(':', 2, 2).toInt() * m_displayedFramesPerSecond + duration.section(':', 3, 3).toInt(); - return frames; + + int totalMinutes = (60 * hours) + minutes; //Total number of minutes + int frameNumber = ((m_displayedFramesPerSecond * 3600 * hours) + (m_displayedFramesPerSecond * 60 * minutes) + (m_displayedFramesPerSecond * seconds) + frames) - (m_dropFrames * (totalMinutes - floor(totalMinutes / 10))); + return frameNumber; } return (int)((duration.section(':', 0, 0).toInt()*3600.0 + duration.section(':', 1, 1).toInt()*60.0 + duration.section(':', 2, 2).toInt()) * m_realFps + duration.section(':', 3, 3).toInt()); } @@ -183,15 +280,15 @@ QString Timecode::getEasyTimecode(const GenTime & time, const double &fps) const QString Timecode::getTimecodeHH_MM_SS_FF(const GenTime & time) const { - if (m_dropFrame) + if (m_dropFrameTimecode) { return getTimecodeDropFrame(time); - + } return getTimecodeHH_MM_SS_FF((int) time.frames(m_realFps)); } const QString Timecode::getTimecodeHH_MM_SS_FF(int frames) const { - if (m_dropFrame) { + if (m_dropFrameTimecode) { return getTimecodeDropFrame(frames); } int seconds = frames / m_displayedFramesPerSecond; @@ -214,7 +311,7 @@ const QString Timecode::getTimecodeHH_MM_SS_FF(int frames) const return text; } -QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const +const QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const { int hundredths = (int)(time.seconds() * 100); int seconds = hundredths / 100; @@ -231,81 +328,60 @@ QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const text.append(QString::number(minutes).rightJustified(2, '0', false)); text.append(':'); text.append(QString::number(seconds).rightJustified(2, '0', false)); - text.append(':'); + if (m_dropFrameTimecode) + text.append(';'); + else + text.append(':'); text.append(QString::number(hundredths).rightJustified(2, '0', false)); return text; } -QString Timecode::getTimecodeFrames(const GenTime & time) const +const QString Timecode::getTimecodeFrames(const GenTime & time) const { return QString::number(time.frames(m_realFps)); } -QString Timecode::getTimecodeSeconds(const GenTime & time) const +const QString Timecode::getTimecodeSeconds(const GenTime & time) const { return QString::number(time.seconds()); } -QString Timecode::getTimecodeDropFrame(const GenTime & time) const +const QString Timecode::getTimecodeDropFrame(const GenTime & time) const { return getTimecodeDropFrame((int)time.frames(m_realFps)); } -QString Timecode::getTimecodeDropFrame(int frames) const +const QString Timecode::getTimecodeDropFrame(int framenumber) const { - // Calculate the timecode using dropframes to remove the difference in fps. Note that this algorithm should work - // for NTSC times, but is untested for any others - it is in no way an "official" algorithm, unless it's by fluke. - - // calculate how many frames need to be dropped every minute. - int toDrop = (int) floor(600.0 * (m_displayedFramesPerSecond - m_realFps) + 0.5); - - int perMinute = toDrop / 9; - int tenthMinute = toDrop % 9; - - // calculate how many frames are in a normal minute, and how many are in a tenth minute. - int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - perMinute; - int tenthMinuteFrames = (m_displayedFramesPerSecond * 60) - tenthMinute;; - - // Number of actual frames in a 10 minute interval : - int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames; - - int tenMinuteIntervals = frames / tenMinutes; - frames = frames % tenMinutes; - - int hours = tenMinuteIntervals / 6; - tenMinuteIntervals = tenMinuteIntervals % 6; + //CONVERT A FRAME NUMBER TO DROP FRAME TIMECODE + //Based on code by David Heidelberger, adapted from Andrew Duncan + //Given an int called framenumber and a double called framerate + //Framerate should be 29.97, 59.94, or 23.976, otherwise the calculations will be off. - // At the point, we have figured out HH:M?:??:?? + int d = floor(framenumber / m_framesPer10Minutes); + int m = framenumber % m_framesPer10Minutes; - int numMinutes; + int framesPerMinute = round(m_realFps * 60) - m_dropFrames; //Number of frames per minute is the round of the framerate * 60 minus the number of dropped frames - if (frames < tenthMinuteFrames) { - // tenth minute logic applies. - numMinutes = 0; + if (m > m_dropFrames) { + framenumber += (m_dropFrames * 9 * d) + m_dropFrames * (floor((m - m_dropFrames) / (round(m_realFps * 60) - m_dropFrames))); } else { - // normal minute logic applies. - numMinutes = 1 + (frames - tenthMinuteFrames) / normalMinuteFrames; - frames = (frames - tenthMinuteFrames) % normalMinuteFrames; - frames += tenthMinute + perMinute; + framenumber += m_dropFrames * 9 * d; } - // We now have HH:MM:??:?? - int seconds = frames / m_displayedFramesPerSecond; - frames = frames % m_displayedFramesPerSecond; - - // We now have HH:MM:SS:FF - - // THANK FUCK FOR THAT. + int frames = framenumber % m_displayedFramesPerSecond; + int seconds = (int) floor(framenumber / m_displayedFramesPerSecond) % 60; + int minutes = (int) floor(floor(framenumber / m_displayedFramesPerSecond) / 60) % 60; + int hours = floor(floor(floor(framenumber / m_displayedFramesPerSecond) / 60) / 60); QString text; text.append(QString::number(hours).rightJustified(2, '0', false)); text.append(':'); - text.append(QString::number(tenMinuteIntervals)); - text.append(QString::number(numMinutes)); + text.append(QString::number(minutes).rightJustified(2, '0', false)); text.append(':'); text.append(QString::number(seconds).rightJustified(2, '0', false)); - text.append(':'); + text.append(';'); text.append(QString::number(frames).rightJustified(2, '0', false)); return text;