|
|
@ -59,7 +59,6 @@ GUID CodecGuid(const Codec codec); |
|
|
|
void FrameRate(const double fps, uint32_t& frameRateNum, uint32_t& frameRateDen); |
|
|
|
void FrameRate(const double fps, uint32_t& frameRateNum, uint32_t& frameRateDen); |
|
|
|
GUID EncodingProfileGuid(const EncodeProfile encodingProfile); |
|
|
|
GUID EncodingProfileGuid(const EncodeProfile encodingProfile); |
|
|
|
GUID EncodingPresetGuid(const EncodePreset nvPreset); |
|
|
|
GUID EncodingPresetGuid(const EncodePreset nvPreset); |
|
|
|
bool Equal(const GUID& g1, const GUID& g2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) |
|
|
|
bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -68,12 +67,48 @@ bool operator==(const EncoderParams& lhs, const EncoderParams& rhs) |
|
|
|
rhs.averageBitRate, rhs.maxBitRate, rhs.targetQuality, rhs.gopLength); |
|
|
|
rhs.averageBitRate, rhs.maxBitRate, rhs.targetQuality, rhs.gopLength); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FFmpegVideoWriter : public EncoderCallback |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
FFmpegVideoWriter(const String& fileName, const Codec codec, const int fps, const Size sz, const int idrPeriod); |
|
|
|
|
|
|
|
~FFmpegVideoWriter(); |
|
|
|
|
|
|
|
void onEncoded(const std::vector<std::vector<uint8_t>>& vPacket); |
|
|
|
|
|
|
|
void onEncodingFinished(); |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
cv::VideoWriter writer; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FFmpegVideoWriter::FFmpegVideoWriter(const String& fileName, const Codec codec, const int fps, const Size sz, const int idrPeriod) { |
|
|
|
|
|
|
|
if (!videoio_registry::hasBackend(CAP_FFMPEG)) |
|
|
|
|
|
|
|
CV_Error(Error::StsNotImplemented, "FFmpeg backend not found"); |
|
|
|
|
|
|
|
const int fourcc = codec == Codec::H264 ? cv::VideoWriter::fourcc('a', 'v', 'c', '1') : cv::VideoWriter::fourcc('h', 'e', 'v', '1'); |
|
|
|
|
|
|
|
writer.open(fileName, fourcc, fps, sz, { VideoWriterProperties::VIDEOWRITER_PROP_RAW_VIDEO, 1, VideoWriterProperties::VIDEOWRITER_PROP_KEY_INTERVAL, idrPeriod }); |
|
|
|
|
|
|
|
if (!writer.isOpened()) |
|
|
|
|
|
|
|
CV_Error(Error::StsUnsupportedFormat, "Unsupported video sink"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FFmpegVideoWriter::onEncodingFinished() { |
|
|
|
|
|
|
|
writer.release(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FFmpegVideoWriter::~FFmpegVideoWriter() { |
|
|
|
|
|
|
|
onEncodingFinished(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FFmpegVideoWriter::onEncoded(const std::vector<std::vector<uint8_t>>& vPacket) { |
|
|
|
|
|
|
|
for (auto& packet : vPacket) { |
|
|
|
|
|
|
|
Mat wrappedPacket(1, packet.size(), CV_8UC1, (void*)packet.data()); |
|
|
|
|
|
|
|
writer.write(wrappedPacket); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RawVideoWriter : public EncoderCallback |
|
|
|
class RawVideoWriter : public EncoderCallback |
|
|
|
{ |
|
|
|
{ |
|
|
|
public: |
|
|
|
public: |
|
|
|
RawVideoWriter(String fileName); |
|
|
|
RawVideoWriter(const String fileName); |
|
|
|
~RawVideoWriter(); |
|
|
|
~RawVideoWriter(); |
|
|
|
void onEncoded(std::vector<std::vector<uint8_t>> vPacket); |
|
|
|
void onEncoded(const std::vector<std::vector<uint8_t>>& vPacket); |
|
|
|
void onEncodingFinished(); |
|
|
|
void onEncodingFinished(); |
|
|
|
private: |
|
|
|
private: |
|
|
|
std::ofstream fpOut; |
|
|
|
std::ofstream fpOut; |
|
|
@ -93,9 +128,9 @@ RawVideoWriter::~RawVideoWriter() { |
|
|
|
onEncodingFinished(); |
|
|
|
onEncodingFinished(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RawVideoWriter::onEncoded(std::vector<std::vector<uint8_t>> vPacket) { |
|
|
|
void RawVideoWriter::onEncoded(const std::vector<std::vector<uint8_t>>& vPacket) { |
|
|
|
for (auto& packet : vPacket) |
|
|
|
for (auto& packet : vPacket) |
|
|
|
fpOut.write(reinterpret_cast<char*>(packet.data()), packet.size()); |
|
|
|
fpOut.write(reinterpret_cast<const char*>(packet.data()), packet.size()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class VideoWriterImpl : public VideoWriter |
|
|
|
class VideoWriterImpl : public VideoWriter |
|
|
@ -172,12 +207,6 @@ VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallback>& encoderCallBack_, c |
|
|
|
Init(codec, fps, frameSz); |
|
|
|
Init(codec, fps, frameSz); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
VideoWriterImpl::VideoWriterImpl(const Ptr<EncoderCallback>& encoderCallback, const Size frameSz, const Codec codec, const double fps, |
|
|
|
|
|
|
|
const ColorFormat colorFormat, const Stream& stream) : |
|
|
|
|
|
|
|
VideoWriterImpl(encoderCallback, frameSz, codec, fps, colorFormat, EncoderParams(), stream) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VideoWriterImpl::release() { |
|
|
|
void VideoWriterImpl::release() { |
|
|
|
pEnc->EndEncode(vPacket); |
|
|
|
pEnc->EndEncode(vPacket); |
|
|
|
encoderCallback->onEncoded(vPacket); |
|
|
|
encoderCallback->onEncoded(vPacket); |
|
|
@ -271,12 +300,6 @@ GUID EncodingPresetGuid(const EncodePreset nvPreset) { |
|
|
|
CV_Error(Error::StsUnsupportedFormat, msg); |
|
|
|
CV_Error(Error::StsUnsupportedFormat, msg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool Equal(const GUID& g1, const GUID& g2) { |
|
|
|
|
|
|
|
if (std::tie(g1.Data1, g1.Data2, g1.Data3, g1.Data4) == std::tie(g2.Data1, g2.Data2, g2.Data3, g2.Data4)) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) |
|
|
|
void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) |
|
|
|
{ |
|
|
|
{ |
|
|
|
NV_ENC_INITIALIZE_PARAMS initializeParams = {}; |
|
|
|
NV_ENC_INITIALIZE_PARAMS initializeParams = {}; |
|
|
@ -293,10 +316,10 @@ void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) |
|
|
|
initializeParams.encodeConfig->rcParams.maxBitRate = encoderParams.maxBitRate; |
|
|
|
initializeParams.encodeConfig->rcParams.maxBitRate = encoderParams.maxBitRate; |
|
|
|
initializeParams.encodeConfig->rcParams.targetQuality = encoderParams.targetQuality; |
|
|
|
initializeParams.encodeConfig->rcParams.targetQuality = encoderParams.targetQuality; |
|
|
|
initializeParams.encodeConfig->gopLength = encoderParams.gopLength; |
|
|
|
initializeParams.encodeConfig->gopLength = encoderParams.gopLength; |
|
|
|
if (Equal(codec, NV_ENC_CODEC_H264_GUID)) |
|
|
|
if (codec == NV_ENC_CODEC_H264_GUID) |
|
|
|
initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.gopLength; |
|
|
|
initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.idrPeriod; |
|
|
|
else if (Equal(codec, NV_ENC_CODEC_HEVC_GUID)) |
|
|
|
else if (codec == NV_ENC_CODEC_HEVC_GUID) |
|
|
|
initializeParams.encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = encoderParams.gopLength; |
|
|
|
initializeParams.encodeConfig->encodeCodecConfig.hevcConfig.idrPeriod = encoderParams.idrPeriod; |
|
|
|
pEnc->CreateEncoder(&initializeParams); |
|
|
|
pEnc->CreateEncoder(&initializeParams); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -371,14 +394,25 @@ EncoderParams VideoWriterImpl::getEncoderParams() const { |
|
|
|
Ptr<VideoWriter> createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, |
|
|
|
Ptr<VideoWriter> createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, |
|
|
|
Ptr<EncoderCallback> encoderCallback, const Stream& stream) |
|
|
|
Ptr<EncoderCallback> encoderCallback, const Stream& stream) |
|
|
|
{ |
|
|
|
{ |
|
|
|
encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); |
|
|
|
return createVideoWriter(fileName, frameSize, codec, fps, colorFormat, EncoderParams(), encoderCallback, stream); |
|
|
|
return makePtr<VideoWriterImpl>(encoderCallback, frameSize, codec, fps, colorFormat, stream); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Ptr<VideoWriter> createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, |
|
|
|
Ptr<VideoWriter> createVideoWriter(const String& fileName, const Size frameSize, const Codec codec, const double fps, const ColorFormat colorFormat, |
|
|
|
const EncoderParams& params, Ptr<EncoderCallback> encoderCallback, const Stream& stream) |
|
|
|
const EncoderParams& params, Ptr<EncoderCallback> encoderCallback, const Stream& stream) |
|
|
|
{ |
|
|
|
{ |
|
|
|
encoderCallback = encoderCallback ? encoderCallback : new RawVideoWriter(fileName); |
|
|
|
CV_Assert(params.idrPeriod >= params.gopLength); |
|
|
|
|
|
|
|
if (!encoderCallback) { |
|
|
|
|
|
|
|
// required until PR for raw video encapsulation is merged and windows dll is updated
|
|
|
|
|
|
|
|
#ifndef WIN32 // remove #define and keep code once merged
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
encoderCallback = new FFmpegVideoWriter(fileName, codec, fps, frameSize, params.idrPeriod); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (...) |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
encoderCallback = new RawVideoWriter(fileName); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
return makePtr<VideoWriterImpl>(encoderCallback, frameSize, codec, fps, colorFormat, params, stream); |
|
|
|
return makePtr<VideoWriterImpl>(encoderCallback, frameSize, codec, fps, colorFormat, params, stream); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|