Restructure benchmarking directory

Remove code for libraries that are no longer benchmarked and
create directories for kvzrtp, ffmpeg and gstreamer.
This commit is contained in:
Aaro Altonen 2020-03-26 11:12:10 +02:00
parent bc6bfe7af0
commit 687e99286f
21 changed files with 185 additions and 724 deletions

3
.gitignore vendored
View File

@ -3,7 +3,10 @@ src/formats/*.o
src/mzrtp/*.o
src/crypto/*.o
libkvzrtp.a
*.a
*main
benchmarks/*/main_*
benchmarks/*/results
benchmarks/*/*data
benchmarks/*/*
*.prof

45
benchmarks/Makefile Normal file
View File

@ -0,0 +1,45 @@
.PHONY: all clean kvzrtp live555 ffmpeg gstreamer
CXX = g++
CXXFLAGS = -Wall -Wextra -O2 -std=c++11 -g
#all: kvzrtp live555 ffmpeg gstreamer
kvzrtp_receiver:
$(CXX) $(CXXFLAGS) -o kvzrtp/receiver kvzrtp/receiver.cc util/util.cc -lkvzrtp -lkvazaar -lpthread -lcryptopp
kvzrtp_sender:
$(CXX) $(CXXFLAGS) -o kvzrtp/sender kvzrtp/sender.cc util/util.cc -lkvzrtp -lkvazaar -lpthread -lcryptopp
kvzrtp_latency:
$(CXX) $(CXXFLAGS) -o kvzrtp/latency kvzrtp/latency.cc util/util.cc -lkvzrtp -lkvazaar -lpthread
# jrtp:
# $(CXX) $(CXXFLAGS) -o main_jrtp jrtp.cc ../util/util.cc -lkvazaar -ljrtp -lpthread
# gstreamer:
# $(CXX) $(CXXFLAGS) -o main_gstreamer gstreamer.cc ../util/util.cc -lkvazaar -lpthread \
# `pkg-config --cflags --libs gstreamer-1.0`
# ccrtp:
# $(CXX) $(CXXFLAGS) -o main_ccrtp ccrtp.cc ../util/util.cc -lkvazaar -lpthread -lccrtp -lcommoncpp -lucommon
# live555:
# $(CXX) $(CXXFLAGS) -o main_live555 live555.cc ../util/util.cc ../util/live555_util.cc \
# -I /usr/local/include/liveMedia \
# -I /usr/local/include/groupsock \
# -I /usr/local/include/BasicUsageEnvironment \
# -I /usr/local/include/UsageEnvironment \
# -lkvazaar -lpthread -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment
# ortp:
# $(CXX) $(CXXFLAGS) -o main_ortp ortp.cc ../util/util.cc -lkvazaar -lpthread -lortp
# ffmpeg:
# $(CXX) $(CXXFLAGS) -o main_ffmpeg ffmpeg.cc ../util/util.cc -lkvazaar `pkg-config --libs libavformat`
# latency_ffmpeg:
# $(CXX) $(CXXFLAGS) -o main_latency_ffmpeg latency_ffmpeg.cc ../util/util.cc -lkvazaar `pkg-config --libs libavformat`
# clean:
# rm -f main_kvzrtp main_jrtp main_ccrtp main_live555 main_ortp main_ffmpeg main_latency_kvzrtp main_latency_ffmpeg main_gstreamer

View File

@ -0,0 +1,61 @@
#include <gst/gst.h>
#include <cstdio>
gint main (gint argc, gchar **argv)
{
GMainLoop *loop;
GstElement *pipeline, *videosrc, *conv,*enc, *pay, *udp, *videoparse;
// init GStreamer
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
// setup pipeline
pipeline = gst_pipeline_new ("pipeline");
#if 0
videosrc = gst_element_factory_make ("videotestsrc", "source");
conv = gst_element_factory_make ("videoconvert", "conv");
enc = gst_element_factory_make("x264enc", "enc");
pay = gst_element_factory_make("rtph264pay", "pay");
g_object_set(G_OBJECT(pay), "config-interval", 1, NULL);
udp = gst_element_factory_make("udpsink", "udp");
g_object_set(G_OBJECT(udp), "host", "127.0.0.1", NULL);
g_object_set(G_OBJECT(udp), "port", 5000, NULL);
#else
videosrc = gst_element_factory_make("filesrc", "source");
g_object_set(G_OBJECT(videosrc), "location", "/home/altonen/test.hevc", NULL);
pay = gst_element_factory_make("rtph265pay", "pay");
g_object_set(G_OBJECT(pay), "pt", 96, NULL);
udp = gst_element_factory_make("udpsink", "udp");
g_object_set(G_OBJECT(udp), "host", "127.0.0.1", NULL);
g_object_set(G_OBJECT(udp), "port", 8888, NULL);
#endif
gst_bin_add_many(GST_BIN(pipeline), videosrc, /* conv, enc,*/ pay, udp, NULL);
if (true != gst_element_link_many(videosrc, /* conv, enc,*/ pay, udp, NULL)) {
fprintf(stderr, "linking gstreamer objects failed!\n");
return -1;
}
fprintf(stderr, "start playing...\n");
/* play stream */
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run(loop);
/* cleanup */
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT (pipeline));
g_main_loop_unref(loop);
return 0;
}

