diff --git a/components/codecs/include/ftl/codecs/h264.hpp b/components/codecs/include/ftl/codecs/h264.hpp new file mode 100644 index 0000000000000000000000000000000000000000..17f649c52220f7ac8b00e6d4ed9b78e18f2847f8 --- /dev/null +++ b/components/codecs/include/ftl/codecs/h264.hpp @@ -0,0 +1,70 @@ +#ifndef _FTL_CODECS_H264_HPP_ +#define _FTL_CODECS_H264_HPP_ + +namespace ftl { +namespace codecs { + +/** + * H.264 codec utility functions. + */ +namespace h264 { + +/** + * H264 Network Abstraction Layer Unit types. + */ +enum class NALType : int { + UNSPECIFIED_0 = 0, + CODED_SLICE_NON_IDR = 1, + CODED_SLICE_PART_A = 2, + CODED_SLICE_PART_B = 3, + CODED_SLICE_PART_C = 4, + CODED_SLICE_IDR = 5, + SEI = 6, + SPS = 7, + PPS = 8, + ACCESS_DELIMITER = 9, + EO_SEQ = 10, + EO_STREAM = 11, + FILTER_DATA = 12, + SPS_EXT = 13, + PREFIX_NAL_UNIT = 14, + SUBSET_SPS = 15, + RESERVED_16 = 16, + RESERVED_17 = 17, + RESERVED_18 = 18, + CODED_SLICE_AUX = 19, + CODED_SLICE_EXT = 20, + CODED_SLICE_DEPTH = 21, + RESERVED_22 = 22, + RESERVED_23 = 23, + UNSPECIFIED_24 = 24, + UNSPECIFIED_25, + UNSPECIFIED_26, + UNSPECIFIED_27, + UNSPECIFIED_28, + UNSPECIFIED_29, + UNSPECIFIED_30, + UNSPECIFIED_31 +}; + +/** + * Extract the NAL unit type from the first NAL header. + * With NvPipe, the 5th byte contains the NAL Unit header. + */ +inline NALType getNALType(const std::vector<uint8_t> &data) { + return static_cast<NALType>(data[4] & 0x1F); +} + +/** + * Check the H264 bitstream for an I-Frame. With NvPipe, all I-Frames start + * with a SPS NAL unit so just check for this. + */ +inline bool isIFrame(const std::vector<uint8_t> &data) { + return getNALType(data) == NALType::SPS; +} + +} +} +} + +#endif // _FTL_CODECS_H264_HPP_ diff --git a/components/codecs/src/decoder.cpp b/components/codecs/src/decoder.cpp index 4cd5437d0cb6ea84251b55bdd139a7c0b799f411..a1809b6157d783782a20e32f46f39f89cd26e8c5 100644 --- a/components/codecs/src/decoder.cpp +++ b/components/codecs/src/decoder.cpp @@ -10,6 +10,7 @@ Decoder *ftl::codecs::allocateDecoder(const ftl::codecs::Packet &pkt) { switch(pkt.codec) { case codec_t::JPG : case codec_t::PNG : return new ftl::codecs::OpenCVDecoder; + case codec_t::H264 : case codec_t::HEVC : return new ftl::codecs::NvPipeDecoder; } diff --git a/components/codecs/src/nvpipe_decoder.cpp b/components/codecs/src/nvpipe_decoder.cpp index 97985cd20c4bd2dea7aa86c829b3b151563c3cfb..79e16f3fa77ca9445faab12e33664243f1247293 100644 --- a/components/codecs/src/nvpipe_decoder.cpp +++ b/components/codecs/src/nvpipe_decoder.cpp @@ -4,6 +4,7 @@ #include <ftl/cuda_util.hpp> #include <ftl/codecs/hevc.hpp> +#include <ftl/codecs/h264.hpp> //#include <cuda_runtime.h> #include <opencv2/core/cuda/common.hpp> @@ -87,8 +88,9 @@ bool NvPipeDecoder::decode(const ftl::codecs::Packet &pkt, cv::Mat &out) { if (pkt.codec == ftl::codecs::codec_t::HEVC) { // Obtain NAL unit type if (ftl::codecs::hevc::isIFrame(pkt.data)) seen_iframe_ = true; + } else if (pkt.codec == ftl::codecs::codec_t::H264) { + if (ftl::codecs::h264::isIFrame(pkt.data)) seen_iframe_ = true; } - // TODO: Parse H264 for i-frame check if (!seen_iframe_) return false; @@ -127,5 +129,5 @@ bool NvPipeDecoder::decode(const ftl::codecs::Packet &pkt, cv::Mat &out) { } bool NvPipeDecoder::accepts(const ftl::codecs::Packet &pkt) { - return pkt.codec == codec_t::HEVC; + return pkt.codec == codec_t::HEVC || pkt.codec == codec_t::H264; } diff --git a/components/rgbd-sources/src/sources/ftlfile/file_source.cpp b/components/rgbd-sources/src/sources/ftlfile/file_source.cpp index 76cd435e7f6d907db95c6074f2aa9365b10f8652..9597bde796f80ac67f38a5a569190001e13d7065 100644 --- a/components/rgbd-sources/src/sources/ftlfile/file_source.cpp +++ b/components/rgbd-sources/src/sources/ftlfile/file_source.cpp @@ -34,13 +34,16 @@ FileSource::FileSource(ftl::rgbd::Source *s, ftl::rgbd::Player *r, int sid) : ft r->onPacket(sid, [this](const ftl::codecs::StreamPacket &spkt, ftl::codecs::Packet &pkt) { host_->notifyRaw(spkt, pkt); - // Should config items be parsed here? + // Some channels are to be directly handled by the source object and + // do not proceed to any subsequent step. + // FIXME: Potential problem, these get processed at wrong time if (spkt.channel == Channel::Configuration) { std::tuple<std::string, std::string> cfg; auto unpacked = msgpack::unpack((const char*)pkt.data.data(), pkt.data.size()); unpacked.get().convert(cfg); LOG(INFO) << "Config Received: " << std::get<1>(cfg); + return; } else if (spkt.channel == Channel::Calibration) { _processCalibration(pkt); @@ -50,7 +53,7 @@ FileSource::FileSource(ftl::rgbd::Source *s, ftl::rgbd::Player *r, int sid) : ft return; } - // FIXME: For bad and old FTL files + // FIXME: For bad and old FTL files where wrong channel is used if (pkt.codec == codec_t::POSE) { _processPose(pkt); return; @@ -60,6 +63,7 @@ FileSource::FileSource(ftl::rgbd::Source *s, ftl::rgbd::Player *r, int sid) : ft } + // TODO: Check I-Frames for H264 if (pkt.codec == codec_t::HEVC) { if (ftl::codecs::hevc::isIFrame(pkt.data)) _removeChannel(spkt.channel); } @@ -147,9 +151,13 @@ bool FileSource::compute(int n, int b) { int64_t lastts = 0; int lastc = 0; + // Go through previously read and cached frames in sequence + // needs to be done due to P-Frames for (auto i=cache_[cache_read_].begin(); i!=cache_[cache_read_].end(); ++i) { auto &c = *i; + // Check for verifying that both channels are received, ie. two frames + // with the same timestamp. if (c.spkt.timestamp > lastts) { lastts = c.spkt.timestamp; lastc = 1; @@ -157,11 +165,6 @@ bool FileSource::compute(int n, int b) { lastc++; } - //LOG(INFO) << "DECODE FRAME: " << c.spkt.timestamp << "," << (int)c.spkt.channel << "," << (int)c.pkt.codec << "," << (int)c.pkt.definition; - - // FIXME: This hack is for old and bad ftl files. - //if ((int)c.pkt.codec >= 100) continue; - if (c.spkt.channel == Channel::Colour) { rgb_.create(cv::Size(ftl::codecs::getWidth(c.pkt.definition),ftl::codecs::getHeight(c.pkt.definition)), CV_8UC3); } else { @@ -177,6 +180,7 @@ bool FileSource::compute(int n, int b) { } } + // FIXME: Consider case of Channel::None if (lastc != 2) { LOG(ERROR) << "Channels not in sync (" << sourceid_ << "): " << lastts; return false; @@ -186,8 +190,7 @@ bool FileSource::compute(int n, int b) { if (rgb_.empty() || depth_.empty()) return false; - //auto cb = host_->callback(); - //if (cb) cb(timestamp_, rgb_, depth_); + // Inform about a decoded frame pair host_->notify(timestamp_, rgb_, depth_); return true; }