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:
parent
bc6bfe7af0
commit
687e99286f
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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.
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue