2
* The contents of this file are subject to the Mozilla Public
3
* License Version 1.1 (the "License"); you may not use this file
4
* except in compliance with the License. You may obtain a copy of
5
* the License at http://www.mozilla.org/MPL/
7
* Software distributed under the License is distributed on an "AS
8
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9
* implied. See the License for the specific language governing
10
* rights and limitations under the License.
12
* The Original Code is MPEG4IP.
14
* The Initial Developer of the Original Code is Cisco Systems Inc.
15
* Portions created by Cisco Systems Inc. are
16
* Copyright (C) Cisco Systems Inc. 2001. All Rights Reserved.
19
* Bill May wmay@cisco.com
24
#include <rtp/memory.h>
25
#include <sdp/sdp.h> // for NTP_TO_UNIX_TIME
26
#include "rtp_bytestream.h"
27
#include "our_config_file.h"
29
//#define DEBUG_RTP_PAKS 1
30
//#define DEBUG_RTP_FRAMES 1
31
//#define DEBUG_RTP_BCAST 1
32
//#define DEBUG_RTP_WCLOCK 1
33
//#define DEBUG_RTP_TS 1
34
//#define DEBUG_SEQUENCE_DROPS 1
36
DEFINE_MESSAGE_MACRO(rtp_message, "rtpbyst")
38
#define rtp_message(loglevel, fmt...) message(loglevel, "rtpbyst", fmt)
41
* add_rtp_packet_to_queue() - adds rtp packet to doubly linked lists -
42
* this is used both by the bytestream, and by the player_media when trying
43
* to determine which rtp payload type is being used.
45
int add_rtp_packet_to_queue (rtp_packet *pak,
52
int16_t head_diff = 0, tail_diff = 0;
54
rtp_message(LOG_DEBUG, "%s - m %u pt %u seq %u ts %x len %d",
56
pak->rtp_pak_m, pak->rtp_pak_pt, pak->rtp_pak_seq,
57
pak->rtp_pak_ts, pak->rtp_data_len);
61
// no packets on queue
66
// take the differences between the head and tail sequence numbers
67
tail_diff = pak->rtp_pak_seq - (*tail)->rtp_pak_seq;
68
head_diff = pak->rtp_pak_seq - (*head)->rtp_pak_seq;
70
if (head_diff == 0 || tail_diff == 0) {
71
// duplicate of head - ignore it
73
rtp_message(LOG_ERR, "%s - Duplicate of pak sequence #%u",
74
name, pak->rtp_pak_seq);
75
} else if (head_diff > 0 && tail_diff < 0) {
77
q = (*head)->rtp_next;
79
for (q = (*head)->rtp_next;
80
q->rtp_pak_seq - pak->rtp_pak_seq <= 0;
83
if (q->rtp_pak_seq == pak->rtp_pak_seq) {
85
rtp_message(LOG_ERR, "%s - duplicate pak received %u",
86
name, pak->rtp_pak_seq);
89
rtp_message(LOG_DEBUG, "%s - insert %u before %u",
90
name, pak->rtp_pak_seq, q->rtp_pak_seq);
91
// insert in the middle
92
q->rtp_prev->rtp_next = pak;
93
pak->rtp_prev = q->rtp_prev;
98
// not in the middle. Insert between the tail and head
99
(*head)->rtp_prev = pak;
100
(*tail)->rtp_next = pak;
101
pak->rtp_next = *head;
102
pak->rtp_prev = *tail;
103
if (abs(head_diff) > abs(tail_diff)) {
105
} else if (head_diff < 0 && head_diff > -10) {
106
// head is closer, so, insert at begin
107
rtp_message(LOG_DEBUG, "%s inserting %u at head %u tail %u",
110
(*head)->rtp_pak_seq,
111
(*tail)->rtp_pak_seq);
116
if (head_diff > 1000 || head_diff < -1000 ||
117
tail_diff > 1000 || tail_diff < -1000) {
118
rtp_message(LOG_DEBUG, "%s inserting %u at tail - head %u tail %u",
121
(*head)->rtp_pak_seq,
122
(*tail)->rtp_pak_seq);
130
if (inserted == false) {
131
rtp_message(LOG_ERR, "%s Couldn't insert pak", name);
132
rtp_message(LOG_DEBUG, "pak seq %u", pak->rtp_pak_seq);
134
rtp_message(LOG_DEBUG, "head seq %u, tail seq %u",
135
(*head)->rtp_pak_seq,
136
(*tail)->rtp_pak_seq);
143
if (q->rtp_next == *head) return 1;
144
#ifdef DEBUG_SEQUENCE_DROPS
145
bool dump_list = false;
148
diff = q->rtp_next->rtp_pak_seq - q->rtp_pak_seq;
149
if (diff < 0 || diff > 2) {
153
} while (dump_list == false && q != *tail);
155
rtp_message(LOG_DEBUG, "%s possible queue error - inserted %u %d %d", name,
156
pak->rtp_pak_seq, head_diff, tail_diff);
157
rtp_message(LOG_DEBUG, "%s seq %u %u diff %d", name,
158
q->rtp_pak_seq, q->rtp_next->rtp_pak_seq, diff);
162
head_diff = q->rtp_next->rtp_pak_seq - q->rtp_pak_seq;
163
rtp_message(LOG_DEBUG, "%u diff next %d", q->rtp_pak_seq, head_diff);
165
} while (q != *head);
167
rtp_message(LOG_DEBUG, "%s - head %u tail %u",
168
name, (*head)->rtp_pak_seq, (*tail)->rtp_pak_seq);
174
CRtpByteStreamBase::CRtpByteStreamBase(const char *name,
182
uint16_t rtp_base_seq,
184
uint32_t rtp_base_ts,
189
COurInByteStream(name)
198
set_rtp_base_ts(rtp_base_ts);
200
m_base_ts_set = false;
204
set_rtp_base_seq(rtp_base_seq);
206
m_rtp_base_seq_set = false;
209
m_have_first_pak_ts = false;
212
temp = config.get_config_value(CONFIG_RTP_BUFFER_TIME_MSEC);
214
m_rtp_buffer_time = temp;
216
m_rtp_buffer_time = TO_U64(2000);
225
m_skip_on_advance_bytes = 0;
226
m_stream_ondemand = ondemand;
227
m_rtcp_received = false;
228
m_rtp_packet_mutex = SDL_CreateMutex();
232
m_have_sync_info = false;
234
calculate_wallclock_offset_from_rtcp(ntp_frac, ntp_sec, rtp_ts);
238
CRtpByteStreamBase::~CRtpByteStreamBase (void)
241
if (m_rtp_packet_mutex) {
242
SDL_DestroyMutex(m_rtp_packet_mutex);
243
m_rtp_packet_mutex = NULL;
247
// set_sync - this is for audio only - it will send messages to any
248
// video rtp bytestream to perform the syncronizatio
249
void CRtpByteStreamBase::set_sync (CPlayerSession *psptr)
254
void CRtpByteStreamBase::init (void)
257
m_offset_in_pak = m_skip_on_advance_bytes;
260
void CRtpByteStreamBase::set_wallclock_offset (uint64_t wclock,
265
uint64_t wclock_calc;
268
if (m_rtcp_received == 1 /*&&
269
m_stream_ondemand == 0*/) {
270
rtp_ts_diff = rtp_ts;
271
rtp_ts_diff -= m_rtcp_rtp_ts;
272
wclock_diff = (int64_t)rtp_ts_diff;
273
wclock_diff *= TO_D64(1000);
274
wclock_diff /= (int64_t)m_timescale;
275
wclock_calc = m_rtcp_ts;
276
wclock_calc += wclock_diff;
278
if (wclock_calc != wclock) {
279
#ifdef DEBUG_RTP_WCLOCK
280
rtp_message(LOG_DEBUG,
281
"%s - set wallclock - wclock should be "U64" is "U64,
282
m_name, wclock_calc, wclock);
284
// don't change wclock offset if it's > 100 msec - otherwise,
285
// it's annoying noise
286
int64_t diff = wclock_calc - wclock;
287
if (abs(diff) > 2 && abs(diff) < 100) {
289
// rtp_message(LOG_DEBUG, "not changing");
290
// we'll allow a msec drift here or there to allow for rounding -
291
// we want this to change every so often
296
had_recvd_rtcp = m_rtcp_received;
297
m_rtcp_received = true;
298
SDL_LockMutex(m_rtp_packet_mutex);
301
m_rtcp_rtp_ts = rtp_ts;
303
if (m_have_first_pak_ts) {
304
// we only want positives here
306
diff = rtp_ts - m_first_pak_rtp_ts;
307
int32_t compare = 3600 * m_timescale;
308
#ifdef DEBUG_RTP_WCLOCK
309
rtp_message(LOG_DEBUG, "%s - 1st rtp ts %u rtp %u %u",
310
m_name, m_first_pak_rtp_ts, rtp_ts, diff);
311
rtp_message(LOG_DEBUG, "%s - 1st ts "U64, m_name, m_first_pak_ts);
313
if (diff > compare) {
314
// adjust once an hour, to keep errors low
315
// we'll adjust the timestamp and rtp timestamp
317
ts_diff = (int64_t)diff;
318
ts_diff *= TO_U64(1000);
319
ts_diff /= (int64_t)m_timescale;
320
m_first_pak_ts += ts_diff;
321
m_first_pak_rtp_ts += diff;
322
#ifdef DEBUG_RTP_WCLOCK
323
rtp_message(LOG_DEBUG, "CHANGE %s - first pak ts is now "U64" rtp %u",
324
m_name, m_first_pak_ts, m_first_pak_rtp_ts);
327
// We've received an RTCP - see if we need to syncronize
328
// the video streams.
329
if (m_psptr != NULL) {
331
sync.first_pak_ts = m_first_pak_ts;
332
sync.first_pak_rtp_ts = m_first_pak_rtp_ts;
333
sync.rtcp_ts = m_rtcp_ts;
334
sync.rtcp_rtp_ts = m_rtcp_rtp_ts;
335
sync.timescale = m_timescale;
336
m_psptr->synchronize_rtp_bytestreams(&sync);
338
// if this is our first rtcp, try to synchronize
339
if (!had_recvd_rtcp) synchronize(NULL);
343
SDL_UnlockMutex(m_rtp_packet_mutex);
347
* calculate_wallclock_offset_from_rtcp
348
* Given certain information from an rtcp message, Calculate what the
349
* wallclock time for rtp sequence number 0 would be.
352
CRtpByteStreamBase::calculate_wallclock_offset_from_rtcp (uint32_t ntp_frac,
358
wclock *= TO_U64(1000);
359
wclock /= (TO_U64(1) << 32);
362
offset -= NTP_TO_UNIX_TIME;
363
offset *= TO_U64(1000);
365
#ifdef DEBUG_RTP_WCLOCK
366
rtp_message(LOG_DEBUG, "%s RTCP data - sec %u frac %u value "U64" ts %u",
367
m_name, ntp_sec, ntp_frac, wclock, rtp_ts);
369
set_wallclock_offset(wclock, rtp_ts);
373
* check_buffering is called to check and see if we should be buffering
375
int CRtpByteStreamBase::check_buffering (void)
377
if (m_buffering == 0) {
378
uint32_t head_ts, tail_ts;
379
if (m_head != NULL) {
381
* Payload type the same. Make sure we have at least 2 seconds of
384
if (check_rtp_frame_complete_for_payload_type()) {
385
head_ts = m_head->rtp_pak_ts;
386
tail_ts = m_tail->rtp_pak_ts;
387
if (head_ts > tail_ts &&
388
((head_ts & (1 << 31)) == (tail_ts & (1 << 31)))) {
394
calc *= TO_U64(1000);
396
if (calc >= m_rtp_buffer_time) {
397
if (m_base_ts_set == false) {
398
rtp_message(LOG_NOTICE,
399
"%s - Setting rtp seq and time from 1st pak",
401
set_rtp_base_ts(m_head->rtp_pak_ts);
402
m_rtpinfo_set_from_pak = 1;
404
m_rtpinfo_set_from_pak = 0;
408
rtp_message(LOG_INFO,
409
"%s buffering complete - head seq %d %u tail seq %d %u "D64,
410
m_name, m_head->rtp_pak_seq, head_ts,
414
m_next_seq = m_head->rtp_pak_seq - 1;
424
* recv_callback - callback for when bytestream is active - basically,
425
* put things on the queue
427
int CRtpByteStreamBase::recv_callback (struct rtp *session, rtp_event *e)
432
rpak = (rtp_packet *)e->data;
433
if (rpak->rtp_data_len == 0) {
436
// need to add lock/unlock of mutex here
437
if (m_have_recv_last_ts) {
438
int32_t diff = rpak->rtp_pak_ts - m_recv_last_ts;
440
ts = m_timescale * 2;
442
if (diff > ts || diff < nts) {
443
rtp_message(LOG_INFO, "%s - rtp timestamp diff %d last %u now %u",
444
m_name, diff, m_recv_last_ts, rpak->rtp_pak_ts);
450
m_have_recv_last_ts = true;
451
m_recv_last_ts = rpak->rtp_pak_ts;
452
if (m_buffering == 0) {
453
rpak->pd.rtp_pd_timestamp = get_time_of_day();
454
rpak->pd.rtp_pd_have_timestamp = 1;
456
if (SDL_mutexP(m_rtp_packet_mutex) == -1) {
457
rtp_message(LOG_CRIT, "SDL Lock mutex failure in rtp bytestream recv");
460
add_rtp_packet_to_queue(rpak, &m_head, &m_tail, m_name);
461
if (SDL_mutexV(m_rtp_packet_mutex) == -1) {
462
rtp_message(LOG_CRIT, "SDL Lock mutex failure in rtp bytestream recv");
471
srpak = (rtcp_sr *)e->data;
472
if (rtp_my_ssrc(session) != e->ssrc) {
473
//rtp_message(LOG_DEBUG, "%s received rtcp", m_name);
474
calculate_wallclock_offset_from_rtcp(srpak->ntp_frac,
484
rtp_message(LOG_DEBUG, "Thread %u - Callback from rtp with %d %p",
485
SDL_ThreadID(),e->type, e->rtp_data);
493
* synchronize is used to adjust a video broadcasts time based
494
* on an audio broadcasts time.
495
* We now start the audio and video just based on the Unix time of the
496
* first packet. Then we use this to adjust when both sides have rtcp
498
* It will also work if we never get in RTCP - this routine won't be
499
* called - but our sync will be off.
501
void CRtpByteStreamBase::synchronize (rtcp_sync_t *sync)
503
// need to recalculate m_first_pak_ts here
504
uint64_t adjust_first_pak_ts;
505
int64_t adjust_first_pak;
506
int64_t audio_diff, our_diff;
509
if (!m_have_sync_info) return;
512
if (m_rtcp_received == false)
515
m_have_sync_info = true;
517
if (m_psptr != NULL) return;
518
if (m_rtcp_received == false) return;
519
if (m_have_first_pak_ts == false) return;
521
// First calculation - use the first packet's timestamp to calculate
522
// what the timestamp value would be at the RTCP's RTP timestamp value
523
// adjust_first_pak is amount we need to add to the first_packet's timestamp
524
// We do this for the data we got for the audio stream
525
adjust_first_pak = sync->rtcp_rtp_ts;
526
adjust_first_pak -= sync->first_pak_rtp_ts;
527
adjust_first_pak *= 1000;
528
adjust_first_pak /= (int64_t)sync->timescale;
530
adjust_first_pak_ts = sync->first_pak_ts;
531
adjust_first_pak_ts += adjust_first_pak;
533
// Now, we compute the difference between that value and what the RTCP
534
// says the timestamp should be
535
audio_diff = adjust_first_pak_ts;
536
audio_diff -= sync->rtcp_ts;
538
#ifdef DEBUG_RTP_WCLOCK
539
rtp_message(LOG_DEBUG, "%s - audio rtcp rtp ts %u first pak %u",
540
m_name, sync->rtcp_rtp_ts, sync->first_pak_rtp_ts);
541
rtp_message(LOG_DEBUG, "%s - audio rtcp ts "U64" first pak "U64,
542
m_name, sync->rtcp_ts, sync->first_pak_ts);
543
rtp_message(LOG_DEBUG, "%s - adjusted first pak "D64" ts "U64,
544
m_name, adjust_first_pak, sync->timescale);
545
rtp_message(LOG_DEBUG, "%s - diff "D64, m_name, audio_diff);
548
// Now, we do the same calculation for the numbers for our timestamps -
549
// find the timestamp by adjusting the first packet's timestamp to the
550
// timestamp based on the current RTCP RTP timestamp;
551
adjust_first_pak = m_rtcp_rtp_ts;
552
adjust_first_pak -= m_first_pak_rtp_ts;
553
adjust_first_pak *= 1000;
554
adjust_first_pak /= (int64_t)m_timescale;
556
adjust_first_pak_ts = m_first_pak_ts;
557
adjust_first_pak_ts += adjust_first_pak;
558
our_diff = adjust_first_pak_ts;
559
our_diff -= m_rtcp_ts;
561
#ifdef DEBUG_RTP_WCLOCK
562
rtp_message(LOG_DEBUG, "%s - our rtcp rtp ts %u first pak %u",
563
m_name, m_rtcp_rtp_ts, m_first_pak_rtp_ts);
564
rtp_message(LOG_DEBUG, "%s - our rtcp ts "U64" first pak "U64,
565
m_name, m_rtcp_ts, m_first_pak_ts);
566
rtp_message(LOG_DEBUG, "%s - adjusted first pak "D64" ts "U64,
567
m_name, adjust_first_pak, m_timescale);
568
rtp_message(LOG_DEBUG, "%s - diff "D64, m_name, our_diff);
569
rtp_message(LOG_INFO, "%s adjusting first pak ts by "D64,
571
audio_diff - our_diff);
573
// Now, we very simply add the difference between the 2 to get
574
// what the equivalent start time would be. Note that these values
575
// for the first packet are not fixed - they change over time to avoid
577
m_first_pak_ts += audio_diff - our_diff;
580
void CRtpByteStreamBase::remove_packet_rtp_queue (rtp_packet *pak,
583
if (pak == NULL) return;
584
SDL_LockMutex(m_rtp_packet_mutex);
585
if ((m_head == pak) &&
586
(m_head->rtp_next == NULL || m_head->rtp_next == m_head)) {
590
pak->rtp_next->rtp_prev = pak->rtp_prev;
591
pak->rtp_prev->rtp_next = pak->rtp_next;
593
m_head = pak->rtp_next;
596
m_tail = pak->rtp_prev;
599
if (pak->rtp_data_len < 0) {
600
// restore the packet data length
601
pak->rtp_data_len = 0 - pak->rtp_data_len;
606
SDL_UnlockMutex(m_rtp_packet_mutex);
609
void CRtpByteStreamBase::flush_rtp_packets (void)
611
rtp_message(LOG_DEBUG, "%s flushed", m_name);
612
while (m_head != NULL) {
613
remove_packet_rtp_queue(m_head, 1);
617
m_recvd_pak_timeout = false;
620
void CRtpByteStreamBase::pause(void)
625
* rtp_periodic - called from the player media rtp task. This basically just
626
* checks for the end of the range.
628
void CRtpByteStreamBase::rtp_periodic (void)
630
if (m_buffering != 0) {
631
if (m_recvd_pak == false) {
632
if (m_recvd_pak_timeout == false) {
633
m_recvd_pak_timeout_time = get_time_of_day();
635
rtp_message(LOG_DEBUG, "%s Starting timeout at "U64,
636
m_name, m_recvd_pak_timeout_time);
641
timeout = get_time_of_day() - m_recvd_pak_timeout_time;
642
if (m_stream_ondemand && get_max_playtime() != 0.0) {
643
uint64_t range_end = (uint64_t)(get_max_playtime() * 1000.0);
644
if (m_last_realtime + timeout >= range_end) {
645
rtp_message(LOG_DEBUG,
646
"%s Timedout at range end - last "U64" range end "U64" "U64,
647
m_name, m_last_realtime, range_end, timeout);
651
// broadcast - perhaps if we time out for a second or 2, we
652
// should re-init rtp ? We definately need to put some timing
654
session_desc_t *sptr = m_fmt->media->parent;
655
if (sptr->time_desc != NULL &&
656
sptr->time_desc->end_time != 0) {
658
this_time = time(NULL);
659
if (this_time > sptr->time_desc->end_time &&
660
timeout >= TO_U64(1000)) {
667
m_recvd_pak_timeout = true;
670
m_recvd_pak_timeout = false;
675
bool CRtpByteStreamBase::check_rtp_frame_complete_for_payload_type (void)
677
return (m_head && m_tail->rtp_pak_m == 1);
680
bool CRtpByteStreamBase::check_seq (uint16_t seq)
682
if (seq != m_next_seq) {
683
rtp_message(LOG_INFO, "%s - rtp sequence is %u should be %u",
684
m_name, seq, m_next_seq);
690
void CRtpByteStreamBase::set_last_seq (uint16_t seq)
692
m_next_seq = seq + 1;
695
uint64_t CRtpByteStreamBase::rtp_ts_to_msec (uint32_t rtp_ts,
697
uint64_t &wrap_offset)
700
uint64_t adjusted_rtp_ts;
701
uint64_t adjusted_wc_rtp_ts;
702
bool have_wrap = false;
703
uint32_t this_mask, last_mask;
705
last_mask = m_last_rtp_ts & (1U << 31);
706
this_mask = rtp_ts & (1U << 31);
708
if (last_mask != this_mask) {
709
if (this_mask == 0) {
710
wrap_offset += (TO_U64(1) << 32);
712
rtp_message(LOG_DEBUG, "%s - have wrap %x new %x", m_name,
713
m_last_rtp_ts, rtp_ts);
715
// need to do something here
719
if (m_stream_ondemand) {
720
adjusted_rtp_ts = wrap_offset;
721
adjusted_rtp_ts += rtp_ts;
722
adjusted_wc_rtp_ts = m_base_rtp_ts;
724
if (adjusted_wc_rtp_ts > adjusted_rtp_ts) {
725
timetick = adjusted_wc_rtp_ts - adjusted_rtp_ts;
726
timetick *= TO_U64(1000);
727
timetick /= m_timescale;
728
if (timetick > m_play_start_time) {
731
timetick = m_play_start_time - timetick;
734
timetick = adjusted_rtp_ts - adjusted_wc_rtp_ts;
735
timetick *= TO_U64(1000);
736
timetick /= m_timescale;
737
timetick += m_play_start_time;
740
// We've got a broadcast scenario here...
741
if (m_have_first_pak_ts == false) {
742
// We haven't processed the first packet yet - we record
744
m_first_pak_rtp_ts = rtp_ts;
745
m_first_pak_ts = uts;
746
m_have_first_pak_ts = true;
747
rtp_message(LOG_DEBUG, "%s first pak ts %u "U64,
748
m_name, m_first_pak_rtp_ts, m_first_pak_ts);
749
// if we have received RTCP, set the wallclock offset, which
750
// triggers the synchronization effort.
751
if (m_rtcp_received) {
752
// calculate other stuff
753
//rtp_message(LOG_DEBUG, "%s rtp_ts_to_msec calling wallclock", m_name);
754
set_wallclock_offset(m_rtcp_ts, m_rtcp_rtp_ts);
757
SDL_LockMutex(m_rtp_packet_mutex);
758
// fairly simple calculation to calculate the timestamp
759
// based on this rtp timestamp, the first pak rtp timestamp and
760
// the first packet timestamp.
764
adder = rtp_ts - m_first_pak_rtp_ts;
765
// adjust once an hour, to keep errors low
766
// we'll adjust the timestamp and rtp timestamp
767
ts_adder = (int64_t)adder;
768
ts_adder *= TO_D64(1000);
769
ts_adder /= (int64_t)m_timescale;
770
m_first_pak_ts += ts_adder;
771
m_first_pak_rtp_ts = rtp_ts;
772
#ifdef DEBUG_RTP_BCAST
773
rtp_message(LOG_DEBUG, "%s adjust for wrap - first pak ts is now "U64" rtp %u",
774
m_name, m_first_pak_ts, m_first_pak_rtp_ts);
778
// adder could be negative here, based on the RTCP we receive
779
adder = rtp_ts - m_first_pak_rtp_ts;
780
ts_adder = (int64_t)adder;
781
ts_adder *= TO_D64(1000);
782
ts_adder /= (int64_t)m_timescale;
783
timetick = m_first_pak_ts;
784
timetick += ts_adder;
785
SDL_UnlockMutex(m_rtp_packet_mutex);
787
#ifdef DEBUG_RTP_BCAST
788
rtp_message(LOG_DEBUG, "%s ts %x base %x "U64" tp "U64" adder %d "D64,
789
m_name, rtp_ts, m_first_pak_rtp_ts, m_first_pak_ts,
790
timetick, adder, ts_adder);
794
rtp_message(LOG_DEBUG,"%s time "U64" %u", m_name, timetick, rtp_ts);
797
m_last_rtp_ts = rtp_ts;
798
m_last_realtime = timetick;
802
bool CRtpByteStreamBase::find_mbit (void)
804
rtp_packet *temp, *first;
805
if (m_head == NULL) return false;
806
SDL_LockMutex(m_rtp_packet_mutex);
807
first = temp = m_head;
809
if (temp->rtp_pak_m == 1) {
810
SDL_UnlockMutex(m_rtp_packet_mutex);
813
temp = temp->rtp_next;
814
} while (temp != NULL && temp != first);
815
SDL_UnlockMutex(m_rtp_packet_mutex);
818
void CRtpByteStreamBase::display_status(void)
820
SDL_LockMutex(m_rtp_packet_mutex);
824
if (m_head == NULL) {
825
rtp_message(LOG_DEBUG, "%s - no packets", m_name);
826
rtp_message(LOG_DEBUG, "%s - last rtp %u last realtime "U64 " wrap "U64,
827
m_name, m_last_rtp_ts, m_last_realtime, m_wrap_offset);
828
SDL_UnlockMutex(m_rtp_packet_mutex);
833
for (pak = m_head; pak->rtp_next != m_head; pak = pak->rtp_next) count++;
834
diff = m_tail->rtp_pak_ts - m_head->rtp_pak_ts;
835
rtp_message(LOG_DEBUG, "%s - %u paks head seq %u ts %u tail seq %u ts %u "D64,
836
m_name, count, m_head->rtp_pak_seq, m_head->rtp_pak_ts,
837
m_tail->rtp_pak_seq, m_tail->rtp_pak_ts, diff * 1000 / m_timescale);
838
rtp_message(LOG_DEBUG, "%s - last rtp %u last realtime "U64 " wrap "U64,
839
m_name, m_last_rtp_ts, m_last_realtime, m_wrap_offset);
840
uint32_t last_rtp_ts = m_last_rtp_ts;
841
uint64_t last_realtime = m_last_realtime;
842
uint64_t wrap_offset = m_wrap_offset;
843
uint64_t msec = rtp_ts_to_msec(m_head->rtp_pak_ts,
844
m_head->pd.rtp_pd_timestamp,
846
m_last_rtp_ts = last_rtp_ts;
847
m_last_realtime = last_realtime;
848
rtp_message(LOG_DEBUG, "head ts "U64, msec);
852
t1 = (int64_t)m_first_pak_rtp_ts;
853
t2 = (int64_t)m_first_pak_ts;
854
rtp_message(LOG_DEBUG, "%s - first %u "D64" real "U64" "D64, m_name,
855
m_first_pak_rtp_ts, t1, m_first_pak_ts, t2);
857
SDL_UnlockMutex(m_rtp_packet_mutex);
860
CRtpByteStream::CRtpByteStream(const char *name,
868
uint16_t rtp_base_seq,
870
uint32_t rtp_base_ts,
875
CRtpByteStreamBase(name, fmt, rtp_pt, ondemand, tickpersec, head, tail,
876
rtp_seq_set, rtp_base_seq, rtp_ts_set, rtp_base_ts,
877
rtcp_received, ntp_frac, ntp_sec, rtp_ts)
879
m_buffer = (uint8_t *)malloc(4096);
880
m_buffer_len_max = 4096;
881
m_bytes_used = m_buffer_len = 0;
884
CRtpByteStream::~CRtpByteStream (void)
890
void CRtpByteStream::reset (void)
892
m_buffer_len = m_bytes_used = 0;
893
CRtpByteStreamBase::reset();
896
bool CRtpByteStream::start_next_frame (uint8_t **buffer,
898
frame_timestamp_t *pts,
910
diff = m_buffer_len - m_bytes_used;
913
// Still bytes in the buffer...
914
*buffer = m_buffer + m_bytes_used;
916
#ifdef DEBUG_RTP_FRAMES
917
rtp_message(LOG_DEBUG, "%s Still left - %d bytes", m_name, *buflen);
920
rtp_message(LOG_DEBUG, "%s start %02x %02x %02x %02x %02x", m_name,
927
pts->msec_timestamp = m_last_realtime;
928
pts->audio_freq_timestamp = m_last_rtp_ts;
929
pts->audio_freq = m_timescale;
930
pts->timestamp_is_pts = true;
933
check_seq(m_head->rtp_pak_seq);
936
while (finished == 0) {
939
// incomplete frame - bail on this
940
player_error_message("%s - This should never happen - rtp bytestream"
941
"is incomplete and active", m_name);
942
player_error_message("Please report to mpeg4ip");
943
player_error_message("first %d seq %u ts %x blen %d",
944
first, seq, rtp_ts, m_buffer_len);
950
remove_packet_rtp_queue(rpak, 0);
953
seq = rpak->rtp_pak_seq + 1;
954
ts = rpak->pd.rtp_pd_timestamp;
955
rtp_ts = rpak->rtp_pak_ts;
958
if ((seq != rpak->rtp_pak_seq) ||
959
(rtp_ts != rpak->rtp_pak_ts)) {
960
if (seq != rpak->rtp_pak_seq) {
961
rtp_message(LOG_INFO, "%s missing rtp sequence - should be %u is %u",
962
m_name, seq, rpak->rtp_pak_seq);
964
rtp_message(LOG_INFO, "%s timestamp error - seq %u should be %x is %x",
965
m_name, seq, rtp_ts, rpak->rtp_pak_ts);
968
rtp_ts = rpak->rtp_pak_ts;
970
seq = rpak->rtp_pak_seq + 1;
974
from = (uint8_t *)rpak->rtp_data + m_skip_on_advance_bytes;
975
len = rpak->rtp_data_len - m_skip_on_advance_bytes;
976
if ((m_buffer_len + len) >= m_buffer_len_max) {
978
m_buffer_len_max = m_buffer_len + len + 1024;
979
m_buffer = (uint8_t *)realloc(m_buffer, m_buffer_len_max);
981
memcpy(m_buffer + m_buffer_len,
985
if (rpak->rtp_pak_m == 1) {
988
set_last_seq(rpak->rtp_pak_seq);
992
*buffer = m_buffer + m_bytes_used;
993
*buflen = m_buffer_len - m_bytes_used;
995
rtp_message(LOG_DEBUG, "%s start %02x %02x %02x %02x %02x", m_name,
1002
#ifdef DEBUG_RTP_FRAMES
1003
rtp_message(LOG_DEBUG, "%s buffer len %d", m_name, m_buffer_len);
1006
timetick = rtp_ts_to_msec(rtp_ts, ts, m_wrap_offset);
1007
m_last_rtp_ts = rtp_ts;
1009
pts->msec_timestamp = timetick;
1010
pts->audio_freq_timestamp = m_last_rtp_ts;
1011
pts->audio_freq = m_timescale;
1012
pts->timestamp_is_pts = true;
1016
bool CRtpByteStream::skip_next_frame (frame_timestamp_t *pts,
1023
*hasSyncFrame = -1; // we don't know if we have a sync frame
1024
m_buffer_len = m_bytes_used = 0;
1025
if (m_head == NULL) return false;
1026
ts = m_head->rtp_pak_ts;
1028
set_last_seq(m_head->rtp_pak_seq);
1029
remove_packet_rtp_queue(m_head, 1);
1030
} while (m_head != NULL && m_head->rtp_pak_ts == ts);
1032
if (m_head == NULL) return false;
1034
m_buffer_len = m_bytes_used = 0;
1035
return start_next_frame(buffer, buflen, pts, ud);
1038
void CRtpByteStream::used_bytes_for_frame (uint32_t bytes)
1040
m_bytes_used += bytes;
1041
#ifdef DEBUG_RTP_FRAMES
1042
rtp_message(LOG_DEBUG, "%s Used %d bytes", m_name, bytes);
1046
bool CRtpByteStream::have_frame (void)
1051
void CRtpByteStream::flush_rtp_packets (void)
1053
CRtpByteStreamBase::flush_rtp_packets();
1055
m_bytes_used = m_buffer_len = 0;
1060
CAudioRtpByteStream::CAudioRtpByteStream (unsigned int rtp_pt,
1067
uint16_t rtp_base_seq,
1069
uint32_t rtp_base_ts,
1074
CRtpByteStream("audio",
1081
rtp_seq_set, rtp_base_seq,
1082
rtp_ts_set, rtp_base_ts,
1089
m_working_pak = NULL;
1092
CAudioRtpByteStream::~CAudioRtpByteStream(void)
1096
bool CAudioRtpByteStream::have_frame (void)
1098
if (m_head == NULL) {
1099
if (m_working_pak != NULL && m_bytes_used < m_working_pak->rtp_data_len) {
1107
bool CAudioRtpByteStream::check_rtp_frame_complete_for_payload_type (void)
1109
return m_head != NULL;
1112
void CAudioRtpByteStream::reset (void)
1114
rtp_message(LOG_DEBUG, "in audiortpreset");
1115
CRtpByteStream::reset();
1118
void CAudioRtpByteStream::flush_rtp_packets(void)
1120
if (m_working_pak != NULL) {
1121
xfree(m_working_pak);
1122
m_working_pak = NULL;
1124
CRtpByteStream::flush_rtp_packets();
1127
bool CAudioRtpByteStream::start_next_frame (uint8_t **buffer,
1129
frame_timestamp_t *pts,
1135
if (m_working_pak != NULL) {
1136
diff = m_working_pak->rtp_data_len - m_bytes_used;
1140
// Still bytes in the buffer...
1141
*buffer = (uint8_t *)m_working_pak->rtp_data + m_bytes_used;
1143
pts->msec_timestamp = m_last_realtime;
1144
pts->audio_freq_timestamp = m_last_rtp_ts;
1145
pts->audio_freq = m_timescale;
1146
pts->timestamp_is_pts = false;
1147
#ifdef DEBUG_RTP_FRAMES
1148
rtp_message(LOG_DEBUG, "%s Still left - %d bytes", m_name, *buflen);
1152
if (m_working_pak) xfree(m_working_pak);
1154
m_bytes_used = m_skip_on_advance_bytes;
1155
m_working_pak = m_head;
1156
check_seq(m_working_pak->rtp_pak_seq);
1157
set_last_seq(m_working_pak->rtp_pak_seq);
1158
remove_packet_rtp_queue(m_working_pak, 0);
1160
*buffer = (uint8_t *)m_working_pak->rtp_data + m_bytes_used;
1161
*buflen = m_working_pak->rtp_data_len;
1162
ts = m_working_pak->rtp_pak_ts;
1163
#ifdef DEBUG_RTP_FRAMES
1164
rtp_message(LOG_DEBUG, "%s buffer seq %d ts %x len %d", m_name,
1165
m_working_pak->rtp_pak_seq,
1166
m_working_pak->rtp_pak_ts, *buflen);
1170
// We're going to have to handle wrap better...
1171
uint64_t retts = rtp_ts_to_msec(ts,
1172
m_working_pak->pd.rtp_pd_timestamp,
1176
pts->msec_timestamp = retts;
1177
pts->audio_freq_timestamp = m_last_rtp_ts;
1178
pts->audio_freq = m_timescale;
1179
pts->timestamp_is_pts = false;