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