BIN
benchmarks/kvzrtp/receiver Executable file

Binary file not shown.

BIN
benchmarks/kvzrtp/sender Executable file

Binary file not shown.

View File

@ -0,0 +1,72 @@
#include <kvzrtp/lib.hh>
#include <kvzrtp/clock.hh>
#include <cstring>
#include<algorithm>
#include <easy/profiler.h>
#define MAX(a, b) (((int)(a) > (int)(b)) ? (int)(a) : (int)(b))
extern void *get_mem(int argc, char **argv, size_t& len);
size_t bytes_sent = 0;
size_t bytes_received = 0;
int main(int argc, char **argv)
{
uint64_t chunk_size = 0;
uint64_t total_size = 0;
uint64_t fake_size = 0;
uint64_t fpt_us = 0;
uint64_t diff = 0;
uint64_t frames = 0;
rtp_error_t ret = RTP_OK;
size_t len = 0;
void *mem = get_mem(argc, argv, len);
kvz_rtp::context rtp_ctx;
kvz_rtp::session *sess = rtp_ctx.create_session("127.0.0.1");
kvz_rtp::media_stream *hevc = sess->create_stream(8889, 8888, RTP_FORMAT_HEVC, RCE_SYSTEM_CALL_DISPATCHER);
std::chrono::high_resolution_clock::time_point start, fpt_start, fpt_end, end;
start = std::chrono::high_resolution_clock::now();
for (int rounds = 0; rounds < 1; ++rounds) {
for (size_t offset = 0, k = 0; offset < len; ++k) {
memcpy(&chunk_size, (uint8_t *)mem + offset, sizeof(uint64_t));
offset += sizeof(uint64_t);
total_size += chunk_size;
fpt_start = std::chrono::high_resolution_clock::now();
if ((ret = hevc->push_frame((uint8_t *)mem + offset, chunk_size, 0)) != RTP_OK) {
fprintf(stderr, "push_frame() failed!\n");
for (;;);
}
fpt_end = std::chrono::high_resolution_clock::now();
diff = std::chrono::duration_cast<std::chrono::milliseconds>(fpt_end - fpt_start).count();
std::this_thread::sleep_for(std::chrono::microseconds(4500));
frames += 1;
offset += chunk_size;
bytes_sent += chunk_size;
fake_size += chunk_size;
fpt_us += diff;
}
}
end = std::chrono::high_resolution_clock::now();
diff = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fprintf(stderr, "%lu bytes, %lu kB, %lu MB took %lu ms %lu s\n",
bytes_sent, bytes_sent / 1000, bytes_sent / 1000 / 1000,
diff, diff / 1000
);
rtp_ctx.destroy_session(sess);
}

View File

