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

Split rfc3984.cpp into several files.

parent 080cb108
......@@ -204,7 +204,6 @@ set(VOIP_SOURCE_FILES_C
voip/stun.c
)
set(VOIP_SOURCE_FILES_CXX
voip/rfc3984.cpp
)
set(VOIP_SOURCE_FILES_OBJC )
set(VOIP_SOURCE_FILES_ASM )
......@@ -305,6 +304,11 @@ if(ENABLE_VIDEO)
)
list(APPEND VOIP_SOURCE_FILES_CXX
utils/h264utils.cpp
voip/h264-nal-packer.cpp
voip/h264-nal-unpacker.cpp
voip/nal-packer.cpp
voip/nal-unpacker.cpp
voip/rfc3984.cpp
)
if(FFMPEG_FOUND AND NOT TURBOJPEG_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
......
......@@ -237,7 +237,7 @@ MSVideoSize ms_h264_sps_get_video_size(const mblk_t *sps) {
} // extern "C"
namespace mediastreamer2 {
namespace mediastreamer {
unsigned int H264FrameAnalyser::Info::toUInt() const {
unsigned int res = 0;
......@@ -289,4 +289,14 @@ bool H264FrameAnalyser::updateParameterSet(const mblk_t *new_parameter_set) {
}
}
mblk_t *H264Tools::prependFuIndicatorAndHeader(mblk_t *m, uint8_t indicator, bool_t start, bool_t end, uint8_t type) {
mblk_t *h = allocb(2, 0);
h->b_wptr[0] = indicator;
h->b_wptr[1] = ((start & 0x1) << 7) | ((end & 0x1) << 6) | type;
h->b_wptr += 2;
h->b_cont = m;
if (start) m->b_rptr++;/*skip original nalu header */
return h;
}
} // namespace mediastreamer2
......@@ -106,7 +106,7 @@ MSVideoSize ms_h264_sps_get_video_size(const mblk_t* sps);
#endif
#ifdef __cplusplus
namespace mediastreamer2 {
namespace mediastreamer {
class H264FrameAnalyser {
public:
......@@ -130,6 +130,12 @@ private:
mblk_t *_lastPps = nullptr;
};
class H264Tools {
public:
static void nalHeaderInit(uint8_t *h, uint8_t nri, uint8_t type) {*h=((nri&0x3)<<5) | (type & ((1<<5)-1));}
static mblk_t *prependFuIndicatorAndHeader(mblk_t *m, uint8_t indicator, bool_t start, bool_t end, uint8_t type);
};
};
#endif
......
......@@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/msticker.h"
#include "rfc3984.hpp"
#include "h264-nal-unpacker.h"
#include "stream_regulator.h"
#if __clang__
......@@ -42,9 +42,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#endif
#include "ortp/b64.h"
#include <ortp/b64.h>
using namespace mediastreamer2;
using namespace mediastreamer;
using namespace b64;
typedef struct _DecData{
......
......@@ -37,15 +37,16 @@ extern "C" {
#ifdef VIDEO_ENABLED
#include "mediastreamer2/msvideo.h"
#include "vp8rtpfmt.h"
#include "rfc3984.hpp"
#include "h264utils.h"
#include "h264-nal-packer.h"
#include "h264-nal-unpacker.h"
#endif // ifdef VIDEO_ENABLED
#undef bool_t
#define bool_t ambigous use ms_bool_t or matroska_bool_t
using namespace mediastreamer2;
using namespace mediastreamer;
static int recorder_close(MSFilter *f, void *arg);
......
/*
Mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <exception>
#include "h264utils.h"
#include "h264-nal-packer.h"
using namespace std;
namespace mediastreamer {
// ========================
// H264NaluToStapAggregator
// ========================
void H264NaluAggregator::setMaxSize(size_t maxSize) {
if (isAggregating()) {
throw logic_error("changing payload size while aggregating NALus into a STAP-A");
}
_maxsize = maxSize;
}
mblk_t *H264NaluAggregator::feed(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 H264NaluAggregator::reset() {
if (_stap) freemsg(_stap);
_size = 0;
}
mblk_t *H264NaluAggregator::completeAggregation() {
mblk_t *res = _stap;
_stap = nullptr;
reset();
return res;
}
mblk_t *H264NaluAggregator::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 *H264NaluAggregator::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 H264NaluAggregator::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 H264NaluSpliter::feed(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);
}
} // namespace mediastreamer
/*
Mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "nal-packer.h"
namespace mediastreamer {
class H264NaluAggregator: public NalPacker::NaluAggregatorInterface {
public:
H264NaluAggregator() {}
~H264NaluAggregator() {reset();}
size_t getMaxSize() const override {return _maxsize;}
void setMaxSize(size_t maxSize) override;
mblk_t *feed(mblk_t *nalu) override;
bool isAggregating() const override {return bool(_stap);}
void reset() override;
mblk_t *completeAggregation() override;
private:
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);
mblk_t *_stap = nullptr;
size_t _size = 0;
size_t _maxsize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
};
class H264NaluSpliter: public NalPacker::NaluSpliterInterface {
public:
H264NaluSpliter() {ms_queue_init(&_q);}
~H264NaluSpliter() {ms_queue_flush(&_q);}
size_t getMaxSize() const override {return _maxsize;}
void setMaxSize(size_t maxSize) override {_maxsize = maxSize;}
void feed(mblk_t *nalu) override;
MSQueue *getPackets() override {return &_q;};
private:
size_t _maxsize = MS_DEFAULT_MAX_PAYLOAD_SIZE;
MSQueue _q;
};
class H264NalPacker: public NalPacker {
public:
enum PacketizationMode {
SingleNalUnitMode,
NonInterleavedMode
};
H264NalPacker(): NalPacker(new H264NaluSpliter(), new H264NaluAggregator()) {}
H264NalPacker(MSFactory *factory): NalPacker(new H264NaluSpliter(), new H264NaluAggregator(), factory) {}
};
} // namespace mediastreamer
/*
Mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "mediastreamer2/msqueue.h"
#include "h264utils.h"
#include "h264-nal-unpacker.h"
using namespace std;
namespace mediastreamer {
// =======================
// H264FUAAggregator class
// =======================
mblk_t *H264FuaAggregator::feed(mblk_t *im) {
mblk_t *om = nullptr;
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 = ms_h264_nalu_get_nri(im);
if (_m != nullptr) {
ms_error("receiving FU-A start while previous FU-A is not "
"finished");
freemsg(_m);
_m = nullptr;
}
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 */
H264Tools::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 != nullptr) {
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 = nullptr;
}
return om;
}
void H264FuaAggregator::reset() {
if (_m) {
freemsg(_m);
_m = nullptr;
}
}
mblk_t *H264FuaAggregator::completeAggregation() {
mblk_t *res = _m;
_m = nullptr;
return res;
}
// =====================
// H264StapASlicer class
// =====================
void H264StapaSpliter::feed(mblk_t *im) {
uint16_t sz;
for (uint8_t *p = im->b_rptr + 1; p < im->b_wptr;) {
memcpy(&sz, p, 2);
sz = ntohs(sz);
mblk_t *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;
}
ms_queue_put(&_q, nal);
}
freemsg(im);
}
//==================================================
// Rfc3984Unpacker
//==================================================
// Public methods
// --------------
H264NalUnpacker::~H264NalUnpacker() {
if (_sps != nullptr) freemsg(_sps);
if (_pps != nullptr) freemsg(_pps);
}
void H264NalUnpacker::setOutOfBandSpsPps(mblk_t *sps, mblk_t *pps) {
if (_sps) freemsg(_sps);
if (_pps) freemsg(_pps);
_sps = sps;
_pps = pps;
}
// Private methods
// ---------------
NalUnpacker::PacketType H264NalUnpacker::getNaluType(const mblk_t *nalu) const {
switch (ms_h264_nalu_get_type(nalu)) {
case MSH264NaluTypeFUA: return PacketType::FragmentationUnit;
case MSH264NaluTypeSTAPA: return PacketType::AggregationPacket;
default: return PacketType::SingleNalUnit;
}
}
H264NalUnpacker::Status H264NalUnpacker::outputFrame(MSQueue *out, const Status &flags) {
if (_status.isKeyFrame && _sps && _pps) {
/*prepend out of band provided sps and pps*/
ms_queue_put(out, _sps);
ms_queue_put(out, _pps);
_sps = NULL;
_pps = NULL;
}
return NalUnpacker::outputFrame(out, flags);
}
} // namespace mediastreamer
/*
Mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include "nal-unpacker.h"
namespace mediastreamer {
class H264FuaAggregator: public NalUnpacker::FuAggregatorInterface {
public:
~H264FuaAggregator() {if (_m) freemsg(_m);}
mblk_t *feed(mblk_t *im) override;
bool isAggregating() const override {return _m != nullptr;}
void reset() override;
mblk_t *completeAggregation() override;
private:
mblk_t *_m = nullptr;
};
class H264StapaSpliter: public NalUnpacker::ApSpliterInterface {
public:
H264StapaSpliter() {ms_queue_init(&_q);}
~H264StapaSpliter() {ms_queue_flush(&_q);}
void feed(mblk_t *im) override;
MSQueue *getNalus() override {return &_q;}
private:
MSQueue _q;
};
class H264NalUnpacker: public NalUnpacker {
public:
H264NalUnpacker(): NalUnpacker(new H264FuaAggregator(), new H264StapaSpliter()) {}
~H264NalUnpacker();
void setOutOfBandSpsPps(mblk_t *sps, mblk_t *pps);
private:
NalUnpacker::PacketType getNaluType(const mblk_t *nalu) const override;
Status outputFrame(MSQueue *out, const Status &flags) override;
mblk_t *_sps = nullptr;
mblk_t *_pps = nullptr;
};
} // namespace mediastreamer
/*
Mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "nal-packer.h"
namespace mediastreamer {
NalPacker::NalPacker(NaluSpliterInterface *naluSpliter, NaluAggregatorInterface *naluAggregator, MSFactory *factory): _naluSpliter(naluSpliter), _naluAggregator(naluAggregator) {
setMaxPayloadSize(ms_factory_get_payload_max_size(factory));
}
void NalPacker::setMaxPayloadSize(size_t size) {
_maxSize = size;
_naluSpliter->setMaxSize(size);
_naluAggregator->setMaxSize(size);
}
void NalPacker::pack(MSQueue *naluq, MSQueue *rtpq, uint32_t ts) {
switch (_packMode) {
case SingleNalUnitMode:
packInSingleNalUnitMode(naluq, rtpq, ts);
break;
case NonInterleavedMode:
packInNonInterleavedMode(naluq, rtpq, ts);
break;
}
}
// Private methods
void NalPacker::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);
if (size > _maxSize) {
ms_warning("This H264 packet does not fit into MTU: size=%u", static_cast<unsigned int>(size));
}
sendPacket(rtpq, ts, m, end);
}
}
void NalPacker::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);
if (_aggregationEnabled) {
if (_naluAggregator->isAggregating()) {
mblk_t *stapPacket = _naluAggregator->feed(m);
if (stapPacket) {
sendPacket(rtpq, ts, stapPacket, false);
} else continue;
}
if (sz < (_maxSize / 2)) {
_naluAggregator->feed(m);
} else {
/*send as single NAL or FU-A*/
if (sz > _maxSize) {
ms_debug("Sending FU-A packets");
fragNaluAndSend(rtpq, ts, m, end);
} else {
ms_debug("Sending Single NAL");
sendPacket(rtpq, ts, m, end);
}
}
} else {