Save HEVC frame info to the HEVC object

This commit is contained in:
Aaro Altonen 2020-09-16 11:04:41 +03:00
parent 7b50e99aa0
commit 7559482a84
4 changed files with 75 additions and 63 deletions

View File

@ -1,5 +1,8 @@
#pragma once
#include <map>
#include <unordered_set>
#include "frame.hh"
#include "media.hh"
#include "queue.hh"
@ -18,6 +21,32 @@ namespace uvg_rtp {
uint8_t fu_headers[3 * uvg_rtp::frame::HEADER_SIZE_HEVC_FU];
};
typedef struct hevc_info {
/* clock reading when the first fragment is received */
uvg_rtp::clock::hrc::hrc_t sframe_time;
/* sequence number of the frame with s-bit */
uint32_t s_seq;
/* sequence number of the frame with e-bit */
uint32_t e_seq;
/* how many fragments have been received */
size_t pkts_received;
/* total size of all fragments */
size_t total_size;
/* map of frame's fragments,
* allows out-of-order insertion and loop-through in order */
std::map<uint16_t, uvg_rtp::frame::rtp_frame *> fragments;
} hevc_info_t;
typedef struct {
std::unordered_map<uint32_t, hevc_info_t> frames;
std::unordered_set<uint32_t> dropped;
} hevc_frame_info_t;
class hevc : public media {
public:
hevc(uvg_rtp::socket *socket, uvg_rtp::rtp *rtp, int flags);
@ -35,12 +64,17 @@ namespace uvg_rtp {
* Return RTP_GENERIC_ERROR if the packet was corrupted in some way */
static rtp_error_t packet_handler(void *arg, int flags, frame::rtp_frame **frame);
/* Return pointer to the internal frame info structure which is relayed to packet handler */
hevc_frame_info_t *get_hevc_frame_info();
protected:
rtp_error_t __push_frame(uint8_t *data, size_t data_len, int flags);
private:
rtp_error_t push_hevc_frame(uint8_t *data, size_t data_len);
rtp_error_t push_hevc_nal(uint8_t *data, size_t data_len, bool more);
hevc_frame_info_t finfo_;
};
};
};

View File

@ -434,7 +434,7 @@ end:
}
uvg_rtp::formats::hevc::hevc(uvg_rtp::socket *socket, uvg_rtp::rtp *rtp, int flags):
media(socket, rtp, flags)
media(socket, rtp, flags), finfo_{}
{
}
@ -459,3 +459,8 @@ rtp_error_t uvg_rtp::formats::hevc::__push_frame(uint8_t *data, size_t data_len,
return push_hevc_frame(data, data_len);
}
uvg_rtp::formats::hevc_frame_info_t *uvg_rtp::formats::hevc::get_hevc_frame_info()
{
return &finfo_;
}

View File

