FFmpeg
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,
158  .p.flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH,
159 #else
160  .p.flags = AVFMT_NOFILE,
161 #endif
162  .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
163 };
164 
165 
166 static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
167 {
168  int ret = av_new_packet(pkt, sizeof(*pkt_data));
169  if (ret < 0)
170  return ret;
171  memcpy(pkt->data, pkt_data, sizeof(*pkt_data));
172 
173  pkt->pts = pkt->dts = pts;
174  pkt->duration = 1;
175 
176  return 0;
177 }
178 
180 {
181  int ret = 0;
182  AVStream *s;
183 
184  ret = avformat_alloc_output_context2(oc, NULL, "fifo", "-");
185  if (ret) {
186  fprintf(stderr, "Failed to create format context: %s\n",
187  av_err2str(ret));
188  return EXIT_FAILURE;
189  }
190 
191  s = avformat_new_stream(*oc, NULL);
192  if (!s) {
193  fprintf(stderr, "Failed to create stream: %s\n",
194  av_err2str(ret));
195  return AVERROR(ENOMEM);
196  }
197 
198  *pkt = av_packet_alloc();
199  if (!*pkt)
200  return AVERROR(ENOMEM);
201 
202  return 0;
203 }
204 
206  AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
207 {
208  int ret = 0, i;
209 
211  if (ret) {
212  fprintf(stderr, "Unexpected write_header failure: %s\n",
213  av_err2str(ret));
214  goto fail;
215  }
216 
217  for (i = 0; i < 15; i++ ) {
218  ret = prepare_packet(pkt, pkt_data, i);
219  if (ret < 0) {
220  fprintf(stderr, "Failed to prepare test packet: %s\n",
221  av_err2str(ret));
222  goto write_trailer_and_fail;
223  }
224  ret = av_write_frame(oc, pkt);
226  if (ret < 0) {
227  fprintf(stderr, "Unexpected write_frame error: %s\n",
228  av_err2str(ret));
229  goto write_trailer_and_fail;
230  }
231  }
232 
233  ret = av_write_frame(oc, NULL);
234  if (ret < 0) {
235  fprintf(stderr, "Unexpected write_frame error during flushing: %s\n",
236  av_err2str(ret));
237  goto write_trailer_and_fail;
238  }
239 
240  ret = av_write_trailer(oc);
241  if (ret < 0) {
242  fprintf(stderr, "Unexpected write_trailer error during flushing: %s\n",
243  av_err2str(ret));
244  goto fail;
245  }
246 
247  return ret;
248 write_trailer_and_fail:
249  av_write_trailer(oc);
250 fail:
251  return ret;
252 }
253 
256 {
257  int ret = 0, i;
258  int64_t write_pkt_start, write_pkt_end, duration;
259 
261  if (ret) {
262  fprintf(stderr, "Unexpected write_header failure: %s\n",
263  av_err2str(ret));
264  return ret;
265  }
266 
267  write_pkt_start = av_gettime_relative();
268  for (i = 0; i < 6; i++ ) {
269  ret = prepare_packet(pkt, data, i);
270  if (ret < 0) {
271  fprintf(stderr, "Failed to prepare test packet: %s\n",
272  av_err2str(ret));
273  goto fail;
274  }
275  ret = av_write_frame(oc, pkt);
277  if (ret < 0) {
278  break;
279  }
280  }
281 
282  write_pkt_end = av_gettime_relative();
283  duration = write_pkt_end - write_pkt_start;
284  if (duration > (SLEEPTIME_50_MS*6)/2) {
285  fprintf(stderr, "Writing packets to fifo muxer took too much time while testing"
286  "buffer overflow with drop_pkts_on_overflow was on.\n");
287  ret = AVERROR_BUG;
288  goto fail;
289  }
290 
291  if (ret) {
292  fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret));
293  goto fail;
294  }
295 
296  ret = av_write_trailer(oc);
297  if (ret < 0)
298  fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret));
299 
300  return ret;
301 fail:
302  av_write_trailer(oc);
303  return ret;
304 }
305 
306 typedef struct TestCase {
309  const char *test_name;
310  const char *options;
311 
315 
317 } TestCase;
318 
319 
320 #define BUFFER_SIZE 64
321 
322 static int run_test(const TestCase *test)
323 {
325  AVFormatContext *oc = NULL;
326  AVPacket *pkt = NULL;
327  char buffer[BUFFER_SIZE];
328  int ret, ret1;
329 
331  if (ret < 0) {
332  fprintf(stderr, "Muxer initialization failed: %s\n", av_err2str(ret));
333  goto end;
334  }
335 
336  if (test->options) {
337  ret = av_dict_parse_string(&opts, test->options, "=", ":", 0);
338  if (ret < 0) {
339  fprintf(stderr, "Failed to parse options: %s\n", av_err2str(ret));
340  goto end;
341  }
342  }
343 
345  "print_deinit_summary=%d:write_header_ret=%d:write_trailer_ret=%d",
346  (int)test->print_summary_on_deinit, test->write_header_ret,
347  test->write_trailer_ret);
348  ret = av_dict_set(&opts, "format_opts", buffer, 0);
349  ret1 = av_dict_set(&opts, "fifo_format", "fifo_test", 0);
350  if (ret < 0 || ret1 < 0) {
351  fprintf(stderr, "Failed to set options for test muxer: %s\n",
352  av_err2str(ret));
353  goto end;
354  }
355 
356  ret = test->test_func(oc, &opts, pkt, &test->pkt_data);
357 
358 end:
359  printf("%s: %s\n", test->test_name, ret < 0 ? "fail" : "ok");
362  av_dict_free(&opts);
363  return ret;
364 }
365 
366 
367 const TestCase tests[] = {
368  /* Simple test in packet-non-dropping mode, we expect to get on the output
369  * exactly what was on input */
370  {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}},
371 
372  /* Each write_packet will fail 3 times before operation is successful. If recovery
373  * Since recovery is on, fifo muxer should not return any errors. */
374  {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0",
375  0, 0, 0, {AVERROR(ETIMEDOUT), 3, 0}},
376 
377  /* By setting low queue_size and sending packets with longer processing time,
378  * this test will cause queue to overflow, since drop_pkts_on_overflow is off
379  * by default, all packets should be processed and fifo should block on full
380  * queue. */
381  {fifo_basic_test, "overflow without packet dropping","queue_size=3",
382  1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
383 
384  /* The test as the upper one, except that drop_on_overflow is turned on. In this case
385  * fifo should not block when the queue is full and slow down producer, so the test
386  * measures time producer spends on write_packet calls which should be significantly
387  * less than number_of_pkts * 50 MS.
388  */
389  {fifo_overflow_drop_test, "overflow with packet dropping", "queue_size=3:drop_pkts_on_overflow=1",
390  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
391 
392  {NULL}
393 };
394 
395 int main(int argc, char *argv[])
396 {
397  int i, ret, ret_all = 0;
398 
399  for (i = 0; tests[i].test_func; i++) {
400  ret = run_test(&tests[i]);
401  if (!ret_all && ret < 0)
402  ret_all = ret;
403  }
404 
405  return ret;
406 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:427
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:510
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:322
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
deinit
static void deinit(AVFormatContext *s)
Definition: chromaprint.c:50
fifo_overflow_drop_test
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:254
FifoTestMuxerContext::pts_written_nr
int pts_written_nr
Definition: fifo_muxer.c:63
AVPacket::data
uint8_t * data
Definition: packet.h:524
AVOption
AVOption.
Definition: opt.h:346
data
const char data[16]
Definition: mxf.c:148
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:542
AVDictionary
Definition: dict.c:34
TestCase::test_name
const char * test_name
Definition: fifo_muxer.c:309
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:74
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:1528
fail
#define fail()
Definition: checkasm.h:179
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:205
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:98
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:487
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:1255
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:66
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:314
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
TestCase::print_summary_on_deinit
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:312
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:1233
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:269
TestCase
Definition: fifo_muxer.c:306
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:179
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:121
TestCase::pkt_data
FailingMuxerPacketData pkt_data
Definition: fifo_muxer.c:316
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:523
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:63
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:223
TestCase::options
const char * options
Definition: fifo_muxer.c:310
tests
const TestCase tests[]
Definition: fifo_muxer.c:367
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:1295
main
int main(int argc, char *argv[])
Definition: fifo_muxer.c:395
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:517
ff_fifo_test_muxer
const FFOutputFormat ff_fifo_test_muxer
Definition: fifo_muxer.c:148
else
else
Definition: snow.txt:125
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:320
FF_API_ALLOW_FLUSH
#define FF_API_ALLOW_FLUSH
Definition: version_major.h:46
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:743
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:71
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
Definition: opt.h:235
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:200
TestCase::test_func
int(* test_func)(AVFormatContext *, AVDictionary **, AVPacket *, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:307
prepare_packet
static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
Definition: fifo_muxer.c:166
AVPacket
This structure stores compressed data.
Definition: packet.h:501
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
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:88
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:313
write_header
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:345
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:94
int
int
Definition: ffmpeg_filter.c:424
snprintf
#define snprintf
Definition: snprintf.h:34
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1283
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