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