2019-03-30 10:22:57 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstring>
|
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
#include "conn.hh"
|
2019-05-17 06:25:11 +00:00
|
|
|
#include "debug.hh"
|
2019-03-30 10:22:57 +00:00
|
|
|
#include "rtp_hevc.hh"
|
2019-05-22 09:43:35 +00:00
|
|
|
#include "send.hh"
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
static int __internal_get_next_frame_start(uint8_t *data, uint32_t offset, uint32_t data_len, uint8_t& start_len)
|
2019-03-30 10:22:57 +00:00
|
|
|
{
|
|
|
|
uint8_t zeros = 0;
|
2019-05-17 06:25:11 +00:00
|
|
|
uint32_t pos = 0;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
while (offset + pos < data_len) {
|
2019-03-30 10:22:57 +00:00
|
|
|
if (zeros >= 2 && data[offset + pos] == 1) {
|
2019-05-22 09:43:35 +00:00
|
|
|
start_len = zeros + 1;
|
2019-05-17 06:25:11 +00:00
|
|
|
return offset + pos + 1;
|
2019-03-30 10:22:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (data[offset + pos] == 0)
|
|
|
|
zeros++;
|
|
|
|
else
|
|
|
|
zeros = 0;
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
static rtp_error_t __internal_push_hevc_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, uint32_t timestamp)
|
2019-03-30 10:22:57 +00:00
|
|
|
{
|
2019-05-22 09:43:35 +00:00
|
|
|
uint32_t data_pos = 0;
|
|
|
|
uint32_t data_left = data_len;
|
|
|
|
rtp_error_t ret = RTP_OK;
|
2019-05-28 07:12:08 +00:00
|
|
|
uint8_t nalType = (data[0] >> 1) & 0x3F;
|
2019-05-22 09:43:35 +00:00
|
|
|
|
|
|
|
if (data_len <= MAX_PAYLOAD) {
|
2019-05-28 07:12:08 +00:00
|
|
|
LOG_DEBUG("send unfrag size %u, type %u", data_len, nalType);
|
2019-05-22 09:43:35 +00:00
|
|
|
return kvz_rtp::generic::push_generic_frame(conn, data, data_len, timestamp);
|
|
|
|
}
|
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
LOG_DEBUG("send frag size: %u, type %u", data_len, nalType);
|
2019-05-22 09:43:35 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
uint8_t header[
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_RTP +
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_HEVC_RTP +
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_HEVC_FU ] = { 0 };
|
2019-05-22 09:43:35 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
conn->fill_rtp_header(header, timestamp);
|
2019-05-22 09:43:35 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
header[kvz_rtp::frame::HEADER_SIZE_RTP + 0] = 49 << 1; /* fragmentation unit */
|
|
|
|
header[kvz_rtp::frame::HEADER_SIZE_RTP + 1] = 1; /* TID */
|
|
|
|
header[kvz_rtp::frame::HEADER_SIZE_RTP +
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_HEVC_RTP] = (1 << 7) | nalType; /* Start bit + NAL type */
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
data_pos = kvz_rtp::frame::HEADER_SIZE_HEVC_RTP;
|
|
|
|
data_left -= kvz_rtp::frame::HEADER_SIZE_HEVC_RTP;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
while (data_left > MAX_PAYLOAD) {
|
|
|
|
if ((ret = kvz_rtp::sender::write_frame(conn, header, sizeof(header), &data[data_pos], MAX_PAYLOAD)) != RTP_OK)
|
2019-05-22 09:43:35 +00:00
|
|
|
goto end;
|
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
data_pos += MAX_PAYLOAD;
|
|
|
|
data_left -= MAX_PAYLOAD;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
|
|
|
/* Clear extra bits */
|
2019-05-28 07:12:08 +00:00
|
|
|
header[kvz_rtp::frame::HEADER_SIZE_RTP +
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_HEVC_RTP] = nalType;
|
2019-03-30 10:22:57 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
header[kvz_rtp::frame::HEADER_SIZE_RTP +
|
|
|
|
kvz_rtp::frame::HEADER_SIZE_HEVC_RTP] |= (1 << 6); /* set E bit to signal end of data */
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-28 07:12:08 +00:00
|
|
|
ret = kvz_rtp::sender::write_frame(conn, header, sizeof(header), &data[data_pos], data_left);
|
2019-03-30 10:22:57 +00:00
|
|
|
|
|
|
|
end:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
rtp_error_t kvz_rtp::hevc::push_hevc_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, uint32_t timestamp)
|
2019-03-30 10:22:57 +00:00
|
|
|
{
|
2019-05-22 09:43:35 +00:00
|
|
|
uint8_t start_len;
|
|
|
|
int32_t prev_offset = 0;
|
|
|
|
int offset = __internal_get_next_frame_start(data, 0, data_len, start_len);
|
|
|
|
prev_offset = offset;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
|
|
|
while (offset != -1) {
|
2019-05-22 09:43:35 +00:00
|
|
|
offset = __internal_get_next_frame_start(data, offset, data_len, start_len);
|
2019-03-30 10:22:57 +00:00
|
|
|
|
|
|
|
if (offset > 4 && offset != -1) {
|
2019-05-22 09:43:35 +00:00
|
|
|
if (__internal_push_hevc_frame(conn, &data[prev_offset], offset - prev_offset - start_len, timestamp) == -1)
|
|
|
|
return RTP_GENERIC_ERROR;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
prev_offset = offset;
|
2019-03-30 10:22:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
if (prev_offset == -1)
|
|
|
|
prev_offset = 0;
|
2019-03-30 10:22:57 +00:00
|
|
|
|
2019-05-22 09:43:35 +00:00
|
|
|
return __internal_push_hevc_frame(conn, &data[prev_offset], data_len - prev_offset, timestamp);
|
2019-03-30 10:22:57 +00:00
|
|
|
}
|