This article is about a rabbit-hole I recently went down, no there will not be any Mad-Hatters or talking cats just video codecs and build flags. The task I was trying to complete seemed simple enough: Use OpenCV to generate a working MP4 video by concatenating frames. Originally I attempted the following and got the error below:
>>> import cv2
>>>
>>> fourcc = cv2.VideoWriter_fourcc(*"avc1")
>>> video_writer = cv2.VideoWriter("movie.mp4", fourcc, 5, (5,5))
Could not find encoder for codec id 27: Encoder not found
For licensing reasons ,opencv-python
does not ship with some of the more common video codecs. The first solution I tried initially was to change the codec to mp4v
with the following change.
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
Problem solved! Let’s go out for some drinks, right? Not so fast. Unfortunately, MP4V
is not supported by most browsers, a fact I learned when I tried to embed one of these videos in a web application. After going down the rabbit hole for a while, I realized that the solution would involve compiling some of the sources manually. I could not find a comprehensive step-by-step solution, so I had to combine instructions from different sources. Below is the Dockerfile
for my working image. Before you use it here are some things to know:
opencv-python
is already installed on this image, if you re-install opencv-python using pip, it will break.- I have gotten the
avc1
codec working for MP4 files, in order to usex264
orh264
I had to change the file extension to.mkv
(If you know how to fix this let me know in the comments).
FROM ubuntu:18.04
WORKDIR /root
ENV OPENCV_VERSION=4.3.0 \
PYTHON_VERSION=3.6 \
PYTHON_VERSION_SHORT=36
RUN apt-get update
RUN apt-get remove -y ffmpeg x264 libx264-dev
RUN apt-get install -y \
build-essential \
cmake \
libjack-jackd2-dev \
libmp3lame-dev \
libopencore-amrnb-dev \
libopencore-amrwb-dev \
libsdl1.2-dev \
libtheora-dev \
libva-dev \
libvdpau-dev \
libvorbis-dev \
libx11-dev \
libxfixes-dev \
libxvidcore-dev \
texi2html \
zlib1g-dev \
wget \
unzip \
yasm \
pkg-config \
libswscale-dev \
libtbb2 \
libtbb-dev \
libjpeg-dev \
libpng-dev \
libtiff-dev \
libavformat-dev \
python${PYTHON_VERSION} \
python3-pip \
libpq-dev
RUN apt-get remove -y x264 ffmpeg libx264-dev && \
apt-get install -y x264 libx264-dev && \
apt-get install -y ffmpeg && \
pip3 install numpy
RUN wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \
unzip ${OPENCV_VERSION}.zip && \
mkdir opencv-${OPENCV_VERSION}/build
WORKDIR /root/opencv-${OPENCV_VERSION}/build
RUN cmake \
-DBUILD_TIFF=ON \
-DBUILD_opencv_java=OFF \
-DWITH_CUDA=OFF \
-DWITH_OPENGL=ON \
-DWITH_OPENCL=ON \
-DWITH_IPP=ON \
-DWITH_TBB=ON \
-DWITH_EIGEN=ON \
-DWITH_V4L=ON \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_INSTALL_PREFIX=$(python${PYTHON_VERSION} -c "import sys; print(sys.prefix)") \
-DPYTHON_EXECUTABLE=$(which python${PYTHON_VERSION}) \
-DPYTHON_INCLUDE_DIR=$(python${PYTHON_VERSION} -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-DPYTHON_PACKAGES_PATH=$(python${PYTHON_VERSION} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
-DPYTHON_DEFAULT_EXECUTABLE=$(which python${PYTHON_VERSION}) \
-DBUILD_NEW_PYTHON_SUPPORT=ON \
-DBUILD_opencv_python3=ON \
-DHAVE_opencv_python3=ON \
-DBUILD_opencv_gapi=OFF \
-DPYTHON3_NUMPY_INCLUDE_DIRS=/usr/local/lib/python${PYTHON_VERSION}/dist-packages/numpy/core/include \
.. \
&& make install
RUN mv \
/root/opencv-${OPENCV_VERSION}/build/lib/python3/cv2.cpython-${PYTHON_VERSION_SHORT}m-x86_64-linux-gnu.so \
/usr/local/lib/python${PYTHON_VERSION}/dist-packages/cv2.so
RUN unlink /usr/bin/python && ln -s /usr/bin/python3 /usr/bin/python
WORKDIR /root
RUN apt clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /root/opencv-${OPENCV_VERSION}