请先看:Transfer-Encoding:chunked详解
where cl
C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.39.33519\bin\Hostx86\x86\cl.exe
where g++
D:\Strawberry\c\bin\g++.exe
编写 httpFlv_server.cpp 如下
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
char* get_filename(char* path) {
char* last_slash = strrchr(path, '/');
// 对于Windows系统,应该是 '\'
if (last_slash == NULL) {
last_slash = strrchr(path, '\\');
}
if (last_slash == NULL) {
return path;
} else {
return last_slash + 1;
}
}
int main(int argc, char *argv[])
{
int port = 8080;
char* path;
if (argc ==1){
path = "/flask/videos/test.flv";
} else if (argc ==2){
path = argv[1];
} else if (argc ==3){
port = atoi(argv[1]);
path = argv[2];
} else {
printf(" usage: httpFlv_server port /your/video.flv ");
return 1;
}
if (port <5000 || port >65500){
printf(" 5000 <= port <= 65500 ");
return 2;
}
printf("%s\n", path);
int n = strlen(path);
if (n >80){
printf(" file path is too long.");
return 3;
}
if (n < 8){
printf(" file path is too short.");
return 3;
}
char* ext = &path[n-4];
if (strcmp(ext, ".flv") !=0){
printf(" file ext is not .flv ");
return 3;
}
printf("httpFlv_server http://127.0.0.1:%d/%s\n", port, get_filename(path));
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
perror("WSAStartup error");
return -1;
}
SOCKET serverFd;
SOCKADDR_IN server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//server_addr.sin_addr.s_addr = inet_addr("192.168.2.61");
server_addr.sin_port = htons(port);
serverFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (bind(serverFd, (SOCKADDR*)&server_addr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
perror("socket bind error");
return -1;
}
if (listen(serverFd, SOMAXCONN) < 0) {
perror("socket listen error");
return -1;
}
constexpr char http_headers[] = \
"HTTP/1.1 200 OK\r\n" \
"Access-Control-Allow-Origin: * \r\n" \
"Content-Type: video/x-flv\r\n" \
"Content-Length: -1\r\n" \
"Connection: Keep-Alive\r\n" \
"Expires: -1\r\n" \
"Pragma: no-cache\r\n" \
"\r\n"
;
int http_headers_len = strlen(http_headers);
/*
constexpr char http_headers[] = \
"HTTP/1.1 200 OK\r\n" \
"Access-Control-Allow-Origin: * \r\n" \
"Cache-Control: no-cache\r\n" \
"Content-Type: video/x-flv\r\n" \
"Connection: close\r\n" \
"Expires: -1\r\n" \ //设置资源的有效期来控制http的缓存
"Pragma: no-cache\r\n" \ //用于客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源
"\r\n"
;
*/
while (true)
{
printf(" waiting ...");
int len = sizeof(SOCKADDR);
SOCKADDR_IN accept_addr;
int clientFd = accept(serverFd, (SOCKADDR*)&accept_addr, &len);
//const char* clientIp = inet_ntoa(accept_addr.sin_addr);
if (clientFd == SOCKET_ERROR) {
perror("accept connection error");
break;
}
printf(" connect ... clientFd=%d\n", clientFd);
// VC++ P182页 int nBufSize=4096
unsigned char buf[4096];
char bufRecv[2001] = { 0 };
FILE* fp;
fp = fopen(path, "rb");
if (!fp) {
printf("Error: fopen %s failed!", path);
break;
}
else {
int times = 0;
while (true) {
times++;
if (times == 1) {
int bufRecvSize = recv(clientFd, bufRecv, 2000, 0);
printf("bufRecvSize=%d, bufRecv=%s\n", bufRecvSize, bufRecv);
send(clientFd, http_headers, http_headers_len, 0);
}
else {
//usleep(1000 * 100);
Sleep(5); // 5ms
int bufLen = fread(buf, 1, sizeof(buf), fp);
// fseek(srcFile, 0, SEEK_CUR);
int ret = send(clientFd, (char*)buf, bufLen, 0);
if (ret <= 0) {
break;
}
else {
//printf("send bufLen=%d,ret=%d \n", bufLen, ret);
}
}
}
}
if (fp) {
fclose(fp);
}
closesocket(clientFd);
printf("close clientFd=%d\n", clientFd);
}
closesocket(serverFd);
return 0;
}
编译 cl httpFlv_server.cpp /EHsc /utf-8
运行 httpFlv_server /flask/videos/test.flv
或者 编写 win_gcc.bat 如下
SET INCLUDE=D:\Strawberry\c\include
SET LIB=D:\Strawberry\c\x86_64-w64-mingw32\lib
g++ %1.cpp -o %1.exe -lws2_32
编译执行 win_gcc.bat httpFlv_server
npm install flv.js -save ;
cd D:\nodejs\node_modules\flv.js\dist ;
copy flv.min.js flv.min.js.map to /flask/static/
编写 flvPlayer.html 如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title> flv.js 播放器</title>
<script src="/static/flv.min.js"></script>
</head>
<body>
<video id="video1" width="800" height="576" controls ></video>
<script>
if (flvjs.isSupported()) {
var video1 = document.getElementById('video1');
var flvplayer = flvjs.createPlayer({
type: 'flv', // 媒体类型: auto, flv, mp4
isLive: false, // 是否是直播流,默认 true
url: 'http://127.0.0.1:8080/test.flv'
});
flvplayer.attachMediaElement(video1);
flvplayer.load(); // 加载流
flvplayer.play(); // 播放流
}
</script>
</body>
</html>
-
用 Chrome 浏览器访问 http://localhost:5555/flv/ 可以播放,测试 Edge 不支持。
-
也可以用 ffplay 测试是否能播放
ffplay -i http://127.0.0.1:8080/test.flv