Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

av1: improve packetizer #1088

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/re_av1.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ int av1_obu_print(struct re_printf *pf, const struct av1_obu_hdr *hdr);
unsigned av1_obu_count(const uint8_t *buf, size_t size);
unsigned av1_obu_count_rtp(const uint8_t *buf, size_t size);
const char *av1_obu_name(enum obu_type type);
bool obu_allowed_rtp(enum obu_type type);


/*
Expand All @@ -59,6 +60,9 @@ typedef int (av1_packet_h)(bool marker, uint64_t rtp_ts,
int av1_packetize_high(bool *newp, bool marker, uint64_t rtp_ts,
const uint8_t *buf, size_t len, size_t maxlen,
av1_packet_h *pkth, void *arg);
int av1_packetize_one_w(bool *newp, bool marker, uint64_t rtp_ts,
const uint8_t *buf, size_t len, size_t maxlen,
av1_packet_h *pkth, void *arg);


enum {
Expand Down
2 changes: 1 addition & 1 deletion src/av1/obu.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <re_dbg.h>


static bool obu_allowed_rtp(enum obu_type type)
bool obu_allowed_rtp(enum obu_type type)
{
switch (type) {

Expand Down
152 changes: 140 additions & 12 deletions src/av1/pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,35 @@ enum {
};


/*
* Calculate length of LEB128 field
*
* Add high 1 bits on all but last (most significant) group to form bytes
*/
static size_t leb128_calc_size(uint64_t value)
{
size_t bytes = 1;

/* Bit7: 1=more bytes coming, 0=complete */
while (value >= 0x80) {

++bytes;

value >>= 7;
}

return bytes;
}


