Commit 3cedee87 authored by François Grisez's avatar François Grisez
Browse files

Create an abstract class for packers

parent e2fdd202
......@@ -292,7 +292,7 @@ typedef struct {
static void *h264_module_new(MSFactory *factory) {
H264Module *mod = bctbx_new0(H264Module, 1);
mod->packer = new Rfc3984Packer(factory);
mod->packer->setMode(Rfc3984Packer::NonInterleavedMode);
mod->packer->setMode(Packer::NonInterleavedMode);
mod->unpacker = new Rfc3984Unpacker();
return mod;
}
......
......@@ -30,114 +30,21 @@ using namespace std;
namespace mediastreamer2 {
// ========================
// H264NaluToStapAggregator
// ========================
void H264NaluToStapAggregator::setMaxSize(size_t maxSize) {
if (isAggregating()) {
throw logic_error("changing payload size while aggregating NALus into a STAP-A");
}
_maxsize = maxSize;
}
mblk_t *H264NaluToStapAggregator::feedNalu(mblk_t *nalu) {
size_t size = msgdsize(nalu);
if (_stap == nullptr) {
_stap = nalu;
_size = size + 3; /* STAP-A header + size */
} else {
if ((_size + size) < (_maxsize - 2)) {
_stap = concatNalus(_stap, nalu);
_size += (size + 2); /* +2 for the STAP-A size field */
} else {
return completeAggregation();
}
}
return nullptr;
}
void H264NaluToStapAggregator::reset() {
if (_stap) freemsg(_stap);
_size = 0;
}
mblk_t *H264NaluToStapAggregator::completeAggregation() {
mblk_t *res = _stap;
_stap = nullptr;
reset();
return res;
}
mblk_t *H264NaluToStapAggregator::concatNalus(mblk_t *m1, mblk_t *m2) {
mblk_t *l = allocb(2, 0);
/*eventually append a STAP-A header to m1, if not already done*/
if (ms_h264_nalu_get_type(m1) != MSH264NaluTypeSTAPA) {
m1 = prependStapA(m1);
}
putNalSize(l, msgdsize(m2));
l->b_cont = m2;
concatb(m1, l);
return m1;
}
mblk_t *H264NaluToStapAggregator::prependStapA(mblk_t *m) {
mblk_t *hm = allocb(3, 0);
H264Tools::nalHeaderInit(hm->b_wptr, ms_h264_nalu_get_nri(m), MSH264NaluTypeSTAPA);
hm->b_wptr += 1;
putNalSize(hm, msgdsize(m));
hm->b_cont = m;
return hm;
}
void H264NaluToStapAggregator::putNalSize(mblk_t *m, size_t sz) {
uint16_t size = htons((uint16_t)sz);
*(uint16_t *)m->b_wptr = size;
m->b_wptr += 2;
}
//=================================================
// H264NalToFuaSpliter class
//=================================================
void H264NaluToFuaSpliter::feedNalu(mblk_t *nalu) {
mblk_t *m;
int payload_max_size = _maxsize - 2; /*minus FU-A header*/
uint8_t fu_indicator;
uint8_t type = ms_h264_nalu_get_type(nalu);
uint8_t nri = ms_h264_nalu_get_nri(nalu);
bool start = true;
H264Tools::nalHeaderInit(&fu_indicator, nri, MSH264NaluTypeFUA);
while (nalu->b_wptr - nalu->b_rptr > payload_max_size) {
m = dupb(nalu);
nalu->b_rptr += payload_max_size;
m->b_wptr = nalu->b_rptr;
m = H264Tools::prependFuIndicatorAndHeader(m, fu_indicator, start, FALSE, type);
ms_queue_put(&_q, m);
start = false;
}
/*send last packet */
m = H264Tools::prependFuIndicatorAndHeader(nalu, fu_indicator, FALSE, TRUE, type);
ms_queue_put(&_q, m);
}
//=================================================
// Rfc3984Pacer class
//=================================================
// ======
// Packer
// ======
Rfc3984Packer::Rfc3984Packer(MSFactory *factory): _spliter(new H264NaluToFuaSpliter()), _aggregator(new H264NaluToStapAggregator()) {
Packer::Packer(SpliterInterface *spliter, AggregatorInterface *aggregator, MSFactory *factory): _spliter(spliter), _aggregator(aggregator) {
setMaxPayloadSize(ms_factory_get_payload_max_size(factory));
}
void Rfc3984Packer::setMaxPayloadSize(size_t size) {
void Packer::setMaxPayloadSize(size_t size) {
_maxSize = size;
_spliter->setMaxSize(size);
_aggregator->setMaxSize(size);
}
void Rfc3984Packer::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
void Packer::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
switch (_mode) {
case SingleNalUnitMode:
packInSingleNalUnitMode(naluq, rtpq, ts);
......@@ -149,7 +56,7 @@ void Rfc3984Packer::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
}
// Private methods
void Rfc3984Packer::packInSingleNalUnitMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
void Packer::packInSingleNalUnitMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
while (mblk_t *m = ms_queue_get(naluq)) {
bool end = ms_queue_empty(naluq);
size_t size = msgdsize(m);
......@@ -160,7 +67,7 @@ void Rfc3984Packer::packInSingleNalUnitMode(MSQueue *naluq, MSQueue *rtpq, uint3
}
}
void Rfc3984Packer::packInNonInterleavedMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
void Packer::packInNonInterleavedMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
while (mblk_t *m = ms_queue_get(naluq)) {
bool end = ms_queue_empty(naluq);
size_t sz = msgdsize(m);
......@@ -199,7 +106,7 @@ void Rfc3984Packer::packInNonInterleavedMode(MSQueue *naluq, MSQueue *rtpq, uint
}
}
void Rfc3984Packer::fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker) {
void Packer::fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker) {
_spliter->feedNalu(nalu);
MSQueue *nalus = _spliter->getNalus();
while (mblk_t *m = ms_queue_get(nalus)) {
......@@ -207,16 +114,109 @@ void Rfc3984Packer::fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bo
}
}
void Rfc3984Packer::sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker) {
void Packer::sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker) {
mblk_set_timestamp_info(m, ts);
mblk_set_marker_info(m, marker);
mblk_set_cseq(m, _refCSeq++);
ms_queue_put(rtpq, m);
}
// ================
// AbstractUnpacker
// ================
// ========================
// H264NaluToStapAggregator
// ========================
void H264NaluToStapAggregator::setMaxSize(size_t maxSize) {
if (isAggregating()) {
throw logic_error("changing payload size while aggregating NALus into a STAP-A");
}
_maxsize = maxSize;
}
mblk_t *H264NaluToStapAggregator::feedNalu(mblk_t *nalu) {
size_t size = msgdsize(nalu);
if (_stap == nullptr) {
_stap = nalu;
_size = size + 3; /* STAP-A header + size */
} else {
if ((_size + size) < (_maxsize - 2)) {
_stap = concatNalus(_stap, nalu);
_size += (size + 2); /* +2 for the STAP-A size field */
} else {
return completeAggregation();
}
}
return nullptr;
}
void H264NaluToStapAggregator::reset() {
if (_stap) freemsg(_stap);
_size = 0;
}
mblk_t *H264NaluToStapAggregator::completeAggregation() {
mblk_t *res = _stap;
_stap = nullptr;
reset();
return res;
}
mblk_t *H264NaluToStapAggregator::concatNalus(mblk_t *m1, mblk_t *m2) {
mblk_t *l = allocb(2, 0);
/*eventually append a STAP-A header to m1, if not already done*/
if (ms_h264_nalu_get_type(m1) != MSH264NaluTypeSTAPA) {
m1 = prependStapA(m1);
}
putNalSize(l, msgdsize(m2));
l->b_cont = m2;
concatb(m1, l);
return m1;
}
mblk_t *H264NaluToStapAggregator::prependStapA(mblk_t *m) {
mblk_t *hm = allocb(3, 0);
H264Tools::nalHeaderInit(hm->b_wptr, ms_h264_nalu_get_nri(m), MSH264NaluTypeSTAPA);
hm->b_wptr += 1;
putNalSize(hm, msgdsize(m));
hm->b_cont = m;
return hm;
}
void H264NaluToStapAggregator::putNalSize(mblk_t *m, size_t sz) {
uint16_t size = htons((uint16_t)sz);
*(uint16_t *)m->b_wptr = size;
m->b_wptr += 2;
}
// =========================
// H264NalToFuaSpliter class
// =========================
void H264NaluToFuaSpliter::feedNalu(mblk_t *nalu) {
mblk_t *m;
int payload_max_size = _maxsize - 2; /*minus FU-A header*/
uint8_t fu_indicator;
uint8_t type = ms_h264_nalu_get_type(nalu);
uint8_t nri = ms_h264_nalu_get_nri(nalu);
bool start = true;
H264Tools::nalHeaderInit(&fu_indicator, nri, MSH264NaluTypeFUA);
while (nalu->b_wptr - nalu->b_rptr > payload_max_size) {
m = dupb(nalu);
nalu->b_rptr += payload_max_size;
m->b_wptr = nalu->b_rptr;
m = H264Tools::prependFuIndicatorAndHeader(m, fu_indicator, start, FALSE, type);
ms_queue_put(&_q, m);
start = false;
}
/*send last packet */
m = H264Tools::prependFuIndicatorAndHeader(nalu, fu_indicator, FALSE, TRUE, type);
ms_queue_put(&_q, m);
}
// ========
// Unpacker
// ========
Unpacker::Unpacker(NaluAggregatorInterface *aggregator, NaluSpliterInterface *spliter): _naluAggregator(aggregator), _naluSpliter(spliter) {
ms_queue_init(&_q);
......@@ -484,7 +484,7 @@ extern "C" {
ms_error("invalid RFC3984 packetization mode [%d]", mode);
return;
}
ctx->packer.setMode(mode == 0 ? mediastreamer2::Rfc3984Packer::SingleNalUnitMode : mediastreamer2::Rfc3984Packer::SingleNalUnitMode);
ctx->packer.setMode(mode == 0 ? mediastreamer2::Packer::SingleNalUnitMode : mediastreamer2::Packer::SingleNalUnitMode);
}
void rfc3984_enable_stap_a(Rfc3984Context *ctx, bool_t yesno) {
......
......@@ -49,13 +49,74 @@ public:
virtual MSQueue *getNalus() = 0;
};
class H264NaluToStapAggregator: public NaluAggregatorInterface {
class Packer {
public:
enum PacketizationMode {
SingleNalUnitMode,
NonInterleavedMode
};
class AggregatorInterface {
public:
virtual ~AggregatorInterface() = default;
virtual size_t getMaxSize() const = 0;
virtual void setMaxSize(size_t maxSize) = 0;
virtual mblk_t *feedNalu(mblk_t *nalu) = 0;
virtual bool isAggregating() const = 0;
virtual void reset() = 0;
virtual mblk_t *completeAggregation() = 0;
};
class SpliterInterface {
public:
virtual ~SpliterInterface() = default;
virtual size_t getMaxSize() const = 0;
virtual void setMaxSize(size_t maxSize) = 0;
virtual void feedNalu(mblk_t *nalu) = 0;
virtual MSQueue *getNalus() = 0;
};
Packer(SpliterInterface *spliter, AggregatorInterface *aggregator) {}
Packer(SpliterInterface *spliter, AggregatorInterface *aggregator, MSFactory *factory);
void setMode(PacketizationMode mode) {_mode = mode;}
PacketizationMode getMode() const {return _mode;}
// some stupid phones don't decode STAP-A packets ...
void enableAggregation(bool yesno) {_aggregationEnabled = yesno;}
bool aggregationEnabled() const {return _aggregationEnabled;}
void setMaxPayloadSize(size_t size);
size_t getMaxPayloadSize() {return _maxSize;}
// process NALus and pack them into RTP payloads
void pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
private:
void packInSingleNalUnitMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void packInNonInterleavedMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker);
void sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker);
size_t _maxSize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
uint16_t _refCSeq = 0;
PacketizationMode _mode = SingleNalUnitMode;
bool _aggregationEnabled = false;
std::unique_ptr<SpliterInterface> _spliter;
std::unique_ptr<AggregatorInterface> _aggregator;
};
class H264NaluToStapAggregator: public Packer::AggregatorInterface {
public:
H264NaluToStapAggregator() {}
~H264NaluToStapAggregator() {reset();}
size_t getMaxSize() const {return _maxsize;}
void setMaxSize(size_t maxSize);
size_t getMaxSize() const override {return _maxsize;}
void setMaxSize(size_t maxSize) override;
mblk_t *feedNalu(mblk_t *nalu) override;
bool isAggregating() const override {return bool(_stap);}
......@@ -72,13 +133,13 @@ private:
size_t _maxsize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
};
class H264NaluToFuaSpliter: public NaluSpliterInterface {
class H264NaluToFuaSpliter: public Packer::SpliterInterface {
public:
H264NaluToFuaSpliter() {ms_queue_init(&_q);}
~H264NaluToFuaSpliter() {ms_queue_flush(&_q);}
size_t getMaxSize() const {return _maxsize;}
void setMaxSize(size_t maxSize) {_maxsize = maxSize;}
size_t getMaxSize() const override {return _maxsize;}
void setMaxSize(size_t maxSize) override {_maxsize = maxSize;}
void feedNalu(mblk_t *nalu) override;
MSQueue *getNalus() override {return &_q;};
......@@ -88,45 +149,15 @@ private:
MSQueue _q;
};
class Rfc3984Packer {
class Rfc3984Packer: public Packer {
public:
enum PacketizationMode {
SingleNalUnitMode,
NonInterleavedMode
};
Rfc3984Packer(): _spliter(new H264NaluToFuaSpliter()), _aggregator(new H264NaluToStapAggregator()) {}
Rfc3984Packer(MSFactory *factory);
void setMode(PacketizationMode mode) {_mode = mode;}
PacketizationMode getMode() const {return _mode;}
// some stupid phones don't decode STAP-A packets ...
void enableAggregation(bool yesno) {_aggregationEnabled = yesno;}
bool aggregationEnabled() const {return _aggregationEnabled;}
void setMaxPayloadSize(size_t size);
size_t getMaxPayloadSize() {return _maxSize;}
// process NALus and pack them into RTP payloads
void pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
private:
void packInSingleNalUnitMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void packInNonInterleavedMode(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker);
void sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker);
static mblk_t *concatNalus(mblk_t *m1, mblk_t *m2);
static mblk_t *prependStapA(mblk_t *m);
static void putNalSize(mblk_t *m, size_t sz);
size_t _maxSize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
uint16_t _refCSeq = 0;
PacketizationMode _mode = SingleNalUnitMode;
bool _aggregationEnabled = false;
std::unique_ptr<H264NaluToFuaSpliter> _spliter;
std::unique_ptr<H264NaluToStapAggregator> _aggregator;
Rfc3984Packer(): Packer(new H264NaluToFuaSpliter(), new H264NaluToStapAggregator()) {}
Rfc3984Packer(MSFactory *factory): Packer(new H264NaluToFuaSpliter(), new H264NaluToStapAggregator(), factory) {}
};
class Unpacker {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment