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 = av_new_packet(pkt, sizeof(*pkt_data));
45  if (ret < 0)
46  return ret;
47  memcpy(pkt->data, pkt_data, sizeof(*pkt_data));
48 
49  pkt->pts = pkt->dts = pts;
50  pkt->duration = 1;
51 
52  return 0;
53 }
54 
56 {
57  int ret = 0;
58  AVStream *s;
59 
60  ret = avformat_alloc_output_context2(oc, NULL, "fifo", "-");
61  if (ret) {
62  fprintf(stderr, "Failed to create format context: %s\n",
63  av_err2str(ret));
64  return EXIT_FAILURE;
65  }
66 
67  s = avformat_new_stream(*oc, NULL);
68  if (!s) {
69  fprintf(stderr, "Failed to create stream: %s\n",
70  av_err2str(ret));
71  return AVERROR(ENOMEM);
72  }
73 
74  *pkt = av_packet_alloc();
75  if (!*pkt)
76  return AVERROR(ENOMEM);
77 
78  return 0;
79 }
80 
82  AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
83 {
84  int ret = 0, i;
85 
86  ret = avformat_write_header(oc, opts);
87  if (ret) {
88  fprintf(stderr, "Unexpected write_header failure: %s\n",
89  av_err2str(ret));
90  goto fail;
91  }
92 
93  for (i = 0; i < 15; i++ ) {
94  ret = prepare_packet(pkt, pkt_data, i);
95  if (ret < 0) {
96  fprintf(stderr, "Failed to prepare test packet: %s\n",
97  av_err2str(ret));
98  goto write_trailer_and_fail;
99  }
100  ret = av_write_frame(oc, pkt);
101  av_packet_unref(pkt);
102  if (ret < 0) {
103  fprintf(stderr, "Unexpected write_frame error: %s\n",
104  av_err2str(ret));
105  goto write_trailer_and_fail;
106  }
107  }
108 
109  ret = av_write_frame(oc, NULL);
110  if (ret < 0) {
111  fprintf(stderr, "Unexpected write_frame error during flushing: %s\n",
112  av_err2str(ret));
113  goto write_trailer_and_fail;
114  }
115 
116  ret = av_write_trailer(oc);
117  if (ret < 0) {
118  fprintf(stderr, "Unexpected write_trailer error during flushing: %s\n",
119  av_err2str(ret));
120  goto fail;
121  }
122 
123  return ret;
124 write_trailer_and_fail:
125  av_write_trailer(oc);
126 fail:
127  return ret;
128 }
129 
132 {
133  int ret = 0, i;
134  int64_t write_pkt_start, write_pkt_end, duration;
135 
136  ret = avformat_write_header(oc, opts);
137  if (ret) {
138  fprintf(stderr, "Unexpected write_header failure: %s\n",
139  av_err2str(ret));
140  return ret;
141  }
142 
143  write_pkt_start = av_gettime_relative();
144  for (i = 0; i < 6; i++ ) {
145  ret = prepare_packet(pkt, data, i);
146  if (ret < 0) {
147  fprintf(stderr, "Failed to prepare test packet: %s\n",
148  av_err2str(ret));
149  goto fail;
150  }
151  ret = av_write_frame(oc, pkt);
152  av_packet_unref(pkt);
153  if (ret < 0) {
154  break;
155  }
156  }
157 
158  write_pkt_end = av_gettime_relative();
159  duration = write_pkt_end - write_pkt_start;
160  if (duration > (SLEEPTIME_50_MS*6)/2) {
161  fprintf(stderr, "Writing packets to fifo muxer took too much time while testing"
162  "buffer overflow with drop_pkts_on_overflow was on.\n");
163  ret = AVERROR_BUG;
164  goto fail;
165  }
166 
167  if (ret) {
168  fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret));
169  goto fail;
170  }
171 
172  ret = av_write_trailer(oc);
173  if (ret < 0)
174  fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret));
175 
176  return ret;
177 fail:
178  av_write_trailer(oc);
179  return ret;
180 }
181 
182 typedef struct TestCase {
183  int (*test_func)(AVFormatContext *, AVDictionary **,
184  AVPacket *, const FailingMuxerPacketData *pkt_data);
185  const char *test_name;
186  const char *options;
187 
191 
193 } TestCase;
194 
195 
196 #define BUFFER_SIZE 64
197 
198 static int run_test(const TestCase *test)
199 {
201  AVFormatContext *oc = NULL;
202  AVPacket *pkt = NULL;
203  char buffer[BUFFER_SIZE];
204  int ret, ret1;
205 
206  ret = initialize_fifo_tst_muxer_chain(&oc, &pkt);
207  if (ret < 0) {
208  fprintf(stderr, "Muxer initialization failed: %s\n", av_err2str(ret));
209  goto end;
210  }
211 
212  if (test->options) {
213  ret = av_dict_parse_string(&opts, test->options, "=", ":", 0);
214  if (ret < 0) {
215  fprintf(stderr, "Failed to parse options: %s\n", av_err2str(ret));
216  goto end;
217  }
218  }
219 
220  snprintf(buffer, BUFFER_SIZE,
221  "print_deinit_summary=%d:write_header_ret=%d:write_trailer_ret=%d",
222  (int)test->print_summary_on_deinit, test->write_header_ret,
223  test->write_trailer_ret);
224  ret = av_dict_set(&opts, "format_opts", buffer, 0);
225  ret1 = av_dict_set(&opts, "fifo_format", "fifo_test", 0);
226  if (ret < 0 || ret1 < 0) {
227  fprintf(stderr, "Failed to set options for test muxer: %s\n",
228  av_err2str(ret));
229  goto end;
230  }
231 
232  ret = test->test_func(oc, &opts, pkt, &test->pkt_data);
233 
234 end:
235  printf("%s: %s\n", test->test_name, ret < 0 ? "fail" : "ok");
237  av_packet_free(&pkt);
238  av_dict_free(&opts);
239  return ret;
240 }
241 
242 
243 const TestCase tests[] = {
244  /* Simple test in packet-non-dropping mode, we expect to get on the output
245  * exactly what was on input */
246  {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}},
247 
248  /* Each write_packet will fail 3 times before operation is successful. If recovery
249  * Since recovery is on, fifo muxer should not return any errors. */
250  {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0",
251  0, 0, 0, {AVERROR(ETIMEDOUT), 3, 0}},
252 
253  /* By setting low queue_size and sending packets with longer processing time,
254  * this test will cause queue to overflow, since drop_pkts_on_overflow is off
255  * by default, all packets should be processed and fifo should block on full
256  * queue. */
257  {fifo_basic_test, "overflow without packet dropping","queue_size=3",
258  1, 0, 0, {0, 0, SLEEPTIME_10_MS}},
259 
260  /* The test as the upper one, except that drop_on_overflow is turned on. In this case
261  * fifo should not block when the queue is full and slow down producer, so the test
262  * measures time producer spends on write_packet calls which should be significantly
263  * less than number_of_pkts * 50 MS.
264  */
265  {fifo_overflow_drop_test, "overflow with packet dropping", "queue_size=3:drop_pkts_on_overflow=1",
266  0, 0, 0, {0, 0, SLEEPTIME_50_MS}},
267 
268  {NULL}
269 };
270 
271 int main(int argc, char *argv[])
272 {
273  int i, ret, ret_all = 0;
274 
275  for (i = 0; tests[i].test_func; i++) {
276  ret = run_test(&tests[i]);
277  if (!ret_all && ret < 0)
278  ret_all = ret;
279  }
280 
281  return ret;
282 }
static int run_test(const TestCase *test)
Definition: fifo_muxer.c:198
#define NULL
Definition: coverity.c:32
#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:1212
int main(int argc, char *argv[])
Definition: fifo_muxer.c:271
static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:81
AVPacket * pkt
Definition: movenc.c:59
Format I/O context.
Definition: avformat.h:1247
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:75
uint8_t
AVOptions.
FailingMuxerPacketData pkt_data
Definition: fifo_muxer.c:192
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:387
const TestCase tests[]
Definition: fifo_muxer.c:243
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4553
int64_t duration
Definition: movenc.c:64
uint8_t * data
Definition: packet.h:369
const char * test_name
Definition: fifo_muxer.c:185
const char * options
Definition: fifo_muxer.c:186
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:99
int write_trailer_ret
Definition: fifo_muxer.c:190
int(* test_func)(AVFormatContext *, AVDictionary **, AVPacket *, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:183
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:136
#define fail()
Definition: checkasm.h:133
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:506
#define BUFFER_SIZE
Definition: fifo_muxer.c:196
#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
Stream structure.
Definition: avformat.h:884
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:634
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:4480
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
static int initialize_fifo_tst_muxer_chain(AVFormatContext **oc, AVPacket **pkt)
Definition: fifo_muxer.c:55
Main libavformat public API header.
int
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:188
#define SLEEPTIME_10_MS
Definition: fifo_muxer.c:32
printf("static const uint8_t my_array[100] = {\n")
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:64
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: packet.h:368
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1274
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
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:130
This structure stores compressed data.
Definition: packet.h:346
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:362
int i
Definition: input.c:407
GLuint buffer
Definition: opengl_enc.c:101
int write_header_ret
Definition: fifo_muxer.c:189