Search code examples
c++opencvvideo-codecs

OpenCV checking if video-codec is installed on machine (C++)


Problem:

I want to implement a safe version to process data into a video via OpenCV, this should work on Windows, Mac and Linux. The data has to be saved in a lossless video-codec.


Saving the file under my current setup is no problem at all, and I know that using -1 as fourcc with videoWriter will pop up a window. What I can't assure is that the system has the ability to show a window at all! So the popup-menu is okay as fallback, but not as the main solution.


Question:

Is there a way to check with OpenCV if a specific video-codec is installed on the machine without running into compile problems? Something like:

if (`codec installed`)
    int codec = opencvfourcc(codec)
else
    int codec = -1

Solution

  • OpenCV uses FFmpeg to decode video files. So if OpenCV has been built with the version of FFmpeg on the system, then we can use the FFmpeg command line to check for availability of our codec of choice. To run system commands from C++, I've used code from here. This post details how to check for OS type.

    #include <cstdio>
    #include <iostream>
    #include <memory>
    #include <stdexcept>
    #include <string>
    #include <array>
    
    #if defined(_WIN32) || defined(_WIN64)
    #define OS_WINDOWS
    #elif defined(__APPLE__) || defined(__MACH__)
    #define OS_OSX
    #elif defined(__linux__)
    #define OS_LINUX
    #endif
    
    std::string exec(const std::string& command ) {
        const char* cmd = command.c_str();
        std::array<char, 128> buffer;
        std::string result;
    
        #if defined(OS_WINDOWS)
        std::shared_ptr<FILE> pipe(_popen(cmd, "r"), _pclose);
        #elif defined(OS_LINUX) || defined (OS_OSX)
        std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
        #endif
    
        if (!pipe) throw std::runtime_error("popen() failed!");
        while (!feof(pipe.get())) {
            if (fgets(buffer.data(), 128, pipe.get()) != nullptr)
                result += buffer.data();
        }
        return result;
    }
    
    int main() {
    
      // codec of choice
      std::string codec = "H264";
    
      // if OS is linux or OSX then use FFmpeg with grep command
      #if defined (OS_LINUX) || defined (OS_OSX)
      std::string command = "ffmpeg -codecs | grep -i ";
      // if WINDOWS then FFmpeg with findstr
      #elif defined (OS_WINDOWS)
      std::string command = "ffmpeg -codecs | findstr /i ";
      #endif
    
      // execute the system command and get the output
      std::string str = exec(command+codec);
    
      // if the output string contains the letters DEV then FFmpeg supports the codec
      // D: Decoding supported
      // E: Encoding supported
      // V: Video codec
      std::size_t found = str.find("DEV");
    
      if(found != std::string::npos)
        std::cout<<"Codec Found"<<std::endl;
    
    return 0;
    }