Save HEVC frame info to the HEVC object
This commit is contained in:
parent
7b50e99aa0
commit
7559482a84
|
@ -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_;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue