void Rtmp::sendTag(FlvTag &tag) { if( ! RTMP_IsConnected(m_rtmp) || RTMP_IsTimedout(m_rtmp) ) { qDebug() << "RTMP error"; exit(0); } RTMP_Write(m_rtmp,tag.constData(),tag.size()); // Handle RTMP ping and such fd_set sockset; struct timeval timeout = {0,0}; FD_ZERO(&sockset); FD_SET(RTMP_Socket(m_rtmp), &sockset); register int result = select(RTMP_Socket(m_rtmp) + 1, &sockset, NULL, NULL, &timeout); if (result == 1 && FD_ISSET(RTMP_Socket(m_rtmp), &sockset) ) { // qDebug() << "RTMP_ReadPacket"; RTMP_ReadPacket(m_rtmp, &m_rtmpPacket); if( ! RTMPPacket_IsReady(&m_rtmpPacket) ) { qDebug() << "Received RTMP packet"; RTMP_ClientPacket(m_rtmp,&m_rtmpPacket); RTMPPacket_Free(&m_rtmpPacket); } } }
static int send_packet(struct rtmp_stream *stream, struct encoder_packet *packet, bool is_header, size_t idx) { uint8_t *data; size_t size; int recv_size = 0; int ret = 0; #ifdef _WIN32 ret = ioctlsocket(stream->rtmp.m_sb.sb_socket, FIONREAD, (u_long*)&recv_size); #else ret = ioctl(stream->rtmp.m_sb.sb_socket, FIONREAD, &recv_size); #endif if (ret >= 0 && recv_size > 0) { if (!discard_recv_data(stream, (size_t)recv_size)) return -1; } flv_packet_mux(packet, &data, &size, is_header); #ifdef TEST_FRAMEDROPS os_sleep_ms(rand() % 40); #endif ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx); bfree(data); obs_free_encoder_packet(packet); stream->total_bytes_sent += size; return ret; }
static int rtmp_write(URLContext *s, const uint8_t *buf, int size) { LibRTMPContext *ctx = s->priv_data; RTMP *r = &ctx->rtmp; return RTMP_Write(r, buf, size); }
static GstFlowReturn gst_rtmp_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstRTMPSink *sink = GST_RTMP_SINK (bsink); GstBuffer *reffed_buf = NULL; if (sink->first) { /* open the connection */ if (!RTMP_IsConnected (sink->rtmp)) { if (!RTMP_Connect (sink->rtmp, NULL) || !RTMP_ConnectStream (sink->rtmp, 0)) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), ("Could not connect to RTMP stream \"%s\" for writing", sink->uri)); RTMP_Free (sink->rtmp); sink->rtmp = NULL; g_free (sink->rtmp_uri); sink->rtmp_uri = NULL; return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (sink, "Opened connection to %s", sink->rtmp_uri); } /* FIXME: Parse the first buffer and see if it contains a header plus a packet instead * of just assuming it's only the header */ GST_LOG_OBJECT (sink, "Caching first buffer of size %d for concatenation", GST_BUFFER_SIZE (buf)); gst_buffer_replace (&sink->cache, buf); sink->first = FALSE; return GST_FLOW_OK; } if (sink->cache) { GST_LOG_OBJECT (sink, "Joining 2nd buffer of size %d to cached buf", GST_BUFFER_SIZE (buf)); gst_buffer_ref (buf); reffed_buf = buf = gst_buffer_join (sink->cache, buf); sink->cache = NULL; } GST_LOG_OBJECT (sink, "Sending %d bytes to RTMP server", GST_BUFFER_SIZE (buf)); if (!RTMP_Write (sink->rtmp, (char *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf))) { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Failed to write data")); if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_ERROR; } if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_OK; }
static void send_meta_data(struct rtmp_stream *stream) { uint8_t *meta_data; size_t meta_data_size; flv_meta_data(stream->output, &meta_data, &meta_data_size); #ifdef FILE_TEST fwrite(meta_data, 1, meta_data_size, stream->test); #else RTMP_Write(&stream->rtmp, (char*)meta_data, (int)meta_data_size); #endif bfree(meta_data); }
static ssize_t rtmp_send(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err) { RTMP *r = conn->proto.generic; ssize_t num; (void)sockindex; /* unused */ num = RTMP_Write(r, (char *)buf, curlx_uztosi(len)); if(num < 0) *err = CURLE_SEND_ERROR; return num; }
static bool send_meta_data(struct rtmp_stream *stream, size_t idx) { uint8_t *meta_data; size_t meta_data_size; bool success = flv_meta_data(stream->output, &meta_data, &meta_data_size, false, idx); if (success) { RTMP_Write(&stream->rtmp, (char*)meta_data, (int)meta_data_size, (int)idx); bfree(meta_data); } return success; }
static int send_packet(struct rtmp_stream *stream, struct encoder_packet *packet, bool is_header) { uint8_t *data; size_t size; int ret = 0; flv_packet_mux(packet, &data, &size, is_header); #ifdef FILE_TEST fwrite(data, 1, size, stream->test); #else ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size); #endif bfree(data); obs_free_encoder_packet(packet); return ret; }
static int send_packet(struct rtmp_stream *stream, struct encoder_packet *packet, bool is_header, size_t idx) { uint8_t *data; size_t size; int ret = 0; flv_packet_mux(packet, &data, &size, is_header); #ifdef TEST_FRAMEDROPS os_sleep_ms(rand() % 40); #endif ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx); bfree(data); obs_free_encoder_packet(packet); stream->total_bytes_sent += size; return ret; }
static GstFlowReturn gst_rtmp_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstRTMPSink *sink = GST_RTMP_SINK (bsink); GstBuffer *reffed_buf = NULL; if (sink->first) { /* FIXME: Parse the first buffer and see if it contains a header plus a packet instead * of just assuming it's only the header */ GST_LOG_OBJECT (sink, "Caching first buffer of size %d for concatenation", GST_BUFFER_SIZE (buf)); gst_buffer_replace (&sink->cache, buf); sink->first = FALSE; return GST_FLOW_OK; } if (sink->cache) { GST_LOG_OBJECT (sink, "Joining 2nd buffer of size %d to cached buf", GST_BUFFER_SIZE (buf)); gst_buffer_ref (buf); reffed_buf = buf = gst_buffer_join (sink->cache, buf); sink->cache = NULL; } GST_LOG_OBJECT (sink, "Sending %d bytes to RTMP server", GST_BUFFER_SIZE (buf)); if (!RTMP_Write (sink->rtmp, (char *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf))) { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Failed to write data")); if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_ERROR; } if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_OK; }
void RTMPWriter::write(uint8_t* data, size_t nbytes) { if(state == RW_STATE_NONE) { printf("error: cannot write to rtmp server because we haven't been initialized. did you call initialize()?\n"); return; } else if(state == RW_STATE_RECONNECTING) { //printf("reconnecting... ignoring data...\n"); return; } else if(state == RW_STATE_DISCONNECTED) { // the caller needs to call reconnect() return; } //printf("rtmp: %ld\n", nbytes); int r = RTMP_Write(rtmp, (const char*)data, (int)nbytes); if(r < 0) { // @todo - we should close and cleanup here!!!! RTMP_Close(rtmp); RTMP_Free(rtmp); rtmp = NULL; printf("error: something went wrong while trying to write data to the rtmp server.\n"); if(state == RW_STATE_DISCONNECTED) { return; } // when initialized and we arrive here, it means we're disconnected else if(state == RW_STATE_INITIALIZED) { state = RW_STATE_DISCONNECTED; if(cb_disconnect) { cb_disconnect(this, cb_user); } } } }
static int send_packet(struct rtmp_stream *stream, struct encoder_packet *packet, bool is_header, size_t idx) { uint8_t *data; size_t size; int recv_size = 0; int ret = 0; if (!stream->new_socket_loop) { #ifdef _WIN32 ret = ioctlsocket(stream->rtmp.m_sb.sb_socket, FIONREAD, (u_long*)&recv_size); #else ret = ioctl(stream->rtmp.m_sb.sb_socket, FIONREAD, &recv_size); #endif if (ret >= 0 && recv_size > 0) { if (!discard_recv_data(stream, (size_t)recv_size)) return -1; } } flv_packet_mux(packet, &data, &size, is_header); #ifdef TEST_FRAMEDROPS droptest_cap_data_rate(stream, size); #endif ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx); bfree(data); if (is_header) bfree(packet->data); else obs_encoder_packet_release(packet); stream->total_bytes_sent += size; return ret; }
int RTMP_Send_packet(RTMP_Packet *pkt) { uint8_t pkt_header[18] = {0}; //根据协议文档,header 最大为14个字节 uint8_t *p = pkt_header; if (pkt->fmt_type > 3) { printf("[RTMP_Send_packet] pkt fmt type error, fmt_type %d\n", pkt->fmt_type); return -1; } /* 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |fmt| cs id | +-+-+-+-+-+-+-+-+ Chunk basic header 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |fmt| 0 | cs id - 64 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Chunk basic header 2 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |fmt| 1 | cs id - 64 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Chunk basic header 3 */ /* 根据上面协议文档中的说明,对header进行拼接 */ if (pkt->channel_id > 65599) { printf("[RTMP_Send_packet] pkt channel id error, channel id %d\n", pkt->channel_id); } if (pkt->channel_id < 64) { *p = (pkt->fmt_type << 6) | (pkt->channel_id); p++; } else if (pkt->channel_id >= 64 && pkt->channel_id < 320) { *p = (pkt->fmt_type << 6) | 0; p++; *p = pkt->channel_id - 64; p++; } else { *p = (pkt->fmt_type << 6) | 1; p++; *p = pkt->channel_id - 64; p++; } /* 根据协议文档,当fmt_type为0时, timestamp为3个byte, msg_length 为3个byte, message type id 为1个byte,msg stream id 为4个byte */ if (pkt->fmt_type == 0) { //set timestamp RTMP_write3byte_to_buffer(&p, pkt->time_stamp); //set msg_length RTMP_write3byte_to_buffer(&p, pkt->data_size); //set msg_type RTMP_write1byte_to_buffer(&p, pkt->msg_type); //set msg stream id RTMP_write4byte_to_buffer_l(&p, pkt->msg_stream_id); //小端序 } //msg header end int send_ret = -1; send_ret = RTMP_Write((char*)pkt_header, p - pkt_header); if (send_ret <= 0) { printf("[RTMP_Send_packet] fmt type 0, send data error %d\n", WSAGetLastError()); return -1; } int send_size = 0; while (send_size < pkt->data_size) { int towrite = RTMP_MIN(g_context.in_chunk_size, pkt->data_size - send_size); send_ret = RTMP_Write((char*)pkt->data + send_size, towrite); if (send_ret <= 0) { printf("[RTMP_Send_packet] fmt type 0, send data error %d\n", WSAGetLastError()); return -1; } send_size += send_ret; //write header if (send_size < pkt->data_size) { uint8_t marker = 0xC0 | pkt->channel_id; send_ret = RTMP_Write((char*)&marker, sizeof(marker)); if (send_ret <= 0) { printf("[RTMP_Send_packet] fmt type 0, send header error %d\n", WSAGetLastError()); return -1; } } } return 0; }
//Publish using RTMP_Write() int publish_using_write(){ uint32_t start_time=0; uint32_t now_time=0; uint32_t pre_frame_time=0; uint32_t lasttime=0; int bNextIsKey=0; char* pFileBuf=NULL; //read from tag header uint32_t type=0; uint32_t datalength=0; uint32_t timestamp=0; RTMP *rtmp=NULL; FILE*fp=NULL; fp=fopen("cuc_ieschool.flv","rb"); if (!fp){ RTMP_LogPrintf("Open File Error.\n"); // CleanupSockets(); return -1; } /* set log level */ //RTMP_LogLevel loglvl=RTMP_LOGDEBUG; //RTMP_LogSetLevel(loglvl); // if (!InitSockets()){ // RTMP_LogPrintf("Init Socket Err\n"); // return -1; // } rtmp=RTMP_Alloc(); RTMP_Init(rtmp); //set connection timeout,default 30s rtmp->Link.timeout=5; if(!RTMP_SetupURL(rtmp,"rtmp://localhost/publishlive/livestream")) { RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n"); RTMP_Free(rtmp); // CleanupSockets(); return -1; } RTMP_EnableWrite(rtmp); //1hour RTMP_SetBufferMS(rtmp, 3600*1000); if (!RTMP_Connect(rtmp,NULL)){ RTMP_Log(RTMP_LOGERROR,"Connect Err\n"); RTMP_Free(rtmp); // CleanupSockets(); return -1; } if (!RTMP_ConnectStream(rtmp,0)){ RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n"); RTMP_Close(rtmp); RTMP_Free(rtmp); //CleanupSockets(); return -1; } printf("Start to send data ...\n"); //jump over FLV Header fseek(fp,9,SEEK_SET); //jump over previousTagSizen fseek(fp,4,SEEK_CUR); start_time=RTMP_GetTime(); while(1) { if((((now_time=RTMP_GetTime())-start_time) <(pre_frame_time)) && bNextIsKey){ //wait for 1 sec if the send process is too fast //this mechanism is not very good,need some improvement if(pre_frame_time>lasttime){ RTMP_LogPrintf("TimeStamp:%8lu ms\n", pre_frame_time); lasttime=pre_frame_time; } sleep(1); continue; } //jump over type fseek(fp,1,SEEK_CUR); if(!ReadU24(&datalength,fp)) break; if(!ReadTime(×tamp,fp)) break; //jump back fseek(fp,-8,SEEK_CUR); pFileBuf=(char*)malloc(11+datalength+4); memset(pFileBuf,0,11+datalength+4); if(fread(pFileBuf,1,11+datalength+4,fp)!=(11+datalength+4)) break; pre_frame_time=timestamp; if (!RTMP_IsConnected(rtmp)){ RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n"); break; } if (!RTMP_Write(rtmp,pFileBuf,11+datalength+4)){ RTMP_Log(RTMP_LOGERROR,"Rtmp Write Error\n"); break; } free(pFileBuf); pFileBuf=NULL; if(!PeekU8(&type,fp)) break; if(type==0x09){ if(fseek(fp,11,SEEK_CUR)!=0) break; if(!PeekU8(&type,fp)){ break; } if(type==0x17) bNextIsKey=1; else bNextIsKey=0; fseek(fp,-11,SEEK_CUR); } } RTMP_LogPrintf("\nSend Data Over\n"); if(fp) fclose(fp); if (rtmp!=NULL){ RTMP_Close(rtmp); RTMP_Free(rtmp); rtmp=NULL; } if(pFileBuf){ free(pFileBuf); pFileBuf=NULL; } //CleanupSockets(); return 0; }
static GstFlowReturn gst_rtmp_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstRTMPSink *sink = GST_RTMP_SINK (bsink); GstBuffer *reffed_buf = NULL; GstMapInfo map; if (sink->first) { /* open the connection */ if (!RTMP_IsConnected (sink->rtmp)) { if (!RTMP_Connect (sink->rtmp, NULL) || !RTMP_ConnectStream (sink->rtmp, 0)) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), ("Could not connect to RTMP stream \"%s\" for writing", sink->uri)); RTMP_Free (sink->rtmp); sink->rtmp = NULL; g_free (sink->rtmp_uri); sink->rtmp_uri = NULL; return GST_FLOW_ERROR; } GST_DEBUG_OBJECT (sink, "Opened connection to %s", sink->rtmp_uri); } /* FIXME: Parse the first buffer and see if it contains a header plus a packet instead * of just assuming it's only the header */ GST_LOG_OBJECT (sink, "Caching first buffer of size %" G_GSIZE_FORMAT " for concatenation", gst_buffer_get_size (buf)); gst_buffer_replace (&sink->cache, buf); sink->first = FALSE; return GST_FLOW_OK; } if (sink->cache) { GST_LOG_OBJECT (sink, "Joining 2nd buffer of size %" G_GSIZE_FORMAT " to cached buf", gst_buffer_get_size (buf)); gst_buffer_ref (buf); reffed_buf = buf = gst_buffer_append (sink->cache, buf); sink->cache = NULL; } GST_LOG_OBJECT (sink, "Sending %" G_GSIZE_FORMAT " bytes to RTMP server", gst_buffer_get_size (buf)); gst_buffer_map (buf, &map, GST_MAP_READ); if (RTMP_Write (sink->rtmp, (char *) map.data, map.size) <= 0) goto write_failed; gst_buffer_unmap (buf, &map); if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_OK; /* ERRORS */ write_failed: { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Failed to write data")); gst_buffer_unmap (buf, &map); if (reffed_buf) gst_buffer_unref (reffed_buf); return GST_FLOW_ERROR; } }
/* * Class: net_butterflytv_rtmp_client_RtmpClient * Method: write * Signature: ([CI)I */ JNIEXPORT jint JNICALL Java_net_ossrs_sea_RtmpClient_write (JNIEnv * env, jobject thiz, jcharArray data, jint size) { return RTMP_Write(rtmp, data, size); }
static int rtmp_write(URLContext *s, const uint8_t *buf, int size) { RTMP *r = s->priv_data; return RTMP_Write(r, buf, size); }
int rtmp_write(LibRTMPContext *ctx , const char *buf, int size) { RTMP *r = &ctx->rtmp; return RTMP_Write(r, buf, size); }