C语言:创建简单的流媒体服务器来播放.flv文件

请先看: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>
  1. 用 Chrome 浏览器访问 http://localhost:5555/flv/  可以播放,测试 Edge 不支持。

  2. 也可以用 ffplay 测试是否能播放
    ffplay -i http://127.0.0.1:8080/test.flv

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值