diff --git a/3rdparty/ffmpeg/opencv_ffmpeg.dll b/3rdparty/ffmpeg/opencv_ffmpeg.dll index eb02a95998..f4101c0273 100644 Binary files a/3rdparty/ffmpeg/opencv_ffmpeg.dll and b/3rdparty/ffmpeg/opencv_ffmpeg.dll differ diff --git a/3rdparty/ffmpeg/opencv_ffmpeg_64.dll b/3rdparty/ffmpeg/opencv_ffmpeg_64.dll index cd3c499806..604f581a1a 100644 Binary files a/3rdparty/ffmpeg/opencv_ffmpeg_64.dll and b/3rdparty/ffmpeg/opencv_ffmpeg_64.dll differ diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index 6c609583fb..03399a0c75 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -1898,18 +1898,29 @@ public: // Callbacks for video encoder, use it if you want to work with raw video stream class EncoderCallBack; + enum SurfaceFormat + { + SF_UYVY = 0, + SF_YUY2, + SF_YV12, + SF_NV12, + SF_IYUV, + SF_BGR, + SF_GRAY = SF_BGR + }; + VideoWriter_GPU(); - VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps); - VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params); - VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps); - VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params); + VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); + VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); + VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); + VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); ~VideoWriter_GPU(); // all methods throws cv::Exception if error occurs - void open(const std::string& fileName, cv::Size frameSize, double fps); - void open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params); - void open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps); - void open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params); + void open(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); + void open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); + void open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format = SF_BGR); + void open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format = SF_BGR); bool isOpened() const; void close(); diff --git a/modules/gpu/src/video_writer.cpp b/modules/gpu/src/video_writer.cpp index 4bacc0b9c0..fc7f7185e1 100644 --- a/modules/gpu/src/video_writer.cpp +++ b/modules/gpu/src/video_writer.cpp @@ -45,15 +45,15 @@ #if !defined HAVE_CUDA || !defined WIN32 cv::gpu::VideoWriter_GPU::VideoWriter_GPU() { throw_nogpu(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double) { throw_nogpu(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr&, cv::Size, double) { throw_nogpu(); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr&, cv::Size, double, const EncoderParams&) { throw_nogpu(); } +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, SurfaceFormat) { throw_nogpu(); } +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); } +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr&, cv::Size, double, SurfaceFormat) { throw_nogpu(); } +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); } cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() {} -void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double) { throw_nogpu(); } -void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, const EncoderParams&) { throw_nogpu(); } -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr&, cv::Size, double) { throw_nogpu(); } -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr&, cv::Size, double, const EncoderParams&) { throw_nogpu(); } +void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, SurfaceFormat) { throw_nogpu(); } +void cv::gpu::VideoWriter_GPU::open(const std::string&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); } +void cv::gpu::VideoWriter_GPU::open(const cv::Ptr&, cv::Size, double, SurfaceFormat) { throw_nogpu(); } +void cv::gpu::VideoWriter_GPU::open(const cv::Ptr&, cv::Size, double, const EncoderParams&, SurfaceFormat) { throw_nogpu(); } bool cv::gpu::VideoWriter_GPU::isOpened() const { return false; } void cv::gpu::VideoWriter_GPU::close() {} void cv::gpu::VideoWriter_GPU::write(const cv::gpu::GpuMat&, bool) { throw_nogpu(); } @@ -124,8 +124,8 @@ namespace class cv::gpu::VideoWriter_GPU::Impl { public: - Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, CodecType codec = H264); - Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec = H264); + Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec = H264); + Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec = H264); void write(const cv::gpu::GpuMat& image, bool lastFrame); @@ -143,6 +143,7 @@ private: cv::Size frameSize_; CodecType codec_; + SurfaceFormat inputFormat_; NVVE_SurfaceFormat surfaceFormat_; NVEncoderWrapper encoder_; @@ -158,13 +159,15 @@ private: static void NVENCAPI HandleOnEndFrame(const NVVE_EndFrameInfo* pefi, void* pUserdata); }; -cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, CodecType codec) : +cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, SurfaceFormat format, CodecType codec) : callback_(callback), frameSize_(frameSize), codec_(codec), - surfaceFormat_(YV12), + inputFormat_(format), cuCtxLock_(0) { + surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_); + initEncoder(fps); initGpuMemory(); @@ -174,13 +177,15 @@ cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, c createHWEncoder(); } -cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, CodecType codec) : +cv::gpu::VideoWriter_GPU::Impl::Impl(const cv::Ptr& callback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format, CodecType codec) : callback_(callback), frameSize_(frameSize), codec_(codec), - surfaceFormat_(YV12), + inputFormat_(format), cuCtxLock_(0) { + surfaceFormat_ = inputFormat_ == SF_BGR ? YV12 : static_cast(inputFormat_); + initEncoder(fps); setEncodeParams(params); @@ -401,10 +406,153 @@ namespace cv { namespace gpu { namespace device } }}} +namespace +{ + // UYVY/YUY2 are both 4:2:2 formats (16bpc) + // Luma, U, V are interleaved, chroma is subsampled (w/2,h) + void copyUYVYorYUY2Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) + { + CUresult res; + + // Source is YUVY/YUY2 4:2:2, the YUV data in a packed and interleaved + + // YUV Copy setup + CUDA_MEMCPY2D stCopyYUV422; + memset((void*)&stCopyYUV422, 0, sizeof(stCopyYUV422)); + stCopyYUV422.srcXInBytes = 0; + stCopyYUV422.srcY = 0; + stCopyYUV422.srcMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyYUV422.srcHost = 0; + stCopyYUV422.srcDevice = (CUdeviceptr) src.data; + stCopyYUV422.srcArray = 0; + stCopyYUV422.srcPitch = src.step; + + stCopyYUV422.dstXInBytes = 0; + stCopyYUV422.dstY = 0; + stCopyYUV422.dstMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyYUV422.dstHost = 0; + stCopyYUV422.dstDevice = (CUdeviceptr) dst.data; + stCopyYUV422.dstArray = 0; + stCopyYUV422.dstPitch = dst.step; + + stCopyYUV422.WidthInBytes = frameSize.width * 2; + stCopyYUV422.Height = frameSize.height; + + // DMA Luma/Chroma + res = cuMemcpy2D(&stCopyYUV422); + CV_Assert( res == CUDA_SUCCESS ); + } + + // YV12/IYUV are both 4:2:0 planar formats (12bpc) + // Luma, U, V chroma planar (12bpc), chroma is subsampled (w/2,h/2) + void copyYV12orIYUVFrame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) + { + CUresult res; + + // Source is YV12/IYUV, this native format is converted to NV12 format by the video encoder + + // (1) luma copy setup + CUDA_MEMCPY2D stCopyLuma; + memset((void*)&stCopyLuma, 0, sizeof(stCopyLuma)); + stCopyLuma.srcXInBytes = 0; + stCopyLuma.srcY = 0; + stCopyLuma.srcMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyLuma.srcHost = 0; + stCopyLuma.srcDevice = (CUdeviceptr) src.data; + stCopyLuma.srcArray = 0; + stCopyLuma.srcPitch = src.step; + + stCopyLuma.dstXInBytes = 0; + stCopyLuma.dstY = 0; + stCopyLuma.dstMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyLuma.dstHost = 0; + stCopyLuma.dstDevice = (CUdeviceptr) dst.data; + stCopyLuma.dstArray = 0; + stCopyLuma.dstPitch = dst.step; + + stCopyLuma.WidthInBytes = frameSize.width; + stCopyLuma.Height = frameSize.height; + + // (2) chroma copy setup, U/V can be done together + CUDA_MEMCPY2D stCopyChroma; + memset((void*)&stCopyChroma, 0, sizeof(stCopyChroma)); + stCopyChroma.srcXInBytes = 0; + stCopyChroma.srcY = frameSize.height << 1; // U/V chroma offset + stCopyChroma.srcMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyChroma.srcHost = 0; + stCopyChroma.srcDevice = (CUdeviceptr) src.data; + stCopyChroma.srcArray = 0; + stCopyChroma.srcPitch = src.step >> 1; // chroma is subsampled by 2 (but it has U/V are next to each other) + + stCopyChroma.dstXInBytes = 0; + stCopyChroma.dstY = frameSize.height << 1; // chroma offset (srcY*srcPitch now points to the chroma planes) + stCopyChroma.dstMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyChroma.dstHost = 0; + stCopyChroma.dstDevice = (CUdeviceptr) dst.data; + stCopyChroma.dstArray = 0; + stCopyChroma.dstPitch = dst.step >> 1; + + stCopyChroma.WidthInBytes = frameSize.width >> 1; + stCopyChroma.Height = frameSize.height; // U/V are sent together + + // DMA Luma + res = cuMemcpy2D(&stCopyLuma); + CV_Assert( res == CUDA_SUCCESS ); + + // DMA Chroma channels (UV side by side) + res = cuMemcpy2D(&stCopyChroma); + CV_Assert( res == CUDA_SUCCESS ); + } + + // NV12 is 4:2:0 format (12bpc) + // Luma followed by U/V chroma interleaved (12bpc), chroma is subsampled (w/2,h/2) + void copyNV12Frame(cv::Size frameSize, const cv::gpu::GpuMat& src, cv::gpu::GpuMat& dst) + { + CUresult res; + + // Source is NV12 in pitch linear memory + // Because we are assume input is NV12 (if we take input in the native format), the encoder handles NV12 as a native format in pitch linear memory + + // Luma/Chroma can be done in a single transfer + CUDA_MEMCPY2D stCopyNV12; + memset((void*)&stCopyNV12, 0, sizeof(stCopyNV12)); + stCopyNV12.srcXInBytes = 0; + stCopyNV12.srcY = 0; + stCopyNV12.srcMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyNV12.srcHost = 0; + stCopyNV12.srcDevice = (CUdeviceptr) src.data; + stCopyNV12.srcArray = 0; + stCopyNV12.srcPitch = src.step; + + stCopyNV12.dstXInBytes = 0; + stCopyNV12.dstY = 0; + stCopyNV12.dstMemoryType = CU_MEMORYTYPE_DEVICE; + stCopyNV12.dstHost = 0; + stCopyNV12.dstDevice = (CUdeviceptr) dst.data; + stCopyNV12.dstArray = 0; + stCopyNV12.dstPitch = dst.step; + + stCopyNV12.WidthInBytes = frameSize.width; + stCopyNV12.Height =(frameSize.height * 3) >> 1; + + // DMA Luma/Chroma + res = cuMemcpy2D(&stCopyNV12); + CV_Assert( res == CUDA_SUCCESS ); + } +} + void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool lastFrame) { - CV_Assert( frame.size() == frameSize_ ); - CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 ); + if (inputFormat_ == SF_BGR) + { + CV_Assert( frame.size() == frameSize_ ); + CV_Assert( frame.type() == CV_8UC1 || frame.type() == CV_8UC3 || frame.type() == CV_8UC4 ); + } + else + { + CV_Assert( frame.size() == videoFrame_.size() ); + CV_Assert( frame.type() == videoFrame_.type() ); + } NVVE_EncodeFrameParams efparams; efparams.Width = frameSize_.width; @@ -422,8 +570,27 @@ void cv::gpu::VideoWriter_GPU::Impl::write(const cv::gpu::GpuMat& frame, bool la CUresult res = cuvidCtxLock(cuCtxLock_, 0); CV_Assert( res == CUDA_SUCCESS ); - if (surfaceFormat_ == YV12) + if (inputFormat_ == SF_BGR) cv::gpu::device::video_encoding::YV12_gpu(frame, frame.channels(), videoFrame_); + else + { + switch (surfaceFormat_) + { + case UYVY: // UYVY (4:2:2) + case YUY2: // YUY2 (4:2:2) + copyUYVYorYUY2Frame(frameSize_, frame, videoFrame_); + break; + + case YV12: // YV12 (4:2:0), Y V U + case IYUV: // IYUV (4:2:0), Y U V + copyYV12orIYUVFrame(frameSize_, frame, videoFrame_); + break; + + case NV12: // NV12 (4:2:0) + copyNV12Frame(frameSize_, frame, videoFrame_); + break; + } + } res = cuvidCtxUnlock(cuCtxLock_, 0); CV_Assert( res == CUDA_SUCCESS ); @@ -480,6 +647,7 @@ private: struct OutputMediaStream_FFMPEG* stream_; std::vector buf_; + bool isKeyFrame_; }; namespace @@ -528,7 +696,7 @@ namespace } EncoderCallBackFFMPEG::EncoderCallBackFFMPEG(const std::string& fileName, cv::Size frameSize, double fps) : - stream_(0) + stream_(0), isKeyFrame_(false) { int buf_size = std::max(frameSize.area() * 4, 1024 * 1024); buf_.resize(buf_size); @@ -552,11 +720,12 @@ unsigned char* EncoderCallBackFFMPEG::acquireBitStream(int* bufferSize) void EncoderCallBackFFMPEG::releaseBitStream(unsigned char* data, int size) { - write_OutputMediaStream_FFMPEG_p(stream_, data, size); + write_OutputMediaStream_FFMPEG_p(stream_, data, size, isKeyFrame_); } void EncoderCallBackFFMPEG::onBeginFrame(int frameNumber, PicType picType) { + isKeyFrame_ = picType == IFRAME; } void EncoderCallBackFFMPEG::onEndFrame(int frameNumber, PicType picType) @@ -570,24 +739,24 @@ cv::gpu::VideoWriter_GPU::VideoWriter_GPU() { } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps) +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format) { - open(fileName, frameSize, fps); + open(fileName, frameSize, fps, format); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params) +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) { - open(fileName, frameSize, fps, params); + open(fileName, frameSize, fps, params, format); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps) +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format) { - open(encoderCallback, frameSize, fps); + open(encoderCallback, frameSize, fps, format); } -cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params) +cv::gpu::VideoWriter_GPU::VideoWriter_GPU(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) { - open(encoderCallback, frameSize, fps, params); + open(encoderCallback, frameSize, fps, params, format); } cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() @@ -595,30 +764,30 @@ cv::gpu::VideoWriter_GPU::~VideoWriter_GPU() close(); } -void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps) +void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, SurfaceFormat format) { close(); cv::Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); - open(encoderCallback, frameSize, fps); + open(encoderCallback, frameSize, fps, format); } -void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params) +void cv::gpu::VideoWriter_GPU::open(const std::string& fileName, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) { close(); cv::Ptr encoderCallback(new EncoderCallBackFFMPEG(fileName, frameSize, fps)); - open(encoderCallback, frameSize, fps, params); + open(encoderCallback, frameSize, fps, params, format); } -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps) +void cv::gpu::VideoWriter_GPU::open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, SurfaceFormat format) { close(); - impl_.reset(new Impl(encoderCallback, frameSize, fps)); + impl_.reset(new Impl(encoderCallback, frameSize, fps, format)); } -void cv::gpu::VideoWriter_GPU::open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params) +void cv::gpu::VideoWriter_GPU::open(const cv::Ptr& encoderCallback, cv::Size frameSize, double fps, const EncoderParams& params, SurfaceFormat format) { close(); - impl_.reset(new Impl(encoderCallback, frameSize, fps, params)); + impl_.reset(new Impl(encoderCallback, frameSize, fps, params, format)); } bool cv::gpu::VideoWriter_GPU::isOpened() const diff --git a/modules/highgui/src/cap_ffmpeg_api.hpp b/modules/highgui/src/cap_ffmpeg_api.hpp index 5aad37a09d..3ce80d4b8e 100644 --- a/modules/highgui/src/cap_ffmpeg_api.hpp +++ b/modules/highgui/src/cap_ffmpeg_api.hpp @@ -71,11 +71,11 @@ typedef void (*CvReleaseVideoWriter_Plugin)( void** writer ); OPENCV_FFMPEG_API struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps); OPENCV_FFMPEG_API void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream); -OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size); +OPENCV_FFMPEG_API void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); typedef struct OutputMediaStream_FFMPEG* (*Create_OutputMediaStream_FFMPEG_Plugin)(const char* fileName, int width, int height, double fps); typedef void (*Release_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream); -typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size); +typedef void (*Write_OutputMediaStream_FFMPEG_Plugin)(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame); #ifdef __cplusplus } diff --git a/modules/highgui/src/cap_ffmpeg_impl.hpp b/modules/highgui/src/cap_ffmpeg_impl.hpp index 973d3924fe..b269543aad 100644 --- a/modules/highgui/src/cap_ffmpeg_impl.hpp +++ b/modules/highgui/src/cap_ffmpeg_impl.hpp @@ -1454,9 +1454,9 @@ void CvVideoWriter_FFMPEG::close() struct OutputMediaStream_FFMPEG { bool open(const char* fileName, int width, int height, double fps); - void write(unsigned char* data, int size); - void close(); + + void write(unsigned char* data, int size, int keyFrame); // add a video output stream to the container static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format); @@ -1698,13 +1698,16 @@ bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, return true; } -void OutputMediaStream_FFMPEG::write(unsigned char* data, int size) +void OutputMediaStream_FFMPEG::write(unsigned char* data, int size, int keyFrame) { // if zero size, it means the image was buffered if (size > 0) { AVPacket pkt; av_init_packet(&pkt); + + if (keyFrame) + pkt.flags |= PKT_FLAG_KEY; pkt.stream_index = video_st_->index; pkt.data = data; @@ -1734,7 +1737,7 @@ void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream) free(stream); } -void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size) +void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame) { - stream->write(data, size); + stream->write(data, size, keyFrame); } diff --git a/modules/highgui/src/cap_ffmpeg_impl_v2.hpp b/modules/highgui/src/cap_ffmpeg_impl_v2.hpp index 4e5b425ca0..8298208380 100755 --- a/modules/highgui/src/cap_ffmpeg_impl_v2.hpp +++ b/modules/highgui/src/cap_ffmpeg_impl_v2.hpp @@ -1620,9 +1620,9 @@ void CvVideoWriter_FFMPEG::close() struct OutputMediaStream_FFMPEG { bool open(const char* fileName, int width, int height, double fps); - void write(unsigned char* data, int size); - void close(); + + void write(unsigned char* data, int size, int keyFrame); // add a video output stream to the container static AVStream* addVideoStream(AVFormatContext *oc, CodecID codec_id, int w, int h, int bitrate, double fps, PixelFormat pixel_format); @@ -1864,7 +1864,7 @@ bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, return true; } -void OutputMediaStream_FFMPEG::write(unsigned char* data, int size) +void OutputMediaStream_FFMPEG::write(unsigned char* data, int size, int keyFrame) { // if zero size, it means the image was buffered if (size > 0) @@ -1872,6 +1872,9 @@ void OutputMediaStream_FFMPEG::write(unsigned char* data, int size) AVPacket pkt; av_init_packet(&pkt); + if (keyFrame) + pkt.flags |= PKT_FLAG_KEY; + pkt.stream_index = video_st_->index; pkt.data = data; pkt.size = size; @@ -1900,7 +1903,7 @@ void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream) free(stream); } -void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size) +void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame) { - stream->write(data, size); + stream->write(data, size, keyFrame); }