#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; }