edge264 Documentation

repository·master·Indexed 19 days ago

https://github.com/tvlabs/edge264

A high-performance, cross-platform H.264/AVC decoder utilizing C vector extensions for optimized performance across various CPU architectures. It supports native builds with x86 ISA dispatching, WebAssembly (including WASM v3 relaxed SIMD), and CMake integration via the edge264::edge264 target. The library provides a C API for decoding NAL units, managing decoding contexts, and retrieving decoded frames via the Edge264Frame structure.

Tokens
2.7K
Snippets
6
Records
14
Agent score
15%

What's inside edge264

  1. Understand the edge264 architecture and programming techniques

    master

    edge264 uses several specialized programming techniques to optimize for performance and code size, aiming to fit within L1 cache and reduce branch predictor pressure. Key architectural patterns include:

    • Single Header Definition: The file src/edge264_internal.h is the central source of truth. It contains all struct definitions, constants, enums, SIMD aliases, inline functions, macros, and exported functions. Developers should consult this file first to understand the codebase.
    • Code Blocks as a Pipeline: Instead of traditional deep function hierarchies, the main decoding loop is a forward pipeline designed as a Directed Acyclic Graph (DAG). Nodes are non-inlined functions and edges are tail calls, which helps mutualize code branches and reduce code size.
    • Structure of Arrays (SoA): The frame buffer uses the Structure of Arrays pattern (storing arrays for each distinct field rather than an array of structures). This allows operations on frames to be expressed efficiently using bitwise and vector operators.
    • SIMD Strategy: The project uses a multiarch approach combining GCC vector extensions with aliased Intel intrinsics. This allows supporting both Intel SSE and ARM NEON with ~80% common code. Some critical algorithms use 'Register-saturating SIMD', intentionally saturating the register bank to improve scaling on later CPUs.
    • Bitstream Handling: Uses a 'Piston cached bitstream reader' (src/edge264_bitstream.c) which reads bits into a size_t[2] intermediate cache, allowing 32/64 bit access per read and wide memory refills. It also performs 'On-the-fly SIMD unescaping' to avoid a separate preprocessing pass.
    • Error Handling: Employs 'Deferred error checking' (src/edge264_headers.c). Rather than checking every value, it clamps inputs to expected ranges and verifies the presence of rbsp_trailing_bit to catch corruption with high probability.
  2. Build edge264 for WebAssembly

    master

    To build edge264 for WebAssembly, use emmake make. To target WASM v3 (which includes relaxed SIMD), add the CFLAGS=-mrelaxed-simd flag.

    emmake make # add CFLAGS=-mrelaxed-simd to target WASM v3
  3. Build edge264 for native platforms

    master

    To build edge264 for your local machine, use the standard make command.

    If you need to distribute a library that runs efficiently across various x86 CPU generations, you can use the VARIANTS option. This allows the library to detect the host ISA at runtime and dispatch to the fastest available implementation. Note that VARIANTS is not required for a single-machine native build where -march=native can be used instead.

    # Standard native build
    make
    
    # Build with specific x86 variants for distribution
    make CFLAGS="-march=x86-64" VARIANTS=x86-64-v2,x86-64-v3 BUILDTEST=no
  4. Integrate edge264 with CMake

    master

    edge264 provides a CMakeLists.txt that wraps its Makefile, allowing easy integration into CMake projects via FetchContent. It exposes the imported target edge264::edge264 which can be used with target_link_libraries.

    cmake_minimum_required(VERSION 3.14)
    project(my_app C)
    
    include(FetchContent)
    FetchContent_Declare(edge264
      GIT_REPOSITORY https://github.com/tvlabs/edge264.git
      GIT_TAG        v1.0  # always pin to a tag or commit hash
    )
    FetchContent_MakeAvailable(edge264)
    
    add_executable(my_app main.c)
    target_link_libraries(my_app PRIVATE edge264::edge264)
  5. Run edge264 tests and benchmarks

    master

    Use make check to run the built-in test suite.

    For advanced testing and display, use the edge264_test executable. It can decode <video>.264 files and compare them against sibling <video>.yuv files.

    Note: If your input is in MP4 format, you may need to convert it to an Annex B byte stream using ffmpeg first.

    # Run the test suite
    make check
    
    # Convert MP4 to Annex B (optional)
    ffmpeg -i vid.mp4 -vcodec copy -bsf h264_mp4toannexb -an vid.264
    
    # Display decoded frames from a directory
    ./edge264_test -d vid.264
    
    # Benchmark instead of display
    ./edge264_test -b vid.264
  6. Fetch decoded frames with edge264_get_frame

    master

    Retrieves the next frame ready for output from the decoder context.

    Parameters:

    • dec: The initialized Edge264Decoder context.
    • out: A pointer to an Edge264Frame structure to be filled with frame data.
    • borrow:
      • If 0: The frame may be accessed until the next call to edge264_decode_NAL.
      • If non-zero: The frame must be explicitly returned using edge264_return_frame.

    Return Codes:

    • 0: Success (one frame returned).
    • EINVAL: dec or out is NULL.
    • ENOMSG: No frame is available for output at this time.
  7. Decode NAL units with edge264_decode_NAL

    master

    Decodes a single NAL unit. This is the primary function for feeding bitstreams into the decoder.

    Parameters:

    • dec: The initialized Edge264Decoder context.
    • buf: Pointer to the first byte of the NAL unit.
    • end: Pointer to the first byte past the buffer. If buf >= end, all buffered frames are made ready for output.
    • free_cb: A callback function called (potentially from another thread) to signal the end of parsing and release the NAL buffer. Only called when returning 0.
    • free_arg: Custom value passed to free_cb.

    Return Codes:

    • 0: Success.
    • ENOBUFS: More frames should be consumed with edge264_get_frame before calling this again with the same NAL.
    • ENOTSUP: Unsupported stream.
    • EBADMSG: Invalid stream.
    • EINVAL: dec or buf is NULL.
    • ENODATA: buf >= end and no frames are left to output.
    • ENOMEM: Memory allocation failed.
  8. Allocate a decoding context with edge264_alloc

    master

    Use edge264_alloc to initialize a decoding context. This function allows fine-grained control over threading, logging, and memory management.

    Parameters:

    • n_threads: Number of background worker threads. Use 0 to disable multithreading or -1 to auto-detect logical cores.
    • log_cb: A fputs-compatible function pointer for logging. Requires the logs variant to be built.
    • log_arg: Custom value passed to log_cb.
    • log_mbs: Set to 1 to enable logging of macroblocks.
    • alloc_cb: Custom allocator for samples and macroblock buffers. If provided, edge264_decode_NAL will call this instead of malloc.
    • free_cb: Custom deallocator for buffers provided by alloc_cb.
    • alloc_arg: Custom value passed to alloc_cb and free_cb.
    // Example: Auto threads, no logs, auto allocs
    Edge264Decoder *dec = edge264_alloc(-1, NULL, NULL, 0, NULL, NULL, NULL);
  9. Find NAL start codes with edge264_find_start_code

    master

    Searches for the next H.264 start code prefix.

    Parameters:

    • buf: First byte of the buffer to search.
    • end: First invalid byte past the buffer.
    • four_byte: If 0, seeks a 3-byte 001 prefix. If non-zero, seeks a 4-byte 0001 prefix.

    Returns: A pointer to the start code, or end if not found.

  10. Manage frame ownership with edge264_return_frame

    master

    If you called edge264_get_frame with borrow != 0, you must return ownership of the frame to the decoder using this function.

    Parameters:

    • dec: The initialized Edge264Decoder context.
    • return_arg: The value stored inside the Edge264Frame.return_arg field.