1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @file
* libavformat multi-client network API usage example.
*
* @example http_multiclient.c
* This example will serve a file without decoding or demuxing it over http.
* Multiple clients can connect and will receive the same file.
*/
//out_url是服务器 in_url是文件
av_format_network_init();//初始化网络库 只在线程安全时或者GnuTLS或者OpenSSL
av_dict_set();//设置AVDictionary
avio_open2();//打开io上下文
avio_accept();//从s服务端读取上下文到c
fork();//分成两个同样的进程 父进程pid为正数 子进程pid为0
//pid==0
// process_client();单独进程
// avio_close();关闭s上下文
//pid>0
// avio_close();关闭c上下文

avio_close();//s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
static void process_client(AVIOContext *client, const char *in_uri)
{
while ((ret = avio_handshake(client)) > 0) {//通过握手协议获取一个新连接
av_opt_get(client, "resource", AV_OPT_SEARCH_CHILDREN, &resource);//获取resource属性
if (resource && strlen(resource))//不是 ""和null
break;
av_freep(&resource);//释放掉
}
if (ret < 0)
goto end;
av_log(client, AV_LOG_TRACE, "resource=%p\n", resource);
if (resource && resource[0] == '/' && !strcmp((resource + 1), in_uri)) {//检查链接合法性
reply_code = 200;
}
else {
reply_code = AVERROR_HTTP_NOT_FOUND;
}
if ((ret = av_opt_set_int(client, "reply_code", reply_code, AV_OPT_SEARCH_CHILDREN)) < 0) {//设置到一个子对象上的reply_code
av_log(client, AV_LOG_ERROR, "Failed to set reply_code: %s.\n", av_err2str(ret));
goto end;
}
av_log(client, AV_LOG_TRACE, "Set reply code to %d\n", reply_code);

while ((ret = avio_handshake(client)) > 0);//正在握手 在这里等待

if (ret < 0)
goto end;

fprintf(stderr, "Handshake performed.\n");
if (reply_code != 200)
goto end;
fprintf(stderr, "Opening input file.\n");
if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, NULL)) < 0) {//通过url创建一个io上下文
av_log(input, AV_LOG_ERROR, "Failed to open input: %s: %s.\n", in_uri,
av_err2str(ret));
goto end;
}
for (;;) {
n = avio_read(input, buf, sizeof(buf));//读
if (n < 0) {
if (n == AVERROR_EOF)
break;
av_log(input, AV_LOG_ERROR, "Error reading from input: %s.\n",
av_err2str(n));
break;
}
avio_write(client, buf, n);//写
avio_flush(client);//刷新
}
end:
avio_flush();
avio_close();
avio_close();
av_freep();
}