FFmpeg  4.0
http_multiclient.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Stephan Holljes
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 /**
24  * @file
25  * libavformat multi-client network API usage example.
26  *
27  * @example http_multiclient.c
28  * This example will serve a file without decoding or demuxing it over http.
29  * Multiple clients can connect and will receive the same file.
30  */
31 
32 #include <libavformat/avformat.h>
33 #include <libavutil/opt.h>
34 #include <unistd.h>
35 
36 static void process_client(AVIOContext *client, const char *in_uri)
37 {
38  AVIOContext *input = NULL;
39  uint8_t buf[1024];
40  int ret, n, reply_code;
41  uint8_t *resource = NULL;
42  while ((ret = avio_handshake(client)) > 0) {
43  av_opt_get(client, "resource", AV_OPT_SEARCH_CHILDREN, &resource);
44  // check for strlen(resource) is necessary, because av_opt_get()
45  // may return empty string.
46  if (resource && strlen(resource))
47  break;
48  av_freep(&resource);
49  }
50  if (ret < 0)
51  goto end;
52  av_log(client, AV_LOG_TRACE, "resource=%p\n", resource);
53  if (resource && resource[0] == '/' && !strcmp((resource + 1), in_uri)) {
54  reply_code = 200;
55  } else {
56  reply_code = AVERROR_HTTP_NOT_FOUND;
57  }
58  if ((ret = av_opt_set_int(client, "reply_code", reply_code, AV_OPT_SEARCH_CHILDREN)) < 0) {
59  av_log(client, AV_LOG_ERROR, "Failed to set reply_code: %s.\n", av_err2str(ret));
60  goto end;
61  }
62  av_log(client, AV_LOG_TRACE, "Set reply code to %d\n", reply_code);
63 
64  while ((ret = avio_handshake(client)) > 0);
65 
66  if (ret < 0)
67  goto end;
68 
69  fprintf(stderr, "Handshake performed.\n");
70  if (reply_code != 200)
71  goto end;
72  fprintf(stderr, "Opening input file.\n");
73  if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, NULL)) < 0) {
74  av_log(input, AV_LOG_ERROR, "Failed to open input: %s: %s.\n", in_uri,
75  av_err2str(ret));
76  goto end;
77  }
78  for(;;) {
79  n = avio_read(input, buf, sizeof(buf));
80  if (n < 0) {
81  if (n == AVERROR_EOF)
82  break;
83  av_log(input, AV_LOG_ERROR, "Error reading from input: %s.\n",
84  av_err2str(n));
85  break;
86  }
87  avio_write(client, buf, n);
88  avio_flush(client);
89  }
90 end:
91  fprintf(stderr, "Flushing client\n");
92  avio_flush(client);
93  fprintf(stderr, "Closing client\n");
94  avio_close(client);
95  fprintf(stderr, "Closing input\n");
96  avio_close(input);
97  av_freep(&resource);
98 }
99 
100 int main(int argc, char **argv)
101 {
103  AVIOContext *client = NULL, *server = NULL;
104  const char *in_uri, *out_uri;
105  int ret, pid;
107  if (argc < 3) {
108  printf("usage: %s input http://hostname[:port]\n"
109  "API example program to serve http to multiple clients.\n"
110  "\n", argv[0]);
111  return 1;
112  }
113 
114  in_uri = argv[1];
115  out_uri = argv[2];
116 
118 
119  if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) {
120  fprintf(stderr, "Failed to set listen mode for server: %s\n", av_err2str(ret));
121  return ret;
122  }
123  if ((ret = avio_open2(&server, out_uri, AVIO_FLAG_WRITE, NULL, &options)) < 0) {
124  fprintf(stderr, "Failed to open server: %s\n", av_err2str(ret));
125  return ret;
126  }
127  fprintf(stderr, "Entering main loop.\n");
128  for(;;) {
129  if ((ret = avio_accept(server, &client)) < 0)
130  goto end;
131  fprintf(stderr, "Accepted client, forking process.\n");
132  // XXX: Since we don't reap our children and don't ignore signals
133  // this produces zombie processes.
134  pid = fork();
135  if (pid < 0) {
136  perror("Fork failed");
137  ret = AVERROR(errno);
138  goto end;
139  }
140  if (pid == 0) {
141  fprintf(stderr, "In child.\n");
142  process_client(client, in_uri);
143  avio_close(server);
144  exit(0);
145  }
146  if (pid > 0)
147  avio_close(client);
148  }
149 end:
150  avio_close(server);
151  if (ret < 0 && ret != AVERROR_EOF) {
152  fprintf(stderr, "Some errors occurred: %s\n", av_err2str(ret));
153  return 1;
154  }
155  return 0;
156 }
#define NULL
Definition: coverity.c:32
int main(int argc, char **argv)
Bytestream IO Context.
Definition: avio.h:161
void av_log_set_level(int level)
Set the log level.
Definition: log.c:385
#define AVIO_FLAG_READ
read-only
Definition: avio.h:654
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:655
#define AVERROR_HTTP_NOT_FOUND
Definition: error.h:79
int avio_accept(AVIOContext *s, AVIOContext **c)
Accept and allocate a client context on a server context.
Definition: aviobuf.c:1279
uint8_t
AVOptions.
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int avformat_network_init(void)
Do global initialization of network libraries.
Definition: utils.c:4922
#define AVERROR_EOF
End of file.
Definition: error.h:55
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:648
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:1190
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
Definition: opt.c:558
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:238
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:555
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
int n
Definition: avisynth_c.h:684
static void process_client(AVIOContext *client, const char *in_uri)
void * buf
Definition: avisynth_c.h:690
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
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:1178
int avio_handshake(AVIOContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: aviobuf.c:1291
Main libavformat public API header.
const OptionDef options[]
Definition: ffmpeg_opt.c:3292
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:751
#define av_freep(p)