@ -1,24 +0,0 @@
.PHONY: all clean kvzrtp # jrtp ccrtp live555 ortp ffmpeg
CXX = g++
CXXFLAGS = -Wall -Wextra -O2 -std=c++11 -g -DBUILD_WITH_EASY_PROFILER
all: kvzrtp live555 ffmpeg
kvzrtp:
$(CXX) $(CXXFLAGS) -o main_kvzrtp kvzrtp.cc ../util/util.cc -lkvzrtp -lkvazaar -lpthread -leasy_profiler
live555:
$(CXX) $(CXXFLAGS) -o main_live555 live555.cc ../util/util.cc ../util/live555_util.cc \
-I /usr/local/include/liveMedia \
-I /usr/local/include/groupsock \
-I /usr/local/include/BasicUsageEnvironment \
-I /usr/local/include/UsageEnvironment \
-lkvazaar -lpthread -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment
ffmpeg:
$(CXX) $(CXXFLAGS) -o main_ffmpeg ffmpeg.cc ../util/util.cc -lkvazaar `pkg-config --libs libavformat` \
-Wno-deprecated-declarations -Wno-unused-variable -Wno-unused-but-set-variable \
-Wno-unused-result -Wno-conversion-null -Wno-unused-parameter
clean:
rm -f main_kvzrtp main_jrtp main_ccrtp main_live555 main_ortp main_ffmpeg

View File

@ -1,67 +0,0 @@
#include <stdio.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libswscale/swscale.h>
}
#include <chrono>
int main(int argc, char** argv) {
// Open the initial context variables that are needed
/* SwsContext *img_convert_ctx; */
AVFormatContext* format_ctx = avformat_alloc_context();
AVCodecContext* codec_ctx = NULL;
int video_stream_index;
// Register everything
av_register_all();
avformat_network_init();
fprintf(stderr, "\n\n--------------------------------------\nreceiver starting...\n");
//open RTSP
AVDictionary *d = NULL;
av_dict_set(&d, "protocol_whitelist", "file,udp,rtp", 0);
char buf[256];
snprintf(buf, sizeof(buf), "%d", 40 * 1024 * 1024);
av_dict_set(&d, "buffer_size", buf, 0);
if (avformat_open_input(&format_ctx, "../../examples/full/sdp/hevc.sdp", NULL, &d) != 0) {
return EXIT_FAILURE;
}
if (avformat_find_stream_info(format_ctx, NULL) < 0) {
return EXIT_FAILURE;
}
//search video stream
for (size_t i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
}
size_t cnt = 0;
size_t size = 0;
AVPacket packet;
av_init_packet(&packet);
//start reading packets from stream and write them to file
av_read_play(format_ctx); //play RTSP
while (av_read_frame(format_ctx, &packet) >= 0) {
if (packet.stream_index == video_stream_index) {
size += packet.size;
}
av_free_packet(&packet);
av_init_packet(&packet);
}
av_read_pause(format_ctx);
return (EXIT_SUCCESS);
}

View File

@ -1,58 +0,0 @@
#include <kvzrtp/lib.hh>
#include <kvzrtp/clock.hh>
#include <cstring>
#include <easy/profiler.h>
extern void *get_mem(int argc, char **argv, size_t& len);
size_t bytes_sent = 0;
size_t bytes_received = 0;
std::chrono::high_resolution_clock::time_point start, end;
void recv_hook(void *arg, kvz_rtp::frame::rtp_frame *frame)
{
(void)arg;
if (bytes_received == 0) {
start = std::chrono::high_resolution_clock::now();
}
bytes_received += frame->payload_len;
fprintf(stderr, "%zu\n", bytes_received);
(void)kvz_rtp::frame::dealloc_frame(frame);
}
void runner(kvz_rtp::context *rtp_ctx, int n, void *mem, size_t len)
{
(void)mem, (void)len;
kvz_rtp::reader *reader = rtp_ctx->create_reader("127.0.0.1", 8888 + n, RTP_FORMAT_HEVC);
/* kvz_rtp::reader *reader = rtp_ctx->create_reader("10.21.25.200", 8888 + n, RTP_FORMAT_HEVC); */
reader->install_recv_hook(NULL, recv_hook);
(void)reader->start();
for (;;)
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
}
int main(int argc, char **argv)
{
/* EASY_PROFILER_ENABLE; */
size_t len = 0;
void *mem = get_mem(argc, argv, len);
kvz_rtp::context rtp_ctx;
for (int i = 0; i < 1; ++i) {
auto t = new std::thread(runner, &rtp_ctx, i, mem, len);
t->detach();
}
for (;;)
std::this_thread::sleep_for(std::chrono::milliseconds(10000));
}

