FFmpeg
Loading...
Searching...
No Matches
vf_fsync.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2023 Thilo Borgmann <thilo.borgmann _at_ mail.de>
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 * Filter for syncing video frames from external source
24 *
25 * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
26 */
27
28#include "libavutil/avstring.h"
29#include "libavutil/error.h"
30#include "libavutil/mem.h"
31#include "libavutil/opt.h"
32#include "libavformat/avio.h"
33#include "video.h"
34#include "filters.h"
35
36#define BUF_SIZE 256
37
38typedef struct FsyncContext {
39 const AVClass *class;
40 AVIOContext *avio_ctx; // reading the map file
41 AVFrame *last_frame; // buffering the last frame for duplicating eventually
42 char *filename; // user-specified map file
43 char *buf; // line buffer for the map file
44 char *cur; // current position in the line buffer
45 char *end; // end pointer of the line buffer
46 int64_t ptsi; // input pts to map to [0-N] output pts
47 int64_t pts; // output pts
48 int tb_num; // output timebase num
49 int tb_den; // output timebase den
51
52#define OFFSET(x) offsetof(FsyncContext, x)
53
54static const AVOption fsync_options[] = {
55 { "file", "set the file name to use for frame sync", OFFSET(filename), AV_OPT_TYPE_STRING, { .str = "" }, .flags= AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
56 { "f", "set the file name to use for frame sync", OFFSET(filename), AV_OPT_TYPE_STRING, { .str = "" }, .flags= AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
57 { NULL }
58};
59
60/**
61 * Fills the buffer from cur to end, add \0 at EOF
62 */
64{
65 int ret;
66 int num = ctx->end - ctx->cur;
67
68 ret = avio_read(ctx->avio_ctx, ctx->cur, num);
69 if (ret < 0)
70 return ret;
71 if (ret < num) {
72 *(ctx->cur + ret) = '\0';
73 }
74
75 return ret;
76}
77
78/**
79 * Copies cur to end to the beginning and fills the rest
80 */
82{
83 int i, ret;
84 int num = ctx->end - ctx->cur;
85
86 for (i = 0; i < num; i++) {
87 ctx->buf[i] = *ctx->cur++;
88 }
89
90 ctx->cur = ctx->buf + i;
91 ret = buf_fill(ctx);
92 if (ret < 0)
93 return ret;
94 ctx->cur = ctx->buf;
95
96 return ret;
97}
98
99/**
100 * Skip from cur over eol
101 */
103{
104 char *i;
105 for (i = ctx->cur; i < ctx->end; i++) {
106 if (*i != '\n')// && *i != '\r')
107 break;
108 }
109 ctx->cur = i;
110}
111
112/**
113 * Get number of bytes from cur until eol
114 *
115 * @return >= 0 in case of success,
116 * -1 in case there is no line ending before end of buffer
117 */
119{
120 int ret = 0;
121 char *i;
122 for (i = ctx->cur; i < ctx->end; i++, ret++) {
123 if (*i == '\0' || *i == '\n')
124 return ret;
125 }
126
127 return -1;
128}
129
130/**
131 * Get number of bytes from cur to '\0'
132 */
134{
135 return av_strnlen(ctx->cur, ctx->end - ctx->cur);
136}
137
139{
140 FsyncContext *s = ctx->priv;
141 AVFilterLink *inlink = ctx->inputs[0];
142 AVFilterLink *outlink = ctx->outputs[0];
143
144 int ret, line_count;
145 AVFrame *frame;
146
147 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
148
150 line_count = buf_get_line_count(s);
151 if (line_count < 0) {
152 line_count = buf_reload(s);
153 if (line_count < 0)
154 return line_count;
155 line_count = buf_get_line_count(s);
156 if (line_count < 0)
157 return line_count;
158 }
159
160 if (avio_feof(s->avio_ctx) && buf_get_zero(s) < 3) {
161 av_log(ctx, AV_LOG_DEBUG, "End of file. To zero = %i\n", buf_get_zero(s));
162 goto end;
163 }
164
165 if (s->last_frame) {
166 ret = av_sscanf(s->cur, "%"PRId64" %"PRId64" %d/%d", &s->ptsi, &s->pts, &s->tb_num, &s->tb_den);
167 if (ret != 4) {
168 av_log(ctx, AV_LOG_ERROR, "Unexpected format found (%i / 4).\n", ret);
170 return AVERROR_INVALIDDATA;
171 }
172
173 av_log(ctx, AV_LOG_DEBUG, "frame %"PRId64" ", s->last_frame->pts);
174
175 if (s->last_frame->pts >= s->ptsi) {
176 av_log(ctx, AV_LOG_DEBUG, ">= %"PRId64": DUP LAST with pts = %"PRId64"\n", s->ptsi, s->pts);
177
178 // clone frame
179 frame = av_frame_clone(s->last_frame);
180 if (!frame) {
182 return AVERROR(ENOMEM);
183 }
184
185 // set output pts and timebase
186 frame->pts = s->pts;
187 frame->time_base = av_make_q((int)s->tb_num, (int)s->tb_den);
188
189 // advance cur to eol, skip over eol in the next call
190 s->cur += line_count;
191
192 // call again
193 if (ff_inoutlink_check_flow(inlink, outlink))
195
196 // filter frame
197 return ff_filter_frame(outlink, frame);
198 } else if (s->last_frame->pts < s->ptsi) {
199 av_log(ctx, AV_LOG_DEBUG, "< %"PRId64": DROP\n", s->ptsi);
200 av_frame_free(&s->last_frame);
201
202 // call again
203 if (ff_inoutlink_check_flow(inlink, outlink))
205
206 return 0;
207 }
208 }
209
210end:
211 if (s->last_frame)
212 av_frame_free(&s->last_frame);
213
214 ret = ff_inlink_consume_frame(inlink, &s->last_frame);
215 if (ret < 0)
216 return ret;
217
218 FF_FILTER_FORWARD_STATUS(inlink, outlink);
219 FF_FILTER_FORWARD_WANTED(outlink, inlink);
220
221 return FFERROR_NOT_READY;
222}
223
225{
226 AVFilterContext *ctx = outlink->src;
227 FilterLink *l = ff_filter_link(outlink);
228 FsyncContext *s = ctx->priv;
229 int ret;
230
231 // read first line to get output timebase
232 ret = av_sscanf(s->cur, "%"PRId64" %"PRId64" %d/%d", &s->ptsi, &s->pts, &s->tb_num, &s->tb_den);
233 if (ret != 4) {
234 av_log(ctx, AV_LOG_ERROR, "Unexpected format found (%i of 4).\n", ret);
236 return AVERROR_INVALIDDATA;
237 }
238
239 l->frame_rate = av_make_q(1, 0); // unknown or dynamic
240 outlink->time_base = av_make_q(s->tb_num, s->tb_den);
241
242 return 0;
243}
244
246{
247 FsyncContext *s = ctx->priv;
248 int ret;
249
250 av_log(ctx, AV_LOG_DEBUG, "filename: %s\n", s->filename);
251
252 s->buf = av_malloc(BUF_SIZE + 1);
253 if (!s->buf)
254 return AVERROR(ENOMEM);
255
256 ret = avio_open(&s->avio_ctx, s->filename, AVIO_FLAG_READ);
257 if (ret < 0)
258 return ret;
259
260 s->cur = s->buf;
261 s->end = s->buf + BUF_SIZE;
262 s->buf[BUF_SIZE] = '\0';
263
264 ret = buf_fill(s);
265 if (ret < 0)
266 return ret;
267
268
269 return 0;
270}
271
273{
274 FsyncContext *s = ctx->priv;
275
276 avio_closep(&s->avio_ctx);
277 av_freep(&s->buf);
278 av_frame_free(&s->last_frame);
279}
280
282
283static const AVFilterPad fsync_outputs[] = {
284 {
285 .name = "default",
286 .type = AVMEDIA_TYPE_VIDEO,
287 .config_props = fsync_config_props,
288 },
289};
290
292 .p.name = "fsync",
293 .p.description = NULL_IF_CONFIG_SMALL("Synchronize video frames from external source."),
294 .p.priv_class = &fsync_class,
296 .init = fsync_init,
297 .uninit = fsync_uninit,
298 .priv_size = sizeof(FsyncContext),
300 .formats_state = FF_FILTER_FORMATS_PASSTHROUGH,
303};
const FFFilter ff_vf_fsync
Definition vf_fsync.c:291
int ff_inoutlink_check_flow(AVFilterLink *inlink, AVFilterLink *outlink)
Check for flow control between input and output.
Definition avfilter.c:1654
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition avfilter.c:229
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition avfilter.c:1520
int avio_open(AVIOContext **s, const char *filename, int flags)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition avio.c:565
int avio_closep(AVIOContext **s)
Close the resource accessed by the AVIOContext *s, free it and set the pointer pointing to it to NULL...
Definition avio.c:717
Buffered I/O operations.
#define AVIO_FLAG_READ
read-only
Definition avio.h:617
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition aviobuf.c:349
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:615
int av_sscanf(const char *string, const char *format,...)
Definition avsscanf.c:962
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
error code definitions
#define AV_OPT_FLAG_FILTERING_PARAM
A generic parameter which can be set by the user for filtering.
Definition opt.h:380
#define AV_OPT_FLAG_VIDEO_PARAM
Definition opt.h:357
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition avfilter.h:182
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition frame.c:483
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
size_t static size_t av_strnlen(const char *s, size_t len)
Get the count of continuous non zero chars starting from the beginning.
Definition avstring.h:141
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
Definition filters.h:694
#define FF_FILTER_FORWARD_STATUS(inlink, outlink)
Acknowledge the status on an input link and forward it to an output link.
Definition filters.h:666
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition filters.h:629
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
Definition filters.h:34
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition filters.h:639
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
@ FF_FILTER_FORMATS_PASSTHROUGH
The default value meaning that this filter supports all formats and (for audio) sample rates and chan...
Definition filters.h:229
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
#define BUF_SIZE
Definition setpts.c:159
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
Bytestream IO Context.
Definition avio.h:160
AVOption.
Definition opt.h:428
char * cur
Definition vf_fsync.c:44
AVIOContext * avio_ctx
Definition vf_fsync.c:40
char * filename
Definition vf_fsync.c:42
char * end
Definition vf_fsync.c:45
char * buf
Definition vf_fsync.c:43
int64_t pts
Definition vf_fsync.c:47
int64_t ptsi
Definition vf_fsync.c:46
AVFrame * last_frame
Definition vf_fsync.c:41
#define av_freep(p)
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
static int buf_fill(FsyncContext *ctx)
Fills the buffer from cur to end, add \0 at EOF.
Definition vf_fsync.c:63
static int buf_get_line_count(FsyncContext *ctx)
Get number of bytes from cur until eol.
Definition vf_fsync.c:118
static int buf_reload(FsyncContext *ctx)
Copies cur to end to the beginning and fills the rest.
Definition vf_fsync.c:81
static const AVFilterPad fsync_outputs[]
Definition vf_fsync.c:283
static int fsync_config_props(AVFilterLink *outlink)
Definition vf_fsync.c:224
static av_cold int fsync_init(AVFilterContext *ctx)
Definition vf_fsync.c:245
static av_cold void fsync_uninit(AVFilterContext *ctx)
Definition vf_fsync.c:272
static void buf_skip_eol(FsyncContext *ctx)
Skip from cur over eol.
Definition vf_fsync.c:102
static int activate(AVFilterContext *ctx)
Definition vf_fsync.c:138
static const AVOption fsync_options[]
Definition vf_fsync.c:54
#define OFFSET(x)
Definition vf_fsync.c:52
static int buf_get_zero(FsyncContext *ctx)
Get number of bytes from cur to '\0'.
Definition vf_fsync.c:133
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37