diff --git a/modules/cudaarithm/src/cuda/polar_cart.cu b/modules/cudaarithm/src/cuda/polar_cart.cu index 725f5741d81..c65b894bf60 100644 --- a/modules/cudaarithm/src/cuda/polar_cart.cu +++ b/modules/cudaarithm/src/cuda/polar_cart.cu @@ -159,25 +159,15 @@ void cv::cuda::cartToPolar(InputArray _xy, OutputArray _mag, OutputArray _angle, GpuMat_ magc(mag); GpuMat_ anglec(angle); + gridTransformUnary(globPtr(xy), globPtr(magc), magnitude_interleaved_func(), stream); + if (angleInDegrees) { - auto f1 = magnitude_interleaved_func(); - auto f2 = direction_interleaved_func(); - cv::cudev::tuple f12 = cv::cudev::make_tuple(f1, f2); - gridTransformTuple(globPtr(xy), - tie(magc, anglec), - f12, - stream); + gridTransformUnary(globPtr(xy), globPtr(anglec), direction_interleaved_func(), stream); } else { - auto f1 = magnitude_interleaved_func(); - auto f2 = direction_interleaved_func(); - cv::cudev::tuple f12 = cv::cudev::make_tuple(f1, f2); - gridTransformTuple(globPtr(xy), - tie(magc, anglec), - f12, - stream); + gridTransformUnary(globPtr(xy), globPtr(anglec), direction_interleaved_func(), stream); } syncOutput(mag, _mag, stream); @@ -191,7 +181,7 @@ void cv::cuda::cartToPolar(InputArray _xy, OutputArray _magAngle, bool angleInDe CV_Assert( xy.type() == CV_32FC2 ); GpuMat magAngle = getOutputMat(_magAngle, xy.size(), CV_32FC2, stream); - + if (angleInDegrees) { gridTransformUnary(globPtr(xy), diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp index 163417108e7..ca0ce204447 100644 --- a/modules/cudacodec/include/opencv2/cudacodec.hpp +++ b/modules/cudacodec/include/opencv2/cudacodec.hpp @@ -208,8 +208,15 @@ class CV_EXPORTS_W EncoderCallback { /** @brief Callback function to signal that the encoded bitstream for one or more frames is ready. @param vPacket The raw bitstream for one or more frames. + @param pts Presentation timestamps for each frame in vPacket using the FPS time base. e.g. fps = 25, pts = 3, presentation time = 3/25 seconds. */ - virtual void onEncoded(const std::vector>& vPacket) = 0; + virtual void onEncoded(const std::vector>& vPacket, const std::vector& pts) = 0; + + /** @brief Set the GOP pattern used by the encoder. + + @param frameIntervalP Specify the GOP pattern as follows : \p frameIntervalP = 0: I, 1 : IPP, 2 : IBP, 3 : IBBP. + */ + virtual bool setFrameIntervalP(const int frameIntervalP) = 0; /** @brief Callback function to that the encoding has finished. * */ diff --git a/modules/cudacodec/src/NvEncoder.cpp b/modules/cudacodec/src/NvEncoder.cpp index 87e3cde2cfc..b94bea200f5 100644 --- a/modules/cudacodec/src/NvEncoder.cpp +++ b/modules/cudacodec/src/NvEncoder.cpp @@ -305,9 +305,10 @@ void NvEncoder::MapResources(uint32_t bfrIdx) m_vMappedInputBuffers[bfrIdx] = mapInputResource.mappedResource; } -void NvEncoder::EncodeFrame(std::vector>& vPacket, NV_ENC_PIC_PARAMS* pPicParams) +void NvEncoder::EncodeFrame(std::vector>& vPacket, std::vector& outputTimeStamps, NV_ENC_PIC_PARAMS* pPicParams) { vPacket.clear(); + outputTimeStamps.clear(); if (!IsHWEncoderInitialized()) { NVENC_THROW_ERROR("Encoder device not found", NV_ENC_ERR_NO_ENCODE_DEVICE); @@ -322,7 +323,7 @@ void NvEncoder::EncodeFrame(std::vector>& vPacket, NV_ENC_P if (nvStatus == NV_ENC_SUCCESS || nvStatus == NV_ENC_ERR_NEED_MORE_INPUT) { m_iToSend++; - GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, true); + GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, outputTimeStamps, true); } else { @@ -353,6 +354,7 @@ NVENCSTATUS NvEncoder::DoEncode(NV_ENC_INPUT_PTR inputBuffer, NV_ENC_OUTPUT_PTR { picParams = *pPicParams; } + picParams.inputTimeStamp = m_iInputFrame++; picParams.version = NV_ENC_PIC_PARAMS_VER; picParams.pictureStruct = NV_ENC_PIC_STRUCT_FRAME; picParams.inputBuffer = inputBuffer; @@ -376,7 +378,7 @@ void NvEncoder::SendEOS() NVENC_API_CALL(m_nvenc.nvEncEncodePicture(m_hEncoder, &picParams)); } -void NvEncoder::EndEncode(std::vector>& vPacket) +void NvEncoder::EndEncode(std::vector>& vPacket, std::vector& outputTimeStamps) { vPacket.clear(); if (!IsHWEncoderInitialized()) @@ -386,10 +388,10 @@ void NvEncoder::EndEncode(std::vector>& vPacket) SendEOS(); - GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, false); + GetEncodedPacket(m_vBitstreamOutputBuffer, vPacket, outputTimeStamps, false); } -void NvEncoder::GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, bool bOutputDelay) +void NvEncoder::GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, std::vector& outputTimeStamps, bool bOutputDelay) { unsigned i = 0; int iEnd = bOutputDelay ? m_iToSend - m_nOutputDelay : m_iToSend; @@ -402,6 +404,7 @@ void NvEncoder::GetEncodedPacket(std::vector& vOutputBuffer, lockBitstreamData.doNotWait = false; NVENC_API_CALL(m_nvenc.nvEncLockBitstream(m_hEncoder, &lockBitstreamData)); + outputTimeStamps.push_back(lockBitstreamData.outputTimeStamp); uint8_t* pData = (uint8_t*)lockBitstreamData.bitstreamBufferPtr; if (vPacket.size() < i + 1) { @@ -499,7 +502,8 @@ void NvEncoder::FlushEncoder() try { std::vector> vPacket; - EndEncode(vPacket); + std::vector outputTimeStamps; + EndEncode(vPacket, outputTimeStamps); } catch (...) { diff --git a/modules/cudacodec/src/NvEncoder.h b/modules/cudacodec/src/NvEncoder.h index c5a53712e14..83fb6fc69ec 100644 --- a/modules/cudacodec/src/NvEncoder.h +++ b/modules/cudacodec/src/NvEncoder.h @@ -100,7 +100,7 @@ class NvEncoder * data, which has been copied to an input buffer obtained from the * GetNextInputFrame() function. */ - virtual void EncodeFrame(std::vector>& vPacket, NV_ENC_PIC_PARAMS* pPicParams = nullptr); + virtual void EncodeFrame(std::vector>& vPacket, std::vector& outputTimeStamps, NV_ENC_PIC_PARAMS* pPicParams = nullptr); /** * @brief This function to flush the encoder queue. @@ -109,7 +109,7 @@ class NvEncoder * from the encoder. The application must call this function before destroying * an encoder session. */ - virtual void EndEncode(std::vector>& vPacket); + virtual void EndEncode(std::vector>& vPacket, std::vector& outputTimeStamps); /** * @brief This function is used to query hardware encoder capabilities. @@ -317,7 +317,7 @@ class NvEncoder * This is called by DoEncode() function. If there is buffering enabled, * this may return without any output data. */ - void GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, bool bOutputDelay); + void GetEncodedPacket(std::vector& vOutputBuffer, std::vector>& vPacket, std::vector& outputTimeStamps, bool bOutputDelay); /** * @brief This is a private function which is used to initialize the bitstream buffers. @@ -369,6 +369,7 @@ class NvEncoder int32_t m_iGot = 0; int32_t m_nEncoderBuffer = 0; int32_t m_nOutputDelay = 0; + int32_t m_iInputFrame = 0; private: void* m_pDevice; diff --git a/modules/cudacodec/src/video_writer.cpp b/modules/cudacodec/src/video_writer.cpp index 2754ac58443..d702acb0bfc 100644 --- a/modules/cudacodec/src/video_writer.cpp +++ b/modules/cudacodec/src/video_writer.cpp @@ -53,6 +53,10 @@ Ptr createVideoWriter(const String&, const Size, const C #else // !defined HAVE_NVCUVENC +#if defined(WIN32) // remove when FFmpeg wrapper includes PR25874 +#define WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE +#endif + NV_ENC_BUFFER_FORMAT EncBufferFormat(const ColorFormat colorFormat); int NChannels(const ColorFormat colorFormat); GUID CodecGuid(const Codec codec); @@ -72,8 +76,9 @@ 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>& vPacket); + void onEncoded(const std::vector>& vPacket, const std::vector& pts); void onEncodingFinished(); + bool setFrameIntervalP(const int frameIntervalP); private: cv::VideoWriter writer; }; @@ -95,21 +100,32 @@ FFmpegVideoWriter::~FFmpegVideoWriter() { onEncodingFinished(); } -void FFmpegVideoWriter::onEncoded(const std::vector>& vPacket) { - for (auto& packet : vPacket) { +void FFmpegVideoWriter::onEncoded(const std::vector>& vPacket, const std::vector& pts) { + CV_Assert(vPacket.size() == pts.size()); + for (int i = 0; i < vPacket.size(); i++){ + std::vector packet = vPacket.at(i); Mat wrappedPacket(1, packet.size(), CV_8UC1, (void*)packet.data()); + const double ptsDouble = static_cast(pts.at(i)); + CV_Assert(static_cast(ptsDouble) == pts.at(i)); +#if !defined(WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE) + CV_Assert(writer.set(VIDEOWRITER_PROP_PTS, ptsDouble)); +#endif writer.write(wrappedPacket); } } +bool FFmpegVideoWriter::setFrameIntervalP(const int frameIntervalP) { + return writer.set(VIDEOWRITER_PROP_DTS_DELAY, static_cast(frameIntervalP - 1)); +} class RawVideoWriter : public EncoderCallback { public: RawVideoWriter(const String fileName); ~RawVideoWriter(); - void onEncoded(const std::vector>& vPacket); + void onEncoded(const std::vector>& vPacket, const std::vector& pts); void onEncodingFinished(); + bool setFrameIntervalP(const int) { return false;} private: std::ofstream fpOut; }; @@ -128,7 +144,7 @@ RawVideoWriter::~RawVideoWriter() { onEncodingFinished(); } -void RawVideoWriter::onEncoded(const std::vector>& vPacket) { +void RawVideoWriter::onEncoded(const std::vector>& vPacket, const std::vector&) { for (auto& packet : vPacket) fpOut.write(reinterpret_cast(packet.data()), packet.size()); } @@ -208,8 +224,9 @@ VideoWriterImpl::VideoWriterImpl(const Ptr& encoderCallBack_, c } void VideoWriterImpl::release() { - pEnc->EndEncode(vPacket); - encoderCallback->onEncoded(vPacket); + std::vector pts; + pEnc->EndEncode(vPacket, pts); + encoderCallback->onEncoded(vPacket, pts); encoderCallback->onEncodingFinished(); } @@ -316,6 +333,11 @@ void VideoWriterImpl::InitializeEncoder(const GUID codec, const double fps) initializeParams.encodeConfig->rcParams.maxBitRate = encoderParams.maxBitRate; initializeParams.encodeConfig->rcParams.targetQuality = encoderParams.targetQuality; initializeParams.encodeConfig->gopLength = encoderParams.gopLength; +#if !defined(WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE) + if (initializeParams.encodeConfig->frameIntervalP > 1) { + CV_Assert(encoderCallback->setFrameIntervalP(initializeParams.encodeConfig->frameIntervalP)); + } +#endif if (codec == NV_ENC_CODEC_H264_GUID) initializeParams.encodeConfig->encodeCodecConfig.h264Config.idrPeriod = encoderParams.idrPeriod; else if (codec == NV_ENC_CODEC_HEVC_GUID) @@ -383,8 +405,9 @@ void VideoWriterImpl::CopyToNvSurface(const InputArray src) void VideoWriterImpl::write(const InputArray frame) { CV_Assert(frame.channels() == nSrcChannels); CopyToNvSurface(frame); - pEnc->EncodeFrame(vPacket); - encoderCallback->onEncoded(vPacket); + std::vector pts; + pEnc->EncodeFrame(vPacket, pts); + encoderCallback->onEncoded(vPacket, pts); }; EncoderParams VideoWriterImpl::getEncoderParams() const { diff --git a/modules/cudacodec/test/test_video.cpp b/modules/cudacodec/test/test_video.cpp index 16782a39088..003fbb7358e 100644 --- a/modules/cudacodec/test/test_video.cpp +++ b/modules/cudacodec/test/test_video.cpp @@ -650,6 +650,9 @@ struct TransCode : testing::TestWithParam } }; +#if defined(WIN32) // remove when FFmpeg wrapper includes PR25874 +#define WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE +#endif CUDA_TEST_P(TransCode, H264ToH265) { @@ -691,6 +694,10 @@ CUDA_TEST_P(TransCode, H264ToH265) for (int i = 0; i < nFrames; ++i) { cap >> frame; ASSERT_FALSE(frame.empty()); +#if !defined(WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE) + const int pts = static_cast(cap.get(CAP_PROP_PTS)); + ASSERT_EQ(i, pts > 0 ? pts : 0); // FFmpeg back end returns dts if pts is zero. +#endif } } ASSERT_EQ(0, remove(outputFile.c_str())); @@ -773,6 +780,10 @@ CUDA_TEST_P(Write, Writer) for (int i = 0; i < nFrames; ++i) { cap >> frame; ASSERT_FALSE(frame.empty()); +#if !defined(WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE) + const int pts = static_cast(cap.get(CAP_PROP_PTS)); + ASSERT_EQ(i, pts > 0 ? pts : 0); // FFmpeg back end returns dts if pts is zero. +#endif } } ASSERT_EQ(0, remove(outputFile.c_str())); @@ -867,6 +878,10 @@ CUDA_TEST_P(EncoderParams, Writer) const bool keyFrameActual = capRaw.get(CAP_PROP_LRF_HAS_KEY_FRAME) == 1.0; const bool keyFrameReference = i % idrPeriod == 0; ASSERT_EQ(keyFrameActual, keyFrameReference); +#if !defined(WIN32_WAIT_FOR_FFMPEG_WRAPPER_UPDATE) + const int pts = static_cast(cap.get(CAP_PROP_PTS)); + ASSERT_EQ(i, pts > 0 ? pts : 0); // FFmpeg back end returns dts if pts is zero. +#endif } } } diff --git a/modules/wechat_qrcode/src/zxing/zxing.hpp b/modules/wechat_qrcode/src/zxing/zxing.hpp index 76efae22c87..e61f36e8723 100644 --- a/modules/wechat_qrcode/src/zxing/zxing.hpp +++ b/modules/wechat_qrcode/src/zxing/zxing.hpp @@ -11,6 +11,7 @@ #ifndef __ZXING_ZXING_HPP__ #define __ZXING_ZXING_HPP__ +#include "opencv2/core/fast_math.hpp" #define COUNTER_TYPE short @@ -54,8 +55,8 @@ typedef unsigned char boolean; #include namespace zxing { -inline bool isnan(float v) { return std::isnan(v); } -inline bool isnan(double v) { return std::isnan(v); } +inline bool isnan(float v) { return cvIsNaN(v) != 0; } +inline bool isnan(double v) { return cvIsNaN(v) != 0; } inline float nan() { return std::numeric_limits::quiet_NaN(); } } // namespace zxing