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); } } }
void RtmpAudio::process_recv_queue(unsigned int ref_ts) { int size; // flush the recv queue into the playout buffer m_q_recv.lock(); while(!q_recv.empty()){ RTMPPacket p = q_recv.front(); q_recv.pop(); m_q_recv.unlock(); //TODO: // - copy RTMP payload into this->samples // - decode // - put packet in playout buffer if(p.m_nBodySize <= (unsigned int)AUDIO_BUFFER_SIZE){ size = p.m_nBodySize-1; memcpy((unsigned char*)samples, p.m_body+1, size); size = decode(size); if(size <= 0){ ERROR("decode() returned %i\n",size); return; } // TODO: generate some reasonable RTP timestamp // bool begin_talk = false; if(!recv_offset_i){ recv_rtp_offset = ref_ts; recv_rtmp_offset = p.m_nTimeStamp; recv_offset_i = true; begin_talk = true; } unsigned int rtp_ts = (p.m_nTimeStamp - recv_rtmp_offset) * (SPEEX_WB_SAMPLE_RATE/1000); playout_buffer.write(ref_ts, rtp_ts, (ShortSample*)((unsigned char *)samples), PCM16_B2S(size), begin_talk); RTMPPacket_Free(&p); } m_q_recv.lock(); } m_q_recv.unlock(); }
void RtmpSessionFini(RTMP_SESSION *pSession) { if(NULL != pSession->prtmp) { RTMP_Free(pSession->prtmp); pSession->prtmp = NULL; } if(NULL != pSession->pPkt) { RTMPPacket_Free(pSession->pPkt); free(pSession->pPkt); pSession->pPkt = NULL; } return ; }
void LibRtmp::SendSetChunkSize(unsigned int chunkSize) { RTMPPacket rtmp_pakt; RTMPPacket_Reset(&rtmp_pakt); RTMPPacket_Alloc(&rtmp_pakt, 4); rtmp_pakt.m_packetType = 0x01; rtmp_pakt.m_nChannel = 0x02; // control channel rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE; rtmp_pakt.m_nInfoField2 = 0; rtmp_pakt.m_nBodySize = 4; UI32ToBytes(rtmp_pakt.m_body, chunkSize); RTMP_SendPacket(rtmp_, &rtmp_pakt, 0); RTMPPacket_Free(&rtmp_pakt); }
bool LibRtmp::Send(const char* buf, int bufLen, int type, unsigned int timestamp) { RTMPPacket rtmp_pakt; RTMPPacket_Reset(&rtmp_pakt); RTMPPacket_Alloc(&rtmp_pakt, bufLen); rtmp_pakt.m_packetType = type; rtmp_pakt.m_nBodySize = bufLen; rtmp_pakt.m_nTimeStamp = timestamp; rtmp_pakt.m_nChannel = 4; rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE; rtmp_pakt.m_nInfoField2 = rtmp_->m_stream_id; memcpy(rtmp_pakt.m_body, buf, bufLen); int retval = RTMP_SendPacket(rtmp_, &rtmp_pakt, 0); RTMPPacket_Free(&rtmp_pakt); return !!retval; }
int RtmpSessionHandshake(RTMP_SESSION *pSession) { int iRet = 0; RTMPPacket *packet = (RTMPPacket *)malloc(sizeof(RTMPPacket)); if(NULL == packet) { return ERROR_FAILED; } RTMPPacket_Init(packet); pSession->pPkt = packet; RTMP *rtmp = RTMP_Alloc(); if(NULL == rtmp ) { return ERROR_FAILED; } RTMP_Init(rtmp); rtmp->m_sb.sb_socket = pSession->socket; pSession->prtmp = rtmp; pSession->state = RTMPSERVER_STATE_INIT; /* 进行握手处理 */ if(RTMP_Serve(rtmp)) { RTMPPacket_Free(pSession->pPkt); RTMPPacket_Init(pSession->pPkt); pSession->handshake = 1; pSession->arglen = 0; SetNonBlocking(pSession->socket); } else { iRet = -1; } return iRet; }
static event_t * rtmp_loop(rtmp_t *r, media_pipe_t *mp, char *url, char *errbuf, size_t errlen) { RTMPPacket p = {0}; int pos = -1, ret; uint32_t dts; event_t *e = NULL; while(1) { if(pos == -1) { mp->mp_eof = 0; ret = RTMP_GetNextMediaPacket(r->r, &p); if(ret == 2) { /* Wait for queues to drain */ mp->mp_eof = 1; again: e = mp_wait_for_empty_queues(mp); if(e != NULL) { e = rtmp_process_event(r, e, NULL); if(e == NULL) goto again; } if(e == NULL) e = event_create_type(EVENT_EOF); break; } if(ret == 0) { int64_t restartpos = r->seekpos_video; if(cancellable_is_cancelled(mp->mp_cancellable)) { snprintf(errbuf, errlen, "Cancelled"); return NULL; } TRACE(TRACE_ERROR, "RTMP", "Disconnected"); sleep(1); if(restartpos == AV_NOPTS_VALUE) { snprintf(errbuf, errlen, "Giving up restart since nothing was decoded"); return NULL; } RTMP_Close(r->r); RTMP_Init(r->r, mp->mp_cancellable); memset(&p, 0, sizeof(p)); TRACE(TRACE_DEBUG, "RTMP", "Reconnecting stream at pos %ld", restartpos); if(!RTMP_SetupURL(r->r, url)) { snprintf(errbuf, errlen, "Unable to setup RTMP session"); return NULL; } if(!RTMP_Connect(r->r, NULL, errbuf, errlen, 5000)) { return NULL; } if(!RTMP_ConnectStream(r->r, 0)) { snprintf(errbuf, errlen, "Unable to stream RTMP session"); return NULL; } if(mp->mp_flags & MP_CAN_SEEK) RTMP_SendSeek(r->r, restartpos / 1000); continue; } dts = p.m_nTimeStamp; switch(p.m_packetType) { case RTMP_PACKET_TYPE_INFO: if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } break; case RTMP_PACKET_TYPE_VIDEO: e = get_packet_v(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case RTMP_PACKET_TYPE_AUDIO: e = get_packet_a(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case 0x16: pos = 0; break; default: TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_packetType); break; } if(pos == -1) RTMPPacket_Free(&p); } if(pos != -1) { if(pos + 11 < p.m_nBodySize) { uint32_t ds = AMF_DecodeInt24(p.m_body + pos + 1); if(pos + 11 + ds + 4 > p.m_nBodySize) { snprintf(errbuf, errlen, "Corrupt stream"); RTMPPacket_Free(&p); return NULL; } dts = AMF_DecodeInt24(p.m_body + pos + 4); dts |= (p.m_body[pos + 7] << 24); if(p.m_body[pos] == RTMP_PACKET_TYPE_INFO) { if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } } else if(p.m_body[pos] == RTMP_PACKET_TYPE_VIDEO) { e = get_packet_v(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else if(p.m_body[pos] == RTMP_PACKET_TYPE_AUDIO) { e = get_packet_a(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else { TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_body[pos]); } pos += 11 + ds + 4; } else { pos = -1; RTMPPacket_Free(&p); } } if(e != NULL) break; } return e; }
void doServe(STREAMING_SERVER * server, // server socket and state (our listening socket) int sockfd // client connection socket ) { server->state = STREAMING_IN_PROGRESS; RTMP rtmp = { 0 }; /* our session with the real client */ RTMPPacket packet = { 0 }; // timeout for http requests fd_set fds; struct timeval tv; memset(&tv, 0, sizeof(struct timeval)); tv.tv_sec = 5; FD_ZERO(&fds); FD_SET(sockfd, &fds); if (select(sockfd + 1, &fds, NULL, NULL, &tv) <= 0) { RTMP_Log(RTMP_LOGERROR, "Request timeout/select failed, ignoring request"); goto quit; } else { RTMP_Init(&rtmp); rtmp.m_sb.sb_socket = sockfd; if (!RTMP_Serve(&rtmp)) { RTMP_Log(RTMP_LOGERROR, "Handshake failed"); goto cleanup; } } server->arglen = 0; while (RTMP_IsConnected(&rtmp) && RTMP_ReadPacket(&rtmp, &packet)) { if (!RTMPPacket_IsReady(&packet)) continue; ServePacket(server, &rtmp, &packet); RTMPPacket_Free(&packet); } cleanup: RTMP_LogPrintf("Closing connection... "); RTMP_Close(&rtmp); /* Should probably be done by RTMP_Close() ... */ rtmp.Link.playpath.av_val = NULL; rtmp.Link.tcUrl.av_val = NULL; rtmp.Link.swfUrl.av_val = NULL; rtmp.Link.pageUrl.av_val = NULL; rtmp.Link.app.av_val = NULL; rtmp.Link.flashVer.av_val = NULL; RTMP_LogPrintf("done!\n\n"); quit: if (server->state == STREAMING_IN_PROGRESS) server->state = STREAMING_ACCEPTING; return; }
// Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' int ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int offset) { const char *body; unsigned int nBodySize; int ret = 0, nRes; body = packet->m_body + offset; nBodySize = packet->m_nBodySize - offset; if (body[0] != 0x02) // make sure it is a string method name we start with { RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", __FUNCTION__); return 0; } AMFObject obj; nRes = AMF_Decode(&obj, body, nBodySize, FALSE); if (nRes < 0) { RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__); return 0; } AMF_Dump(&obj); AVal method; AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method); double txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1)); RTMP_Log(RTMP_LOGDEBUG, "%s, client invoking <%s>", __FUNCTION__, method.av_val); if (AVMATCH(&method, &av_connect)) { AMFObject cobj; AVal pname, pval; int i; server->connect = packet->m_body; packet->m_body = NULL; AMFProp_GetObject(AMF_GetProp(&obj, NULL, 2), &cobj); for (i=0; i<cobj.o_num; i++) { pname = cobj.o_props[i].p_name; pval.av_val = NULL; pval.av_len = 0; if (cobj.o_props[i].p_type == AMF_STRING) pval = cobj.o_props[i].p_vu.p_aval; if (AVMATCH(&pname, &av_app)) { r->Link.app = pval; pval.av_val = NULL; if (!r->Link.app.av_val) r->Link.app.av_val = ""; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_flashVer)) { r->Link.flashVer = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_swfUrl)) { r->Link.swfUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_tcUrl)) { r->Link.tcUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_pageUrl)) { r->Link.pageUrl = pval; pval.av_val = NULL; server->arglen += 6 + pval.av_len; server->argc += 2; } else if (AVMATCH(&pname, &av_audioCodecs)) { r->m_fAudioCodecs = cobj.o_props[i].p_vu.p_number; } else if (AVMATCH(&pname, &av_videoCodecs)) { r->m_fVideoCodecs = cobj.o_props[i].p_vu.p_number; } else if (AVMATCH(&pname, &av_objectEncoding)) { r->m_fEncoding = cobj.o_props[i].p_vu.p_number; } } /* Still have more parameters? Copy them */ if (obj.o_num > 3) { int i = obj.o_num - 3; r->Link.extras.o_num = i; r->Link.extras.o_props = malloc(i*sizeof(AMFObjectProperty)); memcpy(r->Link.extras.o_props, obj.o_props+3, i*sizeof(AMFObjectProperty)); obj.o_num = 3; server->arglen += countAMF(&r->Link.extras, &server->argc); } SendConnectResult(r, txn); } else if (AVMATCH(&method, &av_createStream)) { SendResultNumber(r, txn, ++server->streamID); } else if (AVMATCH(&method, &av_getStreamLength)) { SendResultNumber(r, txn, 10.0); } else if (AVMATCH(&method, &av_play)) { char *file, *p, *q, *cmd, *ptr; AVal *argv, av; int len, argc; uint32_t now; RTMPPacket pc = {0}; AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &r->Link.playpath); /* r->Link.seekTime = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 4)); if (obj.o_num > 5) r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5)); */ if (r->Link.tcUrl.av_len) { len = server->arglen + r->Link.playpath.av_len + 4 + sizeof("rtmpdump") + r->Link.playpath.av_len + 12; server->argc += 5; cmd = malloc(len + server->argc * sizeof(AVal)); ptr = cmd; argv = (AVal *)(cmd + len); argv[0].av_val = cmd; argv[0].av_len = sizeof("rtmpdump")-1; ptr += sprintf(ptr, "rtmpdump"); argc = 1; argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val); argv[argc++].av_len = r->Link.tcUrl.av_len; if (r->Link.app.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -a \"%s\"", r->Link.app.av_val); argv[argc++].av_len = r->Link.app.av_len; } if (r->Link.flashVer.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -f \"%s\"", r->Link.flashVer.av_val); argv[argc++].av_len = r->Link.flashVer.av_len; } if (r->Link.swfUrl.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val); argv[argc++].av_len = r->Link.swfUrl.av_len; } if (r->Link.pageUrl.av_val) { argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -p \"%s\"", r->Link.pageUrl.av_val); argv[argc++].av_len = r->Link.pageUrl.av_len; } if (r->Link.extras.o_num) { ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); AMF_Reset(&r->Link.extras); } argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = ptr + 5; ptr += sprintf(ptr, " -y \"%.*s\"", r->Link.playpath.av_len, r->Link.playpath.av_val); argv[argc++].av_len = r->Link.playpath.av_len; av = r->Link.playpath; /* strip trailing URL parameters */ q = memchr(av.av_val, '?', av.av_len); if (q) { if (q == av.av_val) { av.av_val++; av.av_len--; } else { av.av_len = q - av.av_val; } } /* strip leading slash components */ for (p=av.av_val+av.av_len-1; p>=av.av_val; p--) if (*p == '/') { p++; av.av_len -= p - av.av_val; av.av_val = p; break; } /* skip leading dot */ if (av.av_val[0] == '.') { av.av_val++; av.av_len--; } file = malloc(av.av_len+5); memcpy(file, av.av_val, av.av_len); file[av.av_len] = '\0'; for (p=file; *p; p++) if (*p == ':') *p = '_'; /* Add extension if none present */ if (file[av.av_len - 4] != '.') { av.av_len += 4; } /* Always use flv extension, regardless of original */ if (strcmp(file+av.av_len-4, ".flv")) { strcpy(file+av.av_len-4, ".flv"); } argv[argc].av_val = ptr + 1; argv[argc++].av_len = 2; argv[argc].av_val = file; argv[argc].av_len = av.av_len; ptr += sprintf(ptr, " -o %s", file); now = RTMP_GetTime(); if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename)) { printf("Duplicate request, skipping.\n"); free(file); } else { printf("\n%s\n\n", cmd); fflush(stdout); server->filetime = now; free(server->filename.av_val); server->filename = argv[argc++]; spawn_dumper(argc, argv, cmd); } free(cmd); } pc.m_body = server->connect; server->connect = NULL; RTMPPacket_Free(&pc); ret = 1; RTMP_SendCtrl(r, 0, 1, 0); SendPlayStart(r); RTMP_SendCtrl(r, 1, 1, 0); SendPlayStop(r); } AMF_Reset(&obj); return ret; }
int RtmpAudio::send(unsigned int user_ts, unsigned int size) { m_sender.lock(); if(!sender || !play_stream_id) { //DBG("!sender || !play_stream_id"); m_sender.unlock(); return 0; } // - generate a new RTMP audio packet // - send packet RTMPPacket packet; RTMPPacket_Reset(&packet); packet.m_headerType = send_offset_i ? RTMP_PACKET_SIZE_MEDIUM : RTMP_PACKET_SIZE_LARGE; packet.m_packetType = RTMP_PACKET_TYPE_AUDIO; packet.m_nChannel = 4;//TODO packet.m_nInfoField2 = play_stream_id; if(!send_offset_i){ send_rtmp_offset = user_ts; send_offset_i = true; } unsigned int rtmp_ts = (user_ts - send_rtmp_offset) / (SPEEX_WB_SAMPLE_RATE/1000); packet.m_nTimeStamp = rtmp_ts; RTMPPacket_Alloc(&packet,size+1); packet.m_nBodySize = size+1; // soundType (byte & 0x01) » 0 // 0: mono, 1: stereo // soundSize (byte & 0x02) » 1 // 0: 8-bit, 1: 16-bit // soundRate (byte & 0x0C) » 2 // 0: 5.5 kHz, 1: 11 kHz, 2: 22 kHz, 3: 44 kHz // soundFormat (byte & 0xf0) » 4 // 0: Uncompressed, 1: ADPCM, 2: MP3, 5: Nellymoser 8kHz mono, 6: Nellymoser, 11: Speex // 0xB2: speex, 16kHz packet.m_body[0] = 0xB2; memcpy(packet.m_body+1,(unsigned char*)samples,size); //DBG("sending audio packet: size=%u rtmp_ts=%u StreamID=%u (rtp_ts=%u)\n", // size+1,rtmp_ts,play_stream_id,user_ts); sender->push_back(packet); m_sender.unlock(); //dump_audio(&packet); RTMPPacket_Free(&packet); return size; }
//Publish using RTMP_SendPacket() int publish_using_packet(){ RTMP *rtmp=NULL; RTMPPacket *packet=NULL; uint32_t start_time=0; uint32_t now_time=0; //the timestamp of the previous frame long pre_frame_time=0; long lasttime=0; int bNextIsKey=1; uint32_t preTagsize=0; //packet attributes uint32_t type=0; uint32_t datalength=0; uint32_t timestamp=0; uint32_t streamid=0; FILE*fp=NULL; fp=fopen("../live.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://101.251.251.93:1935/myapp/mystream")) { RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n"); RTMP_Free(rtmp); // CleanupSockets(); return -1; } //if unable,the AMF command would be 'play' instead of 'publish' RTMP_EnableWrite(rtmp); 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; } packet=(RTMPPacket*)malloc(sizeof(RTMPPacket)); RTMPPacket_Alloc(packet,1024*64); RTMPPacket_Reset(packet); packet->m_hasAbsTimestamp = 0; packet->m_nChannel = 0x04; packet->m_nInfoField2 = rtmp->m_stream_id; RTMP_LogPrintf("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; } //not quite the same as FLV spec if(!ReadU8(&type,fp)) break; if(!ReadU24(&datalength,fp)) break; if(!ReadTime(×tamp,fp)) break; if(!ReadU24(&streamid,fp)) break; if (type!=0x08&&type!=0x09){ //jump over non_audio and non_video frame, //jump over next previousTagSizen at the same time fseek(fp,datalength+4,SEEK_CUR); continue; } if(fread(packet->m_body,1,datalength,fp)!=datalength) break; packet->m_headerType = RTMP_PACKET_SIZE_LARGE; packet->m_nTimeStamp = timestamp; packet->m_packetType = type; packet->m_nBodySize = datalength; pre_frame_time=timestamp; if (!RTMP_IsConnected(rtmp)){ RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n"); break; } if (!RTMP_SendPacket(rtmp,packet,0)){ RTMP_Log(RTMP_LOGERROR,"Send Error\n"); break; } if(!ReadU32(&preTagsize,fp)) break; 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 (packet!=NULL){ RTMPPacket_Free(packet); free(packet); packet=NULL; } // CleanupSockets(); return 0; }
static event_t * rtmp_loop(rtmp_t *r, media_pipe_t *mp, char *url, char *errbuf, size_t errlen) { RTMPPacket p = {0}; int pos = -1, ret; uint32_t dts; event_t *e = NULL; mp_set_playstatus_by_hold(mp, 0, NULL); while(1) { if(pos == -1) { mp->mp_eof = 0; ret = RTMP_GetNextMediaPacket(r->r, &p); if(ret == 2) { /* Wait for queues to drain */ mp->mp_eof = 1; again: e = mp_wait_for_empty_queues(mp); if(e != NULL) { e = rtmp_process_event(r, e, NULL); if(e == NULL) goto again; } mp_set_playstatus_stop(mp); if(e == NULL) e = event_create_type(EVENT_EOF); break; } if(ret == 0) { RTMP_Close(r->r); RTMP_Init(r->r); memset(&p, 0, sizeof(p)); TRACE(TRACE_DEBUG, "RTMP", "Reconnecting stream at pos %d", r->seekbase); if(!RTMP_SetupURL(r->r, url)) { snprintf(errbuf, errlen, "Unable to setup RTMP session"); e = NULL; break; } if(!RTMP_Connect(r->r, NULL)) { snprintf(errbuf, errlen, "Unable to connect RTMP session"); e = NULL; break; } if(!RTMP_ConnectStream(r->r, r->can_seek ? r->seekbase / 1000 : 0)) { snprintf(errbuf, errlen, "Unable to stream RTMP session"); return NULL; } r->epoch++; r->lastdts = 0; r->seekbase = AV_NOPTS_VALUE; mp_flush(mp, 0); continue; } dts = p.m_nTimeStamp; switch(p.m_packetType) { case RTMP_PACKET_TYPE_INFO: if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } break; case RTMP_PACKET_TYPE_VIDEO: e = get_packet_v(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case RTMP_PACKET_TYPE_AUDIO: e = get_packet_a(r, (void *)p.m_body, p.m_nBodySize, dts, mp); break; case 0x16: pos = 0; break; default: TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_packetType); break; } if(pos == -1) RTMPPacket_Free(&p); } if(pos != -1) { if(pos + 11 < p.m_nBodySize) { uint32_t ds = AMF_DecodeInt24(p.m_body + pos + 1); if(pos + 11 + ds + 4 > p.m_nBodySize) { snprintf(errbuf, errlen, "Corrupt stream"); RTMPPacket_Free(&p); return NULL; } dts = AMF_DecodeInt24(p.m_body + pos + 4); dts |= (p.m_body[pos + 7] << 24); if(p.m_body[pos] == RTMP_PACKET_TYPE_INFO) { if(handle_metadata(r, p.m_body, p.m_nBodySize, mp, errbuf, errlen)) { RTMPPacket_Free(&p); return NULL; } } else if(p.m_body[pos] == RTMP_PACKET_TYPE_VIDEO) { e = get_packet_v(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else if(p.m_body[pos] == RTMP_PACKET_TYPE_AUDIO) { e = get_packet_a(r, (void *)p.m_body + pos + 11, ds, dts, mp); } else { TRACE(TRACE_DEBUG, "RTMP", "Got unknown packet type %d\n", p.m_body[pos]); } pos += 11 + ds + 4; } else { pos = -1; RTMPPacket_Free(&p); } } if(e != NULL) break; } return e; }
static void RtmpDispatchPkt(RTMP_SESSION *pSession, RTMPPacket *pPkt) { RTMP *pRtmp = pSession->prtmp; /* 处理报文 */ RTMP_Log(RTMP_LOGDEBUG, "%s, received packet type %02X, size %u bytes", __FUNCTION__, pPkt->m_packetType, pPkt->m_nBodySize); switch(pPkt->m_packetType) { case RTMP_PACKET_TYPE_CHUNK_SIZE: { break; } case RTMP_PACKET_TYPE_BYTES_READ_REPORT: { break; } case RTMP_PACKET_TYPE_CONTROL: { break; } case RTMP_PACKET_TYPE_SERVER_BW: { break; } case RTMP_PACKET_TYPE_CLIENT_BW: { break; } case RTMP_PACKET_TYPE_AUDIO: { break; } case RTMP_PACKET_TYPE_VIDEO: { break; } case RTMP_PACKET_TYPE_FLEX_STREAM_SEND: { break; } case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT: { break; } case RTMP_PACKET_TYPE_FLEX_MESSAGE: { RTMP_Log(RTMP_LOGDEBUG, "%s, flex message, size %u bytes, not fully supported", __FUNCTION__, pPkt->m_nBodySize); if (SessionInvoke(pSession, pPkt, 1)) RTMP_Close(pSession->prtmp); break; } case RTMP_PACKET_TYPE_INFO: { break; } case RTMP_PACKET_TYPE_SHARED_OBJECT: { break; } case RTMP_PACKET_TYPE_INVOKE: { RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__, pPkt->m_nBodySize); if (SessionInvoke(pSession, pPkt, 0)) RTMP_Close(pRtmp); break; } case RTMP_PACKET_TYPE_FLASH_VIDEO: { break; } default: { RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__, pPkt->m_packetType); #ifdef _DEBUG RTMP_LogHex(RTMP_LOGDEBUG, pPkt->m_body, pPkt->m_nBodySize); #endif } } RTMPPacket_Free(pPkt); RTMPPacket_Init(pPkt); }