View File

@ -1,38 +0,0 @@
.PHONY: all clean kvzrtp jrtp ccrtp live555 ortp ffmpeg
CXX = g++
CXXFLAGS = -Wall -Wextra -O2 -std=c++11 -g
all: kvzrtp jrtp ccrtp live555 ortp ffmpeg
kvzrtp:
$(CXX) $(CXXFLAGS) -o main_kvzrtp kvzrtp.cc ../util/util.cc -lkvzrtp -lkvazaar -lpthread
latency_kvzrtp:
$(CXX) $(CXXFLAGS) -o main_latency_kvzrtp latency_kvzrtp.cc ../util/util.cc -lkvzrtp -lkvazaar -lpthread
jrtp:
$(CXX) $(CXXFLAGS) -o main_jrtp jrtp.cc ../util/util.cc -lkvazaar -ljrtp -lpthread
ccrtp:
$(CXX) $(CXXFLAGS) -o main_ccrtp ccrtp.cc ../util/util.cc -lkvazaar -lpthread -lccrtp -lcommoncpp -lucommon
live555:
$(CXX) $(CXXFLAGS) -o main_live555 live555.cc ../util/util.cc ../util/live555_util.cc \
-I /usr/local/include/liveMedia \
-I /usr/local/include/groupsock \
-I /usr/local/include/BasicUsageEnvironment \
-I /usr/local/include/UsageEnvironment \
-lkvazaar -lpthread -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment
ortp:
$(CXX) $(CXXFLAGS) -o main_ortp ortp.cc ../util/util.cc -lkvazaar -lpthread -lortp
ffmpeg:
$(CXX) $(CXXFLAGS) -o main_ffmpeg ffmpeg.cc ../util/util.cc -lkvazaar `pkg-config --libs libavformat`
latency_ffmpeg:
$(CXX) $(CXXFLAGS) -o main_latency_ffmpeg latency_ffmpeg.cc ../util/util.cc -lkvazaar `pkg-config --libs libavformat`
clean:
rm -f main_kvzrtp main_jrtp main_ccrtp main_live555 main_ortp main_ffmpeg main_latency_kvzrtp main_latency_ffmpeg

View File

