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 "libavutil/avassert.h"
26 #include "libavformat/avformat.h"
27 #include "libavformat/url.h"
28 #include "libavformat/network.h"
29 
30 #define MAX_TST_PACKETS 128
31 #define SLEEPTIME_50_MS 50000
32 #define SLEEPTIME_10_MS 10000
33 
34 /* This is structure of data sent in packets to
35  * failing muxer */
36 typedef struct FailingMuxerPacketData {
37  int ret; /* return value of write_packet call*/
38  int recover_after; /* set ret to zero after this number of recovery attempts */
39  unsigned sleep_time; /* sleep for this long in write_packet to simulate long I/O operation */
41 
42 static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
43 {
44  int ret;
46  if (!data) {
47  return AVERROR(ENOMEM);
48  }
49  memcpy(data, pkt_data, sizeof(FailingMuxerPacketData));
50  ret = av_packet_from_data(pkt, (uint8_t*) data, sizeof(*data));
51 
52  pkt->pts = pkt->dts = pts;
53  pkt->duration = 1;
54 
55  return ret;
56 }
57 
59 {
60  int ret = 0;
61  AVStream *s;
62 
63  ret = avformat_alloc_output_context2(oc, NULL, "fifo", "-");
64  if (ret) {
65  fprintf(stderr, "Failed to create format context: %s\n",
66  av_err2str(ret));
67  return EXIT_FAILURE;
68  }
69 
70  s = avformat_new_stream(*oc, NULL);
71  if (!s) {
72  fprintf(stderr, "Failed to create stream: %s\n",
73  av_err2str(ret));
74  ret = AVERROR(ENOMEM);
75  }
76 
77  return ret;
78 }
79 
81  const FailingMuxerPacketData *pkt_data)
82 {
83  int ret = 0, i;
84  AVPacket pkt;
85 
87 
88 
90  if (ret) {
91  fprintf(stderr, "Unexpected write_header failure: %s\n",
92  av_err2str(ret));
93  goto fail;
94  }
95 
96  for (i = 0; i < 15; i++ ) {
97  ret = prepare_packet(&pkt, pkt_data, i);
98  if (ret < 0) {
99  fprintf(stderr, "Failed to prepare test packet: %s\n",
100  av_err2str(ret));
101  goto write_trailer_and_fail;
102  }
103  ret = av_write_frame(oc, &pkt);
105  if (ret < 0) {
106  fprintf(stderr, "Unexpected write_frame error: %s\n",
107  av_err2str(ret));
108  goto write_trailer_and_fail;
109  }
110  }
111 
112  ret = av_write_frame(oc, NULL);
113  if (ret < 0) {
114  fprintf(stderr, "Unexpected write_frame error during flushing: %s\n",
115  av_err2str(ret));
116  goto write_trailer_and_fail;
117  }
118 
119  ret = av_write_trailer(oc);
120  if (ret < 0) {
121  fprintf(stderr, "Unexpected write_trailer error during flushing: %s\n",
122  av_err2str(ret));
123  goto fail;
124  }
125 
126  return ret;
127 write_trailer_and_fail:
128  av_write_trailer(oc);
129 fail:
130  return ret;
131 }
132 
135 {
136  int ret = 0, i;
137  int64_t write_pkt_start, write_pkt_end, duration;
138  AVPacket pkt;
139 
141 
143  if (ret) {
144  fprintf(stderr, "Unexpected write_header failure: %s\n",
145  av_err2str(ret));
146  return ret;
147  }
148 
149  write_pkt_start = av_gettime_relative();
150  for (i = 0; i < 6; i++ ) {
151  ret = prepare_packet(&pkt, data, i);
152  if (ret < 0) {
153  fprintf(stderr, "Failed to prepare test packet: %s\n",
154  av_err2str(ret));
155  goto fail;
156  }
157  ret = av_write_frame(oc, &pkt);
159  if (ret < 0) {
160  break;
161  }
162  }
163  write_pkt_end = av_gettime_relative();
164  duration = write_pkt_end - write_pkt_start;
165  if (duration > (SLEEPTIME_50_MS*6)/2) {
166  fprintf(stderr, "Writing packets to fifo muxer took too much time while testing"
167  "buffer overflow with drop_pkts_on_overflow was on.\n");
168  ret = AVERROR_BUG;
169  goto fail;
170  }
171 
172  if (ret) {
173  fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret));
174  goto fail;
175  }
176 
177  ret = av_write_trailer(oc);
178  if (ret < 0)
179  fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret));
180 
181  return ret;
182 fail:
183  av_write_trailer(oc);
184  return ret;
185 }
186 
187 typedef struct TestCase {
189  const char *test_name;
190  const char *options;
191 
195 
197 } TestCase;
198 
199 
200 #define BUFFER_SIZE 64
201 
202 static int run_test(const TestCase *test)
203 {
205  AVFormatContext *oc = NULL;
206  char buffer[BUFFER_SIZE];
207  int ret, ret1;
208 
210  if (ret < 0) {
211  fprintf(stderr, "Muxer initialization failed: %s\n", av_err2str(ret));
212  goto end;
213  }
214 
215  if (test->options) {
216  ret = av_dict_parse_string(&opts, test->options, "=", ":", 0);
217  if (ret < 0) {
218  fprintf(stderr, "Failed to parse options: %s\n", av_err2str(ret));
219  goto end;
220  }
221  }
222 
224  "print_deinit_summary=%d:write_header_ret=%d:write_trailer_ret=%d",
225  (int)test->print_summary_on_deinit, test->write_header_ret,
226  test->write_trailer_ret);
227  ret = av_dict_set(&opts, "format_opts", buffer, 0);
228  ret1 = av_dict_set(&opts, "fifo_format", "fifo_test", 0);
229  if (ret < 0 || ret1 < 0) {
230  fprintf(stderr, "Failed to set options for test muxer: %s\n",
231  av_err2str(ret));
232  goto end;
233  }
234 
235  ret = test->test_func(oc, &opts, &test->pkt_data);
236 
237 end:
238  printf("%s: %s\n", test->test_name, ret < 0 ? "fail" : "ok");
240  av_dict_free(&opts);
241  return ret;
242 }
243 
244 
245 const TestCase tests[] = {
246  /* Simple test in packet-non-dropping mode, we expect to get on the output
247  * exactly what was on input */
248  {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}},
249 
250  /* Each write_packet will fail 3 times before operation is successful. If recovery
251  * Since recovery is on, fifo muxer should not return any errors. */
252  {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0",
253  0, 0, 0, {AVERROR(ETIMEDOUT), 3, 0}},
254 
255  /* By setting low queue_size and sending packets with longer processing time,
256  * this test will cause queue to overflow, since drop_pkts_on_overflow is off
257  * by default, all packets should be processed and fifo should block on full
258  * queue. */
259  {fifo_basic_test, "overflow without packet dropping","queue_size=3",
260  1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
261 
262  /* The test as the upper one, except that drop_on_overflow is turned on. In this case
263  * fifo should not block when the queue is full and slow down producer, so the test
264  * measures time producer spends on write_packet calls which should be significantly
265  * less than number_of_pkts * 50 MS.
266  */
267  {fifo_overflow_drop_test, "overflow with packet dropping", "queue_size=3:drop_pkts_on_overflow=1",
268  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
269 
270  {NULL}
271 };
272 
273 int main(int argc, char *argv[])
274 {
275  int i, ret, ret_all = 0;
276 
277  for (i = 0; tests[i].test_func; i++) {
278  ret = run_test(&tests[i]);
279  if (!ret_all && ret < 0)
280  ret_all = ret;
281  }
282 
283  return ret;
284 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:599
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
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
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4480
run_test
static int run_test(const TestCase *test)
Definition: fifo_muxer.c:202
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
data
const char data[16]
Definition: mxf.c:91
FailingMuxerPacketData
Definition: fifo_test.c:41
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1495
AVDictionary
Definition: dict.c:30
TestCase::test_name
const char * test_name
Definition: fifo_muxer.c:189
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
fail
#define fail()
Definition: checkasm.h:120
pts
static int64_t pts
Definition: transcode_aac.c:647
fifo_overflow_drop_test
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:133
avassert.h
duration
int64_t duration
Definition: movenc.c:63
s
#define s(width, name)
Definition: cbs_vp9.c:257
initialize_fifo_tst_muxer_chain
static int initialize_fifo_tst_muxer_chain(AVFormatContext **oc)
Definition: fifo_muxer.c:58
SLEEPTIME_10_MS
#define SLEEPTIME_10_MS
Definition: fifo_muxer.c:32
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:508
AVFormatContext
Format I/O context.
Definition: avformat.h:1342
opts
AVDictionary * opts
Definition: movenc.c:50
NULL
#define NULL
Definition: coverity.c:32
TestCase::write_trailer_ret
int write_trailer_ret
Definition: fifo_muxer.c:194
TestCase::print_summary_on_deinit
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:192
time.h
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:878
FailingMuxerPacketData::sleep_time
unsigned sleep_time
Definition: fifo_test.c:44
TestCase
Definition: fifo_muxer.c:187
av_packet_from_data
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
Initialize a reference-counted packet from av_malloc()ed data.
Definition: avpacket.c:152
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:119
TestCase::pkt_data
FailingMuxerPacketData pkt_data
Definition: fifo_muxer.c:196
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: avcodec.h:1476
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:203
avformat_alloc_output_context2
int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat, const char *format_name, const char *filename)
Allocate an AVFormatContext for an output format.
Definition: mux.c:148
TestCase::options
const char * options
Definition: fifo_muxer.c:190
tests
const TestCase tests[]
Definition: fifo_muxer.c:245
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:1254
main
int main(int argc, char *argv[])
Definition: fifo_muxer.c:273
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
url.h
uint8_t
uint8_t
Definition: audio_convert.c:194
fifo_basic_test
static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:80
BUFFER_SIZE
#define BUFFER_SIZE
Definition: fifo_muxer.c:200
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:870
FailingMuxerPacketData::ret
int ret
Definition: fifo_test.c:42
avformat.h
network.h
FailingMuxerPacketData::recover_after
int recover_after
Definition: fifo_test.c:43
pkt
static AVPacket pkt
Definition: demuxing_decoding.c:54
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
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4414
test
static void test(const char *pattern, const char *host)
Definition: noproxy.c:23
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:180
prepare_packet
static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
Definition: fifo_muxer.c:42
AVPacket
This structure stores compressed data.
Definition: avcodec.h:1454
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:70
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
TestCase::write_header_ret
int write_header_ret
Definition: fifo_muxer.c:193
int
int
Definition: ffmpeg_filter.c:191
snprintf
#define snprintf
Definition: snprintf.h:34
TestCase::test_func
int(* test_func)(AVFormatContext *, AVDictionary **, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:188
SLEEPTIME_50_MS
#define SLEEPTIME_50_MS
Definition: fifo_muxer.c:31
av_init_packet
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:33