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 
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);
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 
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);
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 {
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 
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 
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");
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 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:403
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:4374
run_test
static int run_test(const TestCase *test)
Definition: fifo_muxer.c:198
fifo_overflow_drop_test
static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *data)
Definition: fifo_muxer.c:130
AVPacket::data
uint8_t * data
Definition: packet.h:365
data
const char data[16]
Definition: mxf.c:142
FailingMuxerPacketData
Definition: fifo_test.c:41
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:383
AVDictionary
Definition: dict.c:30
TestCase::test_name
const char * test_name
Definition: fifo_muxer.c:185
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:70
fail
#define fail()
Definition: checkasm.h:134
pts
static int64_t pts
Definition: transcode_aac.c:652
fifo_basic_test
static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, AVPacket *pkt, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:81
avassert.h
pkt
AVPacket * pkt
Definition: movenc.c:59
duration
int64_t duration
Definition: movenc.c:64
s
#define s(width, name)
Definition: cbs_vp9.c:257
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: avpacket.c:94
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:468
AVFormatContext
Format I/O context.
Definition: avformat.h:1106
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:190
TestCase::print_summary_on_deinit
uint8_t print_summary_on_deinit
Definition: fifo_muxer.c:188
time.h
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1174
FailingMuxerPacketData::sleep_time
unsigned sleep_time
Definition: fifo_test.c:44
TestCase
Definition: fifo_muxer.c:182
initialize_fifo_tst_muxer_chain
static int initialize_fifo_tst_muxer_chain(AVFormatContext **oc, AVPacket **pkt)
Definition: fifo_muxer.c:55
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:192
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:364
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:59
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
TestCase::options
const char * options
Definition: fifo_muxer.c:186
tests
const TestCase tests[]
Definition: fifo_muxer.c:243
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:1236
main
int main(int argc, char *argv[])
Definition: fifo_muxer.c:271
i
int i
Definition: input.c:407
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:358
url.h
BUFFER_SIZE
#define BUFFER_SIZE
Definition: fifo_muxer.c:196
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:832
FailingMuxerPacketData::ret
int ret
Definition: fifo_test.c:42
avformat.h
network.h
FailingMuxerPacketData::recover_after
int recover_after
Definition: fifo_test.c:43
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:4301
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
TestCase::test_func
int(* test_func)(AVFormatContext *, AVDictionary **, AVPacket *, const FailingMuxerPacketData *pkt_data)
Definition: fifo_muxer.c:183
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: packet.h:342
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:189
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:136
int
int
Definition: ffmpeg_filter.c:156
snprintf
#define snprintf
Definition: snprintf.h:34
SLEEPTIME_50_MS
#define SLEEPTIME_50_MS
Definition: fifo_muxer.c:31