@ -1,15 +0,0 @@
# Send throughput benchmarks
The test setup is simple and tries to simulate a simple video conferencing condition where the RTP library is given a chunk of encoded video (H.265/HEVC in this case) and its job is to find the NAL units and send them (and possibly fragment the frame into smaller packets).
Sending the data as discrete NAL units and fragmenting large frames is required by the [RFC 7789](https://tools.ietf.org/html/rfc7798).
To eliminate all other performance-degrading factors and to get the maximum output of each library, the HEVC file was encoded beforehand and it was memory-mapped to the address space for faster reading.
The benchmark tests were on 64-bit Ubuntu Linux with 3.4 GHz Intel i7-4770 and the network card is Intel Ethernet Connection I217-LM (1GbE).
## Notes about the benchmark implementation
JRTPLIB, oRTP and ccRTP are not media-aware and won't do NAL unit extraction nor fragmentation so the test setup must provide this extra functionality.
Some of the libraries don't restrict the frame size at all which results in larger-than-MTU packets. To make comparison fair for all libraries, 1500 was chosen to be the maximum write size and no packet sent is larger than 1500 bytes.

View File

@ -1,151 +0,0 @@
#include <cstring>
#include <iostream>
#include <chrono>
#include <thread>
#include <ccrtp/rtp.h>
using namespace ost;
using namespace std;
extern void *get_mem(int argc, char **argv, size_t& len);
extern int get_next_frame_start(uint8_t *data, uint32_t offset, uint32_t data_len, uint8_t& start_len);
#define MAX_WRITE_SIZE 1441
int push_hevc_nal_unit(RTPSession& session, uint8_t *data, size_t data_len, uint32_t& ts)
{
uint8_t nalType = (data[0] >> 1) & 0x3F;
size_t data_left = data_len;
size_t data_pos = 0;
int status = 0;
if (data_len < MAX_WRITE_SIZE) {
session.putData(ts++, data, data_len);
return 0;
}
uint8_t buffer[2 + 1 + MAX_WRITE_SIZE];
buffer[0] = 49 << 1; /* fragmentation unit */
buffer[1] = 1; /* TID */
buffer[2] = (1 << 7) | nalType; /* Start bit + NAL type */
data_pos = 2;
data_left -= 2;
while (data_left > MAX_WRITE_SIZE) {
memcpy(&buffer[3], &data[data_pos], MAX_WRITE_SIZE);
session.putData(ts, buffer, sizeof(buffer));
data_pos += MAX_WRITE_SIZE;
data_left -= MAX_WRITE_SIZE;
/* Clear extra bits */
buffer[2] = nalType;
}
buffer[2] |= (1 << 6); /* set E bit to signal end of data */
memcpy(&buffer[3], &data[data_pos], data_left);
session.putData(ts++, buffer, 2 + 1 + data_left);
return 0;
}
int push_hevc_chunk(RTPSession& s, uint8_t *data, size_t data_len, uint32_t& ts)
{
uint8_t start_len;
int32_t prev_offset = 0;
int offset = get_next_frame_start(data, 0, data_len, start_len);
prev_offset = offset;
while (offset != -1) {
offset = get_next_frame_start(data, offset, data_len, start_len);
if (offset > 4 && offset != -1) {
push_hevc_nal_unit(s, &data[prev_offset], offset - prev_offset - start_len, ts);
prev_offset = offset;
}
}
if (prev_offset == -1)
prev_offset = 0;
push_hevc_nal_unit(s, &data[prev_offset], data_len - prev_offset, ts);
}
int push_hevc_chunk__(RTPSession& session, uint8_t *mem, size_t chunk_size, uint32_t& ts)
{
int status;
if (chunk_size < MAX_WRITE_SIZE) {
session.putData(0, (uint8_t *)mem, chunk_size);
return 0;
}
for (size_t k = 0; k < chunk_size; k += MAX_WRITE_SIZE) {
size_t write_size = MAX_WRITE_SIZE;
if (chunk_size - k < MAX_WRITE_SIZE)
write_size = chunk_size - k;
session.putData(0, (uint8_t *)mem + k, write_size);
}
ts++;
return 0;
}
int main(int argc, char **argv)
{
size_t len = 0;
void *mem = get_mem(argc, argv, len);
RTPSession s(InetHostAddress("127.0.0.1"), 3333); // bind reception socket
// Initialization
s.addDestination(InetHostAddress("127.0.0.1"), 8888); // set one destination for packets
s.setPayloadFormat(DynamicPayloadFormat(96, 90000));
s.startRunning(); // start running the packet queue scheduler
uint64_t chunk_size, total_size;
uint64_t fpt_ms = 0;
uint64_t fsize = 0;
uint32_t frames = 0;
uint32_t ts = 0;
std::chrono::high_resolution_clock::time_point start, fpt_start, fpt_end, end;
start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < len; ) {
memcpy(&chunk_size, (uint8_t *)mem + i, sizeof(uint64_t));
i += sizeof(uint64_t);
total_size += chunk_size;
fpt_start = std::chrono::high_resolution_clock::now();
push_hevc_chunk(s, (uint8_t *)mem + i, chunk_size, ts);
fpt_end = std::chrono::high_resolution_clock::now();
i += chunk_size;
frames++;
fsize += chunk_size;
uint64_t diff = std::chrono::duration_cast<std::chrono::microseconds>(fpt_end - fpt_start).count();
fpt_ms += diff;
}
end = std::chrono::high_resolution_clock::now();
uint64_t diff = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fprintf(stderr, "%lu bytes, %lu kB, %lu MB took %u ms %u s\n",
fsize, fsize / 1000, fsize / 1000 / 1000,
diff, diff / 1000
);
fprintf(stderr, "# of frames: %u\n", frames);
fprintf(stderr, "avg frame size: %lu\n", fsize / frames);
fprintf(stderr, "avg processing time of frame: %lu\n", fpt_ms / frames);
/* for (;;); */
return 0;
}

