332 lines
8.6 KiB
Markdown
332 lines
8.6 KiB
Markdown
# Intel Media FFMPEG Transcode Container
|
|
|
|
This project hosts a container demonstrating the use of ffmpeg using GPU
|
|
offload for transcode operations.
|
|
|
|
For information on how the Dockerfile in this container is generated,
|
|
see [xe-solutions](https://gitlab.devtools.intel.com/vtt/sws/osgc/solutions/xe-solutions).
|
|
|
|
# To run pre-built container
|
|
The following will download the latest version of the container and run the
|
|
'test' entry point.
|
|
|
|
```bash
|
|
. SOLUTION
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run --rm \
|
|
--group-add ${VIDEO} \
|
|
--volume $(pwd)/data:/data \
|
|
--device /dev/dri \
|
|
${REGISTRY_URL}/intel-compute-clinfo:latest-${OS_DISTRO}-${OS_RELEASE} \
|
|
test
|
|
```
|
|
|
|
NOTE: The VIDEO setup prior to running the container is needed if you are running
|
|
on a host OS that has a different video UID:GID mapping than the guest OS.
|
|
|
|
On some systems, you may also need to do the same for the RENDER group. See
|
|
`scripts/test-image.sh` for an example.
|
|
|
|
# Usage examples
|
|
|
|
Two step from zero-to-hero:
|
|
|
|
1. Download some test content
|
|
2. Transcode with a pre-built container
|
|
|
|
## Download content
|
|
|
|
The following will download the Blender TearsOfSteel video:
|
|
|
|
```bash
|
|
mkdir $(pwd)/data
|
|
wget -O $(pwd)/data/TearsOfSteel.mp4 \
|
|
http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4
|
|
```
|
|
|
|
## Transcode with a pre-built container
|
|
|
|
The following will transcode 'TearsOfSteal.mp4' from AVC (H.264) to a
|
|
5Mbps HEVC (H.265) stream using the GPU.
|
|
|
|
```bash
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run \
|
|
--group-add ${VIDEO} \
|
|
--device=/dev/dri \
|
|
--volume $(pwd)/data:/data \
|
|
amr-registry.caas.intel.com/vtt-osgc/solutions/intel-media-ffmpeg:ubuntu-focal \
|
|
ffmpeg \
|
|
-hwaccel qsv \
|
|
-qsv_device ${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-c:v h264_qsv \
|
|
-i /data/TearsOfSteel.mp4 \
|
|
-c:v hevc_qsv \
|
|
-b:v 5M \
|
|
-y \
|
|
/data/TearsOfSteel-5M.mp4
|
|
```
|
|
|
|
# Getting the container
|
|
|
|
You can get the intel-media-ffmpeg container by either building it
|
|
yourself from the Dockerfile, or by pulling a pre-built image from
|
|
Intel's Harbor instance.
|
|
|
|
## Pull from Harbor
|
|
|
|
```bash
|
|
export OS_DISTRO=ubuntu
|
|
export PACKAGE_STREAM=focal
|
|
TAG=${OS_DISTRO}-${PACKAGE_STREAM}
|
|
docker pull amr-registry.caas.intel.com/vtt-osgc/solutions/intel-media-ffmpeg:${TAG}
|
|
docker tag amr-registry.caas.intel.com/vtt-osgc/solutions/intel-media-ffmpeg:${TAG} intel-media-ffmpeg
|
|
```
|
|
|
|
## Build Ubuntu container
|
|
|
|
NOTE: Ubuntu 19.10 focal packages have not been pushed to
|
|
repositories.intel.com yet. 'PACKAGE_REPOSITORY' is set to
|
|
osgc.jf.intel.com/internal below until the packages are published (by
|
|
end of November'19)
|
|
|
|
```bash
|
|
export OS_DISTRO=ubuntu
|
|
export OS_RELEASE=focal
|
|
export PACKAGE_STREAM=focal
|
|
export PACKAGE_REPOSITORY=https://osgc.jf.intel.com/internal
|
|
export TAG=test-build-${OS_DISTRO}-${PACKAGE_STREAM}-$(date +%Y%m%d)
|
|
scripts/build-dockerfile.sh
|
|
scripts/build-image.sh
|
|
```
|
|
|
|
## Build Red Hat container
|
|
|
|
```bash
|
|
export OS_DISTRO=rhel
|
|
export OS_RELEASE=8.0
|
|
export PACKAGE_STREAM=8.0
|
|
export PACKAGE_REPOSITORY=https://repositories.intel.com/graphics
|
|
export TAG=test-build-${OS_DISTRO}-${PACKAGE_STREAM}-$(date +%Y%m%d)
|
|
scripts/build-dockerfile.sh
|
|
scripts/build-image.sh
|
|
```
|
|
|
|
# Verify hardware access
|
|
|
|
```bash
|
|
TAG=${TAG:-latest}
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run \
|
|
--group-add ${VIDEO} \
|
|
--rm \
|
|
--device=/dev/dri \
|
|
-e QSV_DEVICE=${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-it \
|
|
intel-media-ffmpeg:${TAG} \
|
|
info
|
|
```
|
|
|
|
The above will provide information about the software
|
|
in the container, as well as the detected Intel graphics
|
|
hardware.
|
|
|
|
If you are in a multicard environment, see Appendix A.
|
|
|
|
# Test hardware accelerated FFMPEG media operations
|
|
|
|
First download test content into ./data, then launch
|
|
the Docker container mounting that path to the /data
|
|
volume, running the 'test' command.
|
|
|
|
NOTE: The test media stream is currently hard coded to
|
|
expect the name AUD_WM_E.264 in the container.
|
|
|
|
```bash
|
|
TAG=${TAG:-latest}
|
|
mkdir $(pwd)/data
|
|
wget -O $(pwd)/data/AUD_MW_E.264 \
|
|
https://fate-suite.libav.org/h264-conformance/AUD_MW_E.264
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run \
|
|
--group-add ${VIDEO} \
|
|
--rm \
|
|
--device=/dev/dri \
|
|
-e QSV_DEVICE=${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
--volume $(pwd)/data:/data \
|
|
-it \
|
|
intel-media-ffmpeg:${TAG} \
|
|
test
|
|
```
|
|
|
|
The above will:
|
|
|
|
1. Download a test content file from fate-suite.libav.org into $(pwd)/data
|
|
2. Instantiate the 'intel-media-ffmpeg' container
|
|
3. Perfom the following tests:
|
|
1. decode AUD_MW_E.264 to AUD_MW.yuv
|
|
2. encode AUD_MW.yuv to AUD_MW_E.h264
|
|
3. transcode AUD_MW_E.264 to AUD_MW_E.hevc
|
|
4. transcode AUD_MW_E.264 to two streams at once, AUD_1N-5M.h264 and AUD_1N-4M60FPS.h264
|
|
|
|
Once completed, you can check the contents of $(pwd)/data for the following files:
|
|
|
|
```
|
|
AUD_MW_E.264
|
|
AUD_MW.yuv
|
|
AUD_MW_E.h264
|
|
AUD_MW_E.hevc
|
|
AUD_1N-5M.h264
|
|
AUD_1N-4M60FPS.h264
|
|
```
|
|
|
|
# Want a longer transcode test?
|
|
|
|
The following snippet will download the Blender video 'TearsOfSteel'
|
|
which is available as H.264 AVC, and then use a pre-built ffmpeg
|
|
container to transcode the stream to 5Mbps H.265 HEVC using the GPU.
|
|
|
|
```bash
|
|
TAG=${TAG:-latest}
|
|
mkdir $(pwd)/data
|
|
wget -O $(pwd)/data/TearsOfSteel.mp4 \
|
|
http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run \
|
|
--group-add ${VIDEO} \
|
|
--rm \
|
|
--device=/dev/dri \
|
|
-e QSV_DEVICE=${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-it \
|
|
--volume $(pwd)/data:/data \
|
|
intel-media-ffmpeg:${TAG} \
|
|
transcode TearsOfSteel.mp4 TearsOfSteel-5M.mp4
|
|
```
|
|
|
|
# Launch a shell in the container
|
|
|
|
The examples below are all assumed to be running in the container's environment:
|
|
|
|
```bash
|
|
TAG=${TAG:-latest}
|
|
VIDEO=$(getent group video | sed -E 's,^video:[^:]*:([^:]*):.*$,\1,')
|
|
docker run \
|
|
--group-add ${VIDEO} \
|
|
--rm \
|
|
--device=/dev/dri \
|
|
-e QSV_DEVICE=${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-it \
|
|
intel-media-ffmpeg:${TAG} \
|
|
shell
|
|
```
|
|
|
|
## Decode
|
|
|
|
AVC (H.264) video decode and save as YUV 420P raw file:
|
|
|
|
**NOTE**: Run the following in the container launched previously.
|
|
|
|
```bash
|
|
IN_FILE=AUD_WM_E.264
|
|
OUT_FILE=AUD_MW.yuv
|
|
ffmpeg \
|
|
-hwaccel qsv \
|
|
-qsv_device ${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-c:v h264_qsv \
|
|
-i /data/"${IN_FILE}" \
|
|
-vf hwdownload,format=nv12 -pix_fmt yuv420p \
|
|
-y \
|
|
/data/"${OUT_FILE}"
|
|
```
|
|
|
|
## Encode
|
|
|
|
Encode a 10 frames of 720p raw input as H264 with 5Mbps using VBR mode:
|
|
|
|
**NOTE**: Run the following in the container launched previously.
|
|
|
|
```bash
|
|
IN_FILE=AUD_MW.yuv
|
|
OUT_FILE=AUD_MW_E.h264
|
|
ffmpeg \
|
|
-loglevel debug \
|
|
-init_hw_device vaapi=va:${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-init_hw_device qsv=hw@va \
|
|
-filter_hw_device hw \
|
|
-f rawvideo \
|
|
-pix_fmt yuv420p \
|
|
-s:v 176x144 \
|
|
-i /data/"${IN_FILE}" \
|
|
-vf hwupload=extra_hw_frames=64,format=qsv \
|
|
-c:v h264_qsv \
|
|
-b:v 5M \
|
|
-frames:v 10 \
|
|
-y \
|
|
/data/"${OUT_FILE}"
|
|
```
|
|
|
|
## Transcode
|
|
|
|
### AVC (H.264) => HEVC (H.265) with 5Mbps using VBR
|
|
|
|
**NOTE**: Run the following in the container launched previously.
|
|
|
|
```bash
|
|
IN_FILE=AUD_MW_E.264
|
|
OUT_FILE=AUD_MW_E.hevc
|
|
ffmpeg \
|
|
-loglevel debug \
|
|
-hwaccel qsv \
|
|
-qsv_device ${QSV_DEVICE:-/dev/dri/renderD128} \
|
|
-c:v h264_qsv \
|
|
-i /data/"${IN_FILE}" \
|
|
-c:v hevc_qsv \
|
|
-b:v 5M \
|
|
-y \
|
|
/data/"${OUT_FILE}"
|
|
```
|
|
|
|
### 1:N transcoding
|
|
|
|
**NOTE**: Run the following in the container launched previously.
|
|
|
|
```bash
|
|
IN_FILE=AUD_MW_E.264
|
|
OUT_FILE=AUD_1N_
|
|
ffmpeg \
|
|
-hwaccel qsv \
|
|
-qsv_device ${QSV_DEVICE} \
|
|
-c:v h264_qsv \
|
|
-i /data/"${IN_FILE}" \
|
|
-filter_complex "split=2[s1][s2]; \
|
|
[s1]scale_qsv=1280:720[o1]; \
|
|
[s2]vpp_qsv=framerate=60[o2]" \
|
|
-map [o1] -c:v h264_qsv -b:v 5M /data/"${OUT_FILE}-5M.mp4" \
|
|
-map [o2] -c:v h264_qsv -b:v 4M /data/"${OUT_FILE}-4M60FPS.h264"
|
|
```
|
|
|
|
# Appendix A: Multicard
|
|
|
|
Most of the filters and drivers for ffmpeg will default to connecting to
|
|
/dev/dri/renderD128.
|
|
|
|
If you have multiple cards, the card you want to connect to might be exposed
|
|
on a different render interface.
|
|
|
|
You can configure which interface is used by setting the QSV_DEVICE environment
|
|
variable prior to running intel-docker (or by passing -e QSV_DEVICE to docker
|
|
if you run it manually.)
|
|
|
|
You can find out the correct path for your Intel Graphics card by running:
|
|
|
|
```
|
|
ls -l /dev/dri/by-path/pci-*$(lspci | grep Intel.*Graphics | cut -d " " -f1)*
|
|
```
|
|
|
|
If the interface is on /dev/dri/renderD129, set QSV_DEVICE as follows:
|
|
|
|
```
|
|
export QSV_DEVICE=/dev/dri/renderD129
|
|
```
|
|
|