Commit 47c47b16 authored by François Grisez's avatar François Grisez
Browse files

Create an abstraction for VideoToolbox format description creation and parameter sets generation.

parent b118ab41
......@@ -368,13 +368,14 @@ if(ENABLE_VIDEO)
endif()
endif()
if (APPLE AND (ENABLE_VT_H265 OR ENABLE_VT_H264))
set(VIDEOTOOLBOX_CODEC_SOURCE_FILES
list(APPEND VOIP_SOURCE_FILES_CXX
videofilters/videotoolbox.cpp
voip/h26x/videotoolbox-decoder.cpp
voip/h26x/videotoolbox-encoder.cpp
voip/h26x/videotoolbox-h264-utilities.cpp
voip/h26x/videotoolbox-h265-utilities.cpp
voip/h26x/videotoolbox-utils.cpp
)
list(APPEND VOIP_SOURCE_FILES_CXX ${VIDEOTOOLBOX_CODEC_SOURCE_FILES})
endif()
if(ANDROID)
list(APPEND VOIP_SOURCE_FILES_C
......@@ -541,8 +542,8 @@ bc_apply_compile_flags(VOIP_SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_
if(VOIP_SOURCE_FILES_CXX)
set_source_files_properties(${VOIP_SOURCE_FILES_CXX} PROPERTIES LANGUAGE CXX)
bc_apply_compile_flags(VOIP_SOURCE_FILES_CXX STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX)
if(IOS AND VIDEOTOOLBOX_CODEC_SOURCE_FILES)
set_source_files_properties(${VIDEOTOOLBOX_CODEC_SOURCE_FILES}
if(IOS)
set_source_files_properties(voip/h26x/videotoolbox-h265-utilities.cpp
PROPERTIES COMPILE_FLAGS "-miphoneos-version-min=11.0"
)
endif()
......
......@@ -91,16 +91,19 @@ extern "C" void _register_videotoolbox_if_supported(MSFactory *factory) {
ms_message("Registering VideoToolbox H264 codec");
ms_factory_register_filter(factory, &ms_VideoToolboxH264Encoder_desc);
ms_factory_register_filter(factory, &ms_VideoToolboxH264Decoder_desc);
} else {
ms_message("Cannot register VideoToolbox H264 codec. That "
"requires iOS 8 or MacOS 10.8");
}
if (kCFCoreFoundationVersionNumber >= 1400) { // MacOS >= 10.13 or iOS >= 11.0
ms_message("Registering VideoToolbox H265 codec");
ms_factory_register_filter(factory, &ms_VideoToolboxH265Encoder_desc);
ms_factory_register_filter(factory, &ms_VideoToolboxH265Decoder_desc);
} else {
ms_message("Cannot register VideoToolbox H264 codec. That "
"requires iOS 8 or MacOSX 10.8");
ms_message("Cannot register VideoToolbox H265 codec. That "
"requires iOS 11.0 or MacOS 10.13");
}
#endif
}
......@@ -158,7 +158,7 @@ void H26xParameterSetsStore::extractAllPs(MSQueue *frame) {
}
}
void H26xParameterSetsStore::fetchAllPs(MSQueue *outq) {
void H26xParameterSetsStore::fetchAllPs(MSQueue *outq) const {
MSQueue q;
ms_queue_init(&q);
for(const auto &item : _ps) {
......
......@@ -99,7 +99,7 @@ public:
void extractAllPs(MSQueue *frame);
bool psGatheringCompleted() const;
void fetchAllPs(MSQueue *outq);
void fetchAllPs(MSQueue *outq) const;
protected:
H26xParameterSetsStore(const std::string &mime, const std::initializer_list<int> &psCodes);
......
......@@ -46,26 +46,29 @@ VideoToolboxDecoder::~VideoToolboxDecoder() {
}
bool VideoToolboxDecoder::feed(MSQueue *encodedFrame, uint64_t timestamp) {
_psStore->extractAllPs(encodedFrame);
if (_psStore->hasNewParameters()) {
_psStore->acknowlege();
if (_session) destroyDecoder();
}
if (ms_queue_empty(encodedFrame)) return true;
if (!_psStore->psGatheringCompleted()) {
vth264dec_message("decoding failed because some parameter sets haven't been received yet");
return false;
}
if (_session == nullptr && !createDecoder()) return false;
for (const mblk_t *nalu = ms_queue_peek_first(encodedFrame); !ms_queue_end(encodedFrame, nalu); nalu = ms_queue_next(encodedFrame, nalu)) {
_naluHeader->parse(nalu->b_rptr);
if (_naluHeader->getAbsType().isKeyFramePart()) {
_freeze = false;
break;
try {
_psStore->extractAllPs(encodedFrame);
if (_psStore->hasNewParameters()) {
_psStore->acknowlege();
if (_session) destroyDecoder();
}
if (ms_queue_empty(encodedFrame)) return true;
if (!_psStore->psGatheringCompleted()) throw runtime_error("need more parameter sets");
if (_session == nullptr) createDecoder();
for (const mblk_t *nalu = ms_queue_peek_first(encodedFrame); !ms_queue_end(encodedFrame, nalu); nalu = ms_queue_next(encodedFrame, nalu)) {
_naluHeader->parse(nalu->b_rptr);
if (_naluHeader->getAbsType().isKeyFramePart()) {
_freeze = false;
break;
}
}
if (_freeze) return true;
return decodeFrame(encodedFrame, timestamp);
} catch (const runtime_error &e) {
ms_error("VideoToolboxDecoder: %s", e.what());
ms_error("VideoToolboxDecoder: feeding failed");
return false;
}
if (_freeze) return true;
return decodeFrame(encodedFrame, timestamp);
}
VideoDecoder::Status VideoToolboxDecoder::fetch(mblk_t *&frame) {
......@@ -79,15 +82,13 @@ VideoDecoder::Status VideoToolboxDecoder::fetch(mblk_t *&frame) {
}
}
bool VideoToolboxDecoder::createDecoder() {
void VideoToolboxDecoder::createDecoder() {
OSStatus status;
VTDecompressionOutputCallbackRecord dec_cb = {outputCb, this};
vth264dec_message("creating a decoding session");
if (!formatDescFromSpsPps()) {
return false;
}
formatDescFromSpsPps();
CFMutableDictionaryRef decoder_params = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL);
#if !TARGET_OS_IPHONE
......@@ -104,8 +105,7 @@ bool VideoToolboxDecoder::createDecoder() {
CFRelease(pixel_parameters);
CFRelease(decoder_params);
if(status != noErr) {
vth264dec_error("could not create the decoding context: %s", toString(status).c_str());
return false;
throw runtime_error("could not create the decoding context: " + toString(status));
} else {
#if !TARGET_OS_IPHONE
CFBooleanRef hardware_acceleration;
......@@ -128,8 +128,6 @@ bool VideoToolboxDecoder::createDecoder() {
vth264dec_warning("could not be able to switch to real-time mode: %s", toString(status).c_str());
}
#endif
return true;
}
}
......@@ -184,37 +182,17 @@ bool VideoToolboxDecoder::decodeFrame(MSQueue *encodedFrame, uint64_t timestamp)
return true;
}
bool VideoToolboxDecoder::formatDescFromSpsPps() {
MSQueue parameterSets;
ms_queue_init(&parameterSets);
_psStore->fetchAllPs(&parameterSets);
vector<const uint8_t *> ptrs;
vector<size_t> sizes;
for (const mblk_t *ps = ms_queue_peek_first(&parameterSets); !ms_queue_end(&parameterSets, ps); ps = ms_queue_next(&parameterSets, ps)) {
ptrs.push_back(ps->b_rptr);
sizes.push_back(msgdsize(ps));
void VideoToolboxDecoder::formatDescFromSpsPps() {
try {
unique_ptr<VideoToolboxUtilities> utils(VideoToolboxUtilities::create(_mime));
CMFormatDescriptionRef format_desc = utils->createFormatDescription(*_psStore);
CMVideoDimensions vsize = CMVideoFormatDescriptionGetDimensions(format_desc);
vth264dec_message("new video format %dx%d", int(vsize.width), int(vsize.height));
if (_formatDesc) CFRelease(_formatDesc);
_formatDesc = format_desc;
} catch (const AppleOSError &e) {
throw runtime_error(string("cannot create format description: ") + e.what());
}
CMFormatDescriptionRef format_desc;
OSStatus status;
if (_mime == "video/avc") {
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(nullptr, ptrs.size(), ptrs.data(), sizes.data(), _naluSizeLength, &format_desc);
} else {
status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(nullptr, ptrs.size(), ptrs.data(), sizes.data(), _naluSizeLength, nullptr, &format_desc);
}
ms_queue_flush(&parameterSets);
if(status != noErr) {
vth264dec_error("could not find out the input format: %d", int(status));
return false;
}
CMVideoDimensions vsize = CMVideoFormatDescriptionGetDimensions(format_desc);
vth264dec_message("new video format %dx%d", int(vsize.width), int(vsize.height));
if (_formatDesc) CFRelease(_formatDesc);
_formatDesc = format_desc;
return true;
}
void VideoToolboxDecoder::outputCb(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status,
......
......@@ -55,10 +55,10 @@ private:
mblk_t *_data = nullptr;
};
bool createDecoder();
void createDecoder();
void destroyDecoder();
bool decodeFrame(MSQueue *encodedFrame, uint64_t timestamp);
bool formatDescFromSpsPps();
void formatDescFromSpsPps();
static void outputCb(void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status,
VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer,
......
......@@ -39,6 +39,13 @@ VideoToolboxEncoder::Frame::Frame(Frame &&src) {
}
}
void VideoToolboxEncoder::Frame::insert(MSQueue *q) {
mblk_t *insertionPoint = ms_queue_peek_first(&_nalus);
while (mblk_t *m = ms_queue_get(q)) {
ms_queue_insert(&_nalus, insertionPoint, m);
}
}
VideoToolboxEncoder::VideoToolboxEncoder(const string &mime): H26xEncoder(mime) {
_vsize.width = 0;
_vsize.height = 0;
......@@ -72,6 +79,8 @@ void VideoToolboxEncoder::start() {
OSStatus err;
CFNumberRef value;
unique_ptr<VideoToolboxUtilities> utils(VideoToolboxUtilities::create(_mime));
CFMutableDictionaryRef pixbuf_attr = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, &kCFTypeDictionaryValueCallBacks);
int32_t pixel_type = kCVPixelFormatType_420YpCbCr8Planar;
value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pixel_type);
......@@ -83,15 +92,13 @@ void VideoToolboxEncoder::start() {
CFDictionarySetValue(session_props, kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, kCFBooleanTrue);
#endif
CMVideoCodecType codecType = (_mime == "video/avc" ? kCMVideoCodecType_H264 : kCMVideoCodecType_HEVC);
err = VTCompressionSessionCreate(kCFAllocatorDefault, _vsize.width, _vsize.height, codecType,
err = VTCompressionSessionCreate(kCFAllocatorDefault, _vsize.width, _vsize.height, utils->getCodecType(),
session_props, pixbuf_attr, kCFAllocatorDefault, outputCb, this, &_session);
CFRelease(pixbuf_attr);
CFRelease(session_props);
if(err) throw runtime_error("could not initialize the VideoToolbox compresson session: " + toString(err));
CFTypeRef profileLevel = (_mime == "video/avc" ? kVTProfileLevel_H264_Baseline_AutoLevel : kVTProfileLevel_HEVC_Main_AutoLevel);
err = VTSessionSetProperty(_session, kVTCompressionPropertyKey_ProfileLevel, profileLevel);
err = VTSessionSetProperty(_session, kVTCompressionPropertyKey_ProfileLevel, utils->getDefaultProfileLevel());
if (err != noErr) {
vth264enc_error("could not set H264 profile and level: %s", toString(err).c_str());
}
......@@ -238,63 +245,58 @@ void VideoToolboxEncoder::applyBitrate() {
void VideoToolboxEncoder::outputCb(void *outputCallbackRefCon, void *sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer) {
VideoToolboxEncoder *ctx = static_cast<VideoToolboxEncoder *>(outputCallbackRefCon);
if(sampleBuffer == nullptr || status != noErr) {
vth264enc_error("could not encode frame: error %d", (int)status);
return;
}
if(ctx->_session) {
Frame encodedFrame;
CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
const size_t frame_size = CMBlockBufferGetDataLength(block_buffer);
size_t read_size = 0;
while(read_size < frame_size) {
char *chunk;
size_t chunk_size;
OSStatus status = CMBlockBufferGetDataPointer(block_buffer, read_size, &chunk_size, NULL, &chunk);
if (status != kCMBlockBufferNoErr) {
vth264enc_error("error while reading a chunk of encoded frame: %s", toString(status).c_str());
return;
try {
if (sampleBuffer == nullptr) throw runtime_error("no output buffer");
if (status != noErr) throw AppleOSError(status);
if(ctx->_session) {
Frame encodedFrame;
CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
const size_t frame_size = CMBlockBufferGetDataLength(block_buffer);
size_t read_size = 0;
while(read_size < frame_size) {
char *chunk;
size_t chunk_size;
OSStatus status = CMBlockBufferGetDataPointer(block_buffer, read_size, &chunk_size, NULL, &chunk);
if (status != kCMBlockBufferNoErr) throw runtime_error(string("chunk reading failed: ") + toString(status));
H26xUtils::naluStreamToNalus(reinterpret_cast<uint8_t *>(chunk), chunk_size, encodedFrame.getQueue());
read_size += chunk_size;
}
H26xUtils::naluStreamToNalus(reinterpret_cast<uint8_t *>(chunk), chunk_size, encodedFrame.getQueue());
read_size += chunk_size;
}
bool isKeyFrame = false;
unique_ptr<H26xNaluHeader> header(H26xToolFactory::get(ctx->_mime).createNaluHeader());
for (const mblk_t *nalu = ms_queue_peek_first(encodedFrame.getQueue()); !ms_queue_end(encodedFrame.getQueue(), nalu); nalu = ms_queue_next(encodedFrame.getQueue(), nalu)) {
header->parse(nalu->b_rptr);
if (header->getAbsType().isKeyFramePart()) {
isKeyFrame = true;
break;
bool isKeyFrame = false;
unique_ptr<H26xNaluHeader> header(H26xToolFactory::get(ctx->_mime).createNaluHeader());
for (const mblk_t *nalu = ms_queue_peek_first(encodedFrame.getQueue()); !ms_queue_end(encodedFrame.getQueue(), nalu); nalu = ms_queue_next(encodedFrame.getQueue(), nalu)) {
header->parse(nalu->b_rptr);
if (header->getAbsType().isKeyFramePart()) {
isKeyFrame = true;
break;
}
}
}
if(isKeyFrame) {
mblk_t *insertion_point = ms_queue_peek_first(encodedFrame.getQueue());
CMFormatDescriptionRef format_desc = CMSampleBufferGetFormatDescription(sampleBuffer);
size_t offset = 0;
size_t parameter_set_count;
do {
const uint8_t *parameter_set;
size_t parameter_set_size;
if (ctx->_mime == "video/avc") {
CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format_desc, offset++, &parameter_set, &parameter_set_size, &parameter_set_count, nullptr);
} else {
CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format_desc, offset++, &parameter_set, &parameter_set_size, &parameter_set_count, nullptr);
if(isKeyFrame) {
MSQueue parameterSets;
ms_queue_init(&parameterSets);
try {
ms_message("VideoToolboxEncoder: I-frame created");
unique_ptr<VideoToolboxUtilities> vtUtils(VideoToolboxUtilities::create(ctx->_mime));
vtUtils->getParameterSets(CMSampleBufferGetFormatDescription(sampleBuffer), &parameterSets);
encodedFrame.insert(&parameterSets);
} catch (const AppleOSError &e) {
ms_error("VideoToolboxEncoder: paramter sets generation failed: %s", e.what());
ms_queue_flush(&parameterSets);
}
mblk_t *nalu = allocb(parameter_set_size, 0);
memcpy(nalu->b_wptr, parameter_set, parameter_set_size);
nalu->b_wptr += parameter_set_size;
ms_queue_insert(encodedFrame.getQueue(), insertion_point, nalu);
} while(offset < parameter_set_count);
vth264enc_message("I-frame created");
}
}
ms_mutex_lock(&ctx->_mutex);
ctx->_encodedFrames.push_back(move(encodedFrame));
ms_mutex_unlock(&ctx->_mutex);
ms_mutex_lock(&ctx->_mutex);
ctx->_encodedFrames.push_back(move(encodedFrame));
ms_mutex_unlock(&ctx->_mutex);
}
} catch (const runtime_error &e) {
ms_error("VideoToolboxEncoder: decoding error: %s", e.what());
} catch (const AppleOSError &e) {
ms_error("VideoToolboxEncoder: decoding error: %s", e.what());
}
}
......
......@@ -56,6 +56,7 @@ private:
~Frame() {ms_queue_flush(&_nalus);}
void put(mblk_t *m) {ms_queue_put(&_nalus, m);}
void insert(MSQueue *q);
mblk_t *get() {return ms_queue_get(&_nalus);}
MSQueue *getQueue() {return &_nalus;}
......
/*
Mediastreamer2 videotoolbox-h264-utilities.cpp
Copyright (C) 2018 Belledonne Communications SARL
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 "videotoolbox-h264-utilities.h"
using namespace std;
namespace mediastreamer {
CMVideoCodecType VideoToolboxH264Utilities::getCodecType() const {
return kCMVideoCodecType_H264;
}
CFStringRef VideoToolboxH264Utilities::getDefaultProfileLevel() const {
return kVTProfileLevel_H264_Baseline_AutoLevel;
}
void VideoToolboxH264Utilities::getParameterSet(const CMFormatDescriptionRef format, size_t offset, const uint8_t *&parameterSet, size_t &parameterSetSize, size_t &parameterSetsCount) const {
OSStatus status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, offset, &parameterSet, &parameterSetSize, &parameterSetsCount, nullptr);
if (status != noErr) throw AppleOSError(status);
}
CMFormatDescriptionRef VideoToolboxH264Utilities::createFormatDescription(size_t parameterSetsCount, const uint8_t *parameterSets[], const size_t parameterSetSizes[]) const {
CMFormatDescriptionRef formatDesc;
OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(nullptr, parameterSetsCount, parameterSets, parameterSetSizes, 4, &formatDesc);
if (status != noErr) {
throw AppleOSError(status);
}
return formatDesc;
}
}
/*
Mediastreamer2 videotoolbox-h264-utilities.h
Copyright (C) 2018 Belledonne Communications SARL
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 "videotoolbox-utils.h"
namespace mediastreamer {
class VideoToolboxH264Utilities: public VideoToolboxUtilities {
public:
CMVideoCodecType getCodecType() const override;
CFStringRef getDefaultProfileLevel() const override;
private:
void getParameterSet(const CMFormatDescriptionRef format, size_t offset, const uint8_t *&parameterSet, size_t &parameterSetSize, size_t &parameterSetsCount) const override;
CMFormatDescriptionRef createFormatDescription(size_t parameterSetsCount, const uint8_t *parameterSets[], const size_t parameterSetSizes[]) const override;
};
}
/*
Mediastreamer2 videotoolbox-h265-utilities.cpp
Copyright (C) 2018 Belledonne Communications SARL
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 "videotoolbox-h265-utilities.h"
using namespace std;
namespace mediastreamer {
CMVideoCodecType VideoToolboxH265Utilities::getCodecType() const {
return kCMVideoCodecType_HEVC;
}
CFStringRef VideoToolboxH265Utilities::getDefaultProfileLevel() const {
return kVTProfileLevel_HEVC_Main_AutoLevel;
}
void VideoToolboxH265Utilities::getParameterSet(const CMFormatDescriptionRef format, size_t offset, const uint8_t *&parameterSet, size_t &parameterSetSize, size_t &parameterSetsCount) const {
OSStatus status = CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, offset, &parameterSet, &parameterSetSize, &parameterSetsCount, nullptr);
if (status != noErr) throw AppleOSError(status);
}
CMFormatDescriptionRef VideoToolboxH265Utilities::createFormatDescription(size_t paramterSetsCount, const uint8_t *parameterSets[], const size_t parameterSetSizes[]) const {
CMFormatDescriptionRef formatDesc;
OSStatus status = CMVideoFormatDescriptionCreateFromHEVCParameterSets(nullptr, paramterSetsCount, parameterSets, parameterSetSizes, 4, nullptr, &formatDesc);
if (status != noErr) {
throw AppleOSError(status);
}
return formatDesc;
}
}
/*
Mediastreamer2 videotoolbox-h265-utilities.h
Copyright (C) 2018 Belledonne Communications SARL
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 "videotoolbox-utils.h"
namespace mediastreamer {
class VideoToolboxH265Utilities: public VideoToolboxUtilities {
public:
CMVideoCodecType getCodecType() const override;
CFStringRef getDefaultProfileLevel() const override;
private:
void getParameterSet(const CMFormatDescriptionRef format, size_t offset, const uint8_t *&parameterSet, size_t &parameterSetSize, size_t &parameterSetsCount) const override;
CMFormatDescriptionRef createFormatDescription(size_t paramterSetsCount, const uint8_t *parameterSets[], const size_t parameterSetSizes[]) const override;
};
}
......@@ -20,6 +20,9 @@
#include <sstream>
#include <unordered_map>
#include "videotoolbox-h264-utilities.h"
#include "videotoolbox-h265-utilities.h"
#include "videotoolbox-utils.h"
using namespace std;
......@@ -74,4 +77,52 @@ std::string toString(::OSStatus status) {
return message.str();
}
void VideoToolboxUtilities::getParameterSets(const CMFormatDescriptionRef format, MSQueue *outPs) const {
size_t offset = 0;
size_t parameterSetsCount;
do {
const uint8_t *parameterSet;
size_t parameterSetSize;
getParameterSet(format, offset++, parameterSet, parameterSetSize, parameterSetsCount);
mblk_t *nalu = allocb(parameterSetSize, 0);
memcpy(nalu->b_wptr, parameterSet, parameterSetSize);
nalu->b_wptr += parameterSetSize;
ms_queue_put(outPs, nalu);
} while(offset < parameterSetsCount);
}
CMFormatDescriptionRef VideoToolboxUtilities::createFormatDescription(const H26xParameterSetsStore &psStore) const {
MSQueue parameterSets;
ms_queue_init(&parameterSets);
try {
psStore.fetchAllPs(&parameterSets);
vector<const uint8_t *> ptrs;
vector<size_t> sizes;
for (const mblk_t *ps = ms_queue_peek_first(&parameterSets); !ms_queue_end(&parameterSets, ps); ps = ms_queue_next(&paramete