View File

@ -1,214 +0,0 @@
#include <jrtplib3/rtpsession.h>
#include <jrtplib3/rtpsessionparams.h>
#include <jrtplib3/rtpudpv4transmitter.h>
#include <jrtplib3/rtpipv4address.h>
#include <jrtplib3/rtptimeutilities.h>
#include <jrtplib3/rtppacket.h>
#include <stdlib.h>
#include <iostream>
#include <chrono>
#include <cstring>
using namespace jrtplib;
extern void *get_mem(int argc, char **argv, size_t& len);
extern int get_next_frame_start(uint8_t *data, uint32_t offset, uint32_t data_len, uint8_t& start_len);
#define MAX_WRITE_SIZE 1385
int push_hevc_nal_unit(RTPSession& session, uint8_t *data, size_t data_len)
{
uint8_t nalType = (data[0] >> 1) & 0x3F;
size_t data_left = data_len;
size_t data_pos = 0;
int status = 0;
if (data_len < MAX_WRITE_SIZE) {
if ((status = session.SendPacket(data, data_len)) < 0) {
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
return 0;
}
uint8_t buffer[2 + 1 + MAX_WRITE_SIZE];
buffer[0] = 49 << 1; /* fragmentation unit */
buffer[1] = 1; /* TID */
buffer[2] = (1 << 7) | nalType; /* Start bit + NAL type */
data_pos = 2;
data_left -= 2;
while (data_left > MAX_WRITE_SIZE) {
memcpy(&buffer[3], &data[data_pos], MAX_WRITE_SIZE);
if ((status = session.SendPacket(buffer, sizeof(buffer), 96, false, 0) < 0)) {
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
data_pos += MAX_WRITE_SIZE;
data_left -= MAX_WRITE_SIZE;
/* Clear extra bits */
buffer[2] = nalType;
}
buffer[2] |= (1 << 6); /* set E bit to signal end of data */
memcpy(&buffer[3], &data[data_pos], data_left);
if ((status = session.SendPacket(buffer, 2 + 1 + data_left, 96, true, 1) < 0)) {
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
}
int push_hevc_chunk(RTPSession& s, uint8_t *data, size_t data_len)
{
uint8_t start_len;
int32_t prev_offset = 0;
int offset = get_next_frame_start(data, 0, data_len, start_len);
prev_offset = offset;
while (offset != -1) {
offset = get_next_frame_start(data, offset, data_len, start_len);
if (offset > 4 && offset != -1) {
push_hevc_nal_unit(s, &data[prev_offset], offset - prev_offset - start_len);
prev_offset = offset;
}
}
if (prev_offset == -1)
prev_offset = 0;
push_hevc_nal_unit(s, &data[prev_offset], data_len - prev_offset);
}
int main(int argc, char **argv)
{
size_t len = 0;
void *mem = get_mem(argc, argv, len);
RTPSession session;
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0 / 90000.0);
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(8000);
int status = session.Create(sessionparams,&transparams);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
uint8_t localip[] = { 127, 0, 0, 1 };
RTPIPv4Address addr(localip, 8888);
status = session.AddDestination(addr);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(1);
uint64_t chunk_size, total_size;
uint64_t fpt_ms = 0;
uint64_t fsize = 0;
uint32_t frames = 0;
std::chrono::high_resolution_clock::time_point start, fpt_start, fpt_end, end;
start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < len; ) {
memcpy(&chunk_size, (uint8_t *)mem + i, sizeof(uint64_t));
i += sizeof(uint64_t);
total_size += chunk_size;
fpt_start = std::chrono::high_resolution_clock::now();
push_hevc_chunk(session, (uint8_t *)mem + i, chunk_size);
fpt_end = std::chrono::high_resolution_clock::now();
i += chunk_size;
frames++;
fsize += chunk_size;
uint64_t diff = std::chrono::duration_cast<std::chrono::microseconds>(fpt_end - fpt_start).count();
fpt_ms += diff;
}
end = std::chrono::high_resolution_clock::now();
uint64_t diff = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fprintf(stderr, "%lu bytes, %lu kB, %lu MB took %u ms %u s\n",
fsize, fsize / 1000, fsize / 1000 / 1000,
diff, diff / 1000
);
fprintf(stderr, "# of frames: %u\n", frames);
fprintf(stderr, "avg frame size: %lu\n", fsize / frames);
fprintf(stderr, "avg processing time of frame: %lu\n", fpt_ms / frames);
return 0;
}
#if 0
uint64_t off = 0;
size_t total = 0;
std::chrono::high_resolution_clock::time_point start, end;
start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000; ++i) {
for (size_t k = 0; k < len; ) {
memcpy(&off, (uint8_t *)mem + k, sizeof(uint64_t));
k += sizeof(uint64_t);
status = session.SendPacket(silencebuffer,160);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
k += off;
total += off;
}
}
end = std::chrono::high_resolution_clock::now();
fprintf(stderr, "took %lu milliseconds to send %zu bytes %zu kB %zu MB\n",
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(),
total,
total / 1000,
total / 1000 / 1000
);
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
std::cout << "Got packet with "
<< "extended sequence number "
<< packet->GetExtendedSequenceNumber()
<< " from SSRC " << packet->GetSSRC()
<< std::endl;
session.DeletePacket(packet);
}
} while (session.GotoNextSource());
}
session.EndDataAccess();
#endif

