FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
fifo_muxer.c
Go to the documentation of this file.
1 /*
2  * FIFO pseudo-muxer
3  * Copyright (c) 2016 Jan Sebechlebsky
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 License
9  * 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
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with FFmpeg; if not, write to the Free Software * Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include <stdlib.h>
23 #include "libavutil/opt.h"
24 #include "libavutil/time.h"
25 #include "libavformat/avformat.h"
26 #include "libavformat/mux.h"
27 #include "libavformat/network.h"
28 #include "libavformat/url.h"
29 
30 /*
31  * Include fifo.c directly to override libavformat/fifo.c and
32  * thereby prevent libavformat/fifo.o from being pulled in when linking.
33  * This relies on libavformat always being linked statically to its
34  * test tools (like this one).
35  * Due to FIFO_TEST, our fifo muxer will include special handling
36  * for tests, i.e. it allows to select the fifo_test muxer below
37  * even though it is not accessible via the API.
38  */
39 #define FIFO_TEST
40 #include "libavformat/fifo.c"
41 
42 #define MAX_TST_PACKETS 128
43 #define SLEEPTIME_50_MS 50000
44 #define SLEEPTIME_10_MS 10000
45 
46 /* This is structure of data sent in packets to
47  * failing muxer */
48 typedef struct FailingMuxerPacketData {
49  int ret; /* return value of write_packet call*/
50  int recover_after; /* set ret to zero after this number of recovery attempts */
51  unsigned sleep_time; /* sleep for this long in write_packet to simulate long I/O operation */
53 
54 typedef struct FifoTestMuxerContext {
55  AVClass *class;
58  /* If non-zero, summary of processed packets will be printed in deinit */
60 
65 
67 {
69  return ctx->write_header_ret;
70 }
71 
73 {
75  int ret = 0;
76  if (!pkt) {
77  ctx->flush_count++;
78  } else {
80 
81  if (!data->recover_after) {
82  data->ret = 0;
83  } else {
84  data->recover_after--;
85  }
86 
87  ret = data->ret;
88 
89  if (data->sleep_time) {
90  int64_t slept = 0;
91  while (slept < data->sleep_time) {
93  return AVERROR_EXIT;
95  slept += SLEEPTIME_10_MS;
96  }
97  }
98 
99  if (!ret) {
100  ctx->pts_written[ctx->pts_written_nr++] = pkt->pts;
102  }
103  }
104  return ret;
105 }
106 
108 {
110  return ctx->write_trailer_ret;
111 }
112 
114 {
115  int i;
117 
118  if (!ctx->print_deinit_summary)
119  return;
120 
121  printf("flush count: %d\n", ctx->flush_count);
122  printf("pts seen nr: %d\n", ctx->pts_written_nr);
123  printf("pts seen: ");
124  for (i = 0; i < ctx->pts_written_nr; ++i ) {
125  printf(i ? ",%d" : "%d", ctx->pts_written[i]);
126  }
127  printf("\n");
128 }
129 
130 #define OFF(x) offsetof(FifoTestMuxerContext, x)
131 static const AVOption fifo_test_options[] = {
132  {"write_header_ret", "write_header() return value", OFF(write_header_ret),
133  AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
134  {"write_trailer_ret", "write_trailer() return value", OFF(write_trailer_ret),
135  AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
136  {"print_deinit_summary", "print summary when deinitializing muxer", OFF(print_deinit_summary),
137  AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
138  {NULL}
139  };
140 
141 static const AVClass failing_muxer_class = {
142  .class_name = "Fifo test muxer",
143  .item_name = av_default_item_name,
144  .option = fifo_test_options,
145  .version = LIBAVUTIL_VERSION_INT,
146 };
147 
149  .p.name = "fifo_test",
150  .p.long_name = NULL_IF_CONFIG_SMALL("Fifo test muxer"),
151  .priv_data_size = sizeof(FifoTestMuxerContext),
156  .p.priv_class = &failing_muxer_class,
157  .p.flags = AVFMT_NOFILE,
158  .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
159 };
160 
161 
163 {
164  int ret = av_new_packet(pkt, sizeof(*pkt_data));
165  if (ret < 0)
166  return ret;
167  memcpy(pkt->data, pkt_data, sizeof(*pkt_data));
168 
169  pkt->pts = pkt->dts = pts;
170  pkt->duration = 1;
171 
172  return 0;
173 }
174 
176 {
177  int ret = 0;
178  AVStream *s;
179 
180  ret = avformat_alloc_output_context2(oc, NULL, "fifo", "-");
181  if (ret) {
182  fprintf(stderr, "Failed to create format context: %s\n",
183  av_err2str(ret));
184  return EXIT_FAILURE;
185  }
186 
187  s = avformat_new_stream(*oc, NULL);
188  if (!s) {
189  fprintf(stderr, "Failed to create stream: %s\n",
190  av_err2str(ret));
191  return AVERROR(ENOMEM);
192  }
193 
194  *pkt = av_packet_alloc();
195  if (!*pkt)
196  return AVERROR(ENOMEM);
197 
198  return 0;
199 }
200 
202  AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
203 {
204  int ret = 0, i;
205 
207  if (ret) {
208  fprintf(stderr, "Unexpected write_header failure: %s\n",
209  av_err2str(ret));
210  goto fail;
211  }
212 
213  for (i = 0; i < 15; i++ ) {
214  ret = prepare_packet(pkt, pkt_data, i);
215  if (ret < 0) {
216  fprintf(stderr, "Failed to prepare test packet: %s\n",
217  av_err2str(ret));
218  goto write_trailer_and_fail;
219  }
220  ret = av_write_frame(oc, pkt);
222  if (ret < 0) {
223  fprintf(stderr, "Unexpected write_frame error: %s\n",
224  av_err2str(ret));
225  goto write_trailer_and_fail;
226  }
227  }
228 
229  ret = av_write_frame(oc, NULL);
230  if (ret < 0) {
231  fprintf(stderr, "Unexpected write_frame error during flushing: %s\n",
232  av_err2str(ret));
233  goto write_trailer_and_fail;
234  }
235 
236  ret = av_write_trailer(oc);
237  if (ret < 0) {
238  fprintf(stderr, "Unexpected write_trailer error during flushing: %s\n",
239  av_err2str(ret));
240  goto fail;
241  }
242 
243  return ret;
244 write_trailer_and_fail:
245  av_write_trailer(oc);
246 fail:
247  return ret;
248 }
249 
252 {
253  int ret = 0, i;
254  int64_t write_pkt_start, write_pkt_end, duration;
255 
257  if (ret) {
258  fprintf(stderr, "Unexpected write_header failure: %s\n",
259  av_err2str(ret));
260  return ret;
261  }
262 
263  write_pkt_start = av_gettime_relative();
264  for (i = 0; i < 6; i++ ) {
265  ret = prepare_packet(pkt, data, i);
266  if (ret < 0) {
267  fprintf(stderr, "Failed to prepare test packet: %s\n",
268  av_err2str(ret));
269  goto fail;
270  }
271  ret = av_write_frame(oc, pkt);
273  if (ret < 0) {
274  break;
275  }
276  }
277 
278  write_pkt_end = av_gettime_relative();
279  duration = write_pkt_end - write_pkt_start;
280  if (duration > (SLEEPTIME_50_MS*6)/2) {
281  fprintf(stderr, "Writing packets to fifo muxer took too much time while testing"
282  "buffer overflow with drop_pkts_on_overflow was on.\n");
283  ret = AVERROR_BUG;
284  goto fail;
285  }
286 
287  if (ret) {
288  fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret));
289  goto fail;
290  }
291 
292  ret = av_write_trailer(oc);
293  if (ret < 0)
294  fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret));
295 
296  return ret;
297 fail:
298  av_write_trailer(oc);
299  return ret;
300 }
301 
302 typedef struct TestCase {
305  const char *test_name;
306  const char *options;
307 
311 
313 } TestCase;
314 
315 
316 #define BUFFER_SIZE 64
317 
318 static int run_test(const TestCase *test)
319 {
321  AVFormatContext *oc = NULL;
322  AVPacket *pkt = NULL;
323  char buffer[BUFFER_SIZE];
324  int ret, ret1;
325 
327  if (ret < 0) {
328  fprintf(stderr, "Muxer initialization failed: %s\n", av_err2str(ret));
329  goto end;
330  }
331 
332  if (test->options) {
333  ret = av_dict_parse_string(&opts, test->options, "=", ":", 0);
334  if (ret < 0) {
335  fprintf(stderr, "Failed to parse options: %s\n", av_err2str(ret));
336  goto end;
337  }
338  }
339 
341  "print_deinit_summary=%d:write_header_ret=%d:write_trailer_ret=%d",
342  (int)test->print_summary_on_deinit, test->write_header_ret,
343  test->write_trailer_ret);
344  ret = av_dict_set(&opts, "format_opts", buffer, 0);
345  ret1 = av_dict_set(&opts, "fifo_format", "fifo_test", 0);
346  if (ret < 0 || ret1 < 0) {
347  fprintf(stderr, "Failed to set options for test muxer: %s\n",
348  av_err2str(ret));
349  goto end;
350  }
351 
352  ret = test->test_func(oc, &opts, pkt, &test->pkt_data);
353 
354 end:
355  printf("%s: %s\n", test->test_name, ret < 0 ? "fail" : "ok");
358  av_dict_free(&opts);
359  return ret;
360 }
361 
362 
363 const TestCase tests[] = {
364  /* Simple test in packet-non-dropping mode, we expect to get on the output
365  * exactly what was on input */
366  {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}},
367 
368  /* Each write_packet will fail 3 times before operation is successful. If recovery
369  * Since recovery is on, fifo muxer should not return any errors. */
370  {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0",
371  0, 0, 0, {AVERROR(ETIMEDOUT), 3, 0}},
372 
373  /* By setting low queue_size and sending packets with longer processing time,
374  * this test will cause queue to overflow, since drop_pkts_on_overflow is off
375  * by default, all packets should be processed and fifo should block on full
376  * queue. */
377  {fifo_basic_test, "overflow without packet dropping","queue_size=3",
378  1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
379 
380  /* The test as the upper one, except that drop_on_overflow is turned on. In this case
381  * fifo should not block when the queue is full and slow down producer, so the test
382  * measures time producer spends on write_packet calls which should be significantly
383  * less than number_of_pkts * 50 MS.
384  */
385  {fifo_overflow_drop_test, "overflow with packet dropping", "queue_size=3:drop_pkts_on_overflow=1",
386  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
387 
388  {NULL}
389 };
390 
391 int main(int argc, char *argv[])
392 {
393  int i, ret, ret_all = 0;
394 
395  for (i = 0; tests[i].test_func; i++) {
396  ret = run_test(&tests[i]);
397  if (!ret_all && ret < 0)
398  ret_all = ret;
399  }
400 
401  return ret;
402 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:430
FifoTestMuxerContext
Definition: fifo_muxer.c:54
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
fifo_test_packet
static int fifo_test_packet(AVFormatContext *avf, AVPacket *pkt)
Definition: fifo_muxer.c:72
AVOutputFormat::name
const char * name
Definition: avformat.h:507
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
run_test
static int run_test(const TestCase *test)
Definition: fifo_muxer.c:318
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
int64_t
long long int64_t
Definition: coverity.c:34
deinit
static void deinit(AVFormatContext *s)
Definition: chromaprint.c:52
fifo_overflow_drop_test
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:250
FifoTestMuxerContext::pts_written_nr
int pts_written_nr
Definition: fifo_muxer.c:63
AVPacket::data
uint8_t * data
Definition: packet.h:535
AVOption
AVOption.
Definition: opt.h:429
data
const char data[16]
Definition: mxf.c:149
test
Definition: idctdsp.c:35
FailingMuxerPacketData
Definition: fifo_muxer.c:48
FifoTestMuxerContext::pts_written
int pts_written[MAX_TST_PACKETS]
Definition: fifo_muxer.c:62
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:553
AVDictionary
Definition: dict.c:32
TestCase::test_name
const char * test_name
Definition: fifo_muxer.c:305
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:75
FFOutputFormat::p
AVOutputFormat p
The public AVOutputFormat.
Definition: mux.h:65
AVFormatContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1535
fail
#define fail()
Definition: checkasm.h:193
MAX_TST_PACKETS
#define MAX_TST_PACKETS
Definition: fifo_muxer.c:42
pts
static int64_t pts
Definition: transcode_aac.c:644
fifo_test_header
static int fifo_test_header(AVFormatContext *avf)
Definition: fifo_muxer.c:66
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:854
fifo_basic_test
static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:201
FifoTestMuxerContext::write_header_ret
int write_header_ret
Definition: fifo_muxer.c:56
pkt
AVPacket * pkt
Definition: movenc.c:60
duration
int64_t duration
Definition: movenc.c:65
s
#define s(width, name)
Definition: cbs_vp9.c:198
FifoTestMuxerContext::print_deinit_summary
int print_deinit_summary
Definition: fifo_muxer.c:59
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: packet.c:99
failing_deinit
static void failing_deinit(AVFormatContext *avf)
Definition: fifo_muxer.c:113
ctx
AVFormatContext * ctx
Definition: movenc.c:49
fifo_test_options
static const AVOption fifo_test_options[]
Definition: fifo_muxer.c:131
av_usleep
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
SLEEPTIME_10_MS
#define SLEEPTIME_10_MS
Definition: fifo_muxer.c:44
avformat_write_header
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:467
if
if(ret)
Definition: filter_design.txt:179
failing_muxer_class
static const AVClass failing_muxer_class
Definition: fifo_muxer.c:141
AVFormatContext
Format I/O context.
Definition: avformat.h:1265
opts
AVDictionary * opts
Definition: movenc.c:51
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:75
OFF
#define OFF(x)
Definition: fifo_muxer.c:130
NULL
#define NULL
Definition: coverity.c:32
write_trailer
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:101
TestCase::write_trailer_ret
int write_trailer_ret
Definition: fifo_muxer.c:310
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:239
TestCase::print_summary_on_deinit
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:308
FFOutputFormat
Definition: mux.h:61
time.h
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1176
FailingMuxerPacketData::sleep_time
unsigned sleep_time
Definition: fifo_muxer.c:51
AV_OPT_FLAG_ENCODING_PARAM
#define AV_OPT_FLAG_ENCODING_PARAM
A generic parameter which can be set by the user for muxing or encoding.
Definition: opt.h:352
TestCase
Definition: fifo_muxer.c:302
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
FF_OFMT_FLAG_ALLOW_FLUSH
#define FF_OFMT_FLAG_ALLOW_FLUSH
This flag indicates that the muxer stores data internally and supports flushing it.
Definition: mux.h:38
initialize_fifo_tst_muxer_chain
static int initialize_fifo_tst_muxer_chain(AVFormatContext **oc, AVPacket **pkt)
Definition: fifo_muxer.c:175
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
TestCase::pkt_data
FailingMuxerPacketData pkt_data
Definition: fifo_muxer.c:312
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:468
printf
printf("static const uint8_t my_array[100] = {\n")
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:534
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:64
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:221
TestCase::options
const char * options
Definition: fifo_muxer.c:306
tests
const TestCase tests[]
Definition: fifo_muxer.c:363
av_write_trailer
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1238
main
int main(int argc, char *argv[])
Definition: fifo_muxer.c:391
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:528
ff_fifo_test_muxer
const FFOutputFormat ff_fifo_test_muxer
Definition: fifo_muxer.c:148
fifo_test_trailer
static int fifo_test_trailer(AVFormatContext *avf)
Definition: fifo_muxer.c:107
url.h
BUFFER_SIZE
#define BUFFER_SIZE
Definition: fifo_muxer.c:316
write_packet
static int write_packet(Muxer *mux, OutputStream *ost, AVPacket *pkt)
Definition: ffmpeg_mux.c:209
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:745
FailingMuxerPacketData::ret
int ret
Definition: fifo_muxer.c:49
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:80
avformat.h
network.h
FailingMuxerPacketData::recover_after
int recover_after
Definition: fifo_muxer.c:50
FifoTestMuxerContext::write_trailer_ret
int write_trailer_ret
Definition: fifo_muxer.c:57
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:259
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:141
av_dict_parse_string
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition: dict.c:198
TestCase::test_func
int(* test_func)(AVFormatContext *, AVDictionary **, AVPacket *, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:303
prepare_packet
static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
Definition: fifo_muxer.c:162
AVPacket
This structure stores compressed data.
Definition: packet.h:512
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:327
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
TestCase::write_header_ret
int write_header_ret
Definition: fifo_muxer.c:309
write_header
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:382
avformat_alloc_output_context2
int avformat_alloc_output_context2(AVFormatContext **ctx, const AVOutputFormat *oformat, const char *format_name, const char *filename)
Allocate an AVFormatContext for an output format.
Definition: mux.c:95
snprintf
#define snprintf
Definition: snprintf.h:34
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1293
FifoTestMuxerContext::flush_count
int flush_count
Definition: fifo_muxer.c:61
fifo.c
SLEEPTIME_50_MS
#define SLEEPTIME_50_MS
Definition: fifo_muxer.c:43
mux.h