GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/f_cue.c Lines: 0 36 0.0 %
Date: 2020-10-23 17:01:47 Branches: 0 30 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 2018 Marton Balint
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 License
8
 * 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
14
 * GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17
 * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "libavutil/opt.h"
22
#include "libavutil/time.h"
23
#include "avfilter.h"
24
#include "filters.h"
25
#include "internal.h"
26
27
typedef struct CueContext {
28
    const AVClass *class;
29
    int64_t first_pts;
30
    int64_t cue;
31
    int64_t preroll;
32
    int64_t buffer;
33
    int status;
34
} CueContext;
35
36
static int activate(AVFilterContext *ctx)
37
{
38
    AVFilterLink *inlink = ctx->inputs[0];
39
    AVFilterLink *outlink = ctx->outputs[0];
40
    CueContext *s = ctx->priv;
41
42
    FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
43
44
    if (ff_inlink_queued_frames(inlink)) {
45
        AVFrame *frame = ff_inlink_peek_frame(inlink, 0);
46
        int64_t pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q);
47
48
        if (!s->status) {
49
            s->first_pts = pts;
50
            s->status++;
51
        }
52
        if (s->status == 1) {
53
            if (pts - s->first_pts < s->preroll) {
54
                int ret = ff_inlink_consume_frame(inlink, &frame);
55
                if (ret < 0)
56
                    return ret;
57
                return ff_filter_frame(outlink, frame);
58
            }
59
            s->first_pts = pts;
60
            s->status++;
61
        }
62
        if (s->status == 2) {
63
            frame = ff_inlink_peek_frame(inlink, ff_inlink_queued_frames(inlink) - 1);
64
            pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q);
65
            if (!(pts - s->first_pts < s->buffer && (av_gettime() - s->cue) < 0))
66
                s->status++;
67
        }
68
        if (s->status == 3) {
69
            int64_t diff;
70
            while ((diff = (av_gettime() - s->cue)) < 0)
71
                av_usleep(av_clip(-diff / 2, 100, 1000000));
72
            s->status++;
73
        }
74
        if (s->status == 4) {
75
            int ret = ff_inlink_consume_frame(inlink, &frame);
76
            if (ret < 0)
77
                return ret;
78
            return ff_filter_frame(outlink, frame);
79
        }
80
    }
81
82
    FF_FILTER_FORWARD_STATUS(inlink, outlink);
83
    FF_FILTER_FORWARD_WANTED(outlink, inlink);
84
85
    return FFERROR_NOT_READY;
86
}
87
88
#define OFFSET(x) offsetof(CueContext, x)
89
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
90
static const AVOption options[] = {
91
    { "cue", "cue unix timestamp in microseconds", OFFSET(cue), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, FLAGS },
92
    { "preroll", "preroll duration in seconds", OFFSET(preroll), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS },
93
    { "buffer", "buffer duration in seconds", OFFSET(buffer), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS },
94
    { NULL }
95
};
96
97
#if CONFIG_CUE_FILTER
98
#define cue_options options
99
AVFILTER_DEFINE_CLASS(cue);
100
101
static const AVFilterPad cue_inputs[] = {
102
    {
103
        .name = "default",
104
        .type = AVMEDIA_TYPE_VIDEO,
105
    },
106
    { NULL }
107
};
108
109
static const AVFilterPad cue_outputs[] = {
110
    {
111
        .name = "default",
112
        .type = AVMEDIA_TYPE_VIDEO,
113
    },
114
    { NULL }
115
};
116
117
AVFilter ff_vf_cue = {
118
    .name        = "cue",
119
    .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."),
120
    .priv_size   = sizeof(CueContext),
121
    .priv_class  = &cue_class,
122
    .inputs      = cue_inputs,
123
    .outputs     = cue_outputs,
124
    .activate    = activate,
125
};
126
#endif /* CONFIG_CUE_FILTER */
127
128
#if CONFIG_ACUE_FILTER
129
#define acue_options options
130
AVFILTER_DEFINE_CLASS(acue);
131
132
static const AVFilterPad acue_inputs[] = {
133
    {
134
        .name = "default",
135
        .type = AVMEDIA_TYPE_AUDIO,
136
    },
137
    { NULL }
138
};
139
140
static const AVFilterPad acue_outputs[] = {
141
    {
142
        .name = "default",
143
        .type = AVMEDIA_TYPE_AUDIO,
144
    },
145
    { NULL }
146
};
147
148
AVFilter ff_af_acue = {
149
    .name        = "acue",
150
    .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."),
151
    .priv_size   = sizeof(CueContext),
152
    .priv_class  = &acue_class,
153
    .inputs      = acue_inputs,
154
    .outputs     = acue_outputs,
155
    .activate    = activate,
156
};
157
#endif /* CONFIG_ACUE_FILTER */