基于media-server简单的rtmp服务端实现

前言:和另一篇基于media-server简单的rtsp服务端实现一样,同样是是基于media-server简单的实现rtmp服务端,使用vs2015编译过后,运行程序,使用vlc播放rtmp://127.0.0.1:1935/live/1即可。

 

源码下载: CSDN:简单的rtmp服务端实现, 百度云盘:链接: https://pan.baidu.com/s/1Vn59SDSiwcL6vhWcInBmew 提取码: 62ju 。工程包中有media-server编译好的库,有视频源,设置vs编译通过即可运行。

 

源码:主函数文件 rtmpserver.cpp

#include <iostream>
#include "rtmpsession.h"

#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "librtmp.lib")
#pragma comment(lib, "libflv.lib")

SOCKET Listener = 0;
std::vector<RtmpSessionPtr> AllRtspSession;

int ListenLocalSvc(int port);

int main()
{
	std::cout << "hello rtmp server!" << std::endl;

	if (0 > ListenLocalSvc(1935) ||
		0 > RtmpSession::ReadSourceStream("miniH264.h264"))
	{
		return -1;
	}

	struct rtmp_server_handler_t handler;
	handler.send = rtmp_handler_send;
	handler.onplay = rtmp_handler_onplay;
	handler.onseek = rtmp_handler_onseek;
	handler.onpause = rtmp_handler_onpause;
	handler.onaudio = rtmp_handler_onaudio;
	handler.onvideo = rtmp_handler_onvideo;
	handler.onscript = rtmp_handler_onscript;
	handler.onpublish = rtmp_handler_onpublish;
	handler.ongetduration = rtmp_handler_ongetduration;

	unsigned int startTime, usedTime;
	while (true)
	{
		startTime = GetTickCount();

		struct sockaddr_in clent;
		int len = sizeof(clent);

		int clientSocket = accept(Listener, (sockaddr*)&clent, &len);
		if (clientSocket > 0) 
		{
			printf("accept a client %d\n", clientSocket);
			int value = 10 * 1024 * 1024;
			setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, (char*)&value, sizeof(value));

			RtmpSession *client = new RtmpSession(clientSocket);
			rtmp_server_t* handle = rtmp_server_create(client, &handler);
			client->SetRtmpHandle(handle);
			AllRtspSession.push_back(RtmpSessionPtr(client));
		}

		for (auto it = AllRtspSession.begin(); it != AllRtspSession.end(); )
		{
			it = (0 > (*it)->Run()) ? AllRtspSession.erase(it) : ++it;
		}

		usedTime = GetTickCount() - startTime;
		if (usedTime < 5)
			Sleep(5 - usedTime);
	}
	return 0;
}

int ListenLocalSvc(int port)
{
	WSADATA WSAData;
	WSAStartup(MAKEWORD(2, 0), &WSAData);

	Listener = socket(AF_INET, SOCK_STREAM, 0);
	unsigned long ul = 1;
	int ret = ioctlsocket(Listener, FIONBIO, (unsigned long *)&ul);//设置成非阻塞模式。 

	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = 0;
	sin.sin_port = htons(port);

	if (bind(Listener, (struct sockaddr*) &sin, sizeof(sin)) < 0) 
	{
		printf("bind port %d failed", port);
		closesocket(Listener);
		return -1;
	}

	if (listen(Listener, 20) < 0) 
	{
		printf("listen port %d failed", port);
		closesocket(Listener);
		return -1;
	}
	return 0;
}

每个客户端连上创建一个session类:rtmpsession.h

#pragma once
#include <memory>
#include <vector>
#include <WinSock2.h>
#include "rtmp-server.h"
#include "flv-muxer.h"
#include "flv-proto.h"

enum RS_Status
{
	RS_INIT,
	RS_SIGNALLING,
	RS_PAUSE,
	RS_SENDSTREAM,

	RS_ERROR
};

