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
34 int av_timecode_adjust_ntsc_framenum2(int framenum
, int fps
)
36 /* only works for NTSC 29.97 and 59.94 */
38 int d
, m
, frames_per_10mins
;
42 frames_per_10mins
= 17982;
43 } else if (fps
== 60) {
45 frames_per_10mins
= 35964;
49 d
= framenum
/ frames_per_10mins
;
50 m
= framenum
% frames_per_10mins
;
52 return framenum
+ 9 * drop_frames
* d
+ drop_frames
* ((m
- drop_frames
) / (frames_per_10mins
/ 10));
55 uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode
*tc
, int framenum
)
57 unsigned fps
= tc
->fps
;
58 int drop
= !!(tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
);
61 framenum
+= tc
->start
;
63 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, tc
->fps
);
65 ss
= framenum
/ fps
% 60;
66 mm
= framenum
/ (fps
*60) % 60;
67 hh
= framenum
/ (fps
*3600) % 24;
68 return 0 << 31 | // color frame flag (0: unsync mode, 1: sync mode)
69 drop
<< 30 | // drop frame flag (0: non drop, 1: drop)
70 (ff
/ 10) << 28 | // tens of frames
71 (ff
% 10) << 24 | // units of frames
72 0 << 23 | // PC (NTSC) or BGF0 (PAL)
73 (ss
/ 10) << 20 | // tens of seconds
74 (ss
% 10) << 16 | // units of seconds
75 0 << 15 | // BGF0 (NTSC) or BGF2 (PAL)
76 (mm
/ 10) << 12 | // tens of minutes
77 (mm
% 10) << 8 | // units of minutes
78 0 << 7 | // BGF2 (NTSC) or PC (PAL)
80 (hh
/ 10) << 4 | // tens of hours
81 (hh
% 10); // units of hours
84 char *av_timecode_make_string(const AVTimecode
*tc
, char *buf
, int framenum
)
87 int drop
= tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
;
88 int hh
, mm
, ss
, ff
, neg
= 0;
90 framenum
+= tc
->start
;
92 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, fps
);
95 neg
= tc
->flags
& AV_TIMECODE_FLAG_ALLOWNEGATIVE
;
98 ss
= framenum
/ fps
% 60;
99 mm
= framenum
/ (fps
*60) % 60;
100 hh
= framenum
/ (fps
*3600);
101 if (tc
->flags
& AV_TIMECODE_FLAG_24HOURSMAX
)
103 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%s%02d:%02d:%02d%c%02d",
105 hh
, mm
, ss
, drop
? ';' : ':', ff
);
109 static unsigned bcd2uint(uint8_t bcd
)
111 unsigned low
= bcd
& 0xf;
112 unsigned high
= bcd
>> 4;
113 if (low
> 9 || high
> 9)
115 return low
+ 10*high
;
118 char *av_timecode_make_smpte_tc_string(char *buf
, uint32_t tcsmpte
, int prevent_df
)
120 unsigned hh
= bcd2uint(tcsmpte
& 0x3f); // 6-bit hours
121 unsigned mm
= bcd2uint(tcsmpte
>>8 & 0x7f); // 7-bit minutes
122 unsigned ss
= bcd2uint(tcsmpte
>>16 & 0x7f); // 7-bit seconds
123 unsigned ff
= bcd2uint(tcsmpte
>>24 & 0x3f); // 6-bit frames
124 unsigned drop
= tcsmpte
& 1<<30 && !prevent_df
; // 1-bit drop if not arbitrary bit
125 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%02u:%02u:%02u%c%02u",
126 hh
, mm
, ss
, drop
? ';' : ':', ff
);
130 char *av_timecode_make_mpeg_tc_string(char *buf
, uint32_t tc25bit
)
132 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%02u:%02u:%02u%c%02u",
133 tc25bit
>>19 & 0x1f, // 5-bit hours
134 tc25bit
>>13 & 0x3f, // 6-bit minutes
135 tc25bit
>>6 & 0x3f, // 6-bit seconds
136 tc25bit
& 1<<24 ? ';' : ':', // 1-bit drop flag
137 tc25bit
& 0x3f); // 6-bit frames
141 static int check_fps(int fps
)
144 static const int supported_fps
[] = {24, 25, 30, 48, 50, 60};
146 for (i
= 0; i
< FF_ARRAY_ELEMS(supported_fps
); i
++)
147 if (fps
== supported_fps
[i
])
152 static int check_timecode(void *log_ctx
, AVTimecode
*tc
)
155 av_log(log_ctx
, AV_LOG_ERROR
, "Timecode frame rate must be specified\n");
156 return AVERROR(EINVAL
);
158 if ((tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) && tc
->fps
!= 30 && tc
->fps
!= 60) {
159 av_log(log_ctx
, AV_LOG_ERROR
, "Drop frame is only allowed with 30000/1001 or 60000/1001 FPS\n");
160 return AVERROR(EINVAL
);
162 if (check_fps(tc
->fps
) < 0) {
163 av_log(log_ctx
, AV_LOG_ERROR
, "Timecode frame rate %d/%d not supported\n",
164 tc
->rate
.num
, tc
->rate
.den
);
165 return AVERROR_PATCHWELCOME
;
170 static int fps_from_frame_rate(AVRational rate
)
172 if (!rate
.den
|| !rate
.num
)
174 return (rate
.num
+ rate
.den
/2) / rate
.den
;
177 int av_timecode_check_frame_rate(AVRational rate
)
179 return check_fps(fps_from_frame_rate(rate
));
182 int av_timecode_init(AVTimecode
*tc
, AVRational rate
, int flags
, int frame_start
, void *log_ctx
)
184 memset(tc
, 0, sizeof(*tc
));
185 tc
->start
= frame_start
;
188 tc
->fps
= fps_from_frame_rate(rate
);
189 return check_timecode(log_ctx
, tc
);
192 int av_timecode_init_from_string(AVTimecode
*tc
, AVRational rate
, const char *str
, void *log_ctx
)
195 int hh
, mm
, ss
, ff
, ret
;
197 if (sscanf(str
, "%d:%d:%d%c%d", &hh
, &mm
, &ss
, &c
, &ff
) != 5) {
198 av_log(log_ctx
, AV_LOG_ERROR
, "Unable to parse timecode, "
199 "syntax: hh:mm:ss[:;.]ff\n");
200 return AVERROR_INVALIDDATA
;
203 memset(tc
, 0, sizeof(*tc
));
204 tc
->flags
= c
!= ':' ? AV_TIMECODE_FLAG_DROPFRAME
: 0; // drop if ';', '.', ...
206 tc
->fps
= fps_from_frame_rate(rate
);
208 ret
= check_timecode(log_ctx
, tc
);
212 tc
->start
= (hh
*3600 + mm
*60 + ss
) * tc
->fps
+ ff
;
213 if (tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) { /* adjust frame number */
214 int tmins
= 60*hh
+ mm
;
215 tc
->start
-= 2 * (tmins
- tmins
/10);