Add ability to use custom timestamps for media
Instead of using uvgRTP's internal RTP timestamps, let user specify timestamp for the media when push_frame() is called. Instead of propagating the timestamp through the send stack, store the timestamp value temporarily to the RTP context of the media stream and reset it after push_frame() is done. User should not mix and match uvgRTP's internal RTP timestamps with custom timestamps so either all of the calls or none of the calls should given a timestamp to push_frame(). Custom timestamps should be increased in accordance with the media clock rate, otherwise problems may occur with media reception.
This commit is contained in:
parent
05ad2ceeba
commit
c997a94c2a
|
@ -27,15 +27,23 @@ int main(void)
|
|||
* In this example, we have one media streams with remote participant: hevc */
|
||||
uvg_rtp::media_stream *hevc = sess->create_stream(8888, 8889, RTP_FORMAT_HEVC, 0);
|
||||
|
||||
uint8_t *buffer = new uint8_t[PAYLOAD_MAXLEN];
|
||||
uint8_t *buffer = new uint8_t[PAYLOAD_MAXLEN];
|
||||
uint32_t timestamp = 0;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
|
||||
#ifndef CUSTOM_TIMESTAMPS
|
||||
/* Sending data is as simple as calling push_frame().
|
||||
*
|
||||
* push_frame() will fragment the input buffer into payloads of 1500 bytes and send them to remote */
|
||||
if (hevc->push_frame(buffer, PAYLOAD_MAXLEN, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
#else
|
||||
/* If needed, custom timestamps can be given to push_frame().
|
||||
*
|
||||
* This overrides uvgRTP's own calculations and uses the given timestamp for all RTP packets of "buffer" */
|
||||
if (hevc->push_frame(buffer, PAYLOAD_MAXLEN, (90000 / 30) * timestamp++, RTP_NO_FLAGS) != RTP_OK)
|
||||
fprintf(stderr, "Failed to send RTP frame!");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Session must be destroyed manually */
|
||||
|
|
|
@ -70,13 +70,18 @@ namespace uvg_rtp {
|
|||
* push_frame(..., RTP_MORE | RTP_SLICE); // more data coming in, do not flush queue
|
||||
* push_frame(..., RTP_SLICE); // no more data coming in, flush queue
|
||||
*
|
||||
* If user wishes to manage RTP timestamps himself, he may pass "ts" to push_frame()
|
||||
* which forces uvgRTP to use that timestamp for all RTP packets of "data".
|
||||
*
|
||||
* Return RTP_OK success
|
||||
* Return RTP_INVALID_VALUE if one of the parameters are invalid
|
||||
* Return RTP_MEMORY_ERROR if the data chunk is too large to be processed
|
||||
* Return RTP_SEND_ERROR if uvgRTP failed to send the data to remote
|
||||
* Return RTP_GENERIC_ERROR for any other error condition */
|
||||
rtp_error_t push_frame(uint8_t *data, size_t data_len, int flags);
|
||||
rtp_error_t push_frame(uint8_t *data, size_t data_len, uint32_t ts, int flags);
|
||||
rtp_error_t push_frame(std::unique_ptr<uint8_t[]> data, size_t data_len, int flags);
|
||||
rtp_error_t push_frame(std::unique_ptr<uint8_t[]> data, size_t data_len, uint32_t ts, int flags);
|
||||
|
||||
/* When a frame is received, it is put into the frame vector of the receiver
|
||||
* Calling application can poll frames by calling pull_frame().
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace uvg_rtp {
|
|||
void set_clock_rate(size_t rate);
|
||||
void set_payload(rtp_format_t fmt);
|
||||
void set_dynamic_payload(uint8_t payload);
|
||||
void set_timestamp(uint64_t timestamp);
|
||||
|
||||
void fill_header(uint8_t *buffer);
|
||||
void update_sequence(uint8_t *buffer);
|
||||
|
@ -36,6 +37,9 @@ namespace uvg_rtp {
|
|||
uvg_rtp::clock::hrc::hrc_t wc_start_2;
|
||||
|
||||
size_t sent_pkts_;
|
||||
|
||||
/* Use custom timestamp for the outgoing RTP packets */
|
||||
uint64_t timestamp_;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "media_stream.hh"
|
||||
#include "random.hh"
|
||||
|
||||
#define INVALID_TS UINT64_MAX
|
||||
|
||||
uvg_rtp::media_stream::media_stream(std::string addr, int src_port, int dst_port, rtp_format_t fmt, int flags):
|
||||
srtp_(nullptr),
|
||||
socket_(flags),
|
||||
|
@ -212,6 +214,38 @@ rtp_error_t uvg_rtp::media_stream::push_frame(std::unique_ptr<uint8_t[]> data, s
|
|||
return sender_->push_frame(std::move(data), data_len, flags);
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::media_stream::push_frame(uint8_t *data, size_t data_len, uint32_t ts, int flags)
|
||||
{
|
||||
rtp_error_t ret = RTP_GENERIC_ERROR;
|
||||
|
||||
if (!initialized_) {
|
||||
LOG_ERROR("RTP context has not been initialized fully, cannot continue!");
|
||||
return RTP_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
rtp_->set_timestamp(ts);
|
||||
ret = sender_->push_frame(data, data_len, flags);
|
||||
rtp_->set_timestamp(INVALID_TS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvg_rtp::media_stream::push_frame(std::unique_ptr<uint8_t[]> data, size_t data_len, uint32_t ts, int flags)
|
||||
{
|
||||
rtp_error_t ret = RTP_GENERIC_ERROR;
|
||||
|
||||
if (!initialized_) {
|
||||
LOG_ERROR("RTP context has not been initialized fully, cannot continue!");
|
||||
return RTP_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
rtp_->set_timestamp(ts);
|
||||
ret = sender_->push_frame(std::move(data), data_len, flags);
|
||||
rtp_->set_timestamp(INVALID_TS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uvg_rtp::frame::rtp_frame *uvg_rtp::media_stream::pull_frame()
|
||||
{
|
||||
if (!initialized_) {
|
||||
|
|
27
src/rtp.cc
27
src/rtp.cc
|
@ -10,8 +10,12 @@
|
|||
#include "random.hh"
|
||||
#include "rtp.hh"
|
||||
|
||||
#define INVALID_TS UINT64_MAX
|
||||
|
||||
uvg_rtp::rtp::rtp(rtp_format_t fmt):
|
||||
wc_start_(0), sent_pkts_(0)
|
||||
wc_start_(0),
|
||||
sent_pkts_(0),
|
||||
timestamp_(INVALID_TS)
|
||||
{
|
||||
seq_ = uvg_rtp::random::generate_32() & 0xffff;
|
||||
ts_ = uvg_rtp::random::generate_32();
|
||||
|
@ -94,12 +98,21 @@ void uvg_rtp::rtp::fill_header(uint8_t *buffer)
|
|||
buffer[1] = (payload_ & 0x7f) | (0 << 7);
|
||||
|
||||
*(uint16_t *)&buffer[2] = htons(seq_);
|
||||
*(uint32_t *)&buffer[4] = htonl(
|
||||
ts_
|
||||
+ uvg_rtp::clock::hrc::diff_now(wc_start_2)
|
||||
* clock_rate_
|
||||
/ 1000
|
||||
);
|
||||
*(uint32_t *)&buffer[8] = htonl(ssrc_);
|
||||
|
||||
if (timestamp_ == INVALID_TS) {
|
||||
*(uint32_t *)&buffer[4] = htonl(
|
||||
ts_
|
||||
+ uvg_rtp::clock::hrc::diff_now(wc_start_2)
|
||||
* clock_rate_
|
||||
/ 1000
|
||||
);
|
||||
} else {
|
||||
*(uint32_t *)&buffer[4] = htonl(timestamp_);
|
||||
}
|
||||
}
|
||||
|
||||
void uvg_rtp::rtp::set_timestamp(uint64_t timestamp)
|
||||
{
|
||||
timestamp_= timestamp;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue