Add unique_ptr support for RTP writer API and all media formats

This commit is contained in:
Aaro Altonen 2019-10-11 09:11:21 +03:00
parent 45d2a4ec26
commit 434a07156c
8 changed files with 139 additions and 20 deletions

View File

@ -33,6 +33,21 @@ rtp_error_t kvz_rtp::generic::push_frame(kvz_rtp::connection *conn, uint8_t *dat
return kvz_rtp::send::send_frame(conn, header, sizeof(header), data, data_len);
}
rtp_error_t kvz_rtp::generic::push_frame(kvz_rtp::connection *conn, std::unique_ptr<uint8_t[]> data, size_t data_len, int flags)
{
(void)flags;
if (data_len > MAX_PAYLOAD) {
LOG_WARN("packet is larger (%zu bytes) than MAX_PAYLOAD (%u bytes)", data_len, MAX_PAYLOAD);
}
uint8_t header[kvz_rtp::frame::HEADER_SIZE_RTP];
conn->fill_rtp_header(header);
/* We don't need to transfer the ownership of of "data" to socket because send_frame() executes immediately */
return kvz_rtp::send::send_frame(conn, header, sizeof(header), data.get(), data_len);
}
rtp_error_t kvz_rtp::generic::frame_receiver(kvz_rtp::reader *reader)
{
LOG_INFO("Generic frame receiver starting...");

View File

@ -14,6 +14,9 @@ namespace kvz_rtp {
/* TODO: */
rtp_error_t push_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, int flags);
/* TODO: */
rtp_error_t push_frame(kvz_rtp::connection *conn, std::unique_ptr<uint8_t[]> data, size_t data_len, int flags);
/* TODO: */
rtp_error_t frame_receiver(kvz_rtp::reader *reader);
};

View File

@ -223,7 +223,7 @@ end:
return -1;
}
static rtp_error_t __push_hevc_frame(
static rtp_error_t __push_hevc_nal(
kvz_rtp::connection *conn,
kvz_rtp::frame_queue *fqueue,
uint8_t *data, size_t data_len,
@ -298,7 +298,9 @@ static rtp_error_t __push_hevc_frame(
return ret;
}
return fqueue->flush_queue(conn);
int retzzz = fqueue->flush_queue(conn);
fprintf(stderr, "kvzrtp: %d %u\n", ret, ret);
return (rtp_error_t)retzzz;
#else
if (data_len <= MAX_PAYLOAD) {
LOG_DEBUG("send unfrag size %zu, type %u", data_len, nalType);
@ -347,8 +349,12 @@ static rtp_error_t __push_hevc_frame(
#endif
}
/* TODO: mitä speksi sanoo slicejen lähettämisestä */
rtp_error_t __push_hevc_slice(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, int flags)
static rtp_error_t __push_hevc_slice(
kvz_rtp::connection *conn,
kvz_rtp::frame_queue *fqueue,
uint8_t *data, size_t data_len,
int flags
)
{
rtp_error_t ret;
@ -357,9 +363,6 @@ rtp_error_t __push_hevc_slice(kvz_rtp::connection *conn, uint8_t *data, size_t d
return RTP_INVALID_VALUE;
}
kvz_rtp::frame_queue *fqueue = conn->get_frame_queue();
(void)fqueue->init_transaction(conn);
if (data_len >= MAX_PAYLOAD) {
LOG_ERROR("slice is too big!");
(void)fqueue->deinit_transaction();
@ -378,10 +381,15 @@ rtp_error_t __push_hevc_slice(kvz_rtp::connection *conn, uint8_t *data, size_t d
return ret;
}
rtp_error_t kvz_rtp::hevc::push_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, int flags)
static rtp_error_t __push_hevc_frame(
kvz_rtp::connection *conn,
kvz_rtp::frame_queue *fqueue,
uint8_t *data, size_t data_len,
int flags
)
{
if (flags & RTP_SLICE)
return __push_hevc_slice(conn, data, data_len, flags);
return __push_hevc_slice(conn, fqueue, data, data_len, flags);
#ifdef __linux__
/* find first start code */
@ -396,14 +404,11 @@ rtp_error_t kvz_rtp::hevc::push_frame(kvz_rtp::connection *conn, uint8_t *data,
return kvz_rtp::generic::push_frame(conn, data + r_off, data_len - r_off, flags);
}
kvz_rtp::frame_queue *fqueue = conn->get_frame_queue();
(void)fqueue->init_transaction(conn);
while (offset != -1) {
offset = __get_hevc_start(data, data_len, offset, start_len);
if (offset != -1) {
ret = __push_hevc_frame(conn, fqueue, &data[prev_offset], offset - prev_offset - start_len, true);
ret = __push_hevc_nal(conn, fqueue, &data[prev_offset], offset - prev_offset - start_len, true);
if (ret != RTP_NOT_READY)
goto error;
@ -412,7 +417,7 @@ rtp_error_t kvz_rtp::hevc::push_frame(kvz_rtp::connection *conn, uint8_t *data,
}
}
if ((ret = __push_hevc_frame(conn, fqueue, &data[prev_offset], data_len - prev_offset, false)) == RTP_OK)
if ((ret = __push_hevc_nal(conn, fqueue, &data[prev_offset], data_len - prev_offset, false)) == RTP_OK)
return RTP_OK;
error:
@ -428,7 +433,7 @@ error:
offset = __get_hevc_start(data, data_len, offset, start_len);
if (offset > 4 && offset != -1) {
if (__push_hevc_frame(conn, nullptr, &data[prev_offset], offset - prev_offset - start_len, false) == -1)
if (__push_hevc_nal(conn, nullptr, &data[prev_offset], offset - prev_offset - start_len, false) == -1)
return RTP_GENERIC_ERROR;
prev_offset = offset;
@ -438,10 +443,56 @@ error:
if (prev_offset == -1)
prev_offset = 0;
return __push_hevc_frame(conn, nullptr, &data[prev_offset], data_len - prev_offset, false);
return __push_hevc_nal(conn, nullptr, &data[prev_offset], data_len - prev_offset, false);
#endif
}
rtp_error_t kvz_rtp::hevc::push_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, int flags)
{
if (!conn || !data || data_len == 0)
return RTP_INVALID_VALUE;
rtp_error_t ret = RTP_GENERIC_ERROR;
kvz_rtp::frame_queue *fqueue = conn->get_frame_queue();
if (!fqueue || (ret = fqueue->init_transaction(conn, data, flags)) != RTP_OK) {
LOG_ERROR("Invalid frame queue or failed to initialize transaction!");
return ret;
}
if (flags & RTP_SLICE)
return __push_hevc_slice(conn, fqueue, data, data_len, flags);
return __push_hevc_frame(conn, fqueue, data, data_len, flags);
}
rtp_error_t kvz_rtp::hevc::push_frame(kvz_rtp::connection *conn, std::unique_ptr<uint8_t[]> data, size_t data_len, int flags)
{
if (!conn || !data || data_len == 0)
return RTP_INVALID_VALUE;
if (!conn || !data || data_len == 0)
return RTP_INVALID_VALUE;
uint8_t *data_ptr = nullptr;
rtp_error_t ret = RTP_GENERIC_ERROR;
kvz_rtp::frame_queue *fqueue = conn->get_frame_queue();
if (!fqueue || (ret = fqueue->init_transaction(conn, std::move(data))) != RTP_OK) {
LOG_ERROR("Invalid frame queue or failed to initialize transaction!");
return ret;
}
if ((data_ptr = fqueue->get_active_dataptr()) == nullptr) {
LOG_ERROR("Invalid data pointer, cannot continue!");
return RTP_INVALID_VALUE;
}
if (flags & RTP_SLICE)
return __push_hevc_slice(conn, fqueue, data_ptr, data_len, flags);
return __push_hevc_frame(conn, fqueue, data_ptr, data_len, flags);
}
rtp_error_t kvz_rtp::hevc::frame_receiver(kvz_rtp::reader *reader)
{
#ifdef __RTP_USE_OPTIMISTIC_RECEIVER__

View File

@ -21,6 +21,9 @@ namespace kvz_rtp {
/* TODO: */
rtp_error_t push_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, int flags);
/* TODO: */
rtp_error_t push_frame(kvz_rtp::connection *conn, std::unique_ptr<uint8_t[]> data, size_t data_len, int flags);
/* TODO: */
rtp_error_t frame_receiver(kvz_rtp::reader *reader);
};

View File

@ -44,6 +44,11 @@ rtp_error_t kvz_rtp::opus::push_frame(connection *conn, uint8_t *data, uint32_t
#endif
}
rtp_error_t kvz_rtp::opus::push_frame(connection *conn, std::unique_ptr<uint8_t[]> data, uint32_t data_len, int flags)
{
return kvz_rtp::generic::push_frame(conn, std::move(data), data_len, flags);
}
kvz_rtp::frame::rtp_frame *kvz_rtp::opus::process_opus_frame(
kvz_rtp::frame::rtp_frame *frame,
std::pair<size_t, std::vector<kvz_rtp::frame::rtp_frame *>>& fu,

View File

@ -10,8 +10,12 @@ namespace kvz_rtp {
uint8_t config_number;
};
/* TODO: */
rtp_error_t push_frame(connection *conn, uint8_t *data, uint32_t data_len, int flags);
/* TODO: */
rtp_error_t push_frame(connection *conn, std::unique_ptr<uint8_t[]> data, uint32_t data_len, int flags);
/* Process the incoming Opus frame
* The RTP frame "frame" given as parameter should be considered invalid after calling this function
* and no operatios should be performed on it after the function has returned.

View File

@ -81,7 +81,7 @@ rtp_error_t kvz_rtp::writer::start()
return RTP_OK;
}
rtp_error_t kvz_rtp::writer::push_frame(uint8_t *data, uint32_t data_len, int flags)
rtp_error_t kvz_rtp::writer::push_frame(uint8_t *data, size_t data_len, int flags)
{
switch (get_payload()) {
case RTP_FORMAT_HEVC:
@ -96,6 +96,21 @@ rtp_error_t kvz_rtp::writer::push_frame(uint8_t *data, uint32_t data_len, int fl
}
}
rtp_error_t kvz_rtp::writer::push_frame(std::unique_ptr<uint8_t[]> data, size_t data_len, int flags)
{
switch (get_payload()) {
case RTP_FORMAT_HEVC:
return kvz_rtp::hevc::push_frame(this, std::move(data), data_len, flags);
case RTP_FORMAT_OPUS:
return kvz_rtp::opus::push_frame(this, std::move(data), data_len, flags);
default:
LOG_DEBUG("Format not recognized, pushing the frame as generic");
return kvz_rtp::generic::push_frame(this, std::move(data), data_len, flags);
}
}
sockaddr_in kvz_rtp::writer::get_out_address()
{
return addr_out_;

View File

@ -11,15 +11,38 @@ namespace kvz_rtp {
class writer : public connection {
public:
/* "src_port" is an optional argument, given if holepunching want to be used */
writer(rtp_format_t fmt, std::string dst_addr, int dst_port);
writer(rtp_format_t fmt, std::string dst_addr, int dst_port, int src_port);
~writer();
// open socket for sending frames
/* Open socket for sending frames and start SCD if enabled
* Start RTCP instance if not already started
*
* Return RTP_OK on success
* Return RTP_SOCKET_ERROR if the socket couldn't be initialized
* Return RTP_BIND_ERROR if binding to src_port_ failed
* Return RTP_MEMORY_ERROR if RTCP instance couldn't be allocated
* Return RTP_GENERIC_ERROR for any other error condition */
rtp_error_t start();
/* TODO: */
rtp_error_t push_frame(uint8_t *data, uint32_t data_len, int flags);
/* Split "data" into 1500 byte chunks and send them to remote
*
* NOTE: If SCD has been enabled, calling this version of push_frame()
* requires either that the caller has given a deallocation callback to
* SCD OR that "flags" contains flags "RTP_COPY"
*
* 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 kvzRTP 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);
/* Same as push_frame() defined above but no callback nor RTP_COPY must be provided
* One must call this like: push_frame(std::move(data), ...) to give ownership of the
* memory to kvzRTP */
rtp_error_t push_frame(std::unique_ptr<uint8_t[]> data, size_t data_len, int flags);
/* TODO: remove */
sockaddr_in get_out_address();