api.video
SearchCtrl K

Features

Developers

How do I change my video container without re-encoding using FFMPEG and Python?

September 10, 2021 - Erikka Innes in Python

Sometimes you have a video that won't play easily on your system. One example that comes immediately to mind is when you have a .mkv (Matroska) video on a Mac. Google around, and you'll learn you need to download a particular player, or a QuickTime plug-in called Perian. There are lots of players and even though Perian is discontinued, you could certainly download what you need to play your file. But there's another easy option you could try that won't require a new player or plug-in! You can use transmuxing to change the video container, resulting in a playable video. Another use case might be editing. Many editing tools won't let you use an .mkv file, requiring .mp4 or similar instead. You may want to do the conversion without losing video quality, then convert back. In this situation, transmuxing can help you preserve video quality, while still making your video usable for your project.

What is transmuxing?

Transmuxing is where you change the video container without re-encoding the entire video. It's fast, maintains the current quality of your video and often doesn't use a lot of processing power. Sometimes it's the solution to all your problems. And sometimes it makes more problems. But today, we'll learn a little bit about how to transmux using FFmpeg. Then for Python users, we'll go over how to do the same FFmpeg commands using the ffmpeg-python library.

Installation

Ffmpeg CLI can be a pain to install. If you have a Mac, there's an easy way to install with homebrew though, and we detail that in the start of the Live Stream to the Browser with FFMPEG CLI and Python.

After you have it installed, test it works by checking the version:

ffmpeg -version

Getting started with FFprobe

Something you can try to see what happens, is to change the ending of your video file. Some containers are interchangeable, and you can get away with just changing the file ending manually, though this isn't best practice. It also won't work to move from .mkv to any of mov, mp4, m4a, 3gp, 3g2, or mj2. Typically, whatever file formats are listed when you ffprobe your video are the endings you can manually change your file ending to.

After you have FFprobe installed, run this command on your video:

ffprobe video.mp4

Instead of video.mp4 put the complete title of your video file. As an example, I tried examining a video I have called test_vid.mov. Here's what the results look like:

ffprobe version 4.4 Copyright (c) 2007-2021 the FFmpeg developers built with Apple clang version 12.0.5 (clang-1205.0.22.9) configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox libavutil 56. 70.100 / 56. 70.100 libavcodec 58.134.100 / 58.134.100 libavformat 58. 76.100 / 58. 76.100 libavdevice 58. 13.100 / 58. 13.100 libavfilter 7.110.100 / 7.110.100 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 9.100 / 5. 9.100 libswresample 3. 9.100 / 3. 9.100 libpostproc 55. 9.100 / 55. 9.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test_vid.mov': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf57.83.100 Duration: 00:00:13.35, start: 0.000000, bitrate: 344 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x360, 341 kb/s, 29.97 fps, 29.97 tbr, 30k tbn, 59.94 tbc (default) Metadata: handler_name : VideoHandler vendor_id : [0][0][0][0]

From this we can see the different file formats (mov, mp4, m4a, 3gp, 3g2, mj2), and that it's encoded using the h264 codec.

Here's another example, for a file called giant.mkv:

ffprobe version 4.4 Copyright (c) 2007-2021 the FFmpeg developers built with Apple clang version 12.0.5 (clang-1205.0.22.9) configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox libavutil 56. 70.100 / 56. 70.100 libavcodec 58.134.100 / 58.134.100 libavformat 58. 76.100 / 58. 76.100 libavdevice 58. 13.100 / 58. 13.100 libavfilter 7.110.100 / 7.110.100 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 9.100 / 5. 9.100 libswresample 3. 9.100 / 3. 9.100 libpostproc 55. 9.100 / 55. 9.100 Input #0, matroska,webm, from 'giant.mkv': Metadata: title : Jamaica.Inn.1939.720p.BluRay.x264-x0r[FEATURETTE-Shipwrecked in a Studio: A Video Essy with Donald Spoto] encoder : libebml v1.3.0 + libmatroska v1.4.1 creation_time : 2015-05-25T15:34:54.000000Z Duration: 00:13:06.77, start: 0.097000, bitrate: 2211 kb/s Chapters: Chapter #0:0: start 0.000000, end 785.614000 Metadata: title : Chapter 1 Stream #0:0(eng): Video: h264 (High), yuv420p(tv, bt709, progressive), 1280x720 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 180k tbc (default) Metadata: BPS : 2049790 BPS-eng : 2049790 DURATION : 00:13:06.765000000 DURATION-eng : 00:13:06.765000000 NUMBER_OF_FRAMES: 18863 NUMBER_OF_FRAMES-eng: 18863 NUMBER_OF_BYTES : 201587950 NUMBER_OF_BYTES-eng: 201587950 _STATISTICS_WRITING_APP: mkvmerge v7.4.0 ('Circles') 64bit built on Dec 12 2014 15:04:11 _STATISTICS_WRITING_APP-eng: mkvmerge v7.4.0 ('Circles') 64bit built on Dec 12 2014 15:04:11 _STATISTICS_WRITING_DATE_UTC: 2015-05-25 15:34:54 _STATISTICS_WRITING_DATE_UTC-eng: 2015-05-25 15:34:54 _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES Stream #0:1(eng): Audio: ac3, 48000 Hz, stereo, fltp, 160 kb/s (default) Metadata: title : Stereo BPS : 160000 BPS-eng : 160000 DURATION : 00:13:06.720000000 DURATION-eng : 00:13:06.720000000 NUMBER_OF_FRAMES: 24585 NUMBER_OF_FRAMES-eng: 24585 NUMBER_OF_BYTES : 15734400 NUMBER_OF_BYTES-eng: 15734400 _STATISTICS_WRITING_APP: mkvmerge v7.4.0 ('Circles') 64bit built on Dec 12 2014 15:04:11 _STATISTICS_WRITING_APP-eng: mkvmerge v7.4.0 ('Circles') 64bit built on Dec 12 2014 15:04:11 _STATISTICS_WRITING_DATE_UTC: 2015-05-25 15:34:54 _STATISTICS_WRITING_DATE_UTC-eng: 2015-05-25 15:34:54 _STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES _STATISTICS_TAGS-eng: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES

This one contains streams of data for video and audio. We can see its file formats are matroska or webm and it's also encoded using the h264 codec.

We can convert these files to one another using transmuxing as long as we want to keep using the h.264 codec. If we wanted to use one of these with an h.265 codec, then we'd need to transcode.

Transmuxing

The command to transmux is simple and it looks like this:

ffmpeg -find_stream_info -i YOUR_VIDEO.mkv -map 0 -codec copy -codec:s mov_text NEW_VIDEO.mp4

You're copying the codecs, and you're just changing the file format. You can move back and forth without losing video quality. By adding -map 0, you let ffmpeg know you want to keep all the streams and data in your original video.

Transmuxing with ffmpeg-python

You might want to use ffmpeg with python. In that case you'll need to do the following:

  1. Install ffmpeg-python, with this command: pip install ffmpeg-python
  2. Import it into your code with import ffmpeg.
  3. The basic code sample is really simple, here's all you're doing:

` import ffmpeg

( ffmpeg .input('giant.mkv') .output('output_giant.mov') .run() ) `

The movie will contain your metadata and be playable!

Conclusion

You can transmux between files that used the same codec for compression. If you want to compress with a different codec, you'll have to do transcoding. Transmuxing can be helpful when you need a different format, want to preserve quality and you are okay with using the same codec.

Erikka Innes

Developer Evangelist

Connect your users with videos

Create a free account today