2 * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
3 * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com>
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * @see https://en.wikipedia.org/wiki/SMPTE_time_code
26 * @see http://www.dropframetimecode.org
35 int av_timecode_adjust_ntsc_framenum2(int framenum
, int fps
)
37 /* only works for multiples of NTSC 29.97 */
39 int d
, m
, frames_per_10mins
;
41 if (fps
&& fps
% 30 == 0) {
42 drop_frames
= fps
/ 30 * 2;
43 frames_per_10mins
= fps
/ 30 * 17982;
47 d
= framenum
/ frames_per_10mins
;
48 m
= framenum
% frames_per_10mins
;
50 return framenum
+ 9U * drop_frames
* d
+ drop_frames
* ((m
- drop_frames
) / (frames_per_10mins
/ 10));
53 uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode
*tc
, int framenum
)
55 unsigned fps
= tc
->fps
;
56 int drop
= !!(tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
);
59 framenum
+= tc
->start
;
61 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, tc
->fps
);
63 ss
= framenum
/ fps
% 60;
64 mm
= framenum
/ (fps
*60LL) % 60;
65 hh
= framenum
/ (fps
*3600LL) % 24;
66 return av_timecode_get_smpte(tc
->rate
, drop
, hh
, mm
, ss
, ff
);
69 uint32_t av_timecode_get_smpte(AVRational rate
, int drop
, int hh
, int mm
, int ss
, int ff
)
73 /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
74 See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
75 if (av_cmp_q(rate
, (AVRational
) {30, 1}) == 1) {
77 if (av_cmp_q(rate
, (AVRational
) {50, 1}) == 0)
86 mm
= av_clip(mm
, 0, 59);
87 ss
= av_clip(ss
, 0, 59);
91 tc
|= (ff
/ 10) << 28;
92 tc
|= (ff
% 10) << 24;
93 tc
|= (ss
/ 10) << 20;
94 tc
|= (ss
% 10) << 16;
95 tc
|= (mm
/ 10) << 12;
103 char *av_timecode_make_string(const AVTimecode
*tc
, char *buf
, int framenum_arg
)
106 int drop
= tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
;
107 int hh
, mm
, ss
, ff
, ff_len
, neg
= 0;
108 int64_t framenum
= framenum_arg
;
110 framenum
+= tc
->start
;
112 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, fps
);
114 framenum
= -framenum
;
115 neg
= tc
->flags
& AV_TIMECODE_FLAG_ALLOWNEGATIVE
;
118 ss
= framenum
/ fps
% 60;
119 mm
= framenum
/ (fps
*60LL) % 60;
120 hh
= framenum
/ (fps
*3600LL);
121 if (tc
->flags
& AV_TIMECODE_FLAG_24HOURSMAX
)
123 ff_len
= fps
> 10000 ? 5 : fps
> 1000 ? 4 : fps
> 100 ? 3 : fps
> 10 ? 2 : 1;
124 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%s%02d:%02d:%02d%c%0*d",
126 hh
, mm
, ss
, drop
? ';' : ':', ff_len
, ff
);
130 static unsigned bcd2uint(uint8_t bcd
)
132 unsigned low
= bcd
& 0xf;
133 unsigned high
= bcd
>> 4;
134 if (low
> 9 || high
> 9)
136 return low
+ 10*high
;
139 char *av_timecode_make_smpte_tc_string2(char *buf
, AVRational rate
, uint32_t tcsmpte
, int prevent_df
, int skip_field
)
141 unsigned hh
= bcd2uint(tcsmpte
& 0x3f); // 6-bit hours
142 unsigned mm
= bcd2uint(tcsmpte
>>8 & 0x7f); // 7-bit minutes
143 unsigned ss
= bcd2uint(tcsmpte
>>16 & 0x7f); // 7-bit seconds
144 unsigned ff
= bcd2uint(tcsmpte
>>24 & 0x3f); // 6-bit frames
145 unsigned drop
= tcsmpte
& 1<<30 && !prevent_df
; // 1-bit drop if not arbitrary bit
147 if (av_cmp_q(rate
, (AVRational
) {30, 1}) == 1) {
150 if (av_cmp_q(rate
, (AVRational
) {50, 1}) == 0)
151 ff
+= !!(tcsmpte
& 1 << 7);
153 ff
+= !!(tcsmpte
& 1 << 23);
157 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%02u:%02u:%02u%c%02u",
158 hh
, mm
, ss
, drop
? ';' : ':', ff
);
163 char *av_timecode_make_smpte_tc_string(char *buf
, uint32_t tcsmpte
, int prevent_df
)
165 return av_timecode_make_smpte_tc_string2(buf
, (AVRational
){30, 1}, tcsmpte
, prevent_df
, 1);
168 char *av_timecode_make_mpeg_tc_string(char *buf
, uint32_t tc25bit
)
170 snprintf(buf
, AV_TIMECODE_STR_SIZE
,
171 "%02"PRIu32
":%02"PRIu32
":%02"PRIu32
"%c%02"PRIu32
,
172 tc25bit
>>19 & 0x1f, // 5-bit hours
173 tc25bit
>>13 & 0x3f, // 6-bit minutes
174 tc25bit
>>6 & 0x3f, // 6-bit seconds
175 tc25bit
& 1<<24 ? ';' : ':', // 1-bit drop flag
176 tc25bit
& 0x3f); // 6-bit frames
180 static int check_fps(int fps
)
183 static const int supported_fps
[] = {
184 24, 25, 30, 48, 50, 60, 100, 120, 150,
187 for (i
= 0; i
< FF_ARRAY_ELEMS(supported_fps
); i
++)
188 if (fps
== supported_fps
[i
])
193 static int check_timecode(void *log_ctx
, AVTimecode
*tc
)
195 if ((int)tc
->fps
<= 0) {
196 av_log(log_ctx
, AV_LOG_ERROR
, "Valid timecode frame rate must be specified. Minimum value is 1\n");
197 return AVERROR(EINVAL
);
199 if ((tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) && tc
->fps
% 30 != 0) {
200 av_log(log_ctx
, AV_LOG_ERROR
, "Drop frame is only allowed with multiples of 30000/1001 FPS\n");
201 return AVERROR(EINVAL
);
203 if (check_fps(tc
->fps
) < 0) {
204 av_log(log_ctx
, AV_LOG_WARNING
, "Using non-standard frame rate %d/%d\n",
205 tc
->rate
.num
, tc
->rate
.den
);
210 static int fps_from_frame_rate(AVRational rate
)
212 if (!rate
.den
|| !rate
.num
)
214 return (rate
.num
+ rate
.den
/2LL) / rate
.den
;
217 int av_timecode_check_frame_rate(AVRational rate
)
219 return check_fps(fps_from_frame_rate(rate
));
222 int av_timecode_init(AVTimecode
*tc
, AVRational rate
, int flags
, int frame_start
, void *log_ctx
)
224 memset(tc
, 0, sizeof(*tc
));
225 tc
->start
= frame_start
;
228 tc
->fps
= fps_from_frame_rate(rate
);
229 return check_timecode(log_ctx
, tc
);
232 int av_timecode_init_from_components(AVTimecode
*tc
, AVRational rate
, int flags
, int hh
, int mm
, int ss
, int ff
, void *log_ctx
)
236 memset(tc
, 0, sizeof(*tc
));
239 tc
->fps
= fps_from_frame_rate(rate
);
241 ret
= check_timecode(log_ctx
, tc
);
245 tc
->start
= (hh
*3600 + mm
*60 + ss
) * tc
->fps
+ ff
;
246 if (tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) { /* adjust frame number */
247 int tmins
= 60*hh
+ mm
;
248 tc
->start
-= (tc
->fps
/ 30 * 2) * (tmins
- tmins
/10);
253 int av_timecode_init_from_string(AVTimecode
*tc
, AVRational rate
, const char *str
, void *log_ctx
)
256 int hh
, mm
, ss
, ff
, flags
;
258 if (sscanf(str
, "%d:%d:%d%c%d", &hh
, &mm
, &ss
, &c
, &ff
) != 5) {
259 av_log(log_ctx
, AV_LOG_ERROR
, "Unable to parse timecode, "
260 "syntax: hh:mm:ss[:;.]ff\n");
261 return AVERROR_INVALIDDATA
;
263 flags
= c
!= ':' ? AV_TIMECODE_FLAG_DROPFRAME
: 0; // drop if ';', '.', ...
265 return av_timecode_init_from_components(tc
, rate
, flags
, hh
, mm
, ss
, ff
, log_ctx
);