Can I use videoWriter with FFV1 codec to write 16 bit Monochrome data?

Using Ubuntu Linux, I need to write 16 bit monochrome images to a compressed video file. I’ve found discussion around doing this successfully with FFMPEG and the FFV1 codec by manipulating the IS_COLOR and DEPTH parameters.

I have code that works well to write 8bit RGB images using the FFV1 codec.

The first version of openCV that documents the required parameters is 4.6.0 so I’ve built 4.6.0 from source and written code to open a videowriter and try to get the current values of all of the defined properties.

The getBackEndName() call correctly returns FFMPEG
The get() call returns 0 for all of the named properties, which apparently means that they are not implemented for the current back end.

Am I doing something wrong or is videoWriter integration with FFMPEG not there yet?

Is there any other way to accomplish this? I have wondered if it would be possible to split the 16 bit data into two 8bit “colors” and write that to the FFV1 codec. The result would look like complete garbage to any normal video reader but it could presumably be reconstructed using the reverse process. Required computing power is also a question as this is supposed to be happening in real time.

Well, no one has responded to this but in the meantime, with the help of several friends, I’ve found a way to do lossless compression of 16 bit monochrome data as follows. This requires conversions for both writing and reading and the resulting video file isn’t readable with a standard viewer like VLC.

The method boils down to this:
Instead of saving 16 bit pixels, save twice as many 8 bit pixels. If played back with a standard player like VLC, the image looks stretched twice as wide with vertical stripes.

Neither conversion requires moving much data around so it is reasonably fast.
The following code illustrates the method. I make no claim that the code is elegant or optimal but it may serve as something that others can build on:

cv::VideoWriter compressedVideo;

// Open new file to record video
void fileopenforWrite(std::string filename){
    int codec = cv::VideoWriter::fourcc('F', 'F', 'V', '1');			// lossless ffmpeg based codec
    double mframeRate = 30;
    bool isColour = false;
    cv::Size2i cookedimageSize = mimageSize;
    cookedimageSize.width = cookedimageSize.width*2;     // specify image twice as wide as original 16 bit image
    compressedVideo.open(filename, codec, mframeRate, cookedimageSize, isColour);    // Open the output
}

void write16bit(const cv::Mat & grayframe){				// grayframe assumed to be CV_16UC1
    try {
        cv::Mat frame2b(grayframe.rows, grayframe.cols*2, CV_8UC1);     // Create output frame, double the number of 8 bit pixels as input
        frame2b.data = grayframe.data;  				// point both Mat headers to the same block of data.
        compressedVideo.write(frame2b);					// write image with alternating columns of MSB and LSB
    }
    catch ( cv::Exception& e ) {
        qDebug() << "Video Write failed!" << e.what();
    }
}

cv::VideoCapture vcap;

// Open file to read video
void fileopenforRead(std::string filename) {
    try {
        if (!vcap.open(filename)) {
            qWarning() << "Input Video could not be opened: " << filename.data();
            return;
        }
        qInfo() << "Opened video file " << filename.data();
    }
    catch (cv::Exception e) {
        qCritical() << e.what();
    }
}

void read16bit() {
    try {
        vcap.read(m_frame);					//even though ffprobe recognizes the .avi file as 'gray', openCV returns a 8UC3 matrix
        cv::Mat tframe;
        extractChannel(m_frame,tframe,0);			// discard duplicate channels
        m_frame2.create(tframe.rows, tframe.cols/2, CV_16UC1);  // Create output frame, half the number of 16 bit pixels as input
        m_frame2.data = tframe.data;  				// point both Mat headers to the same block of data.
        emit matReady(m_frame2);				// Qt signal with reconstructed Mat
    }
    catch (cv::Exception e) {
        qCritical() << e.what();
    }
}