Search code examples
opencvffmpeggstreamercodecfourcc

Lossless avi encoding on linux


I am trying to write video using opencv. It is important for me to do this precisely - so it has to be a lossless codec. I am working with OpenCV 2.4.1 on Ubuntu 12.04

Previously, I was using the fourcc code 0. This gave me the exact result I wanted, and I was able to recover the images perfectly.

I am not sure what happened, but as of a recent update (around Jul 20th 2012), something went wrong and I am no longer able to write files with this fourcc code. I really don't remember what it was, but it could have come from doing an update, removing some software from my software center, and some other things I did during general cleaning...

When I check an older file with mediainfo (http://www.fourcc.org/identifier/) I see the following result:

Complete name                            : oldsample.avi
Format                                   : AVI
Format/Info                              : Audio Video Interleave
Format profile                           : OpenDML
File size                                : 1.07 GiB
Duration                                 : 41s 467ms
Overall bit rate                         : 221 Mbps
Writing application                      : Lavf53.5.0
Video
ID                                       : 0
Format                                   : RGB
Codec ID                                 : 0x00000000
Codec ID/Info                            : Basic Windows bitmap format. 1, 4 and 8 bpp     versions are palettised. 16, 24 and 32bpp contain raw RGB samples
Duration                                 : 41s 467ms
Bit rate                                 : 221 Mbps
Width                                    : 640 pixels
Height                                   : 4294966 816 pixels
Display aspect ratio                     : 0.000
Frame rate                               : 30.000 fps
Bit depth                                : 8 bits
Stream size                              : 1.07 GiB (100%)

Now, I see that when I write using the 0 fourcc codec, the program actually defaults to the i420 codec. Here is the output from one of the files I try to write now:

Complete name                            : newsample.avi
Format                                   : AVI
Format/Info                              : Audio Video Interleave
File size                                : 73.0 MiB
Duration                                 : 5s 533ms
Overall bit rate                         : 111 Mbps
Writing application                      : Lavf54.6.100
Video
ID                                       : 0
Format                                   : YUV
Codec ID                                 : I420
Codec ID/Info                            : 8 bit Y plane followed by 8 bit 2x2 subsampled U and V planes.
Duration                                 : 5s 533ms
Bit rate                                 : 111 Mbps
Width                                    : 640 pixels
Height                                   : 480 pixels
Display aspect ratio                     : 4:3
Frame rate                               : 30.000 fps
Compression mode                         : Lossless
Bits/(Pixel*Frame)                       : 12.000
Stream size                              : 72.9 MiB (100%)

This format, and other formats I try to use (like huffyuv HFYU), do not work for me because I end up with effects like this https://i.sstatic.net/lxe8T.jpg - you see the bright artifacts coming in due to what I assume is either lossy compression or chroma subsampling in the case of HFYU which is supposed to be lossless. What you are looking at is the red channel from one of my videos. The perceptual effect is negligible when you look at all 3 channels simultaneously but it is essential that I reconstruct the images exactly.

Furthermore, while I am able to play my old files in media players like vlc, I suddenly find them to be completely incompatible with opencv. When I try to open the older files with a videocapture, the open step works fine, but trying to do a read operation results in a segfault. Furthermore, When I try to write with either:

CV_FOURCC(0,0,0,0)
0

Opencv defaults to I420 for some reason.

Next, I tried using some alternate codecs. 'DIB ' seems like something that should work for me, and on the opencv website (http://opencv.willowgarage.com/wiki/VideoCodecs) it is listed as a 'recommended' codec. However, trying to use this results in the following message:

OpenCV-2.4.1/modules/highgui/src/cap_gstreamer.cpp:483: error: (-210) Gstreamer Opencv backend doesn't support this codec acutally. in function CvVideoWriter_GStreamer::open

Aborted (core dumped)

I checked the opencv source for this codec, and stumbled across the following:

cd OpenCV-2.4.1/modules
grep -i -r "CV_FOURCC" ./*
...
./highgui/src/cap_qt.cpp:    /*if( fourcc == CV_FOURCC( 'D', 'I', 'B', ' ' ))
./highgui/include/opencv2/highgui/highgui_c.h:#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V') /* Use default codec for specified filename (Linux only) */

I tried installing qt4 and reconfiguring with the WITH_QT flag, but that did not change anything. I also tried uncommenting that part of the code and reinstalling opencv, but that also did not work.

My ultimate goal is for any way to efficiently store and retrieve a video stream with 16 bits for every pixel (like 32float would work fine, and then it wouldn't need to be perfect). Right now I am unpacking the 16 bits into the red and green channels, which is why I need it to be perfect - since an error of 1 in the red channel is multiplied by 256 in the final result. I am not having success with any of the fourcc codes available to me.


Solution

  • I ended up figuring this out a little while ago, and finally got a chance to write it up for everyone. You can see my (rather hacky) solution here:

    http://denislantsman.com/?p=111


    Edit: As the website is down the following summarizes what can be found from the Wayback Machine:

    • Save frames as individual PNG images
    • Run ffmpeg to generate a file which can be opened by OpenCV:

      ffmpeg -i ./outimg/depth%d.png -vcodec png depth.mov

    • The following Python snippet may be useful for saving the individual frames

      std::ostringstream out_depth;
      ...
      expand_depth(playback.pDepthMap, expanded_depth, playback.rows, playback.cols);
      out_depth << root << "/outimg/depth" << framecount << ".png";
      cv::imwrite(out_depth.str(), expanded_depth);
      framecount++;
      

      ...