1 /* GStreamer
2 * Copyright (C) 2009 David A. Schleef <ds@schleef.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /*
21 * Utility functions for handing SMPTE Time Codes, as described in
22 * SMPTE Standard 12M-1999.
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "gstsmptetimecode.h"
30
31 #define NTSC_FRAMES_PER_10_MINS (10*60*30 - 10*2 + 2)
32 #define NTSC_FRAMES_PER_HOUR (6*NTSC_FRAMES_PER_10_MINS)
33
34 /**
35 * gst_smpte_time_code_from_frame_number:
36 * @system: SMPTE Time Code system
37 * @time_code: pointer to time code structure
38 * @frame_number: integer frame number
39 *
40 * Converts a frame number to a time code.
41 *
42 * Returns: TRUE if the conversion was successful
43 */
44 gboolean
gst_smpte_time_code_from_frame_number(GstSMPTETimeCodeSystem system,GstSMPTETimeCode * time_code,int frame_number)45 gst_smpte_time_code_from_frame_number (GstSMPTETimeCodeSystem system,
46 GstSMPTETimeCode * time_code, int frame_number)
47 {
48 int ten_mins;
49 int n;
50
51 g_return_val_if_fail (time_code != NULL, FALSE);
52 g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
53
54 time_code->hours = 99;
55 time_code->minutes = 99;
56 time_code->seconds = 99;
57 time_code->frames = 99;
58
59 if (frame_number < 0)
60 return FALSE;
61
62 switch (system) {
63 case GST_SMPTE_TIME_CODE_SYSTEM_30:
64 if (frame_number >= 24 * NTSC_FRAMES_PER_HOUR)
65 return FALSE;
66
67 ten_mins = frame_number / NTSC_FRAMES_PER_10_MINS;
68 frame_number -= ten_mins * NTSC_FRAMES_PER_10_MINS;
69
70 time_code->hours = ten_mins / 6;
71 time_code->minutes = 10 * (ten_mins % 6);
72
73 if (frame_number < 2) {
74 /* treat the first two frames of each ten minutes specially */
75 time_code->seconds = 0;
76 time_code->frames = frame_number;
77 } else {
78 n = (frame_number - 2) / (60 * 30 - 2);
79 time_code->minutes += n;
80 frame_number -= n * (60 * 30 - 2);
81
82 time_code->seconds = frame_number / 30;
83 time_code->frames = frame_number % 30;
84 }
85 break;
86 case GST_SMPTE_TIME_CODE_SYSTEM_25:
87 if (frame_number >= 24 * 60 * 60 * 25)
88 return FALSE;
89
90 time_code->frames = frame_number % 25;
91 frame_number /= 25;
92 time_code->seconds = frame_number % 60;
93 frame_number /= 60;
94 time_code->minutes = frame_number % 60;
95 frame_number /= 60;
96 time_code->hours = frame_number;
97 break;
98 case GST_SMPTE_TIME_CODE_SYSTEM_24:
99 if (frame_number >= 24 * 60 * 60 * 24)
100 return FALSE;
101
102 time_code->frames = frame_number % 24;
103 frame_number /= 24;
104 time_code->seconds = frame_number % 60;
105 frame_number /= 60;
106 time_code->minutes = frame_number % 60;
107 frame_number /= 60;
108 time_code->hours = frame_number;
109 break;
110 }
111
112 return TRUE;
113 }
114
115 /**
116 * gst_smpte_time_code_is_valid:
117 * @system: SMPTE Time Code system
118 * @time_code: pointer to time code structure
119 *
120 * Checks that the time code represents a valid time code.
121 *
122 * Returns: TRUE if the time code is valid
123 */
124 gboolean
gst_smpte_time_code_is_valid(GstSMPTETimeCodeSystem system,GstSMPTETimeCode * time_code)125 gst_smpte_time_code_is_valid (GstSMPTETimeCodeSystem system,
126 GstSMPTETimeCode * time_code)
127 {
128 g_return_val_if_fail (time_code != NULL, FALSE);
129 g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
130
131 if (time_code->hours < 0 || time_code->hours >= 24)
132 return FALSE;
133 if (time_code->minutes < 0 || time_code->minutes >= 60)
134 return FALSE;
135 if (time_code->seconds < 0 || time_code->seconds >= 60)
136 return FALSE;
137 if (time_code->frames < 0)
138 return FALSE;
139
140 switch (system) {
141 case GST_SMPTE_TIME_CODE_SYSTEM_30:
142 if (time_code->frames >= 30)
143 return FALSE;
144 if (time_code->frames >= 2 || time_code->seconds > 0)
145 return TRUE;
146 if (time_code->minutes % 10 != 0)
147 return FALSE;
148 break;
149 case GST_SMPTE_TIME_CODE_SYSTEM_25:
150 if (time_code->frames >= 25)
151 return FALSE;
152 break;
153 case GST_SMPTE_TIME_CODE_SYSTEM_24:
154 if (time_code->frames >= 24)
155 return FALSE;
156 break;
157 }
158 return TRUE;
159 }
160
161 /**
162 * gst_smpte_time_get_frame_number:
163 * @system: SMPTE Time Code system
164 * @frame_number: pointer to frame number
165 * @time_code: pointer to time code structure
166 *
167 * Converts the time code structure to a linear frame number.
168 *
169 * Returns: TRUE if the time code could be converted
170 */
171 gboolean
gst_smpte_time_code_get_frame_number(GstSMPTETimeCodeSystem system,int * frame_number,GstSMPTETimeCode * time_code)172 gst_smpte_time_code_get_frame_number (GstSMPTETimeCodeSystem system,
173 int *frame_number, GstSMPTETimeCode * time_code)
174 {
175 int frame = 0;
176
177 g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system), FALSE);
178 g_return_val_if_fail (time_code != NULL, FALSE);
179
180 if (!gst_smpte_time_code_is_valid (system, time_code)) {
181 return FALSE;
182 }
183
184 switch (system) {
185 case GST_SMPTE_TIME_CODE_SYSTEM_30:
186 frame = time_code->hours * NTSC_FRAMES_PER_HOUR;
187 frame += (time_code->minutes / 10) * NTSC_FRAMES_PER_10_MINS;
188 frame += (time_code->minutes % 10) * (30 * 60 - 2);
189 frame += time_code->seconds * 30;
190 break;
191 case GST_SMPTE_TIME_CODE_SYSTEM_25:
192 time_code->frames =
193 25 * ((time_code->hours * 60 + time_code->minutes) * 60 +
194 time_code->seconds);
195 break;
196 case GST_SMPTE_TIME_CODE_SYSTEM_24:
197 time_code->frames =
198 24 * ((time_code->hours * 60 + time_code->minutes) * 60 +
199 time_code->seconds);
200 break;
201 }
202 frame += time_code->frames;
203
204 if (frame_number) {
205 *frame_number = frame;
206 }
207
208 return TRUE;
209 }
210
211 /**
212 * gst_smpte_time_get_timestamp:
213 * @system: SMPTE Time Code system
214 * @time_code: pointer to time code structure
215 *
216 * Converts the time code structure to a timestamp.
217 *
218 * Returns: Time stamp for time code, or GST_CLOCK_TIME_NONE if time
219 * code is invalid.
220 */
221 GstClockTime
gst_smpte_time_code_get_timestamp(GstSMPTETimeCodeSystem system,GstSMPTETimeCode * time_code)222 gst_smpte_time_code_get_timestamp (GstSMPTETimeCodeSystem system,
223 GstSMPTETimeCode * time_code)
224 {
225 int frame_number;
226
227 g_return_val_if_fail (GST_SMPTE_TIME_CODE_SYSTEM_IS_VALID (system),
228 GST_CLOCK_TIME_NONE);
229 g_return_val_if_fail (time_code != NULL, GST_CLOCK_TIME_NONE);
230
231 if (gst_smpte_time_code_get_frame_number (system, &frame_number, time_code)) {
232 static const int framerate_n[3] = { 3000, 25, 24 };
233 static const int framerate_d[3] = { 1001, 1, 1 };
234
235 return gst_util_uint64_scale (frame_number,
236 GST_SECOND * framerate_d[system], framerate_n[system]);
237 }
238
239 return GST_CLOCK_TIME_NONE;
240 }
241