Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
52868 views
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
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
char *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
{
100
av_log_set_level(AV_LOG_TRACE);
101
AVDictionary *options = NULL;
102
AVIOContext *client = NULL, *server = NULL;
103
const char *in_uri, *out_uri;
104
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();
116
avformat_network_init();
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
}
156
157