JM
JM (Joe Mama Joint Model) is the original H.264 reference encoder, predating alternatives like x264. In the modern day, it joins other MPEG reference encoders such as HM & VTM in their reputations for being highly niche offerings that are used rarely due to their usage complexity & speed disadvantages. Development has been effectively frozen since version 19.1 (2019), & unlike HM or VTM it offers no meaningful efficiency advantage over its production counterpart: x264 has been tuned for two decades & generally matches or beats JM even before considering that x264 is orders of magnitude faster. JM's remaining value is as a conformance ground truth for H.264 & a reference for exotic corners of the standard (multiview, stereo, 4:2:2, High 10, 4:4:4).
Installationâ
Like the other MPEG reference encoders, JM's CMake configuration treats warnings as errors, & its suppression lists were written for compilers circa 2018. Current GCC and Clang both fail out of the box (GCC on -Wunused-but-set-variable, Clang on a whole zoo of newer diagnostics). The practical fix is GCC with two demotions; don't try the same flags with Clang, as it rejects -Wno-error=maybe-uninitialized as an unknown option & then fails on different warnings anyway. GCC with the flags below builds the full suite cleanly.
- Linux & macOS
- Windows
git clone https://vcgit.hhi.fraunhofer.de/jvet/JM
cd JM/
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ \
-DCMAKE_C_FLAGS="-Wno-error=unused-but-set-variable -Wno-error=maybe-uninitialized" \
-DCMAKE_CXX_FLAGS="-Wno-error=unused-but-set-variable -Wno-error=maybe-uninitialized"
make -j$(nproc)
The encoder binary lencod_static can be found within the bin/ directory & can be copied to /usr/local/bin for encoding. The matching decoder is ldecod_static.
With CMake & Visual Studio installed, generate a solution & build the lencod target in Release configuration:
git clone https://vcgit.hhi.fraunhofer.de/jvet/JM
cd JM
mkdir build; cd build
cmake .. -G "Visual Studio 16 2019" -A x64
Usageâ
JM's command line is different from HM & VTM: instead of mixing config files with direct flags, you load one default config with -d & then apply explicit Key=Value overrides with -p. Because -p overrides are explicit, there is no parameter-ordering trap like in the other reference encoders.
lencod_static -d cfg/encoder_main.cfg \
-p InputFile=input.yuv -p OutputFile=output.264 -p ReconFile=/dev/null \
-p SourceWidth=1280 -p SourceHeight=720 -p FrameRate=24 \
-p FramesToBeEncoded=500 -p QPISlice=27 -p QPPSlice=27 -p QPBSlice=27
Input must be a raw planar file (YUV 4:2:0/4:2:2/4:4:4, greyscale or RGB); Y4M is not supported, & stdin piping fails with "Input file - does not exist". Use FFmpeg to dump a raw file first (ffmpeg -i in.mkv -pix_fmt yuv420p input.yuv). Useful parameters:
-d cfg/encoder_main.cfg
Loads the default configuration. The main choices:
| Config file | ProfileIDC | Use case |
|---|---|---|
encoder_main.cfg | 77 (Main) | Default choice, B slices enabled |
encoder_baseline.cfg | 66 (Baseline) | Compatibility profile, no B slices |
encoder_extended.cfg | 88 (Extended) | Rarely useful |
encoder_yuv422.cfg | 122 (High 4:2:2) | 4:2:2 chroma |
Other profiles (High 100, High 10 110, High 4:2:2 122, High 4:4:4 244) are reachable from any config via -p ProfileIDC=100 & friends, with input bit depths up to 14-bit set through SourceBitDepthLuma/SourceBitDepthChroma.
-p InputFile / -p OutputFile / -p ReconFile
Input raw YUV, output raw H.264 bitstream, & reconstructed YUV. ReconFile=/dev/null avoids dumping a useless test_rec.yuv (the default config name) into your working directory. Same for OutputFile: if you don't set it, the bitstream lands in test.264.
-p SourceWidth=1280 -p SourceHeight=720 -p FrameRate=24 -p FramesToBeEncoded=500
Picture dimensions, framerate (float, e.g. 23.976), & number of frames to encode. All four are required; JM has no input autodetection.
-p QPISlice=27 -p QPPSlice=27 -p QPBSlice=27
Fixed QP (0â51) for I, P & B slices separately. There is no CRF-like mode; the alternative is bitrate-targeting rate control: -p RateControlEnable=1 -p Bitrate=1000000 (bits per second).
-p NumberBFrames=2
Number of B slices in the GOP structure. 0 gives I/P-only coding (needed for Baseline).
-p IntraPeriod=24
Period of I-pictures in frames (0 places one only at the start). There is no scene detection; JM's AdaptiveIntraPeriod option only adapts the period to GOP structure length, not to content. For scene-cut keyframes, chunk externally & stitch afterwards.
Muxingâ
The output is a raw (Annex B) H.264 bitstream, which muxes trivially:
ffmpeg -f h264 -i output.264 -c copy output.mp4
Strengths & Weaknessesâ
JM implements essentially the entire H.264 standard: every FREXT profile up to High 4:4:4 Predictive, 8-14 bit depth, lossless, CABAC/CAVLC, multiview & stereo coding, making it a useful conformance & research tool. In exchange it is ancient, effectively unmaintained, awkward to build on modern compilers, limited to raw planar input files, & almost entirely single-threaded (exactly one deblocking loop is OpenMP-parallelized). For any practical H.264 encoding, x264 is the correct tool; reach for JM only when you need the reference implementation itself.