Commit 197839e9 authored by François Grisez's avatar François Grisez
Browse files

Remove unpacking methods from Rfc3984Context class.

parent d99fed8b
......@@ -76,7 +76,7 @@ void ms_h264_bitstream_to_nalus(const uint8_t *bitstream, size_t size, MSQueue *
if (begin) push_nalu(begin, p, nalus);
}
uint8_t ms_h264_nulu_get_nri(const mblk_t *nalu) {
uint8_t ms_h264_nalu_get_nri(const mblk_t *nalu) {
return ((*nalu->b_rptr) >> 5) & 0x3;
}
......
......@@ -43,7 +43,7 @@ extern "C" {
/**
* Extract the NRI value from NALu header.
*/
uint8_t ms_h264_nulu_get_nri(const mblk_t *nalu);
uint8_t ms_h264_nalu_get_nri(const mblk_t *nalu);
/**
* Get the type of a NAL unit
......
......@@ -50,7 +50,7 @@ using namespace b64;
typedef struct _DecData{
mblk_t *sps,*pps;
AVFrame* orig;
Rfc3984Context *unpacker;
Rfc3984Unpacker *unpacker;
MSVideoSize vsize;
struct SwsContext *sws_ctx;
MSAverageFPS fps;
......@@ -90,7 +90,7 @@ static void dec_init(MSFilter *f){
d->sps=NULL;
d->pps=NULL;
d->sws_ctx=NULL;
d->unpacker = new Rfc3984Context();
d->unpacker = new Rfc3984Unpacker();
d->packet_num=0;
dec_open(d);
d->vsize.width=0;
......@@ -289,7 +289,7 @@ static void dec_process(MSFilter *f){
// Reset all contexts when an empty packet is received
if(msgdsize(im) == 0) {
delete d->unpacker;
d->unpacker = new Rfc3984Context();
d->unpacker = new Rfc3984Unpacker();
dec_reinit(d);
ms_stream_regulator_reset(d->regulator);
freemsg(im);
......@@ -303,7 +303,7 @@ static void dec_process(MSFilter *f){
}
ret = d->unpacker->unpack(im,&nalus);
if (ret & Rfc3984Context::Status::FrameAvailable){
if (ret & Rfc3984Unpacker::Status::FrameAvailable){
int size;
uint8_t *p,*end;
bool_t need_reinit=FALSE;
......@@ -339,7 +339,7 @@ static void dec_process(MSFilter *f){
}
p+=len;
}
if (ret & Rfc3984Context::Status::FrameCorrupted) requestPLI = TRUE;
if (ret & Rfc3984Unpacker::Status::FrameCorrupted) requestPLI = TRUE;
}
d->packet_num++;
}
......
......@@ -284,6 +284,7 @@ static void H264Private_load(H264Private *obj, const uint8_t *data) {
/* h264 module */
typedef struct {
Rfc3984Context *rfc3984Context;
Rfc3984Unpacker *unpacker;
H264Private *codecPrivate;
H264Private *lastCodecPrivate;
} H264Module;
......@@ -292,12 +293,14 @@ static void *h264_module_new(MSFactory *factory) {
H264Module *mod = bctbx_new0(H264Module, 1);
mod->rfc3984Context = new Rfc3984Context(factory);
mod->rfc3984Context->setMode(1);
mod->unpacker = new Rfc3984Unpacker();
return mod;
}
static void h264_module_free(void *data) {
H264Module *obj = (H264Module *)data;
delete obj->rfc3984Context;
delete obj->unpacker;
if(obj->codecPrivate != NULL) H264Private_free(obj->codecPrivate);
if(obj->lastCodecPrivate != NULL) H264Private_free(obj->lastCodecPrivate);
bctbx_free(obj);
......@@ -310,7 +313,7 @@ static int h264_module_preprocessing(void *data, MSQueue *input, MSQueue *output
ms_queue_init(&queue);
while((inputBuffer = ms_queue_get(input)) != NULL) {
obj->rfc3984Context->unpack(inputBuffer, &queue);
obj->unpacker->unpack(inputBuffer, &queue);
if(!ms_queue_empty(&queue)) {
mblk_t *frame = ms_queue_get(&queue);
mblk_t *end = frame;
......
......@@ -27,36 +27,11 @@ using namespace std;
namespace mediastreamer2 {
Rfc3984Context::Rfc3984Context() {
ms_queue_init(&_q);
}
Rfc3984Context::Rfc3984Context::Rfc3984Context(MSFactory* factory) {
ms_queue_init(&_q);
setMaxPayloadSize(ms_factory_get_payload_max_size(factory));
}
Rfc3984Context::~Rfc3984Context() {
ms_queue_flush(&_q);
if (_m != nullptr) freemsg(_m);
if (_SPS != nullptr) freemsg(_SPS);
if (_PPS != nullptr) freemsg(_PPS);
if (_lastPPS != nullptr) freemsg(_lastPPS);
if (_lastSPS != nullptr) freemsg(_lastSPS);
}
void Rfc3984Context::setOutOfBandSpsPps(mblk_t *sps, mblk_t *pps){
if (_SPS){
freemsg(_SPS);
}
if (_PPS){
freemsg(_PPS);
}
_SPS = sps;
_PPS = pps;
}
void Rfc3984Context::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
switch(_mode){
case 0:
......@@ -70,89 +45,6 @@ void Rfc3984Context::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
}
}
unsigned int Rfc3984Context::unpack(mblk_t *im, MSQueue *out) {
uint8_t type=ms_h264_nalu_get_type(im);
uint8_t *p;
int marker = mblk_get_marker_info(im);
uint32_t ts=mblk_get_timestamp_info(im);
uint16_t cseq=mblk_get_cseq(im);
unsigned int ret = 0;
//ms_message("Seeing timestamp %u, sequence %u", ts, (int)cseq);
if (_lastTs !=ts){
/*a new frame is arriving, in case the marker bit was not set in previous frame, output it now,
* unless it is a FU-A packet (workaround for buggy implementations)*/
_lastTs =ts;
if (_m ==NULL && !ms_queue_empty(&_q)){
ret = _outputFrame(out, ((unsigned int)Status::FrameAvailable) | (unsigned int)Status::FrameCorrupted);
ms_warning("Incomplete H264 frame (missing marker bit after seq number %u)",
mblk_get_cseq(ms_queue_peek_last(out)));
}
}
if (im->b_cont) msgpullup(im,-1);
if (!_initializedRefCSeq) {
_initializedRefCSeq = TRUE;
_refCSeq = cseq;
} else {
_refCSeq++;
if (_refCSeq != cseq) {
ms_message("sequence inconsistency detected (diff=%i)",(int)(cseq - _refCSeq));
_refCSeq = cseq;
_status |= (unsigned int)Status::FrameCorrupted;
}
}
if (type==MSH264NaluTypeSTAPA){
/*split into nalus*/
uint16_t sz;
uint8_t *buf=(uint8_t*)&sz;
mblk_t *nal;
ms_debug("Receiving STAP-A");
for(p=im->b_rptr+1;p<im->b_wptr;){
buf[0]=p[0];
buf[1]=p[1];
sz=ntohs(sz);
nal=dupb(im);
p+=2;
nal->b_rptr=p;
p+=sz;
nal->b_wptr=p;
if (p>im->b_wptr){
ms_error("Malformed STAP-A packet");
freemsg(nal);
break;
}
_storeNal(nal);
}
freemsg(im);
}else if (type==MSH264NaluTypeFUA){
mblk_t *o= _aggregateFUA(im);
ms_debug("Receiving FU-A");
if (o) _storeNal(o);
}else{
if (_m){
/*discontinued FU-A, purge it*/
freemsg(_m);
_m =NULL;
}
/*single nal unit*/
ms_debug("Receiving single NAL");
_storeNal(im);
}
if (marker){
_lastTs =ts;
ms_debug("Marker bit set");
ret = _outputFrame(out, (unsigned int)Status::FrameAvailable);
}
return ret;
}
// Private methods
void Rfc3984Context::_packMode0(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
mblk_t *m;
......@@ -231,7 +123,7 @@ void Rfc3984Context::_fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu,
int payload_max_size=maxsize-2;/*minus FUA header*/
uint8_t fu_indicator;
uint8_t type=ms_h264_nalu_get_type(nalu);
uint8_t nri= _nalHeaderGetNri(nalu->b_rptr);
uint8_t nri= ms_h264_nalu_get_nri(nalu);
bool_t start=TRUE;
_nalHeaderInit(&fu_indicator,nri,MSH264NaluTypeFUA);
......@@ -255,110 +147,6 @@ void Rfc3984Context::_sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t m
ms_queue_put(rtpq,m);
}
unsigned int Rfc3984Context::_outputFrame(MSQueue *out, unsigned int flags){
unsigned int res = _status;
if (!ms_queue_empty(out)){
ms_warning("rfc3984_unpack: output_frame invoked several times in a row, this should not happen");
}
res |= flags;
if ((res & Status::IsKeyFrame) && _SPS && _PPS){
/*prepend out of band provided sps and pps*/
ms_queue_put(out, _SPS);
_SPS = NULL;
ms_queue_put(out, _PPS);
_PPS = NULL;
}
/* Log some bizarre things */
if ((res & Status::FrameCorrupted) == 0){
if ((res & Status::HasSPS) && (res & Status::HasPPS) && !(res & Status::HasIDR) && !(res & Status::IsKeyFrame)){
/*some decoders may not be happy with this*/
ms_warning("rfc3984_unpack: a frame with SPS+PPS but no IDR was output, starting at seq number %u",
mblk_get_cseq(ms_queue_peek_first(&_q)));
}
}
while(!ms_queue_empty(&_q)){
ms_queue_put(out,ms_queue_get(&_q));
}
_status = 0;
return res;
}
void Rfc3984Context::_storeNal(mblk_t *nal) {
uint8_t type=ms_h264_nalu_get_type(nal);
if ((_status & Status::HasSPS) && (_status & Status::HasPPS) && type != MSH264NaluTypeIDR && mblk_get_marker_info(nal) && _isUniqueISlice(nal->b_rptr+1)){
ms_warning("Receiving a nal unit which is not IDR but a single I-slice bundled with SPS & PPS - considering it as a key frame.");
_status |= Status::IsKeyFrame;
}
if (type == MSH264NaluTypeIDR){
_status |= Status::HasIDR;
_status |= Status::IsKeyFrame;
}else if (type == MSH264NaluTypeSPS){
_status |= Status::HasSPS;
if (_updateParameterSet(&_lastSPS, nal)) {
_status |= Status::NewSPS;
}
}
else if (type == MSH264NaluTypePPS){
_status |= Status::HasPPS;
if (_updateParameterSet(&_lastPPS, nal)) {
_status |= Status::NewPPS;
}
}
ms_queue_put(&_q,nal);
}
mblk_t *Rfc3984Context::_aggregateFUA(mblk_t *im){
mblk_t *om=NULL;
uint8_t fu_header;
uint8_t nri,type;
bool_t start,end;
bool_t marker = mblk_get_marker_info(im);
fu_header=im->b_rptr[1];
type=ms_h264_nalu_get_type(im);
start=fu_header>>7;
end=(fu_header>>6)&0x1;
if (start){
mblk_t *new_header;
nri= _nalHeaderGetNri(im->b_rptr);
if (_m !=NULL){
ms_error("receiving FU-A start while previous FU-A is not "
"finished");
freemsg(_m);
_m =NULL;
}
im->b_rptr+=2; /*skip the nal header and the fu header*/
new_header=allocb(1,0); /* allocate small fragment to put the correct nal header, this is to avoid to write on the buffer
which can break processing of other users of the buffers */
_nalHeaderInit(new_header->b_wptr,nri,type);
new_header->b_wptr++;
mblk_meta_copy(im,new_header);
concatb(new_header,im);
_m =new_header;
}else{
if (_m !=NULL){
im->b_rptr+=2;
concatb(_m,im);
}else{
ms_error("Receiving continuation FU packet but no start.");
freemsg(im);
}
}
if (end && _m){
msgpullup(_m,-1);
om=_m;
mblk_set_marker_info(om, marker); /*set the marker bit of this aggregated NAL as the last fragment received.*/
_m =NULL;
}
return om;
}
// Private static methods
mblk_t *Rfc3984Context::_concatNalus(mblk_t *m1, mblk_t *m2){
mblk_t *l=allocb(2,0);
......@@ -374,7 +162,7 @@ mblk_t *Rfc3984Context::_concatNalus(mblk_t *m1, mblk_t *m2){
mblk_t *Rfc3984Context::_prependStapA(mblk_t *m){
mblk_t *hm=allocb(3,0);
_nalHeaderInit(hm->b_wptr, _nalHeaderGetNri(m->b_rptr),MSH264NaluTypeSTAPA);
_nalHeaderInit(hm->b_wptr, ms_h264_nalu_get_nri(m),MSH264NaluTypeSTAPA);
hm->b_wptr+=1;
_putNalSize(hm,msgdsize(m));
hm->b_cont=m;
......@@ -397,11 +185,6 @@ mblk_t *Rfc3984Context::_prependFuIndicatorAndHeader(mblk_t *m, uint8_t indicato
return h;
}
int Rfc3984Context::_isUniqueISlice(const uint8_t *slice_header){
ms_message("is_unique_I_slice: %i", (int)*slice_header);
return slice_header[0] == 0x88; /*this corresponds to first_mb_in_slice to zero and slice_type = 7*/
}
bool_t Rfc3984Context::_updateParameterSet(mblk_t **last_parameter_set, mblk_t *new_parameter_set) {
if (*last_parameter_set != NULL) {
size_t last_size = (*last_parameter_set)->b_wptr - (*last_parameter_set)->b_rptr;
......@@ -419,24 +202,12 @@ bool_t Rfc3984Context::_updateParameterSet(mblk_t **last_parameter_set, mblk_t *
}
}
// Global public functions
unsigned int operator&(unsigned int val1, Rfc3984Context::Status val2) {
return val1 & static_cast<unsigned int>(val2);
}
unsigned int &operator&=(unsigned int &val1, Rfc3984Context::Status val2) {
return val1 &= static_cast<unsigned int>(val2);
}
unsigned int operator|(unsigned int val1, Rfc3984Context::Status val2) {
return val1 | static_cast<unsigned int>(val2);
}
unsigned int &operator|=(unsigned int &val1, Rfc3984Context::Status val2) {
return val1 |= static_cast<unsigned int>(val2);
}
//==================================================
// Rfc3984Unpacker
//==================================================
// Public methods
// --------------
Rfc3984Unpacker::Rfc3984Unpacker() {
ms_queue_init(&_q);
}
......@@ -540,6 +311,9 @@ unsigned int Rfc3984Unpacker::unpack(mblk_t *im, MSQueue *out) {
return ret;
}
// Private methods
// ---------------
unsigned int Rfc3984Unpacker::_outputFrame(MSQueue *out, unsigned int flags) {
unsigned int res = _status;
......@@ -627,7 +401,7 @@ mblk_t *Rfc3984Unpacker::_aggregateFUA(mblk_t *im) {
end = (fu_header >> 6) & 0x1;
if (start) {
mblk_t *new_header;
nri = ms_h264_nulu_get_nri(im);
nri = ms_h264_nalu_get_nri(im);
if (_m != NULL) {
ms_error("receiving FU-A start while previous FU-A is not "
"finished");
......@@ -665,7 +439,9 @@ int Rfc3984Unpacker::_isUniqueISlice(const uint8_t *slice_header) {
return slice_header[0] == 0x88; /*this corresponds to first_mb_in_slice to zero and slice_type = 7*/
}
//=================================================
// Global public functions
//=================================================
unsigned int operator&(unsigned int val1, Rfc3984Unpacker::Status val2) {
return val1 & static_cast<unsigned int>(val2);
}
......@@ -691,10 +467,11 @@ unsigned int &operator|=(unsigned int &val1, Rfc3984Unpacker::Status val2) {
struct _Rfc3984Context {
mediastreamer2::Rfc3984Context cppImpl;
mediastreamer2::Rfc3984Context packer;
mediastreamer2::Rfc3984Unpacker unpacker;
_Rfc3984Context() = default;
_Rfc3984Context(MSFactory *factory): cppImpl(factory) {}
_Rfc3984Context(MSFactory *factory): packer(factory), unpacker() {}
};
extern "C" {
......@@ -712,23 +489,23 @@ void rfc3984_destroy(Rfc3984Context *ctx) {
}
void rfc3984_set_mode(Rfc3984Context *ctx, int mode) {
ctx->cppImpl.setMode(mode);
ctx->packer.setMode(mode);
}
void rfc3984_enable_stap_a(Rfc3984Context *ctx, bool_t yesno) {
ctx->cppImpl.enableStapA(yesno);
ctx->packer.enableStapA(yesno);
}
void rfc3984_pack(Rfc3984Context *ctx, MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
ctx->cppImpl.pack(naluq, rtpq, ts);
ctx->packer.pack(naluq, rtpq, ts);
}
void rfc3984_unpack_out_of_band_sps_pps(Rfc3984Context *ctx, mblk_t *sps, mblk_t *pps) {
ctx->cppImpl.setOutOfBandSpsPps(sps, pps);
ctx->unpacker.setOutOfBandSpsPps(sps, pps);
}
unsigned int rfc3984_unpack2(Rfc3984Context *ctx, mblk_t *im, MSQueue *naluq) {
return ctx->cppImpl.unpack(im, naluq);
return ctx->unpacker.unpack(im, naluq);
}
}
......@@ -32,20 +32,8 @@ namespace mediastreamer2 {
class Rfc3984Context {
public:
enum class Status {
FrameAvailable = 1,
FrameCorrupted = 1<<1,
IsKeyFrame = 1<<2, // set when a frame has SPS + PPS or IDR (possibly both)
NewSPS = 1<<3,
NewPPS = 1<<4,
HasSPS = 1<<5,
HasPPS = 1<<6,
HasIDR = 1<<7,
};
Rfc3984Context();
Rfc3984Context() = default;
Rfc3984Context(MSFactory *factory);
~Rfc3984Context();
void setMode(int mode) {this->_mode = mode;}
int getMode() const {return this->_mode;}
......@@ -57,59 +45,28 @@ public:
void setMaxPayloadSize(int size) {this->_maxSize = size;}
int getMaxPayloadSize() {return this->_maxSize;}
void setOutOfBandSpsPps(mblk_t *sps, mblk_t *pps);
// process NALUs and pack them into rtp payloads
void pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
/**
* Process incoming rtp data and output NALUs, whenever possible.
* @param ctx the Rfc3984Context object
* @param im a new H264 packet to process
* @param naluq a MSQueue into which a frame ready to be decoded will be output, in the form of a sequence of NAL units.
* @return a bitmask of Rfc3984Status values.
* The return value is a bitmask of the #Rfc3984Status enum.
**/
unsigned int unpack(mblk_t *im, MSQueue *naluq);
private:
void _packMode0(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void _packMode1(MSQueue *naluq, MSQueue *rtpq, uint32_t ts);
void _fragNaluAndSend(MSQueue *rtpq, uint32_t ts, mblk_t *nalu, bool_t marker, int maxsize);
void _sendPacket(MSQueue *rtpq, uint32_t ts, mblk_t *m, bool_t marker);
unsigned int _outputFrame(MSQueue *out, unsigned int flags);
void _storeNal(mblk_t *nal);
mblk_t *_aggregateFUA(mblk_t *im);
static mblk_t *_concatNalus(mblk_t *m1, mblk_t *m2);
static mblk_t *_prependStapA(mblk_t *m);
static uint8_t _nalHeaderGetNri(const uint8_t *h) {return ((*h) >> 5) & 0x3;}
static void _nalHeaderInit(uint8_t *h, uint8_t nri, uint8_t type) {*h=((nri&0x3)<<5) | (type & ((1<<5)-1));}
static void _putNalSize(mblk_t *m, size_t sz);
static mblk_t *_prependFuIndicatorAndHeader(mblk_t *m, uint8_t indicator, bool_t start, bool_t end, uint8_t type);
static int _isUniqueISlice(const uint8_t *slice_header);
static bool_t _updateParameterSet(mblk_t **last_parameter_set, mblk_t *new_parameter_set);
MSQueue _q;
mblk_t *_m = nullptr;
int _maxSize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
unsigned int _status = 0; // bitmask of Rfc3984Status values
mblk_t *_SPS;
mblk_t *_PPS;
mblk_t *_lastSPS = nullptr;
mblk_t *_lastPPS = nullptr;
uint32_t _lastTs = 0x943FEA43;
uint16_t _refCSeq;
uint8_t _mode = 0;
bool _STAPAAllowed = false;
bool _initializedRefCSeq;
};
unsigned int operator&(unsigned int val1, Rfc3984Context::Status val2);
unsigned int &operator&=(unsigned int &val1, Rfc3984Context::Status val2);
unsigned int operator|(unsigned int val1, Rfc3984Context::Status val2);
unsigned int &operator|=(unsigned int &val1, Rfc3984Context::Status val2);
class Rfc3984Unpacker {
public:
enum class Status {
......
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