### Install H264 Bitstream with Autotools Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Installs the built H264 bitstream binaries and libraries to the configured prefix, typically /usr/local. ```sh make install ``` -------------------------------- ### Install Prerequisites for Autotools Build Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Installs necessary build tools and libraries for compiling the H264 bitstream project with Autotools on Debian/Ubuntu systems. ```sh sudo apt-get install build-essential libtool autoconf ffmpeg ``` -------------------------------- ### Configure and Build H264 Bitstream with Autotools Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Configures the project with a specified installation prefix and then builds the H264 bitstream library using make. ```sh ./configure --prefix=/usr/local make ``` -------------------------------- ### Install H264 Bitstream Project with CMake Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Optionally installs the compiled H264 bitstream binaries and headers to the default location using CMake. ```sh cmake --install .builddir ``` -------------------------------- ### Read and Debug H264 NAL Unit Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Example code demonstrating how to find, read, and debug a Network Abstraction Layer (NAL) unit from an H264 bitstream. ```c int nal_start, nal_end; uint8_t* buf; int len; // read some H264 data into buf h264_stream_t* h = h264_new(); find_nal_unit(buf, len, &nal_start, &nal_end); read_nal_unit(h, &buf[nal_start], nal_end - nal_start); debug_nal(h,h->nal); ``` -------------------------------- ### Write H.264 SPS NAL Unit Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Example demonstrating how to construct and write a Sequence Parameter Set (SPS) NAL unit. Ensure the buffer is large enough and check the return value of write_nal_unit to confirm data fit. ```c h264_stream_t* h = h264_new(); h->nal->nal_ref_idc = 0x03; h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS; h->sps->profile_idc = 0x42; h->sps->level_idc = 0x33; h->sps->log2_max_frame_num_minus4 = 0x05; h->sps->log2_max_pic_order_cnt_lsb_minus4 = 0x06; h->sps->num_ref_frames = 0x01; h->sps->pic_width_in_mbs_minus1 = 0x2c; h->sps->pic_height_in_map_units_minus1 = 0x1d; h->sps->frame_mbs_only_flag = 0x01; int len = write_nal_unit(h, buf, size); ``` -------------------------------- ### Find and Read NAL Units in a Buffer Source: https://context7.com/aizvorski/h264bitstream/llms.txt Scans a buffer for H.264 start codes to locate NAL units, then parses each unit using `read_nal_unit`. Handles stream truncation errors. ```c #include #include #include "h264_stream.h" #define BUFSIZE (4 * 1024 * 1024) int main(void) { FILE* f = fopen("video.264", "rb"); uint8_t* buf = malloc(BUFSIZE); size_t sz = fread(buf, 1, BUFSIZE, f); fclose(f); h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { printf("NAL at offset %td, size %d\n", p - buf + nal_start, nal_end - nal_start); int rc = read_nal_unit(h, p + nal_start, nal_end - nal_start); if (rc < 0) { fprintf(stderr, "parse error\n"); } else { printf(" NAL type: %d\n", h->nal->nal_unit_type); } p += nal_end; sz -= nal_end; } h264_free(h); free(buf); return 0; } ``` -------------------------------- ### find_nal_unit Source: https://context7.com/aizvorski/h264bitstream/llms.txt Locates the start and end of a Network Abstraction Layer (NAL) unit within a given buffer by searching for H.264 start codes. It returns the length of the NAL unit payload. ```APIDOC ## find_nal_unit ### Description Scans a byte buffer for the H.264 start code (`0x000001` or `0x00000001`) and returns the byte offset of the NAL payload start and end. Returns the NAL length on success, `0` if no start code was found, or `-1` if the end of the NAL was not found (stream truncated — `*nal_end` is set to `size`). ### Method `int find_nal_unit(const uint8_t* buf, size_t size, int* nal_start, int* nal_end)` ### Parameters - **buf** (`const uint8_t*`) - Required - Pointer to the buffer containing the H.264 data. - **size** (`size_t`) - Required - The size of the buffer in bytes. - **nal_start** (`int*`) - Output - Pointer to an integer that will store the offset of the NAL unit payload start. - **nal_end** (`int*`) - Output - Pointer to an integer that will store the offset of the NAL unit payload end. ### Returns - The length of the NAL unit payload on success. - `0` if no start code was found in the buffer. - `-1` if a start code was found but the end of the NAL unit could not be determined (stream truncated). ### Example ```c #include #include #include "h264_stream.h" #define BUFSIZE (4 * 1024 * 1024) int main(void) { FILE* f = fopen("video.264", "rb"); uint8_t* buf = malloc(BUFSIZE); size_t sz = fread(buf, 1, BUFSIZE, f); fclose(f); h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { printf("NAL at offset %td, size %d\n", p - buf + nal_start, nal_end - nal_start); int rc = read_nal_unit(h, p + nal_start, nal_end - nal_start); if (rc < 0) { fprintf(stderr, "parse error\n"); } else { printf(" NAL type: %d\n", h->nal->nal_unit_type); } p += nal_end; sz -= nal_end; } h264_free(h); free(buf); return 0; } ``` ``` -------------------------------- ### rbsp_to_nal Source: https://context7.com/aizvorski/h264bitstream/llms.txt Converts RBSP data to NAL data by inserting `0x03` emulation-prevention bytes. This function handles the byte-escaping scheme where `0x000000`, `0x000001`, or `0x000002` sequences in RBSP are modified to prevent them from appearing as start codes in the NAL stream. The output buffer must be at least `ceil(3/2 * rbsp_size)` bytes. Returns the actual NAL size written, or -1 if the output buffer is too small. ```APIDOC ## rbsp_to_nal ### Description Converts RBSP data to NAL data by inserting `0x03` emulation-prevention bytes. This function handles the byte-escaping scheme where `0x000000`, `0x000001`, or `0x000002` sequences in RBSP are modified to prevent them from appearing as start codes in the NAL stream. The output buffer must be at least `ceil(3/2 * rbsp_size)` bytes. Returns the actual NAL size written, or `-1` if `nal_buf` is too small. ### Method `int rbsp_to_nal(uint8_t* rbsp_buf, int* rbsp_size, uint8_t* nal_buf, int* nal_size)` ### Parameters #### Path Parameters - **rbsp_buf** (uint8_t*) - Pointer to the input RBSP data buffer. - **rbsp_size** (int*) - Pointer to the size of the RBSP data. This will be updated to reflect the actual bytes consumed. - **nal_buf** (uint8_t*) - Pointer to the output NAL unit buffer. - **nal_size** (int*) - Pointer to the size of the NAL unit buffer. This will be updated to reflect the actual NAL data written. ### Request Example ```c uint8_t rbsp_buf[] = { 0x00, 0x00, 0x01 }; // would be illegal in NAL int rbsp_size = sizeof(rbsp_buf); uint8_t nal_buf[8]; // at least 3/2 * rbsp_size int nal_size = sizeof(nal_buf); int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, nal_buf, &nal_size); if (rc < 0) { fprintf(stderr, "output buffer too small\n"); } else { printf("NAL size: %d\n", nal_size); /* nal_buf[1..nal_size-1] = { 0x00, 0x00, 0x03, 0x01 } */ } ``` ### Response #### Success Response (0 or positive integer) - **nal_size** (int) - The actual size of the generated NAL unit data in `nal_buf`. #### Error Response (-1) - **-1** - Indicates that the `nal_buf` was too small to contain the resulting NAL data. ``` -------------------------------- ### Auto-reconfigure H264 Bitstream Project Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Runs the autoreconf command to generate or update configuration scripts for the H264 bitstream project. ```sh autoreconf -i ``` -------------------------------- ### Bitstream Reading Primitives (C) Source: https://context7.com/aizvorski/h264bitstream/llms.txt Illustrates reading various data types from a bitstream buffer using `bs_t`. Includes fixed-width integers and Exp-Golomb coded values. Requires `bs.h`. ```c #include "bs.h" /* --- Reading --- */ uint8_t data[] = { 0x67, 0x42, 0xc0 }; bs_t* b = bs_new(data, sizeof(data)); uint32_t forbidden = bs_read_f(b, 1); // 0 uint32_t nal_ref = bs_read_u(b, 2); // 3 uint32_t nal_type = bs_read_u(b, 5); // 7 (SPS) uint32_t profile = bs_read_u8(b); // 0x42 = 66 (Baseline) printf("forbidden=%u nal_ref_idc=%u type=%u profile=%u\n", forbidden, nal_ref, nal_type, profile); bs_free(b); /* --- Writing --- */ uint8_t out[16] = {0}; bs_t* w = bs_new(out, sizeof(out)); bs_write_u(w, 1, 0); // forbidden_zero_bit bs_write_u(w, 2, 3); // nal_ref_idc = highest priority bs_write_u(w, 5, 7); // nal_unit_type = SPS bs_write_u8(w, 66); // profile_idc = Baseline printf("wrote %d bytes\n", bs_pos(w)); bs_free(w); /* --- Exp-Golomb --- */ uint8_t eg_buf[] = { 0b00100000 }; // ue(v) = 3 bs_t* eg = bs_new(eg_buf, sizeof(eg_buf)); uint32_t val = bs_read_ue(eg); // val = 3 printf("ue decoded: %u\n", val); bs_free(eg); ``` -------------------------------- ### Convert RBSP to NAL with `rbsp_to_nal` Source: https://context7.com/aizvorski/h264bitstream/llms.txt Inserts H.264 emulation-prevention bytes (0x03) into RBSP data to create Annex-B NAL format. The output buffer must be at least 1.5 times the RBSP size. Returns -1 if the output buffer is too small. ```c uint8_t rbsp_buf[] = { 0x00, 0x00, 0x01 }; // would be illegal in NAL int rbsp_size = sizeof(rbsp_buf); uint8_t nal_buf[8]; // at least 3/2 * rbsp_size int nal_size = sizeof(nal_buf); int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, nal_buf, &nal_size); if (rc < 0) { fprintf(stderr, "output buffer too small\n"); } else { printf("NAL size: %d\n", nal_size); /* nal_buf[1..nal_size-1] = { 0x00, 0x00, 0x03, 0x01 } */ } ``` -------------------------------- ### Create H.264 Stream Context Source: https://context7.com/aizvorski/h264bitstream/llms.txt Allocates and initializes a `h264_stream_t` context. This must be called before any other API operations. Ensure to pair with `h264_free`. ```c #include "h264_stream.h" h264_stream_t* h = h264_new(); if (h == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } /* h->nal, h->sps, h->pps, h->sh, h->seis, etc. are all ready to use */ /* ... do work ... */ h264_free(h); // frees all sub-structures ``` -------------------------------- ### Build H264 Bitstream Project with CMake Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Builds the H264 bitstream project after configuration using CMake. ```sh cmake --build .builddir ``` -------------------------------- ### Serialize NAL Unit with `write_nal_unit` Source: https://context7.com/aizvorski/h264bitstream/llms.txt Serializes a configured NAL unit into Annex-B byte format. Ensure the output buffer is sufficiently large; a safe upper bound is 1.5 times the RBSP size. ```c #include "h264_stream.h" #include h264_stream_t* h = h264_new(); /* Configure an SPS for 1280x720, Baseline profile, Level 3.1 */ h->nal->nal_ref_idc = 3; h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS; memset(h->sps, 0, sizeof(sps_t)); h->sps->profile_idc = 66; // Baseline h->sps->level_idc = 31; // Level 3.1 h->sps->seq_parameter_set_id = 0; h->sps->log2_max_frame_num_minus4 = 0; h->sps->pic_order_cnt_type = 0; h->sps->log2_max_pic_order_cnt_lsb_minus4 = 2; h->sps->num_ref_frames = 1; h->sps->pic_width_in_mbs_minus1 = 79; // (79+1)*16 = 1280 h->sps->pic_height_in_map_units_minus1 = 44; // (44+1)*16 = 720 h->sps->frame_mbs_only_flag = 1; h->sps->direct_8x8_inference_flag = 1; uint8_t out_buf[1024]; int len = write_nal_unit(h, out_buf, sizeof(out_buf)); if (len < 0) { fprintf(stderr, "write_nal_unit failed\n"); } else { printf("SPS NAL unit: %d bytes\n", len); /* out_buf[0..len-1] is a valid Annex-B NAL payload */ } h264_free(h); ``` -------------------------------- ### Convert NAL to RBSP with `nal_to_rbsp` Source: https://context7.com/aizvorski/h264bitstream/llms.txt Strips H.264 Annex B emulation-prevention bytes (0x03) to convert raw NAL data to RBSP. The input and output buffers must be of the same or larger size. Detects invalid byte sequences. ```c uint8_t nal_buf[] = { 0x00, 0x00, 0x03, 0x01 }; // 0x000001 escaped as 0x00000301 int nal_size = sizeof(nal_buf); uint8_t rbsp_buf[sizeof(nal_buf)]; int rbsp_size = sizeof(rbsp_buf); int rc = nal_to_rbsp(nal_buf, &nal_size, rbsp_buf, &rbsp_size); if (rc < 0) { fprintf(stderr, "invalid NAL escaping\n"); } else { printf("RBSP size: %d\n", rbsp_size); /* rbsp_buf now contains { 0x00, 0x00, 0x01 } — the emulation byte removed */ } ``` -------------------------------- ### Read/Write AVCC Record (C) Source: https://context7.com/aizvorski/h264bitstream/llms.txt Demonstrates reading an AVCDecoderConfigurationRecord from a byte buffer and writing it back. Requires `h264_avcc.h`, `h264_stream.h`, and `bs.h`. The `debug_avcc` function can be used to print parsed fields. ```c #include "h264_avcc.h" #include "h264_stream.h" #include "bs.h" /* --- Reading an avcC record --- */ uint8_t avcc_data[] = { 0x01, // configurationVersion = 1 0x42, 0xc0, 0x1e, // profile=66(Baseline), compat=0xc0, level=30 0xff, // lengthSizeMinusOne=3 0xe1, // numSPS=1 0x00, 0x0b, // SPS length = 11 /* SPS NAL bytes */ 0x67,0x42,0xc0,0x1e,0xd9,0x00,0xa0,0x47,0xfe,0xc8,0x10, 0x01, // numPPS=1 0x00, 0x04, // PPS length = 4 /* PPS NAL bytes */ 0x68,0xce,0x38,0x80 }; h264_stream_t* h = h264_new(); avcc_t* avcc = avcc_new(); bs_t* b = bs_new(avcc_data, sizeof(avcc_data)); int rc = read_avcc(avcc, h, b); if (rc < 0) { fprintf(stderr, "read_avcc failed\n"); } else { debug_avcc(avcc); // prints profile, level, SPS/PPS details if (avcc->numOfSequenceParameterSets > 0 && avcc->sps_table[0] != NULL) printf("Width: %d px\n", (avcc->sps_table[0]->pic_width_in_mbs_minus1 + 1) * 16); } /* --- Writing back --- */ uint8_t out[256]; bs_t* bout = bs_new(out, sizeof(out)); write_avcc(avcc, h, bout); bs_free(b); bs_free(bout); avcc_free(avcc); h264_free(h); ``` -------------------------------- ### Analyze H.264 Bitstream Source: https://github.com/aizvorski/h264bitstream/blob/master/samples/HOWTO.md Analyze an H.264 bitstream file and redirect the output to a text file. This command-line tool helps in understanding the structure and content of the bitstream. ```bash ./h264_analyze test.264 > test.out ``` -------------------------------- ### h264_new Source: https://context7.com/aizvorski/h264bitstream/llms.txt Creates and initializes a new H.264 stream context (`h264_stream_t`). This function must be called before any other read or write operations. The returned context pointer is used for all subsequent API calls. ```APIDOC ## h264_new ### Description Allocates and zero-initializes a `h264_stream_t` and all its sub-structures (NAL, SPS/PPS tables, SVC extension structures, slice header, SEI list). Must be called before any read or write operations. The returned pointer is the single context object passed to all other API functions. ### Method `h264_stream_t* h264_new()` ### Returns A pointer to the newly created `h264_stream_t` context, or `NULL` if memory allocation fails. ### Example ```c #include "h264_stream.h" h264_stream_t* h = h264_new(); if (h == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } /* h->nal, h->sps, h->pps, h->sh, h->seis, etc. are all ready to use */ /* ... do work ... */ h264_free(h); // frees all sub-structures ``` ``` -------------------------------- ### Create Black Video Frame with FFmpeg Source: https://github.com/aizvorski/h264bitstream/blob/master/samples/HOWTO.md Use FFmpeg to generate a black video frame of a specified size and duration. This is useful for creating test or placeholder video content. ```bash ffmpeg -f lavfi -i color=c=black:s=640x480:d=0.5 test.y4m ``` -------------------------------- ### Configure H264 Bitstream Project with CMake Source: https://github.com/aizvorski/h264bitstream/blob/master/README.md Configures the H264 bitstream project using CMake. Specify build directory and potentially compiler and build type. ```sh cmake -S . -B .builddir ``` -------------------------------- ### read_debug_nal_unit Source: https://context7.com/aizvorski/h264bitstream/llms.txt Parses and verbosely prints all NAL fields. This function works identically to `read_nal_unit` but additionally prints each individual field name and value to `h264_dbgfile` (which defaults to `stdout`). It is invaluable for debugging and inspecting unknown bitstreams without needing to write separate print code. Output is directed to `h264_dbgfile` if it is set, otherwise to `stdout`. ```APIDOC ## read_debug_nal_unit ### Description Parse and print all NAL fields verbosely. Works identically to `read_nal_unit` but also prints each individual field name and value to `h264_dbgfile` (defaults to `stdout`) as it is parsed. Indispensable for debugging and inspecting unknown bitstreams without writing separate print code. Output is directed to `h264_dbgfile` if set, otherwise `stdout`. ### Method `void read_debug_nal_unit(h264_stream_t* h, uint8_t* nal_data, int nal_size)` ### Parameters #### Path Parameters - **h** (h264_stream_t*) - Pointer to the H.264 stream context. - **nal_data** (uint8_t*) - Pointer to the NAL unit data. - **nal_size** (int) - The size of the NAL unit data. ### Request Example ```c #include "h264_stream.h" #include h264_dbgfile = fopen("analysis.txt", "w"); // redirect output to file h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { read_debug_nal_unit(h, p + nal_start, nal_end - nal_start); p += nal_end; sz -= nal_end; } h264_free(h); fclose(h264_dbgfile); /* analysis.txt now contains a field-by-field dump of every NAL unit */ ``` ### Response This function does not return a value. Its effect is to print detailed NAL unit information to `h264_dbgfile` or `stdout`. ``` -------------------------------- ### Peek NAL Unit Header with `peek_nal_unit` Source: https://context7.com/aizvorski/h264bitstream/llms.txt Quickly reads only the NAL header to determine the NAL unit type without full parsing. Useful for selective parsing of NAL units like parameter sets. ```c h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { int type = peek_nal_unit(h, p + nal_start, nal_end - nal_start); if (type == NAL_UNIT_TYPE_SPS || type == NAL_UNIT_TYPE_PPS) { /* only fully parse parameter sets */ read_nal_unit(h, p + nal_start, nal_end - nal_start); } p += nal_end; sz -= nal_end; } h264_free(h); ``` -------------------------------- ### Debug NAL Unit Parsing with `read_debug_nal_unit` Source: https://context7.com/aizvorski/h264bitstream/llms.txt Parses a NAL unit and verbosely prints all its fields to `h264_dbgfile` (defaults to stdout). Useful for debugging and inspecting bitstreams. ```c #include "h264_stream.h" #include h264_dbgfile = fopen("analysis.txt", "w"); // redirect output to file h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { read_debug_nal_unit(h, p + nal_start, nal_end - nal_start); p += nal_end; sz -= nal_end; } h264_free(h); fclose(h264_dbgfile); /* analysis.txt now contains a field-by-field dump of every NAL unit */ ``` -------------------------------- ### Inspect SEI Messages (C) Source: https://context7.com/aizvorski/h264bitstream/llms.txt Shows how to iterate through parsed SEI messages within an `h264_stream_t` object. Requires `h264_sei.h`. SEI messages are stored in `h->seis` after parsing NAL units of type `NAL_UNIT_TYPE_SEI`. ```c #include "h264_sei.h" /* Manually inspect SEI messages after parsing */ h264_stream_t* h = h264_new(); /* ... read NAL units including SEI ... */ for (int i = 0; i < h->num_seis; i++) { sei_t* sei = h->seis[i]; printf("SEI type=%d size=%d\n", sei->payloadType, sei->payloadSize); if (sei->payloadType == SEI_TYPE_SCALABILITY_INFO && sei->sei_svc != NULL) { printf(" SVC layers: %d\n", sei->sei_svc->num_layers_minus1 + 1); } } h264_free(h); // also frees all seis via sei_free ``` -------------------------------- ### Encode Video to H.264 with x264 Source: https://github.com/aizvorski/h264bitstream/blob/master/samples/HOWTO.md Encode a YUV video file into an H.264 bitstream using the x264 encoder. Ensure the input file format is compatible with x264. ```bash x264 --profile high test.y4m -o test.264 ``` -------------------------------- ### Free H.264 Stream Context Source: https://context7.com/aizvorski/h264bitstream/llms.txt Recursively frees the `h264_stream_t` and all its dynamically allocated sub-structures. Always pair with `h264_new`. ```c h264_stream_t* h = h264_new(); /* ... use h ... */ h264_free(h); // safe to call even if some sub-structures were not populated h = NULL; ``` -------------------------------- ### write_nal_unit Source: https://context7.com/aizvorski/h264bitstream/llms.txt Serializes a NAL unit into bytes. It encodes the RBSP and adds start-code emulation-prevention bytes. The function returns the number of bytes written to the buffer or -1 on error. The buffer must be large enough, with a safe upper bound of 1.5 times the RBSP size. ```APIDOC ## write_nal_unit ### Description Serializes a NAL unit to bytes. This is the inverse of `read_nal_unit`. It reads the NAL type from `h->nal`, dispatches to the appropriate RBSP encoder, then converts RBSP to NAL, adding start-code emulation-prevention bytes. Returns the number of bytes written into `buf`, or `-1` on error. `buf` must be large enough; a safe upper bound is `1.5 × rbsp_size`. ### Method `int write_nal_unit(h264_stream_t* h, uint8_t* buf, int buf_size)` ### Parameters #### Path Parameters - **h** (h264_stream_t*) - Pointer to the H.264 stream context. - **buf** (uint8_t*) - Buffer to write the NAL unit data to. - **buf_size** (int) - The size of the output buffer. ### Request Example ```c #include "h264_stream.h" #include h264_stream_t* h = h264_new(); /* Configure an SPS for 1280x720, Baseline profile, Level 3.1 */ h->nal->nal_ref_idc = 3; h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS; memset(h->sps, 0, sizeof(sps_t)); h->sps->profile_idc = 66; // Baseline h->sps->level_idc = 31; // Level 3.1 h->sps->seq_parameter_set_id = 0; h->sps->log2_max_frame_num_minus4 = 0; h->sps->pic_order_cnt_type = 0; h->sps->log2_max_pic_order_cnt_lsb_minus4 = 2; h->sps->num_ref_frames = 1; h->sps->pic_width_in_mbs_minus1 = 79; // (79+1)*16 = 1280 h->sps->pic_height_in_map_units_minus1 = 44; // (44+1)*16 = 720 h->sps->frame_mbs_only_flag = 1; h->sps->direct_8x8_inference_flag = 1; uint8_t out_buf[1024]; int len = write_nal_unit(h, out_buf, sizeof(out_buf)); if (len < 0) { fprintf(stderr, "write_nal_unit failed\n"); } else { printf("SPS NAL unit: %d bytes\n", len); /* out_buf[0..len-1] is a valid Annex-B NAL payload */ } h264_free(h); ``` ### Response #### Success Response (0 or positive integer) - **len** (int) - The number of bytes written into `buf`. #### Error Response (-1) - **-1** - Indicates an error occurred during serialization. ``` -------------------------------- ### Bitstream (bs_t) API Source: https://context7.com/aizvorski/h264bitstream/llms.txt Provides low-level bitstream primitives for reading and writing individual bits, fixed-width integers, Exp-Golomb coded values, and raw byte blocks from/to a byte buffer. ```APIDOC ## Bitstream (`bs_t`) API — Bit-level read/write primitives `bs_t` is an inline-only bitstream cursor over a byte buffer. It supports reading/writing individual bits, fixed-width unsigned/signed integers, Exp-Golomb coded values (ue/se), and raw byte blocks. Used internally by all NAL parsers but also available directly for custom low-level work. ```c #include "bs.h" /* --- Reading --- */ uint8_t data[] = { 0x67, 0x42, 0xc0 }; bs_t* b = bs_new(data, sizeof(data)); uint32_t forbidden = bs_read_f(b, 1); // 0 uint32_t nal_ref = bs_read_u(b, 2); // 3 uint32_t nal_type = bs_read_u(b, 5); // 7 (SPS) uint32_t profile = bs_read_u8(b); // 0x42 = 66 (Baseline) printf("forbidden=%u nal_ref_idc=%u type=%u profile=%u\n", forbidden, nal_ref, nal_type, profile); bs_free(b); /* --- Writing --- */ uint8_t out[16] = {0}; bs_t* w = bs_new(out, sizeof(out)); bs_write_u(w, 1, 0); // forbidden_zero_bit bs_write_u(w, 2, 3); // nal_ref_idc = highest priority bs_write_u(w, 5, 7); // nal_unit_type = SPS bs_write_u8(w, 66); // profile_idc = Baseline printf("wrote %d bytes\n", bs_pos(w)); bs_free(w); /* --- Exp-Golomb --- */ uint8_t eg_buf[] = { 0b00100000 }; // ue(v) = 3 bs_t* eg = bs_new(eg_buf, sizeof(eg_buf)); uint32_t val = bs_read_ue(eg); // val = 3 printf("ue decoded: %u\n", val); bs_free(eg); ``` ``` -------------------------------- ### nal_to_rbsp Source: https://context7.com/aizvorski/h264bitstream/llms.txt Converts raw NAL data (Annex B format, with `0x03` emulation-prevention bytes) to RBSP (Raw Byte Sequence Payload). This function performs the inverse of the byte-escaping scheme described in H.264 section 7.4.1.1. It returns the actual RBSP size or -1 if an invalid byte sequence is detected. The input and output buffers must be of the same size or larger. ```APIDOC ## nal_to_rbsp ### Description Converts raw NAL data (Annex B format, with `0x03` emulation-prevention bytes) to RBSP. This is the forward direction of the byte-escaping scheme defined in H.264 section 7.4.1.1. Returns the actual RBSP size, or `-1` if an invalid byte sequence is detected. The input and output buffers must be the same size or larger. ### Method `int nal_to_rbsp(uint8_t* nal_buf, int* nal_size, uint8_t* rbsp_buf, int* rbsp_size)` ### Parameters #### Path Parameters - **nal_buf** (uint8_t*) - Pointer to the input NAL unit data buffer. - **nal_size** (int*) - Pointer to the size of the NAL unit data. This will be updated to reflect the actual bytes consumed. - **rbsp_buf** (uint8_t*) - Pointer to the output RBSP buffer. - **rbsp_size** (int*) - Pointer to the size of the RBSP buffer. This will be updated to reflect the actual RBSP data written. ### Request Example ```c uint8_t nal_buf[] = { 0x00, 0x00, 0x03, 0x01 }; // 0x000001 escaped as 0x00000301 int nal_size = sizeof(nal_buf); uint8_t rbsp_buf[sizeof(nal_buf)]; int rbsp_size = sizeof(rbsp_buf); int rc = nal_to_rbsp(nal_buf, &nal_size, rbsp_buf, &rbsp_size); if (rc < 0) { fprintf(stderr, "invalid NAL escaping\n"); } else { printf("RBSP size: %d\n", rbsp_size); /* rbsp_buf now contains { 0x00, 0x00, 0x01 } — the emulation byte removed */ } ``` ### Response #### Success Response (0 or positive integer) - **rbsp_size** (int) - The actual size of the generated RBSP data in `rbsp_buf`. #### Error Response (-1) - **-1** - Indicates that an invalid byte sequence was detected in the NAL data. ``` -------------------------------- ### h264_free Source: https://context7.com/aizvorski/h264bitstream/llms.txt Frees the memory allocated for an H.264 stream context and all its associated sub-structures. This function should always be paired with a prior call to `h264_new`. ```APIDOC ## h264_free ### Description Recursively frees the `h264_stream_t` and every dynamically allocated sub-structure, including SPS/PPS tables, SVC extensions, and any accumulated SEI messages. Always pair with `h264_new`. ### Method `void h264_free(h264_stream_t* h)` ### Parameters - **h** (`h264_stream_t*`) - Required - Pointer to the H.264 stream context to be freed. ### Example ```c h264_stream_t* h = h264_new(); /* ... use h ... */ h264_free(h); // safe to call even if some sub-structures were not populated h = NULL; ``` ``` -------------------------------- ### read_nal_unit Source: https://context7.com/aizvorski/h264bitstream/llms.txt Parses a NAL unit from raw, NAL-escaped bytes. It converts the data to RBSP, reads the NAL header, and dispatches to specific parsers for SPS, PPS, slice headers, SEI messages, etc. The results are stored in the `h264_stream_t` context. ```APIDOC ## read_nal_unit ### Description Converts NAL-escaped bytes to RBSP, reads the NAL header (forbidden bit, `nal_ref_idc`, `nal_unit_type`), then dispatches to the appropriate sub-parser (SPS, PPS, slice header, SEI, AUD, SVC prefix, etc.). Results are written into the corresponding fields of the `h264_stream_t`. Returns the number of bytes consumed from the input buffer, or `-1` on error. ### Method `int read_nal_unit(h264_stream_t* h, const uint8_t* nal_buf, int nal_len)` ### Parameters - **h** (`h264_stream_t*`) - Required - Pointer to the H.264 stream context. - **nal_buf** (`const uint8_t*`) - Required - Pointer to the buffer containing the NAL unit data (without start code). - **nal_len** (`int`) - Required - The length of the NAL unit data in bytes. ### Returns - The number of bytes consumed from the input buffer on success. - `-1` on parsing error. ### Example ```c h264_stream_t* h = h264_new(); uint8_t nal_buf[4096]; int nal_len = /* bytes of one NAL unit (without start code) */; int rc = read_nal_unit(h, nal_buf, nal_len); if (rc < 0) { fprintf(stderr, "failed to parse NAL unit\n"); } else { switch (h->nal->nal_unit_type) { case NAL_UNIT_TYPE_SPS: printf("SPS: profile=%d level=%d width=%d height=%d\n", h->sps->profile_idc, h->sps->level_idc, (h->sps->pic_width_in_mbs_minus1 + 1) * 16, (h->sps->pic_height_in_map_units_minus1 + 1) * 16); break; case NAL_UNIT_TYPE_PPS: printf("PPS: pps_id=%d sps_id=%d\n", h->pps->pic_parameter_set_id, h->pps->seq_parameter_set_id); break; case NAL_UNIT_TYPE_CODED_SLICE_IDR: printf("IDR slice\n"); break; case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: printf("Non-IDR slice: frame_num=%d\n", h->sh->frame_num); break; } } h264_free(h); ``` ``` -------------------------------- ### AVCC Record Operations Source: https://context7.com/aizvorski/h264bitstream/llms.txt Functions for reading, writing, and managing the AVCDecoderConfigurationRecord (avcC) structure used in MP4 and FLV files. Includes lifecycle management with `avcc_new` and `avcc_free`. ```APIDOC ## `avcc_new` / `read_avcc` / `write_avcc` / `avcc_free` — AVC Decoder Configuration Record (MP4/FLV) Reads or writes the `AVCDecoderConfigurationRecord` structure defined in ISO/IEC 14496-15, as found in the `avcC` atom of MP4 files or as the `AVCVideoPacket` payload (type 0) in FLV files. `read_avcc` internally calls `read_nal_unit` for each embedded SPS/PPS. `debug_avcc` prints all fields to `h264_dbgfile`. ```c #include "h264_avcc.h" #include "h264_stream.h" #include "bs.h" /* --- Reading an avcC record --- */ uint8_t avcc_data[] = { 0x01, // configurationVersion = 1 0x42, 0xc0, 0x1e, // profile=66(Baseline), compat=0xc0, level=30 0xff, // lengthSizeMinusOne=3 0xe1, // numSPS=1 0x00, 0x0b, // SPS length = 11 /* SPS NAL bytes */ 0x67,0x42,0xc0,0x1e,0xd9,0x00,0xa0,0x47,0xfe,0xc8,0x10, 0x01, // numPPS=1 0x00, 0x04, // PPS length = 4 /* PPS NAL bytes */ 0x68,0xce,0x38,0x80 }; h264_stream_t* h = h264_new(); avcc_t* avcc = avcc_new(); bs_t* b = bs_new(avcc_data, sizeof(avcc_data)); int rc = read_avcc(avcc, h, b); if (rc < 0) { fprintf(stderr, "read_avcc failed\n"); } else { debug_avcc(avcc); // prints profile, level, SPS/PPS details if (avcc->numOfSequenceParameterSets > 0 && avcc->sps_table[0] != NULL) printf("Width: %d px\n", (avcc->sps_table[0]->pic_width_in_mbs_minus1 + 1) * 16); } /* --- Writing back --- */ uint8_t out[256]; bs_t* bout = bs_new(out, sizeof(out)); write_avcc(avcc, h, bout); bs_free(b); bs_free(bout); avcc_free(avcc); h264_free(h); ``` ``` -------------------------------- ### peek_nal_unit Source: https://context7.com/aizvorski/h264bitstream/llms.txt Reads only the 1-byte NAL header (forbidden bit, `nal_ref_idc`, `nal_unit_type`) without full parsing. This is useful for quickly classifying NAL units before deciding whether to fully parse them. Returns the NAL unit type on success, or -1 if the data does not appear to be a valid NAL. ```APIDOC ## peek_nal_unit ### Description Reads only the 1-byte NAL header (forbidden bit, `nal_ref_idc`, `nal_unit_type`) without full parsing. Useful for quickly classifying NAL units before deciding whether to fully parse them. Returns the NAL unit type on success, or `-1` if the data does not look like a valid NAL. ### Method `int peek_nal_unit(h264_stream_t* h, uint8_t* nal_data, int nal_size)` ### Parameters #### Path Parameters - **h** (h264_stream_t*) - Pointer to the H.264 stream context. - **nal_data** (uint8_t*) - Pointer to the NAL unit data. - **nal_size** (int) - The size of the NAL unit data. ### Request Example ```c h264_stream_t* h = h264_new(); uint8_t* p = buf; int nal_start, nal_end; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { int type = peek_nal_unit(h, p + nal_start, nal_end - nal_start); if (type == NAL_UNIT_TYPE_SPS || type == NAL_UNIT_TYPE_PPS) { /* only fully parse parameter sets */ read_nal_unit(h, p + nal_start, nal_end - nal_start); } p += nal_end; sz -= nal_end; } h264_free(h); ``` ### Response #### Success Response (Integer >= 0) - **type** (int) - The NAL unit type (e.g., `NAL_UNIT_TYPE_SPS`, `NAL_UNIT_TYPE_PPS`). #### Error Response (-1) - **-1** - Indicates that the provided data does not appear to be a valid NAL unit header. ``` -------------------------------- ### SEI Message Lifecycle Source: https://context7.com/aizvorski/h264bitstream/llms.txt Functions for allocating and freeing SEI message objects (`sei_t`). SEI messages are parsed from NAL units of type `NAL_UNIT_TYPE_SEI` and can contain specific payload types like scalability information. ```APIDOC ## `sei_new` / `sei_free` — SEI message lifecycle Allocates or frees a single Supplemental Enhancement Information (`sei_t`) object. SEI messages are accumulated in `h->seis[0..h->num_seis-1]` after calling `read_nal_unit` on a `NAL_UNIT_TYPE_SEI` unit (requires compile-time `-DHAVE_SEI`). The `sei_t` union holds either a generic `uint8_t* data` payload or a parsed `sei_scalability_info_t*` for `SEI_TYPE_SCALABILITY_INFO`. ```c #include "h264_sei.h" /* Manually inspect SEI messages after parsing */ h264_stream_t* h = h264_new(); /* ... read NAL units including SEI ... */ for (int i = 0; i < h->num_seis; i++) { sei_t* sei = h->seis[i]; printf("SEI type=%d size=%d\n", sei->payloadType, sei->payloadSize); if (sei->payloadType == SEI_TYPE_SCALABILITY_INFO && sei->sei_svc != NULL) { printf(" SVC layers: %d\n", sei->sei_svc->num_layers_minus1 + 1); } } h264_free(h); // also frees all seis via sei_free ``` ```