View File

@ -1,139 +0,0 @@
#include <ortp/ortp.h>
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include <chrono>
#include <cstdio>
extern void *get_mem(int argc, char **argv, size_t& len);
extern int get_next_frame_start(uint8_t *data, uint32_t offset, uint32_t data_len, uint8_t& start_len);
#define MAX_WRITE_SIZE 1441
int push_hevc_nal_unit(RtpSession *session, uint8_t *data, size_t data_len, uint32_t& ts)
{
uint8_t nalType = (data[0] >> 1) & 0x3F;
size_t data_left = data_len;
size_t data_pos = 0;
int status = 0;
if (data_len < MAX_WRITE_SIZE) {
rtp_session_send_with_ts(session, (uint8_t *)data, data_len, ts++);
return 0;
}
uint8_t buffer[2 + 1 + MAX_WRITE_SIZE];
buffer[0] = 49 << 1; /* fragmentation unit */
buffer[1] = 1; /* TID */
buffer[2] = (1 << 7) | nalType; /* Start bit + NAL type */
data_pos = 2;
data_left -= 2;
while (data_left > MAX_WRITE_SIZE) {
memcpy(&buffer[3], &data[data_pos], MAX_WRITE_SIZE);
rtp_session_send_with_ts(session, buffer, sizeof(buffer), ts);
data_pos += MAX_WRITE_SIZE;
data_left -= MAX_WRITE_SIZE;
/* Clear extra bits */
buffer[2] = nalType;
}
buffer[2] |= (1 << 6); /* set E bit to signal end of data */
memcpy(&buffer[3], &data[data_pos], data_left);
rtp_session_send_with_ts(session, buffer, 2 + 1 + data_left, ts++);
return 0;
}
int push_hevc_chunk(RtpSession *s, uint8_t *data, size_t data_len, uint32_t &ts)
{
uint8_t start_len;
int32_t prev_offset = 0;
int offset = get_next_frame_start(data, 0, data_len, start_len);
prev_offset = offset;
while (offset != -1) {
offset = get_next_frame_start(data, offset, data_len, start_len);
if (offset > 4 && offset != -1) {
push_hevc_nal_unit(s, &data[prev_offset], offset - prev_offset - start_len, ts);
prev_offset = offset;
}
}
if (prev_offset == -1)
prev_offset = 0;
push_hevc_nal_unit(s, &data[prev_offset], data_len - prev_offset, ts);
}
int main(int argc, char *argv[])
{
RtpSession *session;
uint32_t user_ts = 0;
ortp_init();
ortp_scheduler_init();
ortp_set_log_level_mask(0);
session = rtp_session_new(RTP_SESSION_SENDONLY);
rtp_session_set_scheduling_mode(session, FALSE);
rtp_session_set_blocking_mode(session, FALSE);
rtp_session_set_connected_mode(session, FALSE);
rtp_session_set_remote_addr(session, "127.0.0.1", 8888);
rtp_session_set_payload_type(session, 96);
size_t len = 0;
void *mem = get_mem(argc, argv, len);
uint64_t chunk_size, total_size;
uint64_t fpt_ms = 0;
uint64_t fsize = 0;
uint32_t frames = 0;
uint64_t bytes = 0;
uint32_t ts = 0;
std::chrono::high_resolution_clock::time_point start, fpt_start, fpt_end, end;
start = std::chrono::high_resolution_clock::now();
for (size_t i = 0; i < len; ) {
memcpy(&chunk_size, (uint8_t *)mem + i, sizeof(uint64_t));
i += sizeof(uint64_t);
total_size += chunk_size;
fpt_start = std::chrono::high_resolution_clock::now();
push_hevc_chunk(session, (uint8_t *)mem + i, chunk_size, ts);
fpt_end = std::chrono::high_resolution_clock::now();
i += chunk_size;
frames++;
fsize += chunk_size;
uint64_t diff = std::chrono::duration_cast<std::chrono::microseconds>(fpt_end - fpt_start).count();
fpt_ms += diff;
}
end = std::chrono::high_resolution_clock::now();
uint64_t diff = (uint64_t)std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
fprintf(stderr, "%lu bytes, %lu kB, %lu MB took %lu ms %lu s\n",
fsize, fsize / 1000, fsize / 1000 / 1000,
diff, diff / 1000
);
fprintf(stderr, "# of frames: %u\n", frames);
fprintf(stderr, "avg frame size: %lu\n", fsize / frames);
fprintf(stderr, "avg processing time of frame: %lu\n", fpt_ms / frames);
rtp_session_destroy(session);
ortp_exit();
ortp_global_stats_display();
return 0;
}

View File

@ -1,13 +0,0 @@
#!/bin/zsh
make clean && make all -j8
nohup nc -kluvw 0 localhost 8888 &> /dev/null &
for ((i = 0; i < 1; ++i)); do
./main_kvzrtp &>> results/kvzrtp
./main_jrtp &>> results/jrtp
./main_ccrtp &>> results/ccrtp
./main_ffmpeg &>> results/ffmpeg
./main_live555 &>> results/live555
./main_ortp &>> results/ortp
done

View File

@ -22,8 +22,8 @@ void *get_mem(int argc, char **argv, size_t& len)
char *output = NULL;
if (argc != 3) {
input = (char *)"../util/video.raw";
output = (char *)"../util/out.hevc";
input = (char *)"util/video.raw";
output = (char *)"util/out.hevc";
} else {
input = argv[1];
output = argv[2];
@ -84,9 +84,8 @@ int kvazaar_encode(char *input, char *output)
config->width = width;
config->height = height;
config->hash = kvz_hash::KVZ_HASH_NONE;
config->intra_period = 1;
/* config->vps_period = 64; */
config->qp = 22;
config->intra_period = 64;
config->qp = 18;
config->framerate_num = 120;
config->framerate_denom = 1;