FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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  }
49  if (ret < 0)
50  goto end;
51  av_log(client, AV_LOG_TRACE, "resource=%p\n", resource);
52  if (resource && resource[0] == '/' && !strcmp((resource + 1), in_uri)) {
53  reply_code = 200;
54  } else {
55  reply_code = AVERROR_HTTP_NOT_FOUND;
56  }
57  if ((ret = av_opt_set_int(client, "reply_code", reply_code, AV_OPT_SEARCH_CHILDREN)) < 0) {
58  av_log(client, AV_LOG_ERROR, "Failed to set reply_code: %s.\n", av_err2str(ret));
59  goto end;
60  }
61  av_log(client, AV_LOG_TRACE, "Set reply code to %d\n", reply_code);
62 
63  while ((ret = avio_handshake(client)) > 0);
64 
65  if (ret < 0)
66  goto end;
67 
68  fprintf(stderr, "Handshake performed.\n");
69  if (reply_code != 200)
70  goto end;
71  fprintf(stderr, "Opening input file.\n");
72  if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, NULL)) < 0) {
73  av_log(input, AV_LOG_ERROR, "Failed to open input: %s: %s.\n", in_uri,
74  av_err2str(ret));
75  goto end;
76  }
77  for(;;) {
78  n = avio_read(input, buf, sizeof(buf));
79  if (n < 0) {
80  if (n == AVERROR_EOF)
81  break;
82  av_log(input, AV_LOG_ERROR, "Error reading from input: %s.\n",
83  av_err2str(n));
84  break;
85  }
86  avio_write(client, buf, n);
87  avio_flush(client);
88  }
89 end:
90  fprintf(stderr, "Flushing client\n");
91  avio_flush(client);
92  fprintf(stderr, "Closing client\n");
93  avio_close(client);
94  fprintf(stderr, "Closing input\n");
95  avio_close(input);
96 }
97 
98 int main(int argc, char **argv)
99 {
101  AVIOContext *client = NULL, *server = NULL;
102  const char *in_uri, *out_uri;
103  int ret, pid;
105  if (argc < 3) {
106  printf("usage: %s input http://hostname[:port]\n"
107  "API example program to serve http to multiple clients.\n"
108  "\n", argv[0]);
109  return 1;
110  }
111 
112  in_uri = argv[1];
113  out_uri = argv[2];
114 
115  av_register_all();
117 
118  if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) {
119  fprintf(stderr, "Failed to set listen mode for server: %s\n", av_err2str(ret));
120  return ret;
121  }
122  if ((ret = avio_open2(&server, out_uri, AVIO_FLAG_WRITE, NULL, &options)) < 0) {
123  fprintf(stderr, "Failed to open server: %s\n", av_err2str(ret));
124  return ret;
125  }
126  fprintf(stderr, "Entering main loop.\n");
127  for(;;) {
128  if ((ret = avio_accept(server, &client)) < 0)
129  goto end;
130  fprintf(stderr, "Accepted client, forking process.\n");
131  // XXX: Since we don't reap our children and don't ignore signals
132  // this produces zombie processes.
133  pid = fork();
134  if (pid < 0) {
135  perror("Fork failed");
136  ret = AVERROR(errno);
137  goto end;
138  }
139  if (pid == 0) {
140  fprintf(stderr, "In child.\n");
141  process_client(client, in_uri);
142  avio_close(server);
143  exit(0);
144  }
145  if (pid > 0)
146  avio_close(client);
147  }
148 end:
149  avio_close(server);
150  if (ret < 0 && ret != AVERROR_EOF) {
151  fprintf(stderr, "Some errors occurred: %s\n", av_err2str(ret));
152  return 1;
153  }
154  return 0;
155 }
#define NULL
Definition: coverity.c:32
int main(int argc, char **argv)
Bytestream IO Context.
Definition: avio.h:147
void av_log_set_level(int level)
Set the log level.
Definition: log.c:391
#define AVIO_FLAG_READ
read-only
Definition: avio.h:606
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:607
#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:1156
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 components.
Definition: utils.c:4671
#define AVERROR_EOF
End of file.
Definition: error.h:55
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:204
const OptionDef options[]
Definition: ffserver.c:3969
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:604
#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:1069
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
Definition: opt.c:539
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:224
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:556
#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:1057
int avio_handshake(AVIOContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: aviobuf.c:1168
Main libavformat public API header.
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:732
void av_register_all(void)
Initialize libavformat and register all the muxers, demuxers and protocols.
Definition: allformats.c:44