int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, int32_t *pstarttime, u_int32_t *ptimestamp) { int ret = 0; // packet data char type; int size; char *data = NULL; srs_human_trace("start ingest flv to RTMP stream"); for (; ;) { // tag header if ((ret = srs_flv_read_tag_header(flv, &type, &size, ptimestamp)) != 0) { if (srs_flv_is_eof(ret)) { srs_human_trace("parse completed."); return 0; } srs_human_trace("flv get packet failed. ret=%d", ret); return ret; } if (size <= 0) { srs_human_trace("invalid size=%d", size); break; } // TODO: FIXME: mem leak when error. data = (char *) malloc(size); if ((ret = srs_flv_read_tag_data(flv, data, size)) != 0) { return ret; } u_int32_t timestamp = *ptimestamp; if ((ret = srs_human_print_rtmp_packet(type, timestamp, data, size)) != 0) { srs_human_trace("print packet failed. ret=%d", ret); return ret; } if ((ret = srs_rtmp_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { srs_human_trace("irtmp get packet failed. ret=%d", ret); return ret; } if (*pstarttime < 0) { *pstarttime = *ptimestamp; } re_update(re, *pstarttime, *ptimestamp); } return ret; }
void PushEngine::run(){ while(1){ int64_t currentTime = srs_utils_time_ms(); if(currentTime - m_timeTick > 1000){ m_timeTick = currentTime; #if 0 for(std::list<OneStream*>::iterator it = m_streamList.begin(); it != m_streamList.end(); it++){ m_logger.information("==> current publish [rtmp://%s/live/%s%d] size[%d]", (*it)->ipPort, \ (*it)->prefixName, (*it)->randNum, (*it)->receiveSize/1000); (*it)->receiveSize = 0; } #endif } if(m_jobQueue.size() > 0){ OneStreamSharePtr node = m_jobQueue.get(); if(node.get() != NULL){ node->setExpiredTime(currentTime); node->m_sendIndex = 0; m_streamList.push_back(node); } std::string url = node->getURL(); node->rtmp = srs_rtmp_create(url.c_str()); m_logger.information("begin publish to [%s].", url); if (srs_rtmp_handshake(node->rtmp) != 0) { srs_rtmp_destroy(node->rtmp); // 析构rtmp m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent(node, currentTime, HANDSHAKE_FAIL))); // 发送握手失败事件 m_logger.error("simple handshake to [%s] failed.", url); } if (srs_rtmp_connect_app(node->rtmp) != 0) { srs_rtmp_destroy(node->rtmp); // 析构rtmp m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent(node, currentTime, CONNECT_FAIL))); // 发送连接失败事件 m_logger.error("connect [%s] vhost/app failed.", url); continue; } if (srs_rtmp_publish_stream(node->rtmp) != 0) { srs_rtmp_destroy(node->rtmp); // 析构rtmp m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent(node, currentTime, PUBLIC_FAIL))); // 发送public失败事件 m_logger.error("publish stream [%s] failed.", url); continue; } m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent(node, currentTime, START_STREAM))); // 发送开始推流事件 } // 发送当前时间片的帧到所有链接 for(std::list<OneStreamSharePtr>::iterator it = m_streamList.begin(); it != m_streamList.end(); ){ bool endThisStream = false; if((*it)->m_sendIndex == 0 || (*it)->m_sendIndex + 1 > m_flvFrame.size()){ (*it)->m_baseTimestamp = currentTime; (*it)->m_sendIndex = 0; } if(((*it)->m_baseTimestamp + m_flvFrame[(*it)->m_sendIndex].timestamp) <= currentTime){ Frame f = m_flvFrame[((*it)->m_sendIndex)++]; char* data = (char*)malloc(f.size); memcpy(data, f.data, f.size); if (srs_rtmp_write_packet((*it)->rtmp, f.type, ((*it)->m_baseTimestamp + f.timestamp) % 10000000, data, f.size) != 0) { endThisStream = true; m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent((*it), currentTime, PUSH_STREAM_FAIL))); // 发送推流失败事件 m_logger.error("error to publish [%s].", (*it)->getURL()); } (*it)->addReceiveSize(f.size); } // 推流时间到 if(currentTime > (*it)->getExpiredTime()){ endThisStream = true; m_streamEventQueue.put(StreamEventSharePtr(new StreamEvent((*it), currentTime, END_STREAM))); // 发送推流结束事件 m_logger.information("stop to publish [%s].", (*it)->getURL()); } if(endThisStream){ srs_rtmp_destroy((*it)->rtmp); // 析构rtmp it = m_streamList.erase(it); // 从链表中删除 continue; } else{ it++; } } usleep(10 * 1000); } }
int main(int argc, char **argv) { printf("publish rtmp stream to server like FMLE/FFMPEG/Encoder\n"); printf("srs(simple-rtmp-server) client librtmp library.\n"); printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); if (argc <= 1) { printf("Usage: %s <rtmp_url>\n" " rtmp_url RTMP stream url to publish\n" "For example:\n" " %s rtmp://127.0.0.1:1935/live/livestream\n", argv[0], argv[0]); exit(-1); } // warn it . // @see: https://github.com/winlinvip/simple-rtmp-server/issues/126 srs_human_trace("\033[33m%s\033[0m", "[warning] it's only a sample to use librtmp. " "please never use it to publish and test forward/transcode/edge/HLS whatever. " "you should refer to this tool to use the srs-librtmp to publish the real media stream." "read about: https://github.com/winlinvip/simple-rtmp-server/issues/126"); srs_human_trace("rtmp url: %s", argv[1]); srs_rtmp_t rtmp = srs_rtmp_create(argv[1]); if (srs_rtmp_handshake(rtmp) != 0) { srs_human_trace("simple handshake failed."); goto rtmp_destroy; } srs_human_trace("simple handshake success"); if (srs_rtmp_connect_app(rtmp) != 0) { srs_human_trace("connect vhost/app failed."); goto rtmp_destroy; } srs_human_trace("connect vhost/app success"); if (srs_rtmp_publish_stream(rtmp) != 0) { srs_human_trace("publish stream failed."); goto rtmp_destroy; } srs_human_trace("publish stream success"); u_int32_t timestamp = 0; for (; ;) { char type = SRS_RTMP_TYPE_VIDEO; int size = 4096; char *data = (char *) malloc(4096); timestamp += 40; if (srs_rtmp_write_packet(rtmp, type, timestamp, data, size) != 0) { goto rtmp_destroy; } srs_human_trace("sent packet: type=%s, time=%d, size=%d", srs_human_flv_tag_type2string(type), timestamp, size); usleep(40 * 1000); } rtmp_destroy: srs_rtmp_destroy(rtmp); return 0; }