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