Commit 0c088b68 authored by François Grisez's avatar François Grisez
Browse files

Implementation of H265NalUnpacker class.

parent 3c864e00
......@@ -304,8 +304,10 @@ if(ENABLE_VIDEO)
)
list(APPEND VOIP_SOURCE_FILES_CXX
utils/h264utils.cpp
utils/h265-utils.cpp
voip/h264-nal-packer.cpp
voip/h264-nal-unpacker.cpp
voip/h265-nal-unpacker.cpp
voip/nal-packer.cpp
voip/nal-unpacker.cpp
voip/rfc3984.cpp
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2015 Belledonne Communications <info@belledonne-communications.com>
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 <stdexcept>
#include "mediastreamer2/mscommon.h"
#include "h265-utils.h"
using namespace std;
namespace mediastreamer {
H265NaluType::H265NaluType(uint8_t value) {
if (0xc0 & value) throw out_of_range("H265 NALu type higher than 63");
_value = value;
}
const H265NaluType H265NaluType::Ap = 48;
const H265NaluType H265NaluType::Fu = 49;
void H265NaluHeader::setLayerId(uint8_t layerId) {
if (layerId & 0xc0) throw out_of_range("H265 layer ID wider than 6 bits");
_layerId = layerId;
}
void H265NaluHeader::setTid(uint8_t tid) {
if (tid & 0xf8) throw out_of_range("H265 layer ID wider than 3 bits");
_tid = tid;
}
void H265NaluHeader::parse(const uint8_t *header) {
uint16_t header2 = ntohs(*reinterpret_cast<const uint16_t *>(header));
_tid = header2 & 0x07;
header2 >>= 3;
_layerId = header2 & 0x3f;
header2 >>= 6;
_type = header2 & 0x3f;
}
mblk_t *H265NaluHeader::forge() const {
uint16_t header = _type;
header <<= 6;
header |= _layerId;
header <<= 3;
header |= _tid;
header = htons(header);
mblk_t *newHeader = allocb(2, 0);
*reinterpret_cast<uint16_t *>(newHeader->b_wptr) = header;
newHeader->b_wptr += 2;
return newHeader;
}
void H265FuHeader::parse(const uint8_t *header) {
uint8_t header2 = *header;
_type = header2 & 0x3f;
header2 >>= 6;
bool end = ((header2 & 0x01) != 0);
header2 >>= 1;
bool start = ((header2 & 0x01) != 0);
if (start && end) throw runtime_error("parsing an FU header with both start and end flags enabled");
if (start) {
_pos = Position::Start;
} else if (end) {
_pos = Position::End;
} else {
_pos = Position::Middle;
}
}
mblk_t *H265FuHeader::forge() const {
uint8_t header = (_pos == Position::Start ? 1 : 0);
header <<= 1;
header |= (_pos == Position::End ? 1 : 0);
header <<= 6;
header |= _type;
mblk_t *newHeader = allocb(1, 0);
*newHeader->b_wptr = header;
newHeader++;
return newHeader;
}
}
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2015 Belledonne Communications <info@belledonne-communications.com>
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 <cstdint>
#include <ortp/str_utils.h>
namespace mediastreamer {
class H265NaluType {
public:
H265NaluType() = default;
H265NaluType(uint8_t value);
operator uint8_t() const {return _value;}
bool isVcl() const {return _value < 32;}
static const H265NaluType Ap;
static const H265NaluType Fu;
private:
uint8_t _value = 0;
};
class H265NaluHeader {
public:
H265NaluHeader() = default;
H265NaluHeader(const uint8_t *header) {parse(header);}
void setType(H265NaluType type) {_type = type;}
H265NaluType getType() const {return _type;}
void setLayerId(uint8_t layerId);
uint8_t getLayerId() const {return _layerId;}
void setTid(uint8_t tid);
uint8_t getTid() const {return _tid;}
void parse(const uint8_t *header);
mblk_t *forge() const;
private:
H265NaluType _type;
uint8_t _layerId = 0;
uint8_t _tid = 0;
};
class H265FuHeader {
public:
enum class Position {
Start,
Middle,
End
};
H265FuHeader() = default;
H265FuHeader(const uint8_t *header) {parse(header);}
void setPosition(Position pos) {_pos = pos;}
Position getPosition() const {return _pos;}
void setType(H265NaluType type) {_type = type;}
H265NaluType getType() const {return _type;}
void parse(const uint8_t *header);
mblk_t *forge() const;
private:
Position _pos = Position::Start;
H265NaluType _type;
};
}
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2015 Belledonne Communications <info@belledonne-communications.com>
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 "h265-nal-unpacker.h"
#include "h265-utils.h"
using namespace std;
namespace mediastreamer {
mblk_t *H265NalUnpacker::FuAggregator::feed(mblk_t *packet) {
if (packet->b_wptr - packet->b_rptr < 4) {
ms_error("Dropping H265 FU packet smaller that 4 bytes");
freemsg(packet);
return nullptr;
}
H265FuHeader fuHeader(packet->b_rptr + 3);
packet->b_rptr += 4;
if (fuHeader.getPosition() == H265FuHeader::Position::Start && isAggregating()) {
ms_error("receiving start FU packet while aggregating. Dropping the under construction NALu");
reset();
_m = packet;
return nullptr;
}
if (fuHeader.getPosition() != H265FuHeader::Position::Start && !isAggregating()) {
ms_error("receiving continuation FU packet while aggregation hasn't been started. Doping packet");
freemsg(packet);
return nullptr;
}
if (fuHeader.getPosition() == H265FuHeader::Position::Start) {
_m = packet;
} else {
_m = concatb(_m, packet);
}
if (fuHeader.getPosition() == H265FuHeader::Position::End) {
mblk_t *m = _m;
msgpullup(m, -1);
_m = nullptr;
return m;
} else return nullptr;
}
void H265NalUnpacker::FuAggregator::reset() {
if (_m != nullptr) freemsg(_m);
_m = nullptr;
}
mblk_t *H265NalUnpacker::FuAggregator::completeAggregation() {
mblk_t *res = _m;
_m = nullptr;
return res;
}
void H265NalUnpacker::ApSpliter::feed(mblk_t *packet) {
ms_queue_flush(&_q);
if (packet->b_wptr - packet->b_rptr < 2) {
ms_error("Dropping H265 aggregation packet smaller than 2 bytes");
freemsg(packet);
return;
}
const uint8_t *it;
for (it = packet->b_rptr; it < packet->b_wptr;) {
if (packet->b_wptr - it < 2) break;
uint16_t naluSize = ntohs(*reinterpret_cast<const uint16_t *>(it));
it += 2;
if (it + naluSize > packet->b_wptr) break;
mblk_t *m = allocb(naluSize, 0);
memcpy(m->b_wptr, it, naluSize);
m->b_wptr += naluSize;
ms_queue_put(&_q, m);
it += naluSize;
}
if (it != packet->b_wptr) {
ms_error("Dropping H265 aggregation packet containing truncated NALus");
ms_queue_flush(&_q);
}
}
} // namespace mediastreamer
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2015 Belledonne Communications <info@belledonne-communications.com>
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 H265NalUnpacker: public NalUnpacker {
public:
H265NalUnpacker(): NalUnpacker(new FuAggregator(), new ApSpliter()) {}
private:
class FuAggregator: public NalUnpacker::FuAggregatorInterface {
public:
~FuAggregator() {if (_m != nullptr) freemsg(_m);}
mblk_t *feed(mblk_t *packet) override;
bool isAggregating() const override {return _m != nullptr;}
void reset() override;
mblk_t *completeAggregation() override;
private:
mblk_t *_m = nullptr;
};
class ApSpliter: public NalUnpacker::ApSpliterInterface {
public:
ApSpliter() {ms_queue_init(&_q);}
~ApSpliter() {ms_queue_flush(&_q);}
void feed(mblk_t *packet) override;
MSQueue *getNalus() override {return &_q;}
private:
MSQueue _q;
};
};
} // namespace mediastreamer
......@@ -22,6 +22,8 @@
#include <memory>
#include <ortp/str_utils.h>
#include "mediastreamer2/msqueue.h"
namespace mediastreamer {
class NalUnpacker {
......
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