前言:和另一篇基于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;
}