GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/setts_bsf.c Lines: 0 67 0.0 %
Date: 2021-04-20 15:25:36 Branches: 0 22 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 2021 Paul B Mahol
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
/**
22
 * @file
23
 * Change the PTS/DTS timestamps.
24
 */
25
26
#include "libavutil/opt.h"
27
#include "libavutil/eval.h"
28
29
#include "avcodec.h"
30
#include "bsf.h"
31
#include "bsf_internal.h"
32
33
static const char *const var_names[] = {
34
    "N",           ///< frame number (starting at zero)
35
    "TS",
36
    "POS",         ///< original position in the file of the frame
37
    "PREV_INPTS",  ///< previous  input PTS
38
    "PREV_INDTS",  ///< previous  input DTS
39
    "PREV_OUTPTS", ///< previous output PTS
40
    "PREV_OUTDTS", ///< previous output DTS
41
    "PTS",         ///< original PTS in the file of the frame
42
    "DTS",         ///< original DTS in the file of the frame
43
    "STARTPTS",    ///< PTS at start of movie
44
    "STARTDTS",    ///< DTS at start of movie
45
    "TB",          ///< timebase of the stream
46
    "SR",          ///< sample rate of the stream
47
    NULL
48
};
49
50
enum var_name {
51
    VAR_N,
52
    VAR_TS,
53
    VAR_POS,
54
    VAR_PREV_INPTS,
55
    VAR_PREV_INDTS,
56
    VAR_PREV_OUTPTS,
57
    VAR_PREV_OUTDTS,
58
    VAR_PTS,
59
    VAR_DTS,
60
    VAR_STARTPTS,
61
    VAR_STARTDTS,
62
    VAR_TB,
63
    VAR_SR,
64
    VAR_VARS_NB
65
};
66
67
typedef struct SetTSContext {
68
    const AVClass *class;
69
70
    char *ts_str;
71
    char *pts_str;
72
    char *dts_str;
73
74
    int64_t frame_number;
75
76
    int64_t start_pts;
77
    int64_t start_dts;
78
    int64_t prev_inpts;
79
    int64_t prev_indts;
80
    int64_t prev_outpts;
81
    int64_t prev_outdts;
82
83
    double var_values[VAR_VARS_NB];
84
85
    AVExpr *ts_expr;
86
    AVExpr *pts_expr;
87
    AVExpr *dts_expr;
88
} SetTSContext;
89
90
static int setts_init(AVBSFContext *ctx)
91
{
92
    SetTSContext *s = ctx->priv_data;
93
    int ret;
94
95
    if ((ret = av_expr_parse(&s->ts_expr, s->ts_str,
96
                             var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
97
        av_log(ctx, AV_LOG_ERROR, "Error while parsing ts expression '%s'\n", s->ts_str);
98
        return ret;
99
    }
100
101
    if (s->pts_str) {
102
        if ((ret = av_expr_parse(&s->pts_expr, s->pts_str,
103
                                 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
104
            av_log(ctx, AV_LOG_ERROR, "Error while parsing pts expression '%s'\n", s->pts_str);
105
            return ret;
106
        }
107
    }
108
109
    if (s->dts_str) {
110
        if ((ret = av_expr_parse(&s->dts_expr, s->dts_str,
111
                                 var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
112
            av_log(ctx, AV_LOG_ERROR, "Error while parsing dts expression '%s'\n", s->dts_str);
113
            return ret;
114
        }
115
    }
116
117
    s->frame_number= 0;
118
    s->start_pts   = AV_NOPTS_VALUE;
119
    s->start_dts   = AV_NOPTS_VALUE;
120
    s->prev_inpts  = AV_NOPTS_VALUE;
121
    s->prev_indts  = AV_NOPTS_VALUE;
122
    s->prev_outpts = AV_NOPTS_VALUE;
123
    s->prev_outdts = AV_NOPTS_VALUE;
124
125
    return 0;
126
}
127
128
static int setts_filter(AVBSFContext *ctx, AVPacket *pkt)
129
{
130
    SetTSContext *s = ctx->priv_data;
131
    int64_t new_ts, new_pts, new_dts;
132
    int ret;
133
134
    ret = ff_bsf_get_packet_ref(ctx, pkt);
135
    if (ret < 0)
136
        return ret;
137
138
    if (s->start_pts == AV_NOPTS_VALUE)
139
        s->start_pts = pkt->pts;
140
141
    if (s->start_dts == AV_NOPTS_VALUE)
142
        s->start_dts = pkt->dts;
143
144
    s->var_values[VAR_N]           = s->frame_number++;
145
    s->var_values[VAR_TS]          = pkt->dts;
146
    s->var_values[VAR_POS]         = pkt->pos;
147
    s->var_values[VAR_PTS]         = pkt->pts;
148
    s->var_values[VAR_DTS]         = pkt->dts;
149
    s->var_values[VAR_PREV_INPTS]  = s->prev_inpts;
150
    s->var_values[VAR_PREV_INDTS]  = s->prev_indts;
151
    s->var_values[VAR_PREV_OUTPTS] = s->prev_outpts;
152
    s->var_values[VAR_PREV_OUTDTS] = s->prev_outdts;
153
    s->var_values[VAR_STARTPTS]    = s->start_pts;
154
    s->var_values[VAR_STARTDTS]    = s->start_dts;
155
    s->var_values[VAR_TB]          = ctx->time_base_out.den ? av_q2d(ctx->time_base_out) : 0;
156
    s->var_values[VAR_SR]          = ctx->par_in->sample_rate;
157
158
    new_ts = llrint(av_expr_eval(s->ts_expr, s->var_values, NULL));
159
160
    if (s->pts_str) {
161
        s->var_values[VAR_TS] = pkt->pts;
162
        new_pts = llrint(av_expr_eval(s->pts_expr, s->var_values, NULL));
163
    } else {
164
        new_pts = new_ts;
165
    }
166
167
    if (s->dts_str) {
168
        s->var_values[VAR_TS] = pkt->dts;
169
        new_dts = llrint(av_expr_eval(s->dts_expr, s->var_values, NULL));
170
    } else {
171
        new_dts = new_ts;
172
    }
173
174
    s->var_values[VAR_PREV_INPTS]  = pkt->pts;
175
    s->var_values[VAR_PREV_INDTS]  = pkt->dts;
176
    s->var_values[VAR_PREV_OUTPTS] = new_pts;
177
    s->var_values[VAR_PREV_OUTDTS] = new_dts;
178
179
    pkt->pts = new_pts;
180
    pkt->dts = new_dts;
181
182
    return ret;
183
}
184
185
static void setts_close(AVBSFContext *bsf)
186
{
187
    SetTSContext *s = bsf->priv_data;
188
189
    av_expr_free(s->ts_expr);
190
    s->ts_expr = NULL;
191
    av_expr_free(s->pts_expr);
192
    s->pts_expr = NULL;
193
    av_expr_free(s->dts_expr);
194
    s->dts_expr = NULL;
195
}
196
197
#define OFFSET(x) offsetof(SetTSContext, x)
198
#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_BSF_PARAM)
199
200
static const AVOption options[] = {
201
    { "ts",  "set expression for packet PTS and DTS", OFFSET(ts_str),  AV_OPT_TYPE_STRING, {.str="TS"}, 0, 0, FLAGS },
202
    { "pts", "set expression for packet PTS", OFFSET(pts_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
203
    { "dts", "set expression for packet DTS", OFFSET(dts_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS },
204
    { NULL },
205
};
206
207
static const AVClass setts_class = {
208
    .class_name = "setts_bsf",
209
    .item_name  = av_default_item_name,
210
    .option     = options,
211
    .version    = LIBAVUTIL_VERSION_INT,
212
};
213
214
const AVBitStreamFilter ff_setts_bsf = {
215
    .name           = "setts",
216
    .priv_data_size = sizeof(SetTSContext),
217
    .priv_class     = &setts_class,
218
    .init           = setts_init,
219
    .close          = setts_close,
220
    .filter         = setts_filter,
221
};