Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/*
2
 * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier 
3
 * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch 
4
 *
5
 * This file is part of FFmpeg.
6
 *
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.
11
 *
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.
16
 *
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
20
 */
21
 
22
/**
23
 * @file
24
 * Timecode helpers
25
 * @see https://en.wikipedia.org/wiki/SMPTE_time_code
26
 * @see http://www.dropframetimecode.org
27
 */
28
 
29
#include 
30
#include "timecode.h"
31
#include "log.h"
32
#include "error.h"
33
 
34
int av_timecode_adjust_ntsc_framenum2(int framenum, int fps)
35
{
36
    /* only works for NTSC 29.97 and 59.94 */
37
    int drop_frames = 0;
38
    int d, m, frames_per_10mins;
39
 
40
    if (fps == 30) {
41
        drop_frames = 2;
42
        frames_per_10mins = 17982;
43
    } else if (fps == 60) {
44
        drop_frames = 4;
45
        frames_per_10mins = 35964;
46
    } else
47
        return framenum;
48
 
49
    d = framenum / frames_per_10mins;
50
    m = framenum % frames_per_10mins;
51
 
52
    return framenum + 9 * drop_frames * d + drop_frames * ((m - drop_frames) / (frames_per_10mins / 10));
53
}
54
 
55
uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
56
{
57
    unsigned fps = tc->fps;
58
    int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME);
59
    int hh, mm, ss, ff;
60
 
61
    framenum += tc->start;
62
    if (drop)
63
        framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps);
64
    ff = framenum % 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
 
73
           (ss / 10) << 20 | // tens  of seconds
74
           (ss % 10) << 16 | // units of seconds
75
 
76
           (mm / 10) << 12 | // tens  of minutes
77
           (mm % 10) <<  8 | // units of minutes
78
 
79
 
80
           (hh / 10) <<  4 | // tens  of hours
81
           (hh % 10);        // units of hours
82
}
83
 
84
char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
85
{
86
    int fps = tc->fps;
87
    int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME;
88
    int hh, mm, ss, ff, neg = 0;
89
 
90
    framenum += tc->start;
91
    if (drop)
92
        framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps);
93
    if (framenum < 0) {
94
        framenum = -framenum;
95
        neg = tc->flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE;
96
    }
97
    ff = framenum % fps;
98
    ss = framenum / fps        % 60;
99
    mm = framenum / (fps*60)   % 60;
100
    hh = framenum / (fps*3600);
101
    if (tc->flags & AV_TIMECODE_FLAG_24HOURSMAX)
102
        hh = hh % 24;
103
    snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d",
104
             neg ? "-" : "",
105
             hh, mm, ss, drop ? ';' : ':', ff);
106
    return buf;
107
}
108
 
109
static unsigned bcd2uint(uint8_t bcd)
110
{
111
   unsigned low  = bcd & 0xf;
112
   unsigned high = bcd >> 4;
113
   if (low > 9 || high > 9)
114
       return 0;
115
   return low + 10*high;
116
}
117
 
118
char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
119
{
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);
127
    return buf;
128
}
129
 
130
char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
131
{
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
138
    return buf;
139
}
140
 
141
static int check_fps(int fps)
142
{
143
    int i;
144
    static const int supported_fps[] = {24, 25, 30, 50, 60};
145
 
146
    for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
147
        if (fps == supported_fps[i])
148
            return 0;
149
    return -1;
150
}
151
 
152
static int check_timecode(void *log_ctx, AVTimecode *tc)
153
{
154
    if (tc->fps <= 0) {
155
        av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate must be specified\n");
156
        return AVERROR(EINVAL);
157
    }
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);
161
    }
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;
166
    }
167
    return 0;
168
}
169
 
170
static int fps_from_frame_rate(AVRational rate)
171
{
172
    if (!rate.den || !rate.num)
173
        return -1;
174
    return (rate.num + rate.den/2) / rate.den;
175
}
176
 
177
int av_timecode_check_frame_rate(AVRational rate)
178
{
179
    return check_fps(fps_from_frame_rate(rate));
180
}
181
 
182
int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
183
{
184
    memset(tc, 0, sizeof(*tc));
185
    tc->start = frame_start;
186
    tc->flags = flags;
187
    tc->rate  = rate;
188
    tc->fps   = fps_from_frame_rate(rate);
189
    return check_timecode(log_ctx, tc);
190
}
191
 
192
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
193
{
194
    char c;
195
    int hh, mm, ss, ff, ret;
196
 
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;
201
    }
202
 
203
    memset(tc, 0, sizeof(*tc));
204
    tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ...
205
    tc->rate  = rate;
206
    tc->fps   = fps_from_frame_rate(rate);
207
 
208
    ret = check_timecode(log_ctx, tc);
209
    if (ret < 0)
210
        return ret;
211
 
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);
216
    }
217
    return 0;
218
}