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  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 
117  av_register_all();
119 
120  if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) {
121  fprintf(stderr, "Failed to set listen mode for server: %s\n", av_err2str(ret));
122  return ret;
123  }
124  if ((ret = avio_open2(&server, out_uri, AVIO_FLAG_WRITE, NULL, &options)) < 0) {
125  fprintf(stderr, "Failed to open server: %s\n", av_err2str(ret));
126  return ret;
127  }
128  fprintf(stderr, "Entering main loop.\n");
129  for(;;) {
130  if ((ret = avio_accept(server, &client)) < 0)
131  goto end;
132  fprintf(stderr, "Accepted client, forking process.\n");
133  // XXX: Since we don't reap our children and don't ignore signals
134  // this produces zombie processes.
135  pid = fork();
136  if (pid < 0) {
137  perror("Fork failed");
138  ret = AVERROR(errno);
139  goto end;
140  }
141  if (pid == 0) {
142  fprintf(stderr, "In child.\n");
143  process_client(client, in_uri);
144  avio_close(server);
145  exit(0);
146  }
147  if (pid > 0)
148  avio_close(client);
149  }
150 end:
151  avio_close(server);
152  if (ret < 0 && ret != AVERROR_EOF) {
153  fprintf(stderr, "Some errors occurred: %s\n", av_err2str(ret));
154  return 1;
155  }
156  return 0;
157 }
#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:391
#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:1223
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:4859
#define AVERROR_EOF
End of file.
Definition: error.h:55
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:216
const OptionDef options[]
Definition: ffserver.c:3948
#define av_log(a,...)
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:646
#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:1134
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:236
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:554
#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:1122
int avio_handshake(AVIOContext *c)
Perform one step of the protocol handshake to accept a new client.
Definition: aviobuf.c:1235
Main libavformat public API header.
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:751
#define av_freep(p)
void av_register_all(void)
Initialize libavformat and register all the muxers, demuxers and protocols.
Definition: allformats.c:395