Skip to main content

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​

Requires warning suppressions to build

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.

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.

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.

Main profile encode from a raw YUV file
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 fileProfileIDCUse case
encoder_main.cfg77 (Main)Default choice, B slices enabled
encoder_baseline.cfg66 (Baseline)Compatibility profile, no B slices
encoder_extended.cfg88 (Extended)Rarely useful
encoder_yuv422.cfg122 (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:

Mux to MP4
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.