#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "xop/RtmpServer.h"
#include "xop/HttpFlvServer.h"
#include "xop/RtmpPublisher.h"
#include "xop/RtmpClient.h"
#include "xop/HttpFlvServer.h"
#include "xop/H264Parser.h"
#include "net/EventLoop.h"
#include "CGBlockRingBuffer.h"
#define TEST_RTMP_PUSHER 1
#define TEST_RTMP_CLIENT 0
#define TEST_MULTI_THREAD 0
#define RTMP_URL "rtmp://127.0.0.1:1935/live/01"
#define PUSH_FILE "mcodec1214.h264"
#define HTTP_URL "http://127.0.0.1:8080/live/01.flv"
#define GBUFF_MAX_SIZE 10*1024 * 1024
#define ONE_READ_SIZE 1024*1024
char gbuf[GBUFF_MAX_SIZE] = { 0 };
int gbufDatasize = 0;
int gBytesRead = 0;
int TestRtmpPublisher(xop::EventLoop* event_loop);
//char* sdPath = "data/data/com.example.testrtsp/1218.h264";
char* sdPath = ( char*)PUSH_FILE;
void WriteGbufToFile() {
FILE* m_file = NULL;
m_file = fopen(sdPath, "wb");
if (m_file == NULL)
{
printf("Open %s error %d!", sdPath, errno);
return;
}
int ret = fwrite(gbuf, gbufDatasize, 1, m_file);
printf("ret %d --->!", ret);
fclose(m_file);
return;
}
CGBlockRingBuffer* pRingBuffer;
#define INIT_BUFFER_SIZE 1*1024*1024
int main()
//int rtmpMain()
{
printf("rtmpMain---->");
pRingBuffer = new CGBlockRingBuffer();
pRingBuffer->Init(INIT_BUFFER_SIZE);
//WriteGbufToFile();
//return 0;
int count = 1;
#if TEST_MULTI_THREAD
count = std::thread::hardware_concurrency();
#endif
xop::EventLoop event_loop(count);
/* rtmp server example */
auto rtmp_server = xop::RtmpServer::Create(&event_loop);
rtmp_server->SetChunkSize(60000);
//rtmp_server->SetGopCache(); /* enable gop cache */
rtmp_server->SetEventCallback([](std::string type, std::string stream_path) {
printf("[Event] %s, stream path: %s\n\n", type.c_str(), stream_path.c_str());
});
if (!rtmp_server->Start("0.0.0.0", 1935)) {
printf("RTMP Server listen on 1935 failed.\n");
}
/* http-flv server example */
/*
xop::HttpFlvServer http_flv_server;
http_flv_server.Attach(rtmp_server);
if (!http_flv_server.Start("0.0.0.0", 8080)) {
printf("HTTP FLV Server listen on 8080 failed.\n");
}*/
#if TEST_RTMP_PUSHER
/* rtmp pusher example */
std::thread t([&event_loop]() {
TestRtmpPublisher(&event_loop);
});
t.detach();
#endif
/*
#if TEST_RTMP_CLIENT
auto rtmp_client = xop::RtmpClient::Create(&event_loop);
rtmp_client->SetFrameCB([](uint8_t* payload, uint32_t length, uint8_t codecId, uint32_t timestamp) {
printf("recv frame, type:%u, size:%u,\n", codecId, length);
});
std::string status;
if (rtmp_client->OpenUrl(RTMP_URL, 3000, status) != 0) {
printf("Open url %s failed, status: %s\n", RTMP_URL, status.c_str());
}
#endif
*/
while (1) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
rtmp_server->Stop();
//http_flv_server.Stop();
return 0;
}
class H264File
{
public:
H264File(int bufSize = 5000000);
~H264File();
bool open(const char* path);
void Close();
bool isOpened() const
{
return (m_file != NULL);
}
int readFrame(char* inBuf, int inBufSize, bool* bEndOfFrame);
int readFrameFromGbuf(char* inBuf, int inBufSize, bool* bEndOfFrame);
int readfileToGBbuf();
private:
FILE* m_file = NULL;
char* m_buf = NULL;
int m_bufSize = 0;
int m_bytesUsed = 0;
int m_count = 0;
};
H264File::H264File(int bufSize)
: m_bufSize(bufSize)
{
m_buf = new char[m_bufSize];
}
H264File::~H264File()
{
delete m_buf;
}
bool H264File::open(const char* path)
{
m_file = fopen(path, "rb");
if (m_file == NULL)
{
return false;
}
return true;
}
void H264File::Close()
{
if (m_file)
{
fclose(m_file);
m_file = NULL;
m_count = 0;
m_bytesUsed = 0;
}
}
int H264File::readfileToGBbuf() {
FILE* file = NULL;
file = fopen(sdPath, "rb");
if (file == NULL)
{
printf("Open %s error %d!", sdPath, errno);
return -1;
}
fseek(file, 0, SEEK_SET);
int bytesRead = (int)fread(gbuf, 1, GBUFF_MAX_SIZE, file);
gbufDatasize = bytesRead;
fclose(file);
pRingBuffer->Write((unsigned char*)(gbuf), bytesRead);
printf("readfileToGBbuf ----->\n");
return 0;
}
int pushOneFrame(char* inBuf, int inBufSize) {
if (gbufDatasize + inBufSize > 5 * 1024 * 1024) {
printf("pushOneFrame out---- %d--->\n", gbufDatasize);
return -1;
}
memcpy(gbuf + gbufDatasize, inBuf, inBufSize);
gbufDatasize += inBufSize;
return 1;
}
int H264File::readFrameFromGbuf(char* inBuf, int inBufSize, bool* bEndOfFrame) {
/*
int tmpOneStepRead = ONE_READ_SIZE;
if (gBytesRead >= gbufDatasize) gBytesRead = 0;
if (gbufDatasize - gBytesRead < ONE_READ_SIZE)
tmpOneStepRead = gbufDatasize - gBytesRead;
memcpy(m_buf, gbuf + gBytesRead, tmpOneStepRead);
*/
int tmpOneStepRead = pRingBuffer->getNotRead((UINT8*)m_buf, inBufSize);
if (0 == tmpOneStepRead) {
pRingBuffer->Write((unsigned char*)(gbuf), gbufDatasize);
printf(" pRingBuffer->Write---- %d--->\n", gbufDatasize);
}
//
int bytesRead = tmpOneStepRead;
bool bFindStart = false, bFindEnd = false;
int i = 0, startCode = 3;
*bEndOfFrame = false;
for (i = 0; i < bytesRead - 5; i++)
{
if (m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1)
{
startCode = 3;
}
else if (m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1)
{
startCode = 4;
}
else
{
continue;
}
if (((m_buf[i + startCode] & 0x1F) == 0x5 || (m_buf[i + startCode] & 0x1F) == 0x1) &&
((m_buf[i + startCode + 1] & 0x80) == 0x80))
{
bFindStart = true;
i += 4;
break;
}
}
for (; i < bytesRead - 5; i++)
{
if (m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 1)
{
startCode = 3;
}
else if (m_buf[i] == 0 && m_buf[i + 1] == 0 && m_buf[i + 2] == 0 && m_buf[i + 3] == 1)
{
startCode = 4;
}
else
{
continue;
}
if (((m_buf[i + startCode] & 0x1F) == 0x7) || ((m_buf[i + startCode] & 0x1F) == 0x8)
|| ((m_buf[i + startCode] & 0x1F) == 0x6) || (((m_buf[i + startCode] & 0x1F) == 0x5
|| (m_buf[i + startCode] & 0x1F) == 0x1) && ((m_buf[i + startCode + 1] & 0x80) == 0x80)))
{
bFindEnd = true;
break;
}
}
bool flag = false;
if (bFindStart && !bFindEnd && m_count > 0)
{
flag = bFindEnd = true;
i = bytesRead;
*bEndOfFrame = true;
}
if (!bFindStart || !bFindEnd)
{
this->Close();
return -1;
}
int size = (i <= inBufSize ? i : inBufSize);
// memcpy(inBuf, m_buf, size);
int ret = pRingBuffer->Read((unsigned char*)inBuf, size);
if (ret != size) {
printf("ret %d != size %d\n", ret, size);
}
if (!flag)
{
m_count += 1;
m_bytesUsed += i;
}
else
{
m_count = 0;
m_bytesUsed = 0;
}
gBytesRead = m_bytesUsed;
return size;
}
int TestRtmpPublisher(xop::EventLoop* event_loop)
{
H264File h264_file;
/*
if (!h264_file.open(PUSH_FILE)) {
LOGE("Open %s failed.\n", PUSH_FILE);
return -1;
}
*/
/* push stream to local rtmp server */
xop::MediaInfo media_info;
auto publisher = xop::RtmpPublisher::Create(event_loop);
publisher->SetChunkSize(60000);
std::string status;
if (publisher->OpenUrl(RTMP_URL, 3000, status) < 0) {
printf("Open url %s failed, status: %s\n", RTMP_URL, status.c_str());
return -1;
}
// int buf_size = 500000;
int buf_size = 30000;
bool end_of_frame = false;
bool has_sps_pps = false;
uint8_t* frame_buf = new uint8_t[buf_size];
h264_file.readfileToGBbuf();
while (publisher->IsConnected())
{
//int frameSize = h264_file.readFrame((char*)frame_buf, buf_size, &end_of_frame);
int frameSize = h264_file.readFrameFromGbuf((char*)frame_buf, buf_size, &end_of_frame);
if (frameSize > 0) {
if (!has_sps_pps) {
if (frame_buf[3] == 0x67 || frame_buf[4] == 0x67) {
xop::Nal sps = xop::H264Parser::findNal(frame_buf, frameSize);
if (sps.first != nullptr && sps.second != nullptr && *sps.first == 0x67) {
media_info.sps_size = (uint32_t)(sps.second - sps.first + 1);
media_info.sps.reset(new uint8_t[media_info.sps_size], std::default_delete<uint8_t[]>());
memcpy(media_info.sps.get(), sps.first, media_info.sps_size);
xop::Nal pps = xop::H264Parser::findNal(sps.second, frameSize - (int)(sps.second - frame_buf));
if (pps.first != nullptr && pps.second != nullptr && *pps.first == 0x68) {
media_info.pps_size = (uint32_t)(pps.second - pps.first + 1);
media_info.pps.reset(new uint8_t[media_info.pps_size], std::default_delete<uint8_t[]>());
memcpy(media_info.pps.get(), pps.first, media_info.pps_size);
has_sps_pps = true;
publisher->SetMediaInfo(media_info); /* set sps pps */
printf("Start rtmp pusher, rtmp url: %s , http-flv url: %s \n\n", RTMP_URL, HTTP_URL);
}
}
}
}
if (has_sps_pps) {
publisher->PushVideoFrame(frame_buf, frameSize); /* send h.264 frame */
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
delete frame_buf;
return 0;
}