]> git.sesse.net Git - kdenlive/blob - src/timecode.cpp
Use TimecodeDisplay in marker dialog
[kdenlive] / src / timecode.cpp
1 /***************************************************************************
2                           timecode  -  description
3                              -------------------
4     begin                : Wed Dec 17 2003
5     copyright            : (C) 2003 by Jason Wood
6     email                : jasonwood@blueyonder.co.uk
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include <QValidator>
18
19 #include <KDebug>
20 #include <KLocale>
21
22 #include "timecode.h"
23
24 Timecode::Timecode(Formats format, double framesPerSecond, bool dropFrame)
25 {
26     m_validator = new QRegExpValidator(0);
27     setFormat(framesPerSecond, dropFrame, format);
28 }
29
30 Timecode::~Timecode()
31 {
32 }
33
34 void Timecode::setFormat(double framesPerSecond, bool dropFrame, Formats format)
35 {
36     m_displayedFramesPerSecond = (int)(framesPerSecond + 0.5);
37     m_dropFrame = dropFrame;
38     m_format = format;
39     m_realFps = framesPerSecond;
40     QRegExp regExp;
41     if (m_dropFrame)
42         regExp.setPattern("^\\d{2}:\\d{2}:\\d{2};\\d{2}$");
43     else
44         regExp.setPattern("^\\d{2}:\\d{2}:\\d{2}:\\d{2}$");
45     m_validator->setRegExp(regExp);
46 }
47
48 double Timecode::fps() const
49 {
50     return m_realFps; //m_displayedFramesPerSecond;
51 }
52
53 bool Timecode::df() const
54 {
55     return m_dropFrame;
56 }
57
58 const QValidator *Timecode::validator() const
59 {
60     return m_validator;
61 }
62
63 QString Timecode::reformatSeparators(QString duration) const
64 {
65     if (m_dropFrame)
66         return duration.replace(8, 1, ';');
67     return duration.replace(8, 1, ':');
68 }
69
70 int Timecode::getDisplayFrameCount(const QString duration, bool frameDisplay) const
71 {
72     if (frameDisplay) return duration.toInt();
73     return getFrameCount(duration);
74 }
75
76 int Timecode::getFrameCount(const QString duration) const
77 {
78     if (m_dropFrame) {
79         //Get Hours, Minutes, Seconds, Frames from timecode
80         int hours, minutes, seconds, frames;
81
82         hours = duration.section(':', 0, 0).toInt();
83         minutes = duration.section(':', 1, 1).toInt();
84         if (duration.contains(';')) {
85             seconds = duration.section(';', 0, 0).section(':', 2, 2).toInt();
86             frames = duration.section(';', 1, 1).toInt();
87         } else {
88             //Handle Drop Frame timecode frame calculations, even if the timecode supplied uses incorrect "99:99:99:99" format instead of "99:99:99;99"
89             seconds = duration.section(':', 2, 2).toInt();
90             frames = duration.section(':', 3, 3).toInt();
91         }
92
93         //Calculate the frame count
94         int dropRate = (int)((ceil(m_displayedFramesPerSecond) / 30) * 2);
95         frames += ((hours * 60 + minutes) * 60 + seconds) * m_displayedFramesPerSecond;
96         frames -= dropRate * ((hours * 60 + minutes) - (floor((hours * 60 + minutes) / 10)));
97         return frames;
98     }
99     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());
100 }
101
102 QString Timecode::getDisplayTimecode(const GenTime & time, bool frameDisplay) const
103 {
104     if (frameDisplay) return QString::number((int) time.frames(m_realFps));
105     return getTimecode(time);
106 }
107
108 QString Timecode::getTimecode(const GenTime & time) const
109 {
110     switch (m_format) {
111     case HH_MM_SS_FF:
112         return getTimecodeHH_MM_SS_FF(time);
113         break;
114     case HH_MM_SS_HH:
115         return getTimecodeHH_MM_SS_HH(time);
116         break;
117     case Frames:
118         return getTimecodeFrames(time);
119         break;
120     case Seconds:
121         return getTimecodeSeconds(time);
122         break;
123     default:
124         kWarning() <<
125         "Unknown timecode format specified, defaulting to HH_MM_SS_FF"
126         << endl;
127         return getTimecodeHH_MM_SS_FF(time);
128     }
129 }
130
131 const QString Timecode::getDisplayTimecodeFromFrames(int frames, bool frameDisplay) const
132 {
133     if (frameDisplay) return QString::number(frames);
134     return getTimecodeHH_MM_SS_FF(frames);
135 }
136
137 const QString Timecode::getTimecodeFromFrames(int frames) const
138 {
139     return getTimecodeHH_MM_SS_FF(frames);
140 }
141
142
143 //static
144 QString Timecode::getStringTimecode(int frames, const double &fps)
145 {
146     // Returns the timecode in an hh:mm:ss format
147     int seconds = (int)(frames / fps);
148     int minutes = seconds / 60;
149     seconds = seconds % 60;
150     int hours = minutes / 60;
151     minutes = minutes % 60;
152     QString text;
153     text.append(QString::number(hours).rightJustified(2, '0', false));
154     text.append(':');
155     text.append(QString::number(minutes).rightJustified(2, '0', false));
156     text.append(':');
157     text.append(QString::number(seconds).rightJustified(2, '0', false));
158     return text;
159 }
160
161
162 //static
163 QString Timecode::getEasyTimecode(const GenTime & time, const double &fps)
164 {
165     // Returns the timecode in an easily read display, like 3 min. 5 sec.
166     int frames = (int) time.frames(fps);
167     int seconds = (int)(frames / fps);
168     frames = frames - ((int)(fps * seconds));
169
170     int minutes = seconds / 60;
171     seconds = seconds % 60;
172     int hours = minutes / 60;
173     minutes = minutes % 60;
174
175     QString text;
176     bool trim = false;
177
178     if (hours != 0) {
179         text.append(QString::number(hours).rightJustified(2, '0', false));
180         text.append(' ' + i18n("hour") + ' ');
181         trim = true;
182     }
183     if (minutes != 0 || trim) {
184         if (!trim) {
185             text.append(QString::number(minutes));
186         } else
187             text.append(QString::number(minutes).rightJustified(2, '0', false));
188         text.append(' ' + i18n("min.") + ' ');
189         trim = true;
190     }
191     if (seconds != 0 || trim) {
192         if (!trim) {
193             text.append(QString::number(seconds));
194         } else
195             text.append(QString::number(seconds).rightJustified(2, '0', false));
196         text.append(' ' + i18n("sec."));
197         trim = true;
198     }
199     if (!trim) {
200         text.append(QString::number(frames));
201         text.append(' ' + i18n("frames"));
202     }
203
204     return text;
205 }
206
207
208 const QString Timecode::getTimecodeHH_MM_SS_FF(const GenTime & time) const
209 {
210     if (m_dropFrame)
211         return getTimecodeDropFrame(time);
212
213     return getTimecodeHH_MM_SS_FF((int) time.frames(m_realFps));
214 }
215
216 const QString Timecode::getTimecodeHH_MM_SS_FF(int frames) const
217 {
218     if (m_dropFrame) {
219         return getTimecodeDropFrame(frames);
220     }
221     int seconds = frames / m_displayedFramesPerSecond;
222     frames = frames % m_displayedFramesPerSecond;
223
224     int minutes = seconds / 60;
225     seconds = seconds % 60;
226     int hours = minutes / 60;
227     minutes = minutes % 60;
228
229     QString text;
230     text.append(QString::number(hours).rightJustified(2, '0', false));
231     text.append(':');
232     text.append(QString::number(minutes).rightJustified(2, '0', false));
233     text.append(':');
234     text.append(QString::number(seconds).rightJustified(2, '0', false));
235     text.append(':');
236     text.append(QString::number(frames).rightJustified(2, '0', false));
237
238     return text;
239 }
240
241 QString Timecode::getTimecodeHH_MM_SS_HH(const GenTime & time) const
242 {
243     int hundredths = (int)(time.seconds() * 100);
244     int seconds = hundredths / 100;
245     hundredths = hundredths % 100;
246     int minutes = seconds / 60;
247     seconds = seconds % 60;
248     int hours = minutes / 60;
249     minutes = minutes % 60;
250
251     QString text;
252
253     text.append(QString::number(hours).rightJustified(2, '0', false));
254     text.append(':');
255     text.append(QString::number(minutes).rightJustified(2, '0', false));
256     text.append(':');
257     text.append(QString::number(seconds).rightJustified(2, '0', false));
258     if (m_dropFrame)
259         text.append(';');
260     else
261         text.append(':');
262     text.append(QString::number(hundredths).rightJustified(2, '0', false));
263
264     return text;
265 }
266
267 QString Timecode::getTimecodeFrames(const GenTime & time) const
268 {
269     return QString::number(time.frames(m_realFps));
270 }
271
272 QString Timecode::getTimecodeSeconds(const GenTime & time) const
273 {
274     return QString::number(time.seconds());
275 }
276
277 QString Timecode::getTimecodeDropFrame(const GenTime & time) const
278 {
279     return getTimecodeDropFrame((int)time.frames(m_realFps));
280 }
281
282 QString Timecode::getTimecodeDropFrame(int frames) const
283 {
284     // Calculate the timecode using dropframes to remove the difference in fps. Note that this algorithm should work
285     // for NTSC times, but is untested for any others - it is in no way an "official" algorithm, unless it's by fluke.
286
287     // calculate how many frames need to be dropped every minute.
288     int dropRate = 0;
289     if (m_dropFrame) {
290         dropRate = (int)((ceil(m_displayedFramesPerSecond) / 30) * 2);
291     }
292
293     // calculate how many frames are in a normal minute, and how many are in a tenth minute.
294     int normalMinuteFrames = (m_displayedFramesPerSecond * 60) - dropRate;
295     int tenthMinuteFrames = (m_displayedFramesPerSecond * 60);
296
297     // Number of actual frames in a 10 minute interval :
298     int tenMinutes = (normalMinuteFrames * 9) + tenthMinuteFrames;
299
300     int tenMinuteIntervals = frames / tenMinutes;
301     frames = frames % tenMinutes;
302
303     int hours = tenMinuteIntervals / 6;
304     tenMinuteIntervals = tenMinuteIntervals % 6;
305
306     // At the point, we have figured out HH:M?:??:??
307
308     int numMinutes;
309
310     if (frames < tenthMinuteFrames) {
311         // tenth minute logic applies.
312         numMinutes = 0;
313     } else {
314         // normal minute logic applies.
315         numMinutes = 1 + (frames - tenthMinuteFrames) / normalMinuteFrames;
316         frames = (frames - tenthMinuteFrames) % normalMinuteFrames;
317         frames +=  dropRate;
318     }
319     // We now have HH:MM:??:??
320
321     int seconds = frames / m_displayedFramesPerSecond;
322     frames = frames % m_displayedFramesPerSecond;
323
324     // We now have HH:MM:SS:FF
325
326     // THANK FUCK FOR THAT.
327
328     QString text;
329     text.append(QString::number(hours).rightJustified(2, '0', false));
330     text.append(':');
331     text.append(QString::number(tenMinuteIntervals));
332     text.append(QString::number(numMinutes));
333     text.append(':');
334     text.append(QString::number(seconds).rightJustified(2, '0', false));
335     if (m_dropFrame)
336         text.append(';');
337     else
338         text.append(':');
339     text.append(QString::number(frames).rightJustified(2, '0', false));
340
341     return text;
342 }