mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge pull request #27153 from 03kiko:fix-videowriter-writing-colorless-images-26276
fix #26276: cv::VideoWriter fails writing colorless images #27153 When writing grayscale images (`isColor=false`), `cv::VideoWriter` failed as FFmpeg backend requires input frames to be in a grayscale format. Unlike other backends, FFmpeg doesn't perform this conversion internally and expects the input to be pre-converted. To fix this, I inserted a check in the `CvVideoWriter_FFMPEG_proxy::write` to convert input frames to grayscale when the input has more than 1 channel. If this is true, then the input is converted to a gray image using `cv::cvtColor` (with `cv::COLOR_BGR2GRAY`). Additionally, as suggested in the issue comments, I have correctly propagated the return value of `CvVideoWriter_FFMPEG::writeFrame` back to the `CvVideoWriter_FFMPEG_proxy::write`. This return value wasn't being used, and `writeFrame` was always returning false since the FFmeg's return code `AVERROR(EAGAIN)` was mistakenly being treated as an error. Now it's handled as a signal for additional input (current input was successfully written, and a new frame should be sent. [See FFmpeg documentation for `avcodec_receive_packet`](https://ffmpeg.org/doxygen/6.1/group__lavc__decoding.html)). A warning is displayed if `CvVideoWriter_FFMPEG::writeFrame` returns false. Alternatively, this could be propagated back up to the user, making cv::VideoWriter::write a boolean. Finally, I added a test case to verify if the grayscale conversion is being done correctly. Fixes #26276 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -194,7 +194,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image.getMat().ptr(), (int)image.step(), image.cols(), image.rows(), image.channels(), 0);
|
||||
if (!icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image.getMat().ptr(), (int)image.step(), image.cols(), image.rows(), image.channels(), 0))
|
||||
CV_LOG_WARNING(NULL, "FFmpeg: Failed to write frame");
|
||||
}
|
||||
virtual bool open( const cv::String& filename, int fourcc, double fps, cv::Size frameSize, const VideoWriterParameters& params )
|
||||
{
|
||||
|
||||
@@ -2525,11 +2525,13 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
|
||||
// check parameters
|
||||
if (input_pix_fmt == AV_PIX_FMT_BGR24) {
|
||||
if (cn != 3) {
|
||||
CV_LOG_WARNING(NULL, "write frame skipped - expected 3 channels but got " << cn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (input_pix_fmt == AV_PIX_FMT_GRAY8 || input_pix_fmt == AV_PIX_FMT_GRAY16LE) {
|
||||
if (cn != 1) {
|
||||
CV_LOG_WARNING(NULL, "write frame skipped - expected 1 channel but got " << cn);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2640,14 +2642,16 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
|
||||
}
|
||||
hw_frame->pts = frame_idx;
|
||||
int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, hw_frame, frame_idx);
|
||||
ret = ret_write >= 0 ? true : false;
|
||||
// AVERROR(EAGAIN): continue sending input, not an error
|
||||
ret = (ret_write >= 0 || ret_write == AVERROR(EAGAIN));
|
||||
av_frame_free(&hw_frame);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
picture->pts = frame_idx;
|
||||
int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, picture, frame_idx);
|
||||
ret = ret_write >= 0 ? true : false;
|
||||
// AVERROR(EAGAIN): continue sending input, not an error
|
||||
ret = (ret_write >= 0 || ret_write == AVERROR(EAGAIN));
|
||||
}
|
||||
|
||||
frame_idx++;
|
||||
|
||||
@@ -2699,7 +2699,7 @@ void CvVideoWriter_GStreamer::write(InputArray image)
|
||||
}
|
||||
else if (input_pix_fmt == GST_VIDEO_FORMAT_GRAY16_LE) {
|
||||
if (image.type() != CV_16UC1) {
|
||||
CV_WARN("write frame skipped - expected CV_16UC3");
|
||||
CV_WARN("write frame skipped - expected CV_16UC1");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user