/*
* Z: MUST be set to 1 if the first OBU element is an OBU fragment that is a
* continuation of an OBU fragment from the previous packet, and MUST be
* set to 0 otherwise.
*
* Y: MUST be set to 1 if the last OBU element is an OBU fragment that will
* continue in the next packet, and MUST be set to 0 otherwise.
*/
static void hdr_encode(uint8_t hdr[AV1_AGGR_HDR_SIZE],
bool z, bool y, uint8_t w, bool n)
{
Expand Down Expand Up @@ -51,7 +80,7 @@ static struct mbuf *encode_obu(uint8_t type, const uint8_t *p, size_t len)


static int copy_obus(struct mbuf *mb_pkt, const uint8_t *buf, size_t size,
bool w0)
bool w0, size_t maxlen, unsigned *small_obus)
{
struct mbuf wrap = {
.buf = (uint8_t *)buf,
Expand All @@ -60,12 +89,16 @@ static int copy_obus(struct mbuf *mb_pkt, const uint8_t *buf, size_t size,
.end = size
};
struct mbuf *mb_obu = NULL;
size_t accum = AV1_AGGR_HDR_SIZE;
unsigned count = 0;
enum { OBU_HEADER_SIZE=1 };
int err = 0;

while (mbuf_get_left(&wrap) >= 2) {

struct av1_obu_hdr hdr;
bool last;
size_t tmp;

err = av1_obu_decode(&hdr, &wrap);
if (err) {
Expand Down Expand Up @@ -107,6 +140,17 @@ static int copy_obus(struct mbuf *mb_pkt, const uint8_t *buf, size_t size,
if (err)
goto out;

/* Count number of small OBUs that fits */

tmp = OBU_HEADER_SIZE
+ leb128_calc_size(hdr.size)
+ hdr.size;

accum += tmp;

if (accum < maxlen) {
++count;
}
break;

case AV1_OBU_TEMPORAL_DELIMITER:
Expand All @@ -125,6 +169,9 @@ static int copy_obus(struct mbuf *mb_pkt, const uint8_t *buf, size_t size,
mb_obu = mem_deref(mb_obu);
}

if (small_obus)
*small_obus = count;

out:
mem_deref(mb_obu);
return err;
Expand All @@ -134,13 +181,13 @@ static int copy_obus(struct mbuf *mb_pkt, const uint8_t *buf, size_t size,
static int av1_packetize_internal(bool *newp, bool marker, uint64_t rtp_ts,
const uint8_t *buf, size_t len,
size_t maxlen, uint8_t w,
bool use_w_field, unsigned small_obus,
av1_packet_h *pkth, void *arg)
{
uint8_t hdr[AV1_AGGR_HDR_SIZE];
bool cont = false;
bool z_cont = false;
int err = 0;


if (w > 3) {
DEBUG_WARNING("w too large\n");
return EPROTO;
Expand All @@ -150,21 +197,25 @@ static int av1_packetize_internal(bool *newp, bool marker, uint64_t rtp_ts,

while (len > maxlen) {

hdr_encode(hdr, cont, true, w, *newp);
hdr_encode(hdr, z_cont, true, w, *newp);
*newp = false;

err |= pkth(false, rtp_ts, hdr, sizeof(hdr), buf, maxlen, arg);

buf += maxlen;
len -= maxlen;
cont = true;
z_cont = true;

/* If OBUs are fragmented */
if (w == 2)
w = 1;
if (use_w_field && small_obus > 0) {

if (w==2 || w==3) {
w -= small_obus;
}
}
}

hdr_encode(hdr, cont, false, w, *newp);
hdr_encode(hdr, z_cont, false, w, *newp);
*newp = false;

err |= pkth(marker, rtp_ts, hdr, sizeof(hdr), buf, len, arg);
Expand Down Expand Up @@ -212,18 +263,95 @@ int av1_packetize_high(bool *newp, bool marker, uint64_t rtp_ts,
w = count;
}

err = copy_obus(mb_pkt, buf, len, count > MAX_OBUS);
bool use_w_field = count <= MAX_OBUS;
unsigned small_obus = 0;

err = copy_obus(mb_pkt, buf, len, count > MAX_OBUS,
maxlen, &small_obus);
if (err)
goto out;

err = av1_packetize_internal(newp, marker, rtp_ts,
mb_pkt->buf, mb_pkt->end, maxlen,
w,
w, use_w_field, small_obus,
pkth, arg);
if (err)
goto out;

out:
mem_deref(mb_pkt);
return err;
}


/**
* Packetize an AV1 bitstream with one or more OBUs, using W=1 mode
*
* @param newp Pointer to new stream flag
* @param marker Set marker bit
* @param rtp_ts RTP timestamp
* @param buf Input buffer
* @param len Buffer length
* @param maxlen Maximum RTP packet size
* @param pkth Packet handler
* @param arg Handler argument
*
* @return 0 if success, otherwise errorcode
*
* W: two bit field that describes the number of OBU elements in the packet.
* This field MUST be set equal to 0 or equal to the number of OBU elements
* contained in the packet. If set to 0, each OBU element MUST be preceded
* by a length field.
* If not set to 0 (i.e., W = 1, 2 or 3) the last OBU element MUST NOT be
* preceded by a length field.
*
*/
int av1_packetize_one_w(bool *newp, bool marker, uint64_t rtp_ts,
const uint8_t *buf, size_t len, size_t maxlen,
av1_packet_h *pkth, void *arg)
{
struct mbuf wrap = {
.buf = (uint8_t *)buf,
.size = len,
.pos = 0,
.end = len
};
int err = 0;

while (mbuf_get_left(&wrap) >= 2) {

struct av1_obu_hdr hdr;
size_t start = wrap.pos;

err = av1_obu_decode(&hdr, &wrap);
if (err) {
DEBUG_WARNING("av1: encode: hdr dec error (%m)\n",
err);
return err;
}

if (obu_allowed_rtp(hdr.type)) {

size_t header_size = wrap.pos - start;
size_t total_size = header_size + hdr.size;
bool last = (hdr.size == mbuf_get_left(&wrap));
bool use_w_field = true;

err = av1_packetize_internal(newp,
marker && last,
rtp_ts,
&wrap.buf[start],
total_size,
maxlen,
1,
use_w_field,
0,
pkth,
arg);
if (err)
return err;
}

mbuf_advance(&wrap, hdr.size);
}

return err;
}
Loading