class RtmpSession
{
	unsigned int mFrameSeq;
	unsigned long mLastFrameTS;
	flv_muxer_t *mPacker;

	int SendStream();
	int RecvSignaling();
public:
	int mSocket;
	RS_Status mStatus;
	rtmp_server_t *mRtmpHandle;

	RtmpSession(int sock);
	~RtmpSession();

	void SetRtmpHandle(rtmp_server_t* handle) { mRtmpHandle = handle; }
	static int ReadSourceStream(char *fileName);
	int Run();
};

using RtmpSessionPtr = std::shared_ptr<RtmpSession>;

int handler(void* param, int type, const void* data, size_t bytes, u_int ts);
int rtmp_handler_send(void* param, const void* header, size_t len, const void* payload, size_t bytes);
int rtmp_handler_onpublish(void* param, const char* app, const char* stream, const char* type);
int rtmp_handler_onscript(void* param, const void* data, size_t bytes, uint32_t timestamp);
int rtmp_handler_onaudio(void* param, const void* data, size_t bytes, uint32_t timestamp);
int rtmp_handler_onvideo(void* param, const void* data, size_t bytes, uint32_t timestamp);
int rtmp_handler_onplay(void* param, const char* app, const char* stream, double start, double duration, uint8_t reset);
int rtmp_handler_onpause(void* param, int pause, uint32_t ms);
int rtmp_handler_onseek(void* param, uint32_t ms);
int rtmp_handler_ongetduration(void* param, const char* app, const char* stream, double* duration);

源文件:rtmpsession.cpp

#include "rtmpsession.h"
#include <WinSock2.h>
#include <string>

char buffer[5 * 1024];
char rtpPkg[1600];
std::vector<char*> StreamFrame;


RtmpSession::RtmpSession(int sock):
	mRtmpHandle(NULL),
	mSocket(sock),
	mFrameSeq(0),
	mPacker(NULL),
	mLastFrameTS(0),
	mStatus(RS_INIT)
{
}

RtmpSession::~RtmpSession()
{
	if (mPacker)
		flv_muxer_destroy(mPacker);

	if(mRtmpHandle)
		rtmp_server_destroy(mRtmpHandle);

	closesocket(mSocket);
	printf("close socket %d\n", mSocket);
}

int RtmpSession::ReadSourceStream(char *fileName)
{
	FILE *fp = fopen(fileName, "rb");
	if (fp == NULL)
	{
		printf("open file:%s error\n", fileName);
		return -1;
	}
	unsigned int size;
	while (true)
	{
		if (4 != fread(&size, 1, 4, fp))
			break;
		char *frame = (char*)malloc(size + 5);
		memcpy(frame, &size, 4);
		if (size != fread(frame + 4, 1, size, fp))
			break;

		StreamFrame.push_back(frame);
	}
	fclose(fp);
	return 0;
}

int RtmpSession::Run()
{
	if (mStatus == RS_ERROR)
	{
		return -1;
	}
	else if (mStatus == RS_SENDSTREAM)
	{
		SendStream();
	}

	return RecvSignaling();
}

int RtmpSession::RecvSignaling()
{
	int len = recv(mSocket, buffer, 5 * 1024, 0);
	if (len <= 0)
		return 0;

	printf("recv data size:%d\n", len);
	rtmp_server_input(mRtmpHandle, (uint8_t*)buffer, len);
	return 0;
}

int RtmpSession::SendStream()
{
	if(mPacker == NULL)
		mPacker = flv_muxer_create(handler, this);

	if (GetTickCount() - mLastFrameTS > 40)
	{
		mLastFrameTS = GetTickCount();
		char *frame = StreamFrame[mFrameSeq%StreamFrame.size()];
		flv_muxer_avc(mPacker, frame + 4, *(int*)frame, mFrameSeq * 40, mFrameSeq * 40);
		mFrameSeq++;
	}
	return 0;
}

int handler(void* param, int type, const void* data, size_t bytes, u_int ts)
{
	RtmpSession *session = (RtmpSession*)param;
	if(type == FLV_TYPE_VIDEO)
		return rtmp_server_send_video(session->mRtmpHandle, data, bytes, ts);
	else if (type == FLV_TYPE_AUDIO)
		return rtmp_server_send_audio(session->mRtmpHandle, data, bytes, ts);
	else if (type == FLV_TYPE_SCRIPT)
		return rtmp_server_send_script(session->mRtmpHandle, data, bytes, ts);
	return 0;
}

int rtmp_handler_send(void* param, const void* header, size_t len, const void* payload, size_t bytes)
{
	RtmpSession *session = (RtmpSession*)param;
	int ret = send(session->mSocket, (char*)header, len, 0);
	ret += send(session->mSocket, (char*)payload, bytes, 0);
	if (ret != len + bytes)
		session->mStatus = RS_ERROR;
	return ret;
}

int rtmp_handler_onplay(void* param, const char* app, const char* stream, double start, double duration, uint8_t reset)
{
	RtmpSession *session = (RtmpSession*)param;
	session->mStatus = RS_SENDSTREAM;
	return 0;
}

int rtmp_handler_onpause(void* param, int pause, uint32_t ms)
{
	return 0;
}

int rtmp_handler_onseek(void* param, uint32_t ms)
{
	return 0;
}

int rtmp_handler_onpublish(void* param, const char* app, const char* stream, const char* type)
{
	
	return 0;
}

int rtmp_handler_onscript(void* param, const void* data, size_t bytes, uint32_t timestamp)
{
	return 0;
}

int rtmp_handler_onvideo(void* param, const void* data, size_t bytes, uint32_t timestamp)
{
	return 0;
}

int rtmp_handler_onaudio(void* param, const void* data, size_t bytes, uint32_t timestamp)
{
	return 0;
}

int rtmp_handler_ongetduration(void* param, const char* app, const char* stream, double* duration)
{
	return 0;
}

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Node-Media-Server 是一个基于 Node.js 开发的高效流媒体服务器,它支持 RTMP、HLS、HTTP-FLV 等多种协议,可以实现流媒体的推流、转码、分发等功能。以下是使用 Node-Media-Server 实现高效推流的步骤: 1. 安装 Node-Media-Server 可以使用 npm 或 yarn 安装 Node-Media-Server,具体命令如下: ``` npm install node-media-server ``` 或 ``` yarn add node-media-server ``` 2. 创建 Node-Media-Server 实例 在 Node.js 文件中引入 Node-Media-Server 模块,并创建一个 Node-Media-Server 实例,示例如下: ```javascript const NodeMediaServer = require('node-media-server'); const config = { rtmp: { port: 1935, chunk_size: 60000, gop_cache: true, ping: 60, ping_timeout: 30 }, http: { port: 8000, allow_origin: '*' }, trans: { ffmpeg: '/usr/local/bin/ffmpeg', tasks: [ { app: 'live', hls: true, hlsFlags: '[hls_time=2:hls_list_size=3:hls_flags=delete_segments]', dash: true, dashFlags: '[f=dash:window_size=3:extra_window_size=5]' } ] } }; const nms = new NodeMediaServer(config); ``` 3. 监听推流事件 在创建 Node-Media-Server 实例后,可以监听推流事件,例如 `prePublish` 事件,该事件在客户端开始推流之前触发,可以在该事件中进行推流鉴权等操作。示例如下: ```javascript nms.on('prePublish', (id, StreamPath, args) => { const session = nms.getSession(id); // 进行推流鉴权等操作 }); ``` 4. 启动 Node-Media-Server 在配置好 Node-Media-Server 实例并监听推流事件后,可以调用 `nms.run()` 方法启动 Node-Media-Server,示例如下: ```javascript nms.run(); ``` 以上是使用 Node-Media-Server 实现高效推流的基本步骤,可以根据实际需求进行相应的配置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值