common: FPS API for sending
This commit is contained in:
parent
0d795f5f8a
commit
2abf0bc4ef
|
@ -358,6 +358,9 @@ namespace uvgrtp {
|
|||
std::unique_ptr<uvgrtp::holepuncher> holepuncher_;
|
||||
|
||||
std::string cname_;
|
||||
|
||||
int fps_enumerator_ = 30;
|
||||
int fps_denominator_ = 1;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -278,6 +278,10 @@ enum RTP_CTX_CONFIGURATION_FLAGS {
|
|||
* to use jumbo frames, it can set the MTU size to 9000 bytes */
|
||||
RCC_MTU_SIZE = 5,
|
||||
|
||||
RCC_FPS_ENUMERATOR = 6,
|
||||
|
||||
RCC_FPS_DENOMINATOR = 7,
|
||||
|
||||
RCC_LAST
|
||||
};
|
||||
|
||||
|
|
|
@ -164,3 +164,8 @@ rtp_error_t uvgrtp::formats::media::packet_handler(void *arg, int flags, uvgrtp:
|
|||
|
||||
return RTP_OK;
|
||||
}
|
||||
|
||||
void uvgrtp::formats::media::set_fps(int enumerator, int denominator)
|
||||
{
|
||||
fqueue_->set_fps(enumerator, denominator);
|
||||
}
|
|
@ -62,6 +62,8 @@ namespace uvgrtp {
|
|||
/* Return pointer to the internal frame info structure which is relayed to packet handler */
|
||||
media_frame_info_t *get_media_frame_info();
|
||||
|
||||
void set_fps(int enumarator, int denominator);
|
||||
|
||||
protected:
|
||||
virtual rtp_error_t push_media_frame(uint8_t *data, size_t data_len, int flags);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "random.hh"
|
||||
#include "debug.hh"
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
|
@ -27,7 +28,10 @@ uvgrtp::frame_queue::frame_queue(std::shared_ptr<uvgrtp::socket> socket, std::sh
|
|||
max_ccount_(MAX_CHUNK_COUNT* max_mcount_),
|
||||
rtp_(rtp),
|
||||
socket_(socket),
|
||||
flags_(flags)
|
||||
flags_(flags),
|
||||
frame_interval_(),
|
||||
fps_sync_point_(),
|
||||
frames_since_sync_(0)
|
||||
{}
|
||||
|
||||
uvgrtp::frame_queue::~frame_queue()
|
||||
|
@ -285,7 +289,37 @@ rtp_error_t uvgrtp::frame_queue::flush_queue()
|
|||
if (active_->packets.size() > 1)
|
||||
((uint8_t *)&active_->rtp_headers[active_->rtphdr_ptr - 1])[1] |= (1 << 7);
|
||||
|
||||
if (socket_->sendto(active_->packets, 0) != RTP_OK) {
|
||||
if (fps)
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point this_moment = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::high_resolution_clock::time_point next_frame = next_frame_time();
|
||||
|
||||
if (next_frame > this_moment)
|
||||
{
|
||||
UVG_LOG_DEBUG("Updating fps sync point");
|
||||
fps_sync_point_ = this_moment;
|
||||
next_frame = next_frame_time();
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds packet_interval = frame_interval_/ active_->packets.size();
|
||||
|
||||
for (int i = 0; i < active_->packets.size(); ++i)
|
||||
{
|
||||
std::chrono::high_resolution_clock::time_point next_packet = this_moment + i * packet_interval;
|
||||
|
||||
// sleep until next packet time
|
||||
std::this_thread::sleep_for(next_packet - std::chrono::high_resolution_clock::now());
|
||||
|
||||
// send pkt vects
|
||||
if (socket_->sendto(active_->packets[i], 0) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send packet: %s", strerror(errno));
|
||||
(void)deinit_transaction();
|
||||
return RTP_SEND_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (socket_->sendto(active_->packets, 0) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to flush the message queue: %s", strerror(errno));
|
||||
(void)deinit_transaction();
|
||||
return RTP_SEND_ERROR;
|
||||
|
@ -295,6 +329,11 @@ rtp_error_t uvgrtp::frame_queue::flush_queue()
|
|||
return deinit_transaction();
|
||||
}
|
||||
|
||||
inline std::chrono::high_resolution_clock::time_point uvgrtp::frame_queue::next_frame_time()
|
||||
{
|
||||
return fps_sync_point_ + frame_interval_* (frames_since_sync_ + 1);
|
||||
}
|
||||
|
||||
void uvgrtp::frame_queue::update_rtp_header()
|
||||
{
|
||||
memcpy(&active_->rtp_headers[active_->rtphdr_ptr], &active_->rtp_common, sizeof(active_->rtp_common));
|
||||
|
|
|
@ -149,10 +149,22 @@ namespace uvgrtp {
|
|||
* significant memory leaks */
|
||||
void install_dealloc_hook(void (*dealloc_hook)(void *));
|
||||
|
||||
void set_fps(int enumerator, int denominator)
|
||||
{
|
||||
fps = enumerator > 0 && denominator > 0;
|
||||
if (denominator > 0)
|
||||
{
|
||||
frame_interval_ = std::chrono::nanoseconds(uint64_t(1.0 / double(enumerator / denominator) * 1000*1000*1000));
|
||||
}
|
||||
fps_sync_point_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void enqueue_finalize(uvgrtp::buf_vec& tmp);
|
||||
|
||||
inline std::chrono::high_resolution_clock::time_point next_frame_time();
|
||||
|
||||
transaction_t *active_;
|
||||
|
||||
/* Deallocation hook is stored here and copied to transaction upon initialization */
|
||||
|
@ -166,6 +178,12 @@ namespace uvgrtp {
|
|||
|
||||
/* RTP context flags */
|
||||
int flags_;
|
||||
|
||||
bool fps = false;
|
||||
std::chrono::nanoseconds frame_interval_;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point fps_sync_point_;
|
||||
uint64_t frames_since_sync_ = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ uvgrtp::media_stream::media_stream(std::string cname, std::string addr,
|
|||
reception_flow_(nullptr),
|
||||
media_(nullptr),
|
||||
holepuncher_(nullptr),
|
||||
cname_(cname)
|
||||
cname_(cname),
|
||||
fps_enumerator_(30),
|
||||
fps_denominator_(1)
|
||||
{
|
||||
fmt_ = fmt;
|
||||
addr_ = addr;
|
||||
|
@ -572,6 +574,20 @@ rtp_error_t uvgrtp::media_stream::configure_ctx(int flag, ssize_t value)
|
|||
}
|
||||
break;
|
||||
|
||||
case RCC_FPS_ENUMERATOR: {
|
||||
fps_enumerator_ = value;
|
||||
|
||||
media_->set_fps(fps_enumerator_, fps_denominator_);
|
||||
break;
|
||||
}
|
||||
|
||||
case RCC_FPS_DENOMINATOR: {
|
||||
fps_denominator_ = value;
|
||||
|
||||
media_->set_fps(fps_enumerator_, fps_denominator_);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return RTP_INVALID_VALUE;
|
||||
}
|
||||
|
|
|
@ -133,8 +133,6 @@ TEST(FormatTests, h265)
|
|||
cleanup_sess(ctx, sess);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(FormatTests, h265_large)
|
||||
{
|
||||
std::cout << "Starting h265 test" << std::endl;
|
||||
|
@ -148,6 +146,11 @@ TEST(FormatTests, h265_large)
|
|||
{
|
||||
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
|
||||
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_H26X_PREPEND_SC);
|
||||
|
||||
if (receiver)
|
||||
{
|
||||
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 40 * 1000 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> test_sizes = {100000, 200000, 300000, 400000, 500000, 750000, 1000000};
|
||||
|
@ -169,6 +172,48 @@ TEST(FormatTests, h265_large)
|
|||
cleanup_sess(ctx, sess);
|
||||
}
|
||||
|
||||
TEST(FormatTests, h265_large_fps)
|
||||
{
|
||||
std::cout << "Starting h265 test" << std::endl;
|
||||
uvgrtp::context ctx;
|
||||
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
|
||||
|
||||
uvgrtp::media_stream* sender = nullptr;
|
||||
uvgrtp::media_stream* receiver = nullptr;
|
||||
|
||||
if (sess)
|
||||
{
|
||||
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
|
||||
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_H26X_PREPEND_SC);
|
||||
|
||||
if (receiver)
|
||||
{
|
||||
sender->configure_ctx(RCC_FPS_ENUM, 100);
|
||||
sender->configure_ctx(RCC_FPS_DENUM, 1);
|
||||
|
||||
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 40 * 1000 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> test_sizes = { 100000, 200000, 300000, 400000, 500000, 750000, 1000000 };
|
||||
|
||||
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
|
||||
int rtp_flags = RTP_NO_FLAGS;
|
||||
int nal_type = 5;
|
||||
rtp_format_t format = RTP_FORMAT_H265;
|
||||
int test_runs = 10;
|
||||
|
||||
for (auto& size : test_sizes)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
|
||||
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
|
||||
}
|
||||
|
||||
cleanup_ms(sess, sender);
|
||||
cleanup_ms(sess, receiver);
|
||||
cleanup_sess(ctx, sess);
|
||||
}
|
||||
|
||||
TEST(FormatTests, h266)
|
||||
{
|
||||
std::cout << "Starting h266 test" << std::endl;
|
||||
|
|
Loading…
Reference in New Issue