@ -30,29 +30,6 @@ enum NAL_TYPES {
NT_OTHER = 0xff
};
typedef std::unordered_map<uint32_t, struct hevc_info> frame_info_t;
struct hevc_info {
/* clock reading when the first fragment is received */
uvg_rtp::clock::hrc::hrc_t sframe_time;
/* sequence number of the frame with s-bit */
uint32_t s_seq;
/* sequence number of the frame with e-bit */
uint32_t e_seq;
/* how many fragments have been received */
size_t pkts_received;
/* total size of all fragments */
size_t total_size;
/* map of frame's fragments,
* allows out-of-order insertion and loop-through in order */
std::map<uint16_t, uvg_rtp::frame::rtp_frame *> fragments;
};
static int __get_frag(uvg_rtp::frame::rtp_frame *frame)
{
bool first_frag = frame->payload[2] & 0x80;
@ -84,33 +61,29 @@ static inline uint8_t __get_nal(uvg_rtp::frame::rtp_frame *frame)
return NT_OTHER;
}
static inline bool __frame_late(hevc_info& hinfo)
static inline bool __frame_late(uvg_rtp::formats::hevc_info_t& hinfo)
{
return (uvg_rtp::clock::hrc::diff_now(hinfo.sframe_time) >= RTP_FRAME_MAX_DELAY);
}
static void __drop_frame(frame_info_t& finfo, uint32_t ts)
static void __drop_frame(uvg_rtp::formats::hevc_frame_info_t *finfo, uint32_t ts)
{
uint16_t s_seq = finfo.at(ts).s_seq;
uint16_t e_seq = finfo.at(ts).e_seq;
uint16_t s_seq = finfo->frames.at(ts).s_seq;
uint16_t e_seq = finfo->frames.at(ts).e_seq;
LOG_INFO("Dropping frame %u, %u - %u", ts, s_seq, e_seq);
for (auto& fragment : finfo.at(ts).fragments)
for (auto& fragment : finfo->frames.at(ts).fragments)
(void)uvg_rtp::frame::dealloc_frame(fragment.second);
finfo.erase(ts);
finfo->frames.erase(ts);
}
rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp::frame::rtp_frame **out)
{
(void)arg;
static frame_info_t finfo;
static std::unordered_set<uint32_t> dropped;
uvg_rtp::frame::rtp_frame *frame;
bool enable_idelay = !(flags & RCE_HEVC_NO_INTRA_DELAY);
auto finfo = (uvg_rtp::formats::hevc_frame_info_t *)arg;
/* Use "intra" to keep track of intra frames
*
@ -148,10 +121,10 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
}
/* initialize new frame */
if (finfo.find(c_ts) == finfo.end()) {
if (finfo->frames.find(c_ts) == finfo->frames.end()) {
/* make sure we haven't discarded the frame "c_ts" before */
if (dropped.find(c_ts) != dropped.end()) {
if (finfo->dropped.find(c_ts) != finfo->dropped.end()) {
LOG_WARN("packet belonging to a dropped frame was received!");
return RTP_GENERIC_ERROR;
}
@ -160,40 +133,40 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
if (nal_type == NT_INTRA) {
if (intra != INVALID_TS && enable_idelay) {
__drop_frame(finfo, intra);
dropped.insert(intra);
finfo->dropped.insert(intra);
}
intra = c_ts;
}
finfo[c_ts].s_seq = INVALID_SEQ;
finfo[c_ts].e_seq = INVALID_SEQ;
finfo->frames[c_ts].s_seq = INVALID_SEQ;
finfo->frames[c_ts].e_seq = INVALID_SEQ;
if (frag_type == FT_START) finfo[c_ts].s_seq = c_seq;
if (frag_type == FT_END) finfo[c_ts].e_seq = c_seq;
if (frag_type == FT_START) finfo->frames[c_ts].s_seq = c_seq;
if (frag_type == FT_END) finfo->frames[c_ts].e_seq = c_seq;
finfo[c_ts].sframe_time = uvg_rtp::clock::hrc::now();
finfo[c_ts].total_size = frame->payload_len - HEVC_HDR_SIZE;
finfo[c_ts].pkts_received = 1;
finfo->frames[c_ts].sframe_time = uvg_rtp::clock::hrc::now();
finfo->frames[c_ts].total_size = frame->payload_len - HEVC_HDR_SIZE;
finfo->frames[c_ts].pkts_received = 1;
finfo[c_ts].fragments[c_seq] = frame;
finfo->frames[c_ts].fragments[c_seq] = frame;
return RTP_OK;
}
finfo[c_ts].fragments[c_seq] = frame;
finfo->frames[c_ts].fragments[c_seq] = frame;
finfo[c_ts].pkts_received += 1;
finfo[c_ts].total_size += (frame->payload_len - HEVC_HDR_SIZE);
finfo->frames[c_ts].pkts_received += 1;
finfo->frames[c_ts].total_size += (frame->payload_len - HEVC_HDR_SIZE);
if (frag_type == FT_START)
finfo[c_ts].s_seq = c_seq;
finfo->frames[c_ts].s_seq = c_seq;
if (frag_type == FT_END)
finfo[c_ts].e_seq = c_seq;
finfo->frames[c_ts].e_seq = c_seq;
if (finfo[c_ts].s_seq != INVALID_SEQ && finfo[c_ts].e_seq != INVALID_SEQ) {
if (finfo->frames[c_ts].s_seq != INVALID_SEQ && finfo->frames[c_ts].e_seq != INVALID_SEQ) {
size_t received = 0;
size_t fptr = 0;
size_t s_seq = finfo[c_ts].s_seq;
size_t e_seq = finfo[c_ts].e_seq;
size_t s_seq = finfo->frames[c_ts].s_seq;
size_t e_seq = finfo->frames[c_ts].e_seq;
if (s_seq > e_seq)
received = 0xffff - s_seq + e_seq + 2;
@ -201,12 +174,12 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
received = e_seq - s_seq + 1;
/* we've received every fragment and the frame can be reconstructed */
if (received == finfo[c_ts].pkts_received) {
if (received == finfo->frames[c_ts].pkts_received) {
/* intra is still in progress, do not return the inter */
if (nal_type == NT_INTER && intra != INVALID_TS && enable_idelay) {
__drop_frame(finfo, c_ts);
dropped.insert(c_ts);
finfo->dropped.insert(c_ts);
return RTP_OK;
}
@ -214,10 +187,10 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
(uint8_t)((frame->payload[0] & 0x81) | ((frame->payload[2] & 0x3f) << 1)),
(uint8_t)frame->payload[1]
};
/* uvg_rtp::frame::rtp_frame *out = uvg_rtp::frame::alloc_rtp_frame(); */
uvg_rtp::frame::rtp_frame *complete = uvg_rtp::frame::alloc_rtp_frame();
complete->payload_len = finfo[c_ts].total_size + uvg_rtp::frame::HEADER_SIZE_HEVC_NAL;
complete->payload_len = finfo->frames[c_ts].total_size + uvg_rtp::frame::HEADER_SIZE_HEVC_NAL;
complete->payload = new uint8_t[complete->payload_len];
std::memcpy(&complete->header, &(*out)->header, RTP_HDR_SIZE);
@ -225,7 +198,7 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
fptr += uvg_rtp::frame::HEADER_SIZE_HEVC_NAL;
for (auto& fragment : finfo.at(c_ts).fragments) {
for (auto& fragment : finfo->frames.at(c_ts).fragments) {
std::memcpy(
&complete->payload[fptr],
&fragment.second->payload[HEVC_HDR_SIZE],
@ -239,15 +212,15 @@ rtp_error_t uvg_rtp::formats::hevc::packet_handler(void *arg, int flags, uvg_rtp
intra = INVALID_TS;
*out = complete;
finfo.erase(c_ts);
finfo->frames.erase(c_ts);
return RTP_PKT_READY;
}
}
if (__frame_late(finfo.at(c_ts))) {
if (__frame_late(finfo->frames.at(c_ts))) {
if (nal_type != NT_INTRA || (nal_type == NT_INTRA && !enable_idelay)) {
__drop_frame(finfo, c_ts);
dropped.insert(c_ts);
finfo->dropped.insert(c_ts);
}
}

View File

@ -135,7 +135,7 @@ rtp_error_t uvg_rtp::media_stream::init()
media_ = new uvg_rtp::formats::hevc(socket_, rtp_, ctx_config_.flags);
pkt_dispatcher_->install_aux_handler(
rtp_handler_key_,
nullptr,
dynamic_cast<uvg_rtp::formats::hevc *>(media_)->get_hevc_frame_info(),
dynamic_cast<uvg_rtp::formats::hevc *>(media_)->packet_handler
);
break;