int rtp_queue_unlock(void* queue, void* ptr, int size) { unsigned int v; struct rtp_queue *q; struct rtp_frame *frame; time64_t tnow = time64_now(); q = (struct rtp_queue *)queue; frame = (struct rtp_frame *)ptr - 1; assert(frame->ptr == (unsigned char *)ptr); v = ntohl(((const unsigned int *)ptr)[0]); frame->seq = RTP_SEQ(v); // frame->timestamp = ntohl(((const unsigned int *)ptr)[1]); // frame->ssrc = ntohl(((const unsigned int *)ptr)[2]); frame->clock = time64_now(); frame->len = size; assert(!frame->next); locker_lock(&q->locker); rtp_queue_push(q, frame); // rtp_queue_dump(q); locker_unlock(&q->locker); return 0; }
void time64_test(void) { time_t t; time64_t t64, _t64; struct tm *tm; struct tm64 tm64; char gmt[64]; char utc[64]; t64 = time64_now(); time64_utc(t64, &tm64); t = time64_to_gmtime(t64); _t64 = time64_from_gmtime(t); assert(_t64/1000 == t64 / 1000); tm = gmtime(&t); assert(tm64.year==tm->tm_year && tm64.month==tm->tm_mon && tm64.day==tm->tm_mday && tm64.wday==tm->tm_wday && tm64.hour==tm->tm_hour && tm64.minute==tm->tm_min && tm64.second==tm->tm_sec); sprintf(gmt, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); time64_format(t64, "%04Y-%02M-%02D %02h:%02m:%02s", utc); assert(0 == strcmp(utc, gmt)); _t64 = time64_from("%04Y-%02M-%02D %02h:%02m:%02s", utc); assert(t64/1000 == _t64/1000); }
static struct rtp_frame* rtp_queue_pop(struct rtp_queue* q) { struct rtp_frame* frame = NULL; if(q->head && (q->head->seq == q->expected || time64_now() - q->head->clock > q->threshold)) { frame = q->head; q->head = frame->next; if(q->tail == frame) { assert(!q->head); assert(!q->tail->next); q->tail = NULL; } } return frame; }
int H264FileSource::Play() { m_status = 1; time64_t clock = time64_now(); if(0 == m_rtp_clock || m_rtp_clock + 40 < clock) { void* ptr = NULL; size_t bytes = 0; if(0 == m_reader.GetNextFrame(m_pos, ptr, bytes)) { rtp_h264_packer()->input(m_rtppacker, ptr, bytes, clock); m_rtp_clock = clock; SendRTCP(); return 1; } } return 0; }
int H264FileSource::SendRTCP() { // make sure have sent RTP packet time64_t clock = time64_now(); int interval = rtp_rtcp_interval(m_rtp); if(0 == m_rtcp_clock || m_rtcp_clock + interval < clock) { char rtcp[1024] = {0}; size_t n = rtp_rtcp_report(m_rtp, rtcp, sizeof(rtcp)); // send RTCP packet struct sockaddr_in addrin; socket_addr_ipv4(&addrin, m_ip.c_str(), m_port[1]); socket_sendto(m_socket[1], rtcp, n, 0, (struct sockaddr*)&addrin, sizeof(addrin)); m_rtcp_clock = clock; } return 0; }
int rtp_queue_lock(void* queue, void** ptr, int size) { struct rtp_queue *q; struct rtp_frame* frame; q = (struct rtp_queue *)queue; if(size < 0 || size > MAX_SIZE) return -1; // invalid size frame = (struct rtp_frame*)malloc(sizeof(struct rtp_frame) + size); if(!frame) return -1; // alloc memory error memset(frame, 0, sizeof(*frame)); frame->capacity = size; frame->ptr = (unsigned char*)(frame+1); frame->clock = time64_now(); *ptr = frame->ptr; return 0; }
static int STDCALL hls_server_worker(void* param) { int r, type; time64_t clock; uint32_t timestamp; hls_playlist_t* playlist = (hls_playlist_t*)param; std::string file = playlist->file + ".flv"; while (1) { void* flv = flv_reader_create(file.c_str()); void* demuxer = flv_demuxer_create(flv_handler, playlist->hls); clock = 0; static unsigned char packet[2 * 1024 * 1024]; while ((r = flv_reader_read(flv, &type, ×tamp, packet, sizeof(packet))) > 0) { time64_t now = time64_now(); if (0 == clock) { clock = now; } else { if (timestamp > now - clock) system_sleep(timestamp - (now - clock)); } assert(0 == flv_demuxer_input(demuxer, type, packet, r, timestamp)); } flv_demuxer_destroy(demuxer); flv_reader_destroy(flv); } hls_media_destroy(playlist->hls); //hls_m3u8_destroy(playlist->m3u8); //s_playlists.erase(); //delete playlist; return thread_destroy(playlist->t); }
int rtcp_input_rtp(struct rtp_context *ctx, const void* data, size_t bytes, time64_t *time) { time64_t clock; rtp_packet_t pkt; struct rtp_member *sender; if(0 != rtp_packet_deserialize(&pkt, data, bytes)) return -1; // packet error assert(2 == pkt.rtp.v); sender = rtp_sender_fetch(ctx, pkt.rtp.ssrc); if(!sender) return -1; clock = time64_now(); // RFC3550 A.8 Estimating the Interarrival Jitter // the jitter estimate is updated: if(0 != sender->rtp_clock) { int D; D = (int)((unsigned int)((clock - sender->rtp_clock)*ctx->frequence/1000) - (pkt.rtp.timestamp - sender->rtp_timestamp)); if(D < 0) D = -D; sender->jitter += (D - sender->jitter)/16.0; } sender->rtp_clock = clock; sender->rtp_timestamp = pkt.rtp.timestamp; sender->rtp_octets += pkt.payloadlen; ++sender->rtp_packets; // RFC3550 A.1 RTP Data Header Validity Checks if(0 == sender->seq_max && 0 == sender->seq_cycles) { sender->seq_probation = 0; sender->seq_max = (uint16_t)pkt.rtp.seq; sender->seq_base = (uint16_t)pkt.rtp.seq; } else if( RTP_SEQ_DIFF(pkt.rtp.seq, sender->seq_max) < RTP_MISORDER) { if(pkt.rtp.seq < 0x1000 && sender->seq_max > 0x8000) { sender->seq_cycles += 1; sender->seq_max = (uint16_t)pkt.rtp.seq; } else { sender->seq_max = (uint16_t)MAX(pkt.rtp.seq, sender->seq_max); } } else { if(++sender->seq_probation > RTP_MINISEQ) { sender->seq_cycles = 0; sender->seq_probation = 0; sender->seq_max = (uint16_t)pkt.rtp.seq; sender->seq_base = (uint16_t)pkt.rtp.seq; } } // calculate wallclock from RTP timestamp if(0 != sender->rtcp_sr.ntpmsw) { *time = (uint64_t)ntp2clock((((uint64_t)sender->rtcp_sr.ntpmsw) << 32) | sender->rtcp_sr.ntplsw); *time += ((uint64_t)(uint32_t)(sender->rtp_timestamp - sender->rtcp_sr.rtpts)) * 1000 / ctx->frequence; // rtp timestamp round per 13-hours(0xFFFFFFFF / 90000 / 3600) // update wall-clock per hour if(clock - sender->rtcp_sr_clock > 1 * 3600 * 1000 || (uint32_t)RTP_ABS((int32_t)(sender->rtp_timestamp - sender->rtcp_sr.rtpts)) > 0x10000000) { time64_t ltnow; ltnow = clock2ntp(*time); sender->rtcp_sr_clock = clock; sender->rtcp_sr.rtpts = sender->rtp_timestamp; sender->rtcp_sr.ntpmsw = (uint32_t)((ltnow >> 32) & 0xFFFFFFFF); sender->rtcp_sr.ntplsw = (uint32_t)ltnow; }