Skip to content

fix #26276: cv::VideoWriter fails writing colorless images #27153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: 4.x
Choose a base branch
from
3 changes: 2 additions & 1 deletion modules/videoio/src/cap_ffmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ class CvVideoWriter_FFMPEG_proxy CV_FINAL :
}
}

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 )
{
Expand Down
8 changes: 6 additions & 2 deletions modules/videoio/src/cap_ffmpeg_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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++;
Expand Down
2 changes: 1 addition & 1 deletion modules/videoio/src/cap_gstreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
77 changes: 77 additions & 0 deletions modules/videoio/test/test_ffmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,4 +953,81 @@ inline static std::string videoio_ffmpeg_16bit_name_printer(const testing::TestP

INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_16bit, testing::ValuesIn(sixteen_bit_modes), videoio_ffmpeg_16bit_name_printer);

typedef tuple<int /*inputType*/, int /*Depth*/, bool /*isColor*/, bool /*isValid*/, string /*description*/> ChannelMismatchTestParams;
typedef testing::TestWithParam< ChannelMismatchTestParams > videoio_ffmpeg_channel_mismatch;

TEST_P(videoio_ffmpeg_channel_mismatch, basic)
{
if (!videoio_registry::hasBackend(CAP_FFMPEG))
throw SkipTestException("FFmpeg backend was not found");

const string filename = "mismatch_video.mp4";
int input_type = get<0>(GetParam());
int depth = get<1>(GetParam());
bool is_Color = get<2>(GetParam());
bool is_valid = get<3>(GetParam());
const string description = get<4>(GetParam());

const double fps = 15.0;
const int fourcc = VideoWriter::fourcc('m', 'p', '4', 'v');
const Mat frame(480, 640, input_type, Scalar::all(0));

VideoWriter writer(filename, fourcc, fps, frame.size(),
{
cv::VIDEOWRITER_PROP_DEPTH, depth,
VIDEOWRITER_PROP_IS_COLOR, is_Color
});

if (!writer.isOpened())
throw SkipTestException("Failed to open video writer");

for (int i = 1; i <= 15; i++)
{
// In case of mismatch between input frame channels and
// expected depth/isColor configuration a warning should be printed communicating it
writer.write(frame);
}

writer.release();

VideoCapture cap(filename, CAP_FFMPEG);

if (is_valid) {
ASSERT_TRUE(cap.isOpened()) << "Can't open video for " << description;
EXPECT_EQ(cap.get(CAP_PROP_FRAME_COUNT), 15) << "All frames should be written for: " << description;
} else {
ASSERT_FALSE(cap.isOpened()) << "Video capture should fail to open for: " << description;
}

std::remove(filename.c_str());
}

const ChannelMismatchTestParams mismatch_cases[] =
{
// Testing input frame channels and expected depth/isColor combinations

// Open VideoWriter depth/isColor combination: CV_8U/true, everything with 3 channels should be valid
make_tuple(CV_16UC1, CV_8U, true, false, "input_CV_16UC1_expected_CV_8U_isColor_true"),
make_tuple(CV_8UC1, CV_8U, true, false, "input_CV_8UC1_expected_CV_8U_isColor_true"),
make_tuple(CV_8UC3, CV_8U, true, true, "input_CV_8UC3_expected_CV_8U_isColor_true_valid"),
make_tuple(CV_16UC3, CV_8U, true, true, "input_CV_16UC3_expected_CV_8U_isColor_true_valid"),

// Open VideoWriter depth/isColor combination: 16U,8U/false, everything with 1 channel should be valid
make_tuple(CV_8UC3, CV_8U, false, false, "input_CV_8UC3_expected_CV_8U_isColor_false"),
make_tuple(CV_16UC3, CV_8U, false, false, "input_CV_16UC3_expected_CV_8U_isColor_false"),
make_tuple(CV_8UC3, CV_16U, false, false, "input_CV_8UC3_expected_CV_16U_isColor_false"),
make_tuple(CV_16UC3, CV_16U, false, false, "input_CV_16UC3_expected_CV_16U_isColor_false"),
make_tuple(CV_8UC1, CV_16U, false, true, "input_CV_8UC1_expected_CV_16U_isColor_false_valid"),
make_tuple(CV_16UC1, CV_8U, false, true, "input_CV_16UC1_expected_CV_8U_isColor_false_valid"),
};

inline static std::string videoio_ffmpeg_mismatch_name_printer(const testing::TestParamInfo<videoio_ffmpeg_channel_mismatch::ParamType>& info)
{
std::ostringstream os;
os << get<4>(info.param);
return os.str();
}

INSTANTIATE_TEST_CASE_P(/**/, videoio_ffmpeg_channel_mismatch, testing::ValuesIn(mismatch_cases), videoio_ffmpeg_mismatch_name_printer);

}} // namespace
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy