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