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;
45  FailingMuxerPacketData *data = av_malloc(sizeof(*data));
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 
86  av_init_packet(&pkt);
87 
88 
89  ret = avformat_write_header(oc, opts);
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);
104  av_packet_unref(&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 
140  av_init_packet(&pkt);
141 
142  ret = avformat_write_header(oc, opts);
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);
158  av_packet_unref(&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 {
188  int (*test_func)(AVFormatContext *, AVDictionary **,const FailingMuxerPacketData *pkt_data);
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 
223  snprintf(buffer, BUFFER_SIZE,
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 }
static int run_test(const TestCase *test)
Definition: fifo_muxer.c:202
#define NULL
Definition: coverity.c:32
static int initialize_fifo_tst_muxer_chain(AVFormatContext **oc)
Definition: fifo_muxer.c:58
#define SLEEPTIME_50_MS
Definition: fifo_muxer.c:31
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:878
int main(int argc, char *argv[])
Definition: fifo_muxer.c:273
static AVPacket pkt
Format I/O context.
Definition: avformat.h:1358
uint8_t
#define av_malloc(s)
AVOptions.
FailingMuxerPacketData pkt_data
Definition: fifo_muxer.c:196
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1495
const TestCase tests[]
Definition: fifo_muxer.c:245
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
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4465
int64_t duration
Definition: movenc.c:63
const char * test_name
Definition: fifo_muxer.c:189
const char * options
Definition: fifo_muxer.c:190
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
int write_trailer_ret
Definition: fifo_muxer.c:194
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
simple assert() macros that are a bit more flexible than ISO C assert().
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
#define fail()
Definition: checkasm.h:120
AVDictionary * opts
Definition: movenc.c:50
static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts)
Definition: fifo_muxer.c:42
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
#define BUFFER_SIZE
Definition: fifo_muxer.c:200
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
#define s(width, name)
Definition: cbs_vp9.c:257
static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:80
int(* test_func)(AVFormatContext *, AVDictionary **, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:188
Stream structure.
Definition: avformat.h:881
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
static void test(const char *pattern, const char *host)
Definition: noproxy.c:23
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:599
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
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4399
static int64_t pts
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
Main libavformat public API header.
int
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:192
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:33
#define SLEEPTIME_10_MS
Definition: fifo_muxer.c:32
printf("static const uint8_t my_array[100] = {\n")
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1476
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
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:133
unbuffered private I/O API
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
This structure stores compressed data.
Definition: avcodec.h:1454
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
GLuint buffer
Definition: opengl_enc.c:101
int write_header_ret
Definition: fifo_muxer.c:193