From 53027e82e8c1e18d38ccb2f906954842edd2b789 Mon Sep 17 00:00:00 2001 From: Jan Stabenow Date: Thu, 12 May 2022 21:51:49 +0200 Subject: [PATCH] Add multi build setup --- .editorconfig | 11 + .github/workflows/build_base_alpine-rpi.yaml | 79 ++++ .../workflows/build_base_alpine-vaapi.yaml | 88 ++++ .github/workflows/build_base_alpine.yaml | 71 +++ Build.alpine.env | 13 + Build.alpine.rpi.env | 2 + Build.alpine.vaapi.env | 10 + Dockerfile.alpine | 128 +++++ Dockerfile.alpine.rpi | 145 ++++++ Dockerfile.alpine.vaapi | 172 +++++++ Dockerfile_FFmpeg_2-3 | 101 ---- Dockerfile_FFmpeg_4 | 100 ---- README.md | 126 ++--- contrib/ffmpeg-jsonstats.patch | 440 ++++++++++++++++++ 14 files changed, 1196 insertions(+), 290 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/build_base_alpine-rpi.yaml create mode 100644 .github/workflows/build_base_alpine-vaapi.yaml create mode 100644 .github/workflows/build_base_alpine.yaml create mode 100644 Build.alpine.env create mode 100644 Build.alpine.rpi.env create mode 100644 Build.alpine.vaapi.env create mode 100644 Dockerfile.alpine create mode 100644 Dockerfile.alpine.rpi create mode 100644 Dockerfile.alpine.vaapi delete mode 100644 Dockerfile_FFmpeg_2-3 delete mode 100644 Dockerfile_FFmpeg_4 create mode 100644 contrib/ffmpeg-jsonstats.patch diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1998a65 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/.github/workflows/build_base_alpine-rpi.yaml b/.github/workflows/build_base_alpine-rpi.yaml new file mode 100644 index 0000000..eb7213b --- /dev/null +++ b/.github/workflows/build_base_alpine-rpi.yaml @@ -0,0 +1,79 @@ +name: 'Build base:alpine-ffmpeg-rpi' + +on: + workflow_dispatch: + push: + branches-ignore: + - '**' + +jobs: + docker: + runs-on: [self-hosted] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - uses: cardinalby/export-env-action@v1 + with: + envFile: 'Build.alpine.env' + export: 'true' + expandWithJobEnv: 'true' + expand: 'true' + + - uses: cardinalby/export-env-action@v1 + with: + envFile: 'Build.alpine.rpi.env' + export: 'true' + expandWithJobEnv: 'true' + expand: 'true' + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: linux/arm/v7 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build Multi-Arch + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: . + file: ./Dockerfile.alpine.rpi + build-args: | + ALPINE_IMAGE=${{ env.OS_NAME }}:${{ env.OS_VERSION }} + FREETYPE_VERSION=${{ env.FREETYPE_VERSION }} + XML2_VERSION=${{ env.XML2_VERSION }} + SRT_VERSION=${{ env.SRT_VERSION }} + X264_VERSION=${{ env.X264_VERSION }} + X265_VERSION=${{ env.X265_VERSION }} + VPX_VERSION=${{ env.VPX_VERSION }} + LAME_VERSION=${{ env.LAME_VERSION }} + OPUS_VERSION=${{ env.OPUS_VERSION }} + VORBIS_VERSION=${{ env.VORBIS_VERSION }} + FFMPEG_VERSION=${{ env.FFMPEG_VERSION }} + RPI_VERSION=${{ env.RPI_VERSION }} + platforms: linux/arm/v7 + push: true + tags: | + datarhei/base:${{ env.OS_NAME }}-ffmpeg-rpi-${{ env.OS_VERSION }}-${{ env.FFMPEG_VERSION }} + datarhei/base:${{ env.OS_NAME }}-ffmpeg-rpi-latest + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new diff --git a/.github/workflows/build_base_alpine-vaapi.yaml b/.github/workflows/build_base_alpine-vaapi.yaml new file mode 100644 index 0000000..f3e0aec --- /dev/null +++ b/.github/workflows/build_base_alpine-vaapi.yaml @@ -0,0 +1,88 @@ +name: 'Build base:alpine-ffmpeg-vvapi' + +on: + workflow_dispatch: + push: + branches-ignore: + - '**' + +jobs: + docker: + runs-on: [self-hosted] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - uses: cardinalby/export-env-action@v1 + with: + envFile: 'Build.alpine.env' + export: 'true' + expandWithJobEnv: 'true' + expand: 'true' + + - uses: cardinalby/export-env-action@v1 + with: + envFile: 'Build.alpine.vaapi.env' + export: 'true' + expandWithJobEnv: 'true' + expand: 'true' + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build Multi-Arch + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: . + file: ./Dockerfile.alpine.vaapi + build-args: | + ALPINE_IMAGE=${{ env.OS_NAME }}:${{ env.OS_VERSION }} + FREETYPE_VERSION=${{ env.FREETYPE_VERSION }} + XML2_VERSION=${{ env.XML2_VERSION }} + SRT_VERSION=${{ env.SRT_VERSION }} + X264_VERSION=${{ env.X264_VERSION }} + X265_VERSION=${{ env.X265_VERSION }} + VPX_VERSION=${{ env.VPX_VERSION }} + LAME_VERSION=${{ env.LAME_VERSION }} + OPUS_VERSION=${{ env.OPUS_VERSION }} + VORBIS_VERSION=${{ env.VORBIS_VERSION }} + FFMPEG_VERSION=${{ env.FFMPEG_VERSION }} + LIBAV_VERSION=${{ env.LIBAV_VERSION }} + LIBVDPAU_VERSION=${{ env.LIBVDPAU_VERSION }} + MESA_VA_GALLIUM_VERSION=${{ env.MESA_VA_GALLIUM_VERSION }} + MESA_VDPAU_GALLIUM_VERSION=${{ env.MESA_VDPAU_GALLIUM_VERSION }} + LIBVA_VDPAU_DRIVER_VERSION=${{ env.LIBVA_VDPAU_DRIVER_VERSION }} + INTEL_GMMLIB_VERSION=${{ env.INTEL_GMMLIB_VERSION }} + INTEL_MEDIA_DRIVER_VERSION=${{ env.INTEL_MEDIA_DRIVER_VERSION }} + INTEL_MEDIA_SDK_VERSION=${{ env.INTEL_MEDIA_SDK_VERSION }} + INTEL_VAAPI_DRIVER=${{ env.INTEL_VAAPI_DRIVER }} + + platforms: linux/amd64 + push: true + tags: | + datarhei/base:${{ env.OS_NAME }}-ffmpeg-vaapi-${{ env.OS_VERSION }}-${{ env.FFMPEG_VERSION }} + datarhei/base:${{ env.OS_NAME }}-ffmpeg-vaapi-latest + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new diff --git a/.github/workflows/build_base_alpine.yaml b/.github/workflows/build_base_alpine.yaml new file mode 100644 index 0000000..95d7e41 --- /dev/null +++ b/.github/workflows/build_base_alpine.yaml @@ -0,0 +1,71 @@ +name: 'Build base:alpine-ffmpeg' + +on: + workflow_dispatch: + push: + branches-ignore: + - '**' + +jobs: + docker: + runs-on: [self-hosted] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - uses: cardinalby/export-env-action@v1 + with: + envFile: 'Build.alpine.env' + export: 'true' + expandWithJobEnv: 'true' + expand: 'true' + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build Multi-Arch + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: . + file: ./Dockerfile.alpine + build-args: | + ALPINE_IMAGE=${{ env.OS_NAME }}:${{ env.OS_VERSION }} + FREETYPE_VERSION=${{ env.FREETYPE_VERSION }} + XML2_VERSION=${{ env.XML2_VERSION }} + SRT_VERSION=${{ env.SRT_VERSION }} + X264_VERSION=${{ env.X264_VERSION }} + X265_VERSION=${{ env.X265_VERSION }} + VPX_VERSION=${{ env.VPX_VERSION }} + LAME_VERSION=${{ env.LAME_VERSION }} + OPUS_VERSION=${{ env.OPUS_VERSION }} + VORBIS_VERSION=${{ env.VORBIS_VERSION }} + FFMPEG_VERSION=${{ env.FFMPEG_VERSION }} + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: | + datarhei/base:${{ env.OS_NAME }}-ffmpeg-${{ env.OS_VERSION }}-${{ env.FFMPEG_VERSION }} + datarhei/base:${{ env.OS_NAME }}-ffmpeg-latest + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new diff --git a/Build.alpine.env b/Build.alpine.env new file mode 100644 index 0000000..27eaa06 --- /dev/null +++ b/Build.alpine.env @@ -0,0 +1,13 @@ +# FFMPEG BASE PACKAGES +OS_NAME=alpine +OS_VERSION=3.15 +FREETYPE_VERSION=2.11.1-r1 +XML2_VERSION=2.9.13-r0 +SRT_VERSION=1.4.2-r1 +X264_VERSION=20210613-r0 +X265_VERSION=3.5-r0 +VPX_VERSION=1.10.0-r0 +LAME_VERSION=3.100-r0 +OPUS_VERSION=1.3.1-r1 +VORBIS_VERSION=1.3.7-r0 +FFMPEG_VERSION=4.4.2 diff --git a/Build.alpine.rpi.env b/Build.alpine.rpi.env new file mode 100644 index 0000000..a31a8fd --- /dev/null +++ b/Build.alpine.rpi.env @@ -0,0 +1,2 @@ +# FFMPEG RPI PACKAGES +RPI_VERSION=0.20200813-r0 \ No newline at end of file diff --git a/Build.alpine.vaapi.env b/Build.alpine.vaapi.env new file mode 100644 index 0000000..3c6a4dd --- /dev/null +++ b/Build.alpine.vaapi.env @@ -0,0 +1,10 @@ +# FFMPEG VAAPI PACKAGES +LIBAV_VERSION=2.14.0-r0 +LIBVDPAU_VERSION=1.5-r0 +MESA_VA_GALLIUM_VERSION=21.3.8-r1 +MESA_VDPAU_GALLIUM_VERSION=21.3.8-r1 +LIBVA_VDPAU_DRIVER_VERSION=0.7.4-r2 +INTEL_GMMLIB_VERSION=22.1.2-r0 +INTEL_MEDIA_DRIVER_VERSION=22.4.1-r0 +INTEL_MEDIA_SDK_VERSION=22.4.1-r0 +INTEL_VAAPI_DRIVER=2.4.1-r0 \ No newline at end of file diff --git a/Dockerfile.alpine b/Dockerfile.alpine new file mode 100644 index 0000000..8d54bbf --- /dev/null +++ b/Dockerfile.alpine @@ -0,0 +1,128 @@ +ARG ALPINE_IMAGE=alpine:3.15 + +FROM $ALPINE_IMAGE as builder + +ARG FREETYPE_VERSION=2.11.1-r1 +ARG XML2_VERSION=2.9.13-r0 +ARG SRT_VERSION=1.4.2-r1 +ARG X264_VERSION=20210613-r0 +ARG X265_VERSION=3.5-r0 +ARG VPX_VERSION=1.10.0-r0 +ARG LAME_VERSION=3.100-r0 +ARG OPUS_VERSION=1.3.1-r1 +ARG VORBIS_VERSION=1.3.7-r0 +ARG FFMPEG_VERSION=4.4.2 + +ENV PKG_CONFIG_PATH=/usr/lib/pkgconfig \ + SRC=/usr + +# install build packages +RUN apk add --update \ + autoconf \ + automake \ + bash \ + binutils \ + bzip2 \ + ca-certificates \ + cmake \ + coreutils \ + curl \ + diffutils \ + g++ \ + gcc \ + libgcc \ + libssl1.1 \ + libtool \ + linux-headers \ + make \ + musl-dev \ + nasm \ + openssl-dev \ + patch \ + tar \ + zlib-dev + +# install shared ffmpeg libs +RUN apk add -U \ + freetype-dev=${FREETYPE_VERSION} \ + libxml2-dev=${XML2_VERSION} \ + libsrt-dev=${SRT_VERSION} \ + x264-dev=${X264_VERSION} \ + x265-dev=${X265_VERSION} \ + libvpx-dev=${VPX_VERSION} \ + lame-dev=${LAME_VERSION} \ + opus-dev=${OPUS_VERSION} \ + libvorbis-dev=${VORBIS_VERSION} + +# install and patch ffmpeg +RUN mkdir -p /dist && cd /dist && \ + curl -OLk http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar -xvz -f ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + rm ffmpeg-${FFMPEG_VERSION}.tar.gz + +COPY ./contrib /contrib + +RUN cd /dist/ffmpeg-${FFMPEG_VERSION} && \ + patch -p1 < /contrib/ffmpeg-jsonstats.patch && \ + ./configure \ + --extra-version=datarhei \ + --prefix="${SRC}" \ + --extra-libs="-lpthread -lxml2 -lm -lz -lsupc++ -lstdc++ -lssl -lcrypto -lz -lc -ldl" \ + --enable-nonfree \ + --enable-gpl \ + --enable-version3 \ + --enable-postproc \ + --enable-static \ + --enable-openssl \ + --enable-libxml2 \ + --enable-libfreetype \ + --enable-libsrt \ + --enable-libx264 \ + --enable-libx265 \ + --enable-libvpx \ + --enable-libmp3lame \ + --enable-libopus \ + --enable-libvorbis \ + --disable-ffplay \ + --disable-debug \ + --disable-doc \ + --disable-shared && \ + make -j$(nproc) && \ + make install + +# export shared ffmpeg libs +RUN mkdir -p /ffmpeg/lib && \ + cp \ + /usr/lib/libfreetype.so.6 \ + /usr/lib/libbrotlidec.so.1 \ + /usr/lib/libbrotlicommon.so.1 \ + /usr/lib/libbz2.so.1 \ + /usr/lib/libpng16.so.16 \ + /usr/lib/libxml2.so.2 \ + /usr/lib/liblzma.so.5 \ + /usr/lib/libsrt.so.1 \ + /usr/lib/libx264.so.163 \ + /usr/lib/libx265.so.199 \ + /usr/lib/libvpx.so.6 \ + /usr/lib/libmp3lame.so.0 \ + /usr/lib/libopus.so.0 \ + /usr/lib/libvorbis.so.0 \ + /usr/lib/libogg.so.0 \ + /usr/lib/libvorbisenc.so.2 \ + /usr/lib/libgcc_s.so.1 \ + /usr/lib/libstdc++.so.6 \ + /ffmpeg/lib + +FROM $ALPINE_IMAGE as final + +COPY --from=builder /usr/bin/ffmpeg /usr/bin/ffmpeg +COPY --from=builder /ffmpeg/lib/* /usr/lib/ + +RUN apk add --no-cache \ + ca-certificates \ + tzdata && \ + ffmpeg -buildconf + +WORKDIR /tmp +ENTRYPOINT ["/usr/bin/ffmpeg"] +CMD ["-version"] diff --git a/Dockerfile.alpine.rpi b/Dockerfile.alpine.rpi new file mode 100644 index 0000000..cff19c9 --- /dev/null +++ b/Dockerfile.alpine.rpi @@ -0,0 +1,145 @@ +ARG ALPINE_IMAGE=alpine:3.15 + +FROM $ALPINE_IMAGE as builder + +ARG RPI_VERSION=0.20200813-r0 + +ARG FREETYPE_VERSION=2.11.1-r1 +ARG XML2_VERSION=2.9.13-r0 +ARG SRT_VERSION=1.4.2-r1 +ARG X264_VERSION=20210613-r0 +ARG X265_VERSION=3.5-r0 +ARG VPX_VERSION=1.10.0-r0 +ARG LAME_VERSION=3.100-r0 +ARG OPUS_VERSION=1.3.1-r1 +ARG VORBIS_VERSION=1.3.7-r0 +ARG ALSA_VERSION=1.2.5.1-r1 +ARG FFMPEG_VERSION=4.4.2 + +ENV PKG_CONFIG_PATH=/usr/lib/pkgconfig \ + SRC=/usr + +# install build packages +RUN apk add -U \ + autoconf \ + automake \ + bash \ + binutils \ + bzip2 \ + ca-certificates \ + cmake \ + coreutils \ + curl \ + diffutils \ + g++ \ + gcc \ + libgcc \ + libssl1.1 \ + libtool \ + linux-headers \ + make \ + musl-dev \ + nasm \ + openssl-dev \ + patch \ + tar \ + zlib-dev + +# install shared ffmpeg libs +RUN apk add \ + raspberrypi-dev=${RPI_VERSION} \ + raspberrypi-libs=${RPI_VERSION} \ + libxml2-dev=${XML2_VERSION} \ + freetype-dev=${FREETYPE_VERSION} \ + libsrt-dev=${SRT_VERSION} \ + x264-dev=${X264_VERSION} \ + x265-dev=${X265_VERSION} \ + libvpx-dev=${VPX_VERSION} \ + lame-dev=${LAME_VERSION} \ + opus-dev=${OPUS_VERSION} \ + libvorbis-dev=${VORBIS_VERSION} \ + alsa-lib-dev=${ALSA_VERSION} + +# install and patch ffmpeg +RUN mkdir -p /dist && cd /dist && \ + curl -OLk http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar -xvz -f ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + rm ffmpeg-${FFMPEG_VERSION}.tar.gz + +COPY ./contrib /contrib + +RUN cd /dist/ffmpeg-${FFMPEG_VERSION} && \ + patch -p1 < /contrib/ffmpeg-jsonstats.patch && \ + ./configure \ + --extra-version=datarhei \ + --prefix="${SRC}" \ + --extra-libs="-lpthread -lxml2 -lm -lz -lsupc++ -lstdc++ -lssl -lcrypto -lz -lc -ldl" \ + --enable-nonfree \ + --enable-gpl \ + --enable-version3 \ + --enable-postproc \ + --enable-static \ + --enable-openssl \ + --enable-libxml2 \ + --enable-omx \ + --enable-omx-rpi \ + --enable-mmal \ + --enable-v4l2_m2m \ + --enable-alsa \ + --enable-libfreetype \ + --enable-libsrt \ + --enable-libx264 \ + --enable-libx265 \ + --enable-libvpx \ + --enable-libmp3lame \ + --enable-libopus \ + --enable-libvorbis \ + --disable-ffplay \ + --disable-debug \ + --disable-doc \ + --disable-shared && \ + make -j$(nproc) && \ + make install + +# export shared ffmpeg libs + +RUN mkdir -p /ffmpeg/lib && \ + cp \ + /usr/lib/libfreetype.so.6 \ + /usr/lib/libbrotlidec.so.1 \ + /usr/lib/libbrotlicommon.so.1 \ + /usr/lib/libbz2.so.1 \ + /usr/lib/libpng16.so.16 \ + /usr/lib/libxml2.so.2 \ + /usr/lib/liblzma.so.5 \ + /usr/lib/libsrt.so.1 \ + /usr/lib/libx264.so.163 \ + /usr/lib/libx265.so.199 \ + /usr/lib/libvpx.so.6 \ + /usr/lib/libmp3lame.so.0 \ + /usr/lib/libopus.so.0 \ + /usr/lib/libvorbis.so.0 \ + /usr/lib/libogg.so.0 \ + /usr/lib/libvorbisenc.so.2 \ + /usr/lib/libgcc_s.so.1 \ + /usr/lib/libstdc++.so.6 \ + /ffmpeg/lib + +FROM $ALPINE_IMAGE as final + +COPY --from=builder /usr/bin/ffmpeg /usr/bin/ffmpeg +COPY --from=builder /ffmpeg/lib/* /usr/lib/ + +ARG RPI_VERSION=0.20200813-r0 + +RUN apk add --no-cache \ + ca-certificates \ + tzdata \ + alsa-lib \ + raspberrypi-libs=${RPI_VERSION} && \ + echo "/opt/vc/lib:/usr/local/lib:/usr/lib:/lib" > /etc/ld-musl-armhf.path && \ + ffmpeg -buildconf + +WORKDIR /tmp +ENTRYPOINT ["/usr/bin/ffmpeg"] +CMD ["-version"] diff --git a/Dockerfile.alpine.vaapi b/Dockerfile.alpine.vaapi new file mode 100644 index 0000000..51eb616 --- /dev/null +++ b/Dockerfile.alpine.vaapi @@ -0,0 +1,172 @@ +ARG ALPINE_IMAGE=alpine:3.15 + +FROM $ALPINE_IMAGE as builder + +ARG LIBAV_VERSION=2.14.0-r0 +ARG LIBVDPAU_VERSION=1.5-r0 +ARG MESA_VA_GALLIUM_VERSION=21.3.8-r1 +ARG MESA_VDPAU_GALLIUM_VERSION=21.3.8-r1 +ARG LIBVA_VDPAU_DRIVER_VERSION=0.7.4-r2 +ARG INTEL_GMMLIB_VERSION=22.1.2-r0 +ARG INTEL_MEDIA_DRIVER_VERSION=22.4.1-r0 +ARG INTEL_MEDIA_SDK_VERSION=22.4.1-r0 +ARG INTEL_VAAPI_DRIVER=2.4.1-r0 + +ARG FREETYPE_VERSION=2.11.1-r1 +ARG SRT_VERSION=1.4.2-r1 +ARG X264_VERSION=20210613-r0 +ARG X265_VERSION=3.5-r0 +ARG VPX_VERSION=1.10.0-r0 +ARG LAME_VERSION=3.100-r0 +ARG OPUS_VERSION=1.3.1-r1 +ARG VORBIS_VERSION=1.3.7-r0 +ARG FFMPEG_VERSION=4.4.1 + +ENV PKG_CONFIG_PATH=/usr/lib/pkgconfig \ + SRC=/usr + +# install build packages +RUN apk add --update \ + autoconf \ + automake \ + bash \ + binutils \ + bzip2 \ + ca-certificates \ + cmake \ + coreutils \ + curl \ + diffutils \ + g++ \ + gcc \ + libgcc \ + libssl1.1 \ + libtool \ + linux-headers \ + make \ + musl-dev \ + nasm \ + openssl-dev \ + patch \ + tar \ + zlib-dev + +# install shared ffmpeg libs +RUN apk add -U \ + freetype-dev=${FREETYPE_VERSION} \ + libsrt-dev=${SRT_VERSION} \ + x264-dev=${X264_VERSION} \ + x265-dev=${X265_VERSION} \ + libvpx-dev=${VPX_VERSION} \ + lame-dev=${LAME_VERSION} \ + opus-dev=${OPUS_VERSION} \ + libvorbis-dev=${VORBIS_VERSION} + +# install shared ffmpeg libs +RUN echo http://dl-2.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories +RUN apk add -U \ + libva-dev=${LIBAV_VERSION} \ + libvdpau-dev=${LIBVDPAU_VERSION} \ + libva-intel-driver=${INTEL_VAAPI_DRIVER} \ + mesa-va-gallium=${MESA_VA_GALLIUM_VERSION} \ + mesa-vdpau-gallium=${MESA_VDPAU_GALLIUM_VERSION} + +# install shared ffmpeg libs +RUN echo http://dl-2.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories +RUN apk add -U \ + intel-gmmlib-dev=${INTEL_GMMLIB_VERSION} \ + intel-media-driver-dev=${INTEL_MEDIA_DRIVER_VERSION} \ + intel-media-sdk-dev=${INTEL_MEDIA_SDK_VERSION} + +# install shared ffmpeg libs +RUN echo http://dl-2.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories +RUN apk add -U \ + libva-vdpau-driver=${LIBVA_VDPAU_DRIVER_VERSION} + +# install and patch ffmpeg +RUN mkdir -p /dist && cd /dist && \ + curl -OLk http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + tar -xvz -f ffmpeg-${FFMPEG_VERSION}.tar.gz && \ + rm ffmpeg-${FFMPEG_VERSION}.tar.gz + +COPY ./contrib /contrib + +RUN cd /dist/ffmpeg-${FFMPEG_VERSION} && \ + patch -p1 < /contrib/ffmpeg-jsonstats.patch && \ + ./configure \ + --extra-version=datarhei \ + --prefix="${SRC}" \ + --extra-libs="-lpthread -lm -lz -lsupc++ -lstdc++ -lssl -lcrypto -lz -lc -ldl" \ + --enable-nonfree \ + --enable-gpl \ + --enable-version3 \ + --enable-static \ + --enable-openssl \ + --enable-libfreetype \ + --enable-libsrt \ + --enable-libx264 \ + --enable-libx265 \ + --enable-libvpx \ + --enable-libmp3lame \ + --enable-libopus \ + --enable-libvorbis \ + --enable-libmfx \ + --enable-vaapi \ + --enable-vdpau \ + --disable-ffplay \ + --disable-debug \ + --disable-doc \ + --disable-shared && \ + make -j$(nproc) && \ + make install + +# export shared ffmpeg libs + +RUN mkdir -p /ffmpeg/lib && \ + cp \ + /usr/lib/libfreetype.so.6 \ + /usr/lib/libbrotlidec.so.1 \ + /usr/lib/libbrotlicommon.so.1 \ + /usr/lib/libbz2.so.1 \ + /usr/lib/libpng16.so.16 \ + /usr/lib/libsrt.so.1 \ + /usr/lib/libx264.so.163 \ + /usr/lib/libx265.so.199 \ + /usr/lib/libvpx.so.6 \ + /usr/lib/libmp3lame.so.0 \ + /usr/lib/libopus.so.0 \ + /usr/lib/libvorbis.so.0 \ + /usr/lib/libogg.so.0 \ + /usr/lib/libvorbisenc.so.2 \ + /usr/lib/libgcc_s.so.1 \ + /usr/lib/libstdc++.so.6 \ + /usr/lib/libxcb.so.1 \ + /usr/lib/libXau.so.6 \ + /usr/lib/libXdmcp.so.6 \ + /usr/lib/libbsd.so.0 \ + /usr/lib/libmd.so.0 \ + /usr/lib/libxcb-shm.so.0 \ + /usr/lib/libxcb-shape.so.0 \ + /usr/lib/libxcb-xfixes.so.0 \ + /usr/lib/libva.so.2 \ + /usr/lib/libmfx.so.1 \ + /usr/lib/libva-drm.so.2 \ + /usr/lib/libdrm.so.2 \ + /usr/lib/libvdpau.so.1 \ + /usr/lib/libXext.so.6 \ + /usr/lib/libX11.so.6 \ + /ffmpeg/lib + +FROM $ALPINE_IMAGE as final + +COPY --from=builder /usr/bin/ffmpeg /usr/bin/ffmpeg +COPY --from=builder /ffmpeg/lib/* /usr/lib/ + +RUN apk add --no-cache \ + ca-certificates \ + tzdata && \ + ffmpeg -buildconf + +WORKDIR /tmp +ENTRYPOINT ["/usr/bin/ffmpeg"] +CMD ["-version"] \ No newline at end of file diff --git a/Dockerfile_FFmpeg_2-3 b/Dockerfile_FFmpeg_2-3 deleted file mode 100644 index 084c364..0000000 --- a/Dockerfile_FFmpeg_2-3 +++ /dev/null @@ -1,101 +0,0 @@ -ARG ALPINE_IMAGE=alpine:latest - -FROM $ALPINE_IMAGE as builder - -ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \ - SRC=/usr/local - -ARG FDKAAC_VERSION=0.1.5 -ARG LAME_VERSION=3.99.5 -ARG X264_VERSION=20180607-2245-stable -ARG FFMPEG_VERSION=2.8.14 - -RUN buildDeps="autoconf \ - automake \ - bash \ - binutils \ - bzip2 \ - cmake \ - curl \ - coreutils \ - g++ \ - gcc \ - gnupg \ - libtool \ - make \ - python \ - openssl-dev \ - tar \ - yasm \ - zlib-dev" && \ - export MAKEFLAGS="-j$(($(grep -c ^processor /proc/cpuinfo) + 1))" && \ - apk update && \ - apk upgrade && \ - apk add --update ${buildDeps} libgcc libstdc++ ca-certificates libssl1.0 - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - echo "http://ftp.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2" && \ - curl -sL http://ftp.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2 | \ - tar -jx --strip-components=1 && \ - ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --enable-shared && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - LAME_GIT_VERSION=$(echo ${LAME_VERSION} | tr '.' '_') && \ - curl -sL https://github.com/rbrito/lame/archive/RELEASE__${LAME_GIT_VERSION}.tar.gz | \ - tar -zx --strip-components=1 && \ - cp /usr/share/automake-*/config.guess config.guess && \ - ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-static --enable-nasm --datarootdir="${DIR}" && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -sL https://github.com/mstorsjo/fdk-aac/archive/v${FDKAAC_VERSION}.tar.gz | \ - tar -zx --strip-components=1 && \ - autoreconf -fiv && \ - ./configure --prefix="${SRC}" --disable-static --datadir="${DIR}" && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -sLO http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - tar -zx --strip-components=1 -f ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - ./configure \ - --bindir="${SRC}/bin" \ - --extra-libs=-ldl \ - --extra-cflags="-I${SRC}/include" \ - --extra-ldflags="-L${SRC}/lib" \ - --extra-libs=-ldl \ - --prefix="${SRC}" \ - --enable-nonfree \ - --enable-gpl \ - --enable-version3 \ - --enable-avresample \ - --enable-libmp3lame \ - --enable-libx264 \ - --enable-openssl \ - --enable-postproc \ - --enable-small \ - --enable-libfdk_aac \ - --enable-shared \ - --disable-debug \ - --disable-doc \ - --disable-static \ - --disable-ffserver && \ - make && \ - make install && \ - hash -r - -FROM $ALPINE_IMAGE - -COPY --from=builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg -COPY --from=builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe -COPY --from=builder /usr/local/lib /usr/local/lib - -RUN apk add --update --no-cache libssl1.0 && \ - ffmpeg -buildconf - -CMD ["--help"] -ENTRYPOINT ["ffmpeg"] -WORKDIR /tmp/ffmpeg \ No newline at end of file diff --git a/Dockerfile_FFmpeg_4 b/Dockerfile_FFmpeg_4 deleted file mode 100644 index 7d7c300..0000000 --- a/Dockerfile_FFmpeg_4 +++ /dev/null @@ -1,100 +0,0 @@ -ARG ALPINE_IMAGE=alpine:latest - -FROM $ALPINE_IMAGE as builder - -ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \ - SRC=/usr/local - -ARG FDKAAC_VERSION=0.1.5 -ARG LAME_VERSION=3.99.5 -ARG X264_VERSION=20180607-2245-stable -ARG FFMPEG_VERSION=4.0 - -RUN buildDeps="autoconf \ - automake \ - bash \ - binutils \ - bzip2 \ - cmake \ - curl \ - coreutils \ - g++ \ - gcc \ - gnupg \ - libtool \ - make \ - python \ - openssl-dev \ - tar \ - yasm \ - zlib-dev" && \ - export MAKEFLAGS="-j$(($(grep -c ^processor /proc/cpuinfo) + 1))" && \ - apk update && \ - apk upgrade && \ - apk add --update ${buildDeps} libgcc libstdc++ ca-certificates libssl1.0 - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - echo "http://ftp.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2" && \ - curl -sL http://ftp.videolan.org/pub/videolan/x264/snapshots/x264-snapshot-${X264_VERSION}.tar.bz2 | \ - tar -jx --strip-components=1 && \ - ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --enable-shared && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - LAME_GIT_VERSION=$(echo ${LAME_VERSION} | tr '.' '_') && \ - curl -sL https://github.com/rbrito/lame/archive/RELEASE__${LAME_GIT_VERSION}.tar.gz | \ - tar -zx --strip-components=1 && \ - cp /usr/share/automake-*/config.guess config.guess && \ - ./configure --prefix="${SRC}" --bindir="${SRC}/bin" --disable-static --enable-nasm --datarootdir="${DIR}" && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -sL https://github.com/mstorsjo/fdk-aac/archive/v${FDKAAC_VERSION}.tar.gz | \ - tar -zx --strip-components=1 && \ - autoreconf -fiv && \ - ./configure --prefix="${SRC}" --disable-static --datadir="${DIR}" && \ - make && \ - make install - -RUN DIR=$(mktemp -d) && cd ${DIR} && \ - curl -sLO http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - tar -zx --strip-components=1 -f ffmpeg-${FFMPEG_VERSION}.tar.gz && \ - ./configure \ - --bindir="${SRC}/bin" \ - --extra-libs=-ldl \ - --extra-cflags="-I${SRC}/include" \ - --extra-ldflags="-L${SRC}/lib" \ - --extra-libs=-ldl \ - --prefix="${SRC}" \ - --enable-nonfree \ - --enable-gpl \ - --enable-version3 \ - --enable-avresample \ - --enable-libmp3lame \ - --enable-libx264 \ - --enable-openssl \ - --enable-postproc \ - --enable-small \ - --enable-libfdk_aac \ - --enable-shared \ - --disable-debug \ - --disable-doc \ - --disable-static && \ - make && \ - make install && \ - hash -r - -FROM $ALPINE_IMAGE - -COPY --from=builder /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg -COPY --from=builder /usr/local/bin/ffprobe /usr/local/bin/ffprobe -COPY --from=builder /usr/local/lib /usr/local/lib - -RUN apk add --update --no-cache libssl1.0 && \ - ffmpeg -buildconf - -CMD ["--help"] -ENTRYPOINT ["ffmpeg"] -WORKDIR /tmp/ffmpeg \ No newline at end of file diff --git a/README.md b/README.md index d42422b..f9629dd 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,43 @@ -# FFmpeg -FFmpeg Development Image for H.264-Processing (e.g. RTMP, HLS) - -* Alpine Linux (3.7) -* FFmpeg -* Docker-Images for AMD64/X86, ARMHF (e.g. Raspberry-Pi) and AARCH64 (e.g. Pine64) +# FFmpeg Base +FFmpeg base image for [datarhei/core](https://github.com/datarhei/core). +## Config: ```sh -./configure - --enable-nonfree - --enable-gpl - --enable-version3 - --enable-avresample - --enable-libmp3lame - --enable-libx264 - --enable-openssl - --enable-postproc - --enable-small - --enable-libfdk_aac - --enable-shared - --disable-debug - --disable-doc - --disable-static - --disable-ffserver (removed in v4) +--enable-libfreetype +--enable-libsrt +--enable-libx264 +--enable-libx265 +--enable-libvpx +--enable-libmp3lame +--enable-libopus +--enable-libvorbis +``` +*Additional informations can be found in the Dockerfiles.* + +## Patches: +- JSON-Stats (expands progress data per file in json format) + +## Images and Plattforms: +Dockerimage | OS | Plattform | GPU +-----------|----|-----------|---- +docker.io/datarhei/ffmpeg:latest | Alpine 3.15 | linux/amd64, linux/arm64, linux/arm/v7 | - +docker.io/datarhei/ffmpeg:rpi-latest | Alpine 3.15 | Raspberry Pi (linux/arm/v7) | MMAL/OMX +docker.io/datarhei/ffmpeg:vaapi-latest | Alpine 3.15 | linux/amd64 | Intel VAAPI + +## Testing +```sh +$ docker buildx create builder +$ docker buildx use builder +$ docker buildx inspect builder --bootstrap +$ docker buildx build --platform linux/amd64 linux/arm64 linux/arm/v7 -f Dockerfile -t ffmpeg:dev --load . +$ docker buildx rm builder ``` -* `4.0.1`, `4.0`, `4` (docker pull `datarhei/ffmpeg:4.0`) -* `4.0.1-armhf`, `4.0-armhf`, `4-armhf` (docker pull `datarhei/ffmpeg:4.0-armhf`) -* `4.0.1-aarch64`, `4.0-aarch64`, `4-aarch64` (docker pull `datarhei/ffmpeg:4.0-aarch64`) -* `3.4.2`, `3.4`, `3` (docker pull `datarhei/ffmpeg:3.4`) -* `3.3.7`, `3.3` (docker pull `datarhei/ffmpeg:3.3`) -* `3.3.7-armhf`, `3.3-armhf`, `3-armhf` (docker pull `datarhei/ffmpeg:3.3-armhf`) -* `3.3.7-aarch64`, `3.3-aarch64`, `3-aarch64` (docker pull `datarhei/ffmpeg:3.3-aarch64`) -* `3.2.10`, `3.2` (docker pull `datarhei/ffmpeg:3.2`) -* `3.2.10-armhf`, `3.2-armhf` (docker pull `datarhei/ffmpeg:3.2-armhf`) -* `3.2.10-aarch64`, `3.2-aarch64` (docker pull `datarhei/ffmpeg:3.2-aarch64`) -* `3.1.11`, `3.1` (docker pull `datarhei/ffmpeg:3.1`) -* `3.1.11-armhf`, `3.1-armhf` (docker pull `datarhei/ffmpeg:3.1-armhf`) -* `3.1.11-aarch64`, `3.1-aarch64` (docker pull `datarhei/ffmpeg:3.1-aarch64`) -* `3.0.11`, `3.0` (docker pull `datarhei/ffmpeg:3.0`) -* `3.0.11-armhf`, `3.0-armhf` (docker pull `datarhei/ffmpeg:3.0-armhf`) -* `3.0.11-aarch64`, `3.0-aarch64` (docker pull `datarhei/ffmpeg:3.0-aarch64`) -* `2.8.14`, `2.8`, `2` (docker pull `datarhei/ffmpeg:2.8`) -* `2.8.14-armhf`, `2.8-armhf`, `2-armhf` (docker pull `datarhei/ffmpeg:2.8-armhf`) -* `2.8.14-aarch64`, `2.8-aarch64`, `2-aarch64` (docker pull `datarhei/ffmpeg:2.8-aarch64`) +## Known problems: +The libraries are currently not compiled due to errors caused by Docker virtualisation. -## Build your own Image +## Feature requests: +Please create an issue with your use case and all the requirements. -#### FFmpeg 4+ -```sh -docker build -f Dockerfile_FFmpeg_4 -t ffmpeg:amd64 \ - --build-arg ALPINE_IMAGE=alpine:latest \ - --build-arg FFMPEG_VERSION=4.0 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . - -docker build -f Dockerfile_FFmpeg_4 -t ffmpeg:armhf \ - --build-arg ALPINE_IMAGE=resin/armhf-alpine:latest \ - --build-arg FFMPEG_VERSION=4.0 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . - -docker build -f Dockerfile_FFmpeg_4 -t ffmpeg:aarch64 \ - --build-arg ALPINE_IMAGE=resin/aarch64-alpine:latest \ - --build-arg FFMPEG_VERSION=4.0 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . -``` - -#### FFmpeg 2-3 -```sh -docker build -f Dockerfile_FFmpeg_2-3 -t ffmpeg:amd64 \ - --build-arg ALPINE_IMAGE=alpine:latest \ - --build-arg FFMPEG_VERSION=3.3.7 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . - -docker build -f Dockerfile_FFmpeg_2-3 -t ffmpeg:armhf \ - --build-arg ALPINE_IMAGE=resin/armhf-alpine:latest \ - --build-arg FFMPEG_VERSION=3.3.7 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . - -docker build -f Dockerfile_FFmpeg_2-3 -t ffmpeg:aarch64 \ - --build-arg ALPINE_IMAGE=resin/aarch64-alpine:latest \ - --build-arg FFMPEG_VERSION=3.3.7 \ - --build-arg FDKAAC_VERSION=0.1.5 \ - --build-arg LAME_VERSION=3.99.5 \ - --build-arg X264_VERSION=20180607-2245-stable . -``` \ No newline at end of file +## Licence +LGPL-licensed with optional components licensed under GPL. Please refer to the LICENSE file for detailed information. diff --git a/contrib/ffmpeg-jsonstats.patch b/contrib/ffmpeg-jsonstats.patch new file mode 100644 index 0000000..91b96f6 --- /dev/null +++ b/contrib/ffmpeg-jsonstats.patch @@ -0,0 +1,440 @@ +From df7dfb5351f77a672de5a6d613678888f560afcb Mon Sep 17 00:00:00 2001 +From: Ingo Oppermann +Date: Tue, 1 Jun 2021 08:53:52 +0200 +Subject: [PATCH v20] JSON progress report (ffmpeg 4.4) + +--- + fftools/ffmpeg.c | 262 +++++++++++++++++++++++++++++++++++++++++-- + fftools/ffmpeg.h | 1 + + fftools/ffmpeg_opt.c | 69 ++++++++++++ + 3 files changed, 322 insertions(+), 10 deletions(-) + +diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c +index 46bb014..e5e00c9 100644 +--- a/fftools/ffmpeg.c ++++ b/fftools/ffmpeg.c +@@ -1699,12 +1699,11 @@ static void print_final_stats(int64_t total_size) + } + } + +-static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time) ++static void print_default_report(int is_last_report, int64_t timer_start, int64_t cur_time) + { + AVBPrint buf, buf_script; + OutputStream *ost; +- AVFormatContext *oc; +- int64_t total_size; ++ int64_t total_size = 0; + AVCodecContext *enc; + int frame_number, vid, i; + double bitrate; +@@ -1733,13 +1732,6 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti + + t = (cur_time-timer_start) / 1000000.0; + +- +- oc = output_files[0]->ctx; +- +- total_size = avio_size(oc->pb); +- if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too +- total_size = avio_tell(oc->pb); +- + vid = 0; + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC); +@@ -1822,6 +1814,9 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti + + if (is_last_report) + nb_frames_drop += ost->last_dropped; ++ ++ total_size += ost->data_size; ++ total_size += ost->enc_ctx->extradata_size; + } + + secs = FFABS(pts) / AV_TIME_BASE; +@@ -1909,6 +1904,251 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti + print_final_stats(total_size); + } + ++static void print_json_report(int is_last_report, int64_t timer_start, int64_t cur_time) ++{ ++ AVBPrint buf; ++ InputStream *ist; ++ OutputStream *ost; ++ uint64_t stream_size, total_size = 0; ++ AVCodecContext *enc, *dec; ++ int i, j; ++ uint64_t first_vid, first_frame_number = 0, first_packet_number = 0; ++ double speed; ++ int64_t min_pts = INT64_MIN + 1, pts = INT64_MIN + 1; ++ static int64_t last_time = -1; ++ int hours, mins, secs, us; ++ const char *hours_sign; ++ float t, q; ++ float first_q = -1; ++ ++ if (!print_jsonstats && !is_last_report && !progress_avio) { ++ return; ++ } ++ ++ if (!is_last_report) { ++ if (last_time == -1) { ++ last_time = cur_time; ++ return; ++ } ++ if ((cur_time - last_time) < 500000) { ++ return; ++ } ++ last_time = cur_time; ++ } ++ ++ t = (cur_time-timer_start) / 1000000.0; ++ ++ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); ++ ++ av_bprintf(&buf, "ffmpeg.progress:{"); ++ av_bprintf(&buf, "\"inputs\":["); ++ for (i = 0; i < nb_input_files; i++) { ++ InputFile *f = input_files[i]; ++ ++ for (j = 0; j < f->nb_streams; j++) { ++ ist = input_streams[f->ist_index + j]; ++ dec = ist->dec_ctx; ++ ++ av_bprintf(&buf, "{"); ++ av_bprintf(&buf, "\"index\":%d,\"stream\":%d,", i, j); ++ ++ av_bprintf(&buf, "\"frame\":%"PRIu64",\"packet\":%"PRIu64",", ist->frames_decoded == 0 ? ist->nb_packets : ist->frames_decoded, ist->nb_packets); ++ ++ av_bprintf(&buf, "\"size_kb\":%.0f", ist->data_size / 1024.0); ++ ++ if(i == (nb_input_files - 1) && j == (f->nb_streams - 1)) { ++ av_bprintf(&buf, "}"); ++ } ++ else { ++ av_bprintf(&buf, "},"); ++ } ++ } ++ } ++ ++ av_bprintf(&buf, "],"); ++ ++ // check libavcodec/utils.c:avcodec_string ++ // check libavformat/dump.c:av_dump_format ++ // check libavcodec/avcodec.h:struct AVCodec and struct AVCodecContext ++ // check libavformat/avformat.h:struct AVStream ++ // check fftools/ffmpeg.h:struct OutputStream ++ ++ first_vid = 1; ++ ++ av_bprintf(&buf, "\"outputs\":["); ++ for (i = 0; i < nb_output_streams; i++) { ++ OutputFile *f; ++ q = -1; ++ ost = output_streams[i]; ++ f = output_files[ost->file_index]; ++ enc = ost->enc_ctx; ++ if (!ost->stream_copy) { ++ q = ost->quality / (float) FF_QP2LAMBDA; ++ } ++ ++ av_bprintf(&buf, "{"); ++ av_bprintf(&buf, "\"index\":%d,\"stream\":%d,", ost->file_index, ost->index); ++ ++ av_bprintf(&buf, "\"frame\":%"PRIu64",\"packet\":%"PRIu64",", ost->frames_encoded == 0 ? ost->packets_written : ost->frames_encoded, ost->packets_written); ++ ++ if(enc->codec_type == AVMEDIA_TYPE_VIDEO) { ++ av_bprintf(&buf, "\"q\":%.1f,", q); ++ ++ if(first_vid == 1) { ++ first_frame_number = ost->frames_encoded == 0 ? ost->packets_written : ost->frames_encoded; ++ first_packet_number = ost->packets_written; ++ first_q = q; ++ ++ first_vid = 0; ++ } ++ } ++ ++ /* compute min output value */ ++ pts = INT64_MIN + 1; ++ if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE) { ++ pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st), ost->st->time_base, AV_TIME_BASE_Q)); ++ min_pts = FFMAX(min_pts, av_rescale_q(av_stream_get_end_pts(ost->st), ost->st->time_base, AV_TIME_BASE_Q)); ++ } ++ ++ if (is_last_report) { ++ nb_frames_drop += ost->last_dropped; ++ } ++ ++ stream_size = ost->data_size + ost->enc_ctx->extradata_size; ++ total_size += stream_size; ++ ++ av_bprintf(&buf, "\"size_kb\":%.0f", stream_size / 1024.0); ++ ++ if(i == (nb_output_streams - 1)) { ++ av_bprintf(&buf, "}"); ++ } ++ else { ++ av_bprintf(&buf, "},"); ++ } ++ } ++ ++ av_bprintf(&buf, "],"); ++ ++ av_bprintf(&buf, "\"frame\":%"PRIu64",\"packet\":%"PRIu64",\"q\":%.1f,", first_frame_number, first_packet_number, first_q); ++ ++ av_bprintf(&buf, "\"size_kb\":%.0f,", total_size / 1024.0); ++ ++ secs = FFABS(min_pts) / AV_TIME_BASE; ++ us = FFABS(min_pts) % AV_TIME_BASE; ++ mins = secs / 60; ++ secs %= 60; ++ hours = mins / 60; ++ mins %= 60; ++ hours_sign = (min_pts < 0) ? "-" : ""; ++ ++ if(min_pts != AV_NOPTS_VALUE) { ++ av_bprintf(&buf, "\"time\":\"%s%dh%dm%d.%ds\",", hours_sign, hours, mins, secs, (100 * us) / AV_TIME_BASE); ++ } ++ ++ speed = t != 0.0 ? (double)min_pts / AV_TIME_BASE / t : -1; ++ av_bprintf(&buf, "\"speed\":%.3g,", speed); ++ ++ av_bprintf(&buf, "\"dup\":%d,\"drop\":%d", nb_frames_dup, nb_frames_drop); ++ av_bprintf(&buf, "}"); ++ ++ if (print_jsonstats || is_last_report) { ++ fprintf(stderr, "%s\n", buf.str); ++ fflush(stderr); ++ } ++ ++ av_bprint_finalize(&buf, NULL); ++} ++ ++static void print_json_outputs() { ++ static int ost_all_initialized = 0; ++ int i; ++ int nb_initialized = 0; ++ ++ if(print_jsonstats != 1 && print_stats != -1) { ++ return; ++ } ++ ++ if(ost_all_initialized == 1) { ++ return; ++ } ++ ++ // check if all outputs are initialized ++ for (i = 0; i < nb_output_streams; i++) { ++ OutputStream *ost = output_streams[i]; ++ if (ost->initialized) { ++ nb_initialized++; ++ } ++ } ++ ++ // only if all outputs are initialized, dump the outputs ++ if (nb_initialized == nb_output_streams) { ++ ost_all_initialized = 1; ++ ++ AVBPrint buf; ++ ++ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); ++ ++ av_bprintf(&buf, "ffmpeg.outputs:["); ++ for (i = 0; i < nb_output_streams; i++) { ++ OutputStream *ost = output_streams[i]; ++ OutputFile *f = output_files[ost->file_index]; ++ AVFormatContext *ctx = f->ctx; ++ AVStream *st = ost->st; ++ AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); ++ AVCodecContext *enc = ost->enc_ctx; ++ ++ av_bprintf(&buf, "{"); ++ av_bprintf(&buf, "\"url\":\"%s\",\"format\":\"%s\",\"index\":%d,\"stream\":%d,", ctx->url, ctx->oformat->name, ost->file_index, ost->index); ++ av_bprintf(&buf, "\"type\":\"%s\",\"codec\":\"%s\",\"coder\":\"%s\",\"bitrate_kbps\":%"PRId64",", media_type_string(enc->codec_type), avcodec_get_name(enc->codec_id), ost->stream_copy ? "copy" : (enc->codec ? enc->codec->name : "unknown"), enc->bit_rate / 1000); ++ av_bprintf(&buf, "\"duration_sec\":%f,\"language\":\"%s\"", 0.0, lang != NULL ? lang->value : "und"); ++ ++ if(enc->codec_type == AVMEDIA_TYPE_VIDEO) { ++ float fps = 0; ++ if(st->avg_frame_rate.den && st->avg_frame_rate.num) { ++ fps = av_q2d(st->avg_frame_rate); ++ } ++ ++ av_bprintf(&buf, ",\"fps\":%f,\"pix_fmt\":\"%s\",\"width\":%d,\"height\":%d", fps, st->codecpar->format == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(st->codecpar->format), st->codecpar->width, st->codecpar->height); ++ } ++ else if(enc->codec_type == AVMEDIA_TYPE_AUDIO) { ++ char layout[128]; ++ ++ av_get_channel_layout_string(layout, sizeof(layout), enc->channels, enc->channel_layout); ++ ++ av_bprintf(&buf, ",\"sampling_hz\":%d,\"layout\":\"%s\",\"channels\":%d", enc->sample_rate, layout, enc->channels); ++ } ++ ++ if(i == (nb_output_streams - 1)) { ++ av_bprintf(&buf, "}"); ++ } ++ else { ++ av_bprintf(&buf, "},"); ++ } ++ } ++ ++ av_bprintf(&buf, "]"); ++ ++ fprintf(stderr, "%s\n", buf.str); ++ ++ av_bprint_clear(&buf); ++ } ++ ++ return; ++} ++ ++static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time) ++{ ++ if (!print_stats && !print_jsonstats && !is_last_report && !progress_avio) ++ return; ++ ++ if (print_stats == 1) { ++ print_default_report(is_last_report, timer_start, cur_time); ++ } ++ else { ++ print_json_report(is_last_report, timer_start, cur_time); ++ } ++} ++ + static void ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) + { + // We never got any input. Set a fake format, which will +@@ -3048,6 +3288,8 @@ static int check_init_output_file(OutputFile *of, int file_index) + av_dump_format(of->ctx, file_index, of->ctx->url, 1); + nb_output_dumped++; + ++ print_json_outputs(); ++ + if (sdp_filename || want_sdp) + print_sdp(); + +diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h +index 606f2af..e7e9a46 100644 +--- a/fftools/ffmpeg.h ++++ b/fftools/ffmpeg.h +@@ -621,6 +621,7 @@ extern int debug_ts; + extern int exit_on_error; + extern int abort_on_flags; + extern int print_stats; ++extern int print_jsonstats; + extern int64_t stats_period; + extern int qp_hist; + extern int stdin_interaction; +diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c +index 807e783..d48c02a 100644 +--- a/fftools/ffmpeg_opt.c ++++ b/fftools/ffmpeg_opt.c +@@ -41,6 +41,7 @@ + #include "libavutil/parseutils.h" + #include "libavutil/pixdesc.h" + #include "libavutil/pixfmt.h" ++#include "libavutil/bprint.h" + + #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" + +@@ -167,6 +168,7 @@ int debug_ts = 0; + int exit_on_error = 0; + int abort_on_flags = 0; + int print_stats = -1; ++int print_jsonstats = -1; + int qp_hist = 0; + int stdin_interaction = 1; + int frame_bits_per_raw_sample = 0; +@@ -3348,6 +3350,69 @@ static int open_files(OptionGroupList *l, const char *inout, + return 0; + } + ++static void print_json_inputs() { ++ if(print_jsonstats != 1 && print_stats != -1) { ++ return; ++ } ++ ++ AVBPrint buf; ++ int i, j; ++ ++ av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); ++ ++ av_bprintf(&buf, "ffmpeg.inputs:["); ++ for (i = 0; i < nb_input_files; i++) { ++ InputFile *f = input_files[i]; ++ AVFormatContext *ctx = f->ctx; ++ ++ float duration = 0; ++ if (ctx->duration != AV_NOPTS_VALUE) { ++ duration = (float)(ctx->duration + (ctx->duration <= INT64_MAX - 5000 ? 5000 : 0)) / (float)AV_TIME_BASE; ++ } ++ ++ for (j = 0; j < f->nb_streams; j++) { ++ InputStream *ist = input_streams[f->ist_index + j]; ++ AVCodecContext *dec = ist->dec_ctx; ++ AVStream *st = ist->st; ++ AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0); ++ ++ av_bprintf(&buf, "{"); ++ av_bprintf(&buf, "\"url\":\"%s\",\"format\":\"%s\",\"index\":%d,\"stream\":%d,", ctx->url, ctx->iformat->name, i, j); ++ av_bprintf(&buf, "\"type\":\"%s\",\"codec\":\"%s\",\"coder\":\"%s\",\"bitrate_kbps\":%"PRId64",", media_type_string(dec->codec_type), avcodec_get_name(dec->codec_id), dec->codec ? dec->codec->name : "unknown", dec->bit_rate / 1000); ++ av_bprintf(&buf, "\"duration_sec\":%f,\"language\":\"%s\"", duration, lang != NULL ? lang->value : "und"); ++ ++ if(dec->codec_type == AVMEDIA_TYPE_VIDEO) { ++ float fps = 0; ++ if(st->avg_frame_rate.den && st->avg_frame_rate.num) { ++ fps = av_q2d(st->avg_frame_rate); ++ } ++ ++ av_bprintf(&buf, ",\"fps\":%f,\"pix_fmt\":\"%s\",\"width\":%d,\"height\":%d", fps, st->codecpar->format == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(st->codecpar->format), st->codecpar->width, st->codecpar->height); ++ } ++ else if(dec->codec_type == AVMEDIA_TYPE_AUDIO) { ++ char layout[128]; ++ ++ av_get_channel_layout_string(layout, sizeof(layout), dec->channels, dec->channel_layout); ++ ++ av_bprintf(&buf, ",\"sampling_hz\":%d,\"layout\":\"%s\",\"channels\":%d", dec->sample_rate, layout, dec->channels); ++ } ++ ++ if(i == (nb_input_files - 1) && j == (f->nb_streams - 1)) { ++ av_bprintf(&buf, "}"); ++ } ++ else { ++ av_bprintf(&buf, "},"); ++ } ++ } ++ } ++ ++ av_bprintf(&buf, "]"); ++ ++ fprintf(stderr, "%s\n", buf.str); ++ ++ return; ++} ++ + int ffmpeg_parse_options(int argc, char **argv) + { + OptionParseContext octx; +@@ -3381,6 +3446,8 @@ int ffmpeg_parse_options(int argc, char **argv) + goto fail; + } + ++ print_json_inputs(); ++ + /* create the complex filtergraphs */ + ret = init_complex_filters(); + if (ret < 0) { +@@ -3584,6 +3651,8 @@ const OptionDef options[] = { + "enable automatic conversion filters globally" }, + { "stats", OPT_BOOL, { &print_stats }, + "print progress report during encoding", }, ++ { "jsonstats", OPT_BOOL, { &print_jsonstats }, ++ "print JSON progress report during encoding", }, + { "stats_period", HAS_ARG | OPT_EXPERT, { .func_arg = opt_stats_period }, + "set the period at which ffmpeg updates stats and -progress output", "time" }, + { "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT | + +base-commit: 9dcc10e319b3533e0cef975c013b5fdf02e67ea2 +-- +2.24.3 (Apple Git-128) +