I am trying to get video details (length, height, width, and content type) from a video based on a URL. By using the nuget package https://www.nuget.org/packages/NReco.VideoInfo.LT I was able to create an Azure Function running locally pointing to my local install of FFProbe rather easily. However, the trick is now making it compatible with an Azure Function and, to the best of my knowledge, the easiest way to do that is by providing a Docker image that contains everything needed (this would be running on a Linux machine).
So, let's get into the code. Previously, this is what I had working if I ran the function locally:
var ffProbe = new NReco.VideoInfo.FFProbe();
ffProbe.FFProbeExeName = "ffprobe.exe"; // just "ffprobe" for Linux/OS-X
ffProbe.ToolPath = "C:\\tools\\ffmpeg\\bin";
var videoInfo = ffProbe.GetMediaInfo(videoUrl);
Now, (and again, this is the best to my knowledge), to get it to run in a Linux environment using Docker, I've run into several issues.
So, the first attempt was the easy way I suppose and try to do a apt-get install ffmpeg. This was the Dockerfile (Sorry, this is going to be a long post... but better to show everything I suppose):
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS installer-env
# 0. Install essential packages
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get install -y ffmpeg
ENV AzureWebJobsStorage=""
COPY . /src/dotnet-function-app
RUN cd /src/dotnet-function-app && \
mkdir -p /home/site/wwwroot && \
dotnet publish *.csproj --output /home/site/wwwroot
RUN mkdir -p /home/site/wwwroot/bin
RUN mv /usr/bin/* /home/site/wwwroot/bin
# To enable ssh & remote debugging on app service change the base image to the one below
# FROM mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
FROM mcr.microsoft.com/azure-functions/dotnet:3.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"]
I change the code to
var ffProbe = new NReco.VideoInfo.FFProbe();
ffProbe.FFProbeExeName = "ffprobe"; // just "ffprobe" for Linux/OS-X
ffProbe.ToolPath = "/home/site/wwwroot/bin";
var videoInfo = ffProbe.GetMediaInfo(videoUrl);
That builds, but when I run it, I get an error: error while loading shared libraries: libavdevice.so.58
So, I do some digging and it looks like I have to go the manual build route. Which isn't ideal, but I give it a go and adjust the Dockerfile:
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS installer-env
# 0. Install essential packages
RUN apt-get update -qq && apt-get -y install \
autoconf \
automake \
build-essential \
cmake \
git-core \
libass-dev \
libfreetype6-dev \
libsdl2-dev \
libtool \
libva-dev \
libvdpau-dev \
libvorbis-dev \
libxcb1-dev \
libxcb-shm0-dev \
libxcb-xfixes0-dev \
pkg-config \
texinfo \
wget \
zlib1g-dev \
nasm \
yasm \
libx265-dev \
libnuma-dev \
libvpx-dev \
libmp3lame-dev \
libopus-dev \
libx264-dev
RUN mkdir -p /home/site/wwwroot
RUN mkdir -p /home/site/wwwroot/ffmpeg_sources /home/site/wwwroot/bin && cd /home/site/wwwroot/ffmpeg_sources && \
wget -O ffmpeg-4.3.1.tar.bz2 https://ffmpeg.org/releases/ffmpeg-4.3.1.tar.bz2 && \
tar xjvf ffmpeg-4.3.1.tar.bz2 && \
cd ffmpeg-4.3.1 && \
PATH="/home/site/wwwroot/bin:$PATH" PKG_CONFIG_PATH="/home/site/wwwroot/ffmpeg_build/lib/pkgconfig" ./configure \
--prefix="/home/site/wwwroot/ffmpeg_build" \
--pkg-config-flags="--static" \
--extra-cflags="-I/home/site/wwwroot/ffmpeg_build/include" \
--extra-ldflags="-L/home/site/wwwroot/ffmpeg_build/lib" \
--extra-libs="-lpthread -lm" \
--bindir="/home/site/wwwroot/bin" \
--enable-gpl \
--enable-libass \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-nonfree && \
PATH="/home/site/wwwroot/bin:$PATH" make -j8 && \
make install -j8 && \
hash -r
ENV AzureWebJobsStorage=""
COPY . /src/dotnet-function-app
RUN cd /src/dotnet-function-app && \
dotnet publish *.csproj --output /home/site/wwwroot
FROM mcr.microsoft.com/azure-functions/dotnet:3.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"]
Again, that builds and then I try to run, this time getting the same error but for a different file: error while loading shared libraries: libxcb.so.1
So, I should mention that Docker is somewhat new to me, so I could be missing something easy. But I've tried to figure this out all night until I decided that I needed some advice. My main app is also hosted on a linux machine, so that would be a no go there. Besides the Azure Function approach, the other crazy idea is spinning up a low-priority Windows VM for like $20 a month... but then I have to configure IIS and all that stuff. So, it would be great to figure out what I'm doing wrong or if it's even feasible. I've gotten Python/Selenium to work using Docker and Azure Functions before based off of https://github.com/rebremer/azure-function-selenium... so I'm hoping it's just me not being familiar with Docker enough.
Any help to get this working for me would be greatly appreciated. If you have any questions, please don't hesitate to ask.
Thanks!