Repository: opencv/opencv
File: modules/videoio/src/cap_ffmpeg_impl.hpp (C++)

Code before:
        ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
        if (ret < 0)
            ;
        else if (got_output) {
            if (pkt.pts != (int64_t)AV_NOPTS_VALUE)
                pkt.pts = av_rescale_q(pkt.pts, c->time_base, video_st->time_base);
            if (pkt.dts != (int64_t)AV_NOPTS_VALUE)
                pkt.dts = av_rescale_q(pkt.dts, c->time_base, video_st->time_base);
            if (pkt.duration)
                pkt.duration = av_rescale_q(pkt.duration, c->time_base, video_st->time_base);
            pkt.stream_index= video_st->index;
            ret = av_write_frame(oc, &pkt);
            _opencv_ffmpeg_av_packet_unref(&pkt);
        }
        else
            ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
#endif
    }
    return ret;
}

/// write a frame with FFMPEG
bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int type, int origin )
{
    if (!encode_video) {
        CV_Assert((type == CV_16UC1 || type == CV_8UC1) && ((width > 0 && height == 1) || (width == 1 && height > 0 && step == 1)));
        const bool set_key_frame = key_frame ? key_frame : idr_period ? frame_idx % idr_period == 0 : 1;
        bool ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame);
        frame_idx++;
        return ret;
    }

    // check parameters and do conversions if needed
    cv::Mat inputMat(height, width, type, (void*)data, step);
    cv::Mat convertedMat;
    switch (input_pix_fmt) {
        case AV_PIX_FMT_BGR24: // expected CV_8UC3
            if (type == CV_8UC3)
                convertedMat = inputMat;
            else {
                if (type == CV_16UC1) // CV_16UC1 -> CV_8UC1
                    inputMat.convertTo(inputMat, CV_8UC1, 1.0 / 256);
                cv::cvtColor(inputMat, convertedMat, cv::COLOR_GRAY2BGR); // CV_8UC1 -> CV_8UC3
            }
            break;
        case AV_PIX_FMT_GRAY8: // expected CV_8UC1
            if (type == CV_8UC1)
                convertedMat = inputMat;
            else if (type == CV_8UC3) // CV_8UC3 -> CV_8UC1
                cv::cvtColor(inputMat, convertedMat, COLOR_BGR2GRAY);
            else // CV_16UC1 -> CV_8UC1

Review comment (suggestion):
In case of `encode_video = False` we should accept only raw bytes arrays.
So we should have CV_8UC1 data type only.
Expected layout is 1xN or Nx1.

This change must be reverted.

Code after:
        ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
        if (ret < 0)
            ;
        else if (got_output) {
            if (pkt.pts != (int64_t)AV_NOPTS_VALUE)
                pkt.pts = av_rescale_q(pkt.pts, c->time_base, video_st->time_base);
            if (pkt.dts != (int64_t)AV_NOPTS_VALUE)
                pkt.dts = av_rescale_q(pkt.dts, c->time_base, video_st->time_base);
            if (pkt.duration)
                pkt.duration = av_rescale_q(pkt.duration, c->time_base, video_st->time_base);
            pkt.stream_index= video_st->index;
            ret = av_write_frame(oc, &pkt);
            _opencv_ffmpeg_av_packet_unref(&pkt);
        }
        else
            ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
#endif
    }
    return ret;
}

/// write a frame with FFMPEG
bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin )
{
    if (!encode_video) {
        CV_Assert(cn == 1 && ((width > 0 && height == 1) || (width == 1 && height > 0 && step == 1)));
        const bool set_key_frame = key_frame ? key_frame : idr_period ? frame_idx % idr_period == 0 : 1;
        bool ret = icv_av_encapsulate_video_FFMPEG(oc, video_st, context, (uint8_t*)data, width, frame_idx, pts_index, b_frame_dts_delay, set_key_frame);
        frame_idx++;
        return ret;
    }

    // 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;
        }
    }
    else {
        CV_LOG_WARNING(NULL, "Input data does not match selected pixel format: "
                       << av_get_pix_fmt_name(input_pix_fmt)
                       << ", number of channels: " << cn);
        CV_Assert(false);
    }