iter2 step2: GLib/GStreamer compat shim, build succeeds
Vendored gsth265parser + nalutils + gstbitreader + gstbytereader (the
Step 1 commit) compile cleanly against libc + libv4l2 only after
adding 1 compat translation unit + 5 stub headers, no edits to the
vendored .c/.h files themselves.
src/h265_parser/gst_compat.{h,c} — new files (MIT, original work):
- GLib type aliases (gboolean, gchar, gint*, guint*, gsize, gpointer)
- Memory helpers (g_malloc/g_free as #define free, g_memdup2 inline)
- Asserts as no-op + parser-return-code-propagation
- All GST_DEBUG/INFO/WARNING/ERROR/LOG/FIXME as no-ops (the parser
is heavy on debug logging; we compile it all out)
- GArray implementation (~100 LOC, just enough for gsth265parser.c's
24 call sites)
- GList full struct with .data/.next/.prev so callers compile;
list-manipulation functions abort() — dead code paths only
- Byte-order read/write macros (GST_READ_UINT8/16/24/32/64_LE/BE,
GST_WRITE_UINT8/16/24/32_BE) — aarch64 LE inlines
- g_once_init_enter/leave as simple gate
- G_MAXUINT*, G_MAXINT*, G_MINxxx, G_GNUC_* attribute macros, etc.
- Opaque GstBuffer/GstMemory/GstMapInfo + abort-stub functions for
the encoder-side SEI-insertion paths the libva backend never invokes
- gst_util_ceil_log2 real impl (used by slice-header parser; dead
for our SPS-only call path but cheaper to implement than stub)
src/h265_parser/gst/{gst.h,base/base-prelude.h,base/gstbitwriter.h,
codecparsers/codecparsers-prelude.h,glib-compat-private.h} — 5 new
stub headers (MIT). All include gst_compat.h. gstbitwriter.h adds
abort-stub functions for the bit-writer API (used by nalutils.c's NAL
emulation-prevention encoder path — dead code for the parse-only
libva backend).
src/meson.build — added the 5 new .c source files and 10 new .h
headers; added include_directories('h265_parser') to the include path
so the vendored files' '#include <gst/base/...>' style references
resolve to the stub headers + actual vendored files in the local
tree.
Build verified: ninja -C build produces v4l2_request_drv_video.so
(682 KB, up from 485 KB pre-vendor — the +200 KB is the vendored
parser code). nm shows gst_h265_parse_sps, gst_h265_parse_sps_ext,
gst_h265_parser_identify_nalu, and the other functions we need for
Step 4 are present in the binary.
Two #warning messages from gsth265parser.h about API stability are
upstream-intentional and harmless ('The H.265 parsing library is
unstable API and may change in future').
This commit completes Step 2 of ampere-kernel-decoders iter2 Phase 6.
Backend remains functionally identical to pre-iter2 — the new code
compiles + links but is not yet called from h265_set_controls (that's
Step 4). Existing 5 codecs continue to work as before.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
/* Stub for <gst/base/base-prelude.h> — GStreamer base-lib prelude.
|
||||||
|
* In upstream GStreamer, this sets up the GstBaseExport macro + GObject
|
||||||
|
* boilerplate. We bypass all of that and provide only what our four
|
||||||
|
* vendored .c files actually need (gst_compat.h's typedefs).
|
||||||
|
*
|
||||||
|
* Crucially we also #define GST_BASE_API to nothing so the function
|
||||||
|
* declarations in gstbitreader.h / gstbytereader.h drop the
|
||||||
|
* dllimport / visibility attribute prefix.
|
||||||
|
*/
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_BASE_PRELUDE_STUB
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_BASE_PRELUDE_STUB
|
||||||
|
#include "gst_compat.h"
|
||||||
|
#define GST_BASE_API
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/* Stub for <gst/base/gstbitwriter.h>.
|
||||||
|
*
|
||||||
|
* The vendored nalutils.c uses GstBitWriter for NAL emulation-prevention
|
||||||
|
* byte INSERTION during write-side (encoder) operations. The libva
|
||||||
|
* backend never invokes those paths — we only PARSE NAL units, never
|
||||||
|
* write them. The functions must still compile + link though, so we
|
||||||
|
* stub them with abort() runtime guards: if any future code path
|
||||||
|
* accidentally invokes a writer function, we fail-fast instead of
|
||||||
|
* silently corrupting.
|
||||||
|
*
|
||||||
|
* Header surface mirrors upstream gstbitwriter.h minimally — enough
|
||||||
|
* for nalutils.c to compile.
|
||||||
|
*/
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_GSTBITWRITER_STUB
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_GSTBITWRITER_STUB
|
||||||
|
|
||||||
|
#include "gst_compat.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint8 *data;
|
||||||
|
guint bit_size;
|
||||||
|
guint bit_capacity;
|
||||||
|
gboolean auto_grow;
|
||||||
|
gboolean owned;
|
||||||
|
} GstBitWriter;
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
gst_bit_writer_init(GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_bit_writer_init_with_size(GstBitWriter *bw, guint size, gboolean fixed) {
|
||||||
|
(void)bw; (void)size; (void)fixed; abort();
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
gst_bit_writer_reset(GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline gboolean
|
||||||
|
gst_bit_writer_put_bits_uint8(GstBitWriter *bw, guint8 value, guint nbits) {
|
||||||
|
(void)bw; (void)value; (void)nbits; abort();
|
||||||
|
}
|
||||||
|
static inline gboolean
|
||||||
|
gst_bit_writer_align_bytes(GstBitWriter *bw, guint8 trailing_bit) {
|
||||||
|
(void)bw; (void)trailing_bit; abort();
|
||||||
|
}
|
||||||
|
static inline guint8 *
|
||||||
|
gst_bit_writer_get_data(GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline guint
|
||||||
|
gst_bit_writer_get_size(const GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline guint
|
||||||
|
gst_bit_writer_reset_and_get_size(GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline guint8 *
|
||||||
|
gst_bit_writer_reset_and_get_data(GstBitWriter *bw) { (void)bw; abort(); }
|
||||||
|
static inline gboolean
|
||||||
|
gst_bit_writer_put_bits_uint16(GstBitWriter *bw, guint16 value, guint nbits) {
|
||||||
|
(void)bw; (void)value; (void)nbits; abort();
|
||||||
|
}
|
||||||
|
static inline gboolean
|
||||||
|
gst_bit_writer_put_bits_uint32(GstBitWriter *bw, guint32 value, guint nbits) {
|
||||||
|
(void)bw; (void)value; (void)nbits; abort();
|
||||||
|
}
|
||||||
|
static inline gboolean
|
||||||
|
gst_bit_writer_put_bytes(GstBitWriter *bw, const guint8 *data, guint nbytes) {
|
||||||
|
(void)bw; (void)data; (void)nbytes; abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GST_BIT_WRITER_BIT_SIZE(bw) ((bw)->bit_size)
|
||||||
|
#define GST_BIT_WRITER_DATA(bw) ((bw)->data)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Stub for <gst/codecparsers/codecparsers-prelude.h>.
|
||||||
|
* Same shape as base-prelude.h — drop the GObject boilerplate + define
|
||||||
|
* the GstCodecParsersAPI macro to nothing.
|
||||||
|
*/
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_CODECPARSERS_PRELUDE_STUB
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_CODECPARSERS_PRELUDE_STUB
|
||||||
|
#include "gst_compat.h"
|
||||||
|
#define GST_CODEC_PARSERS_API
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/* Stub for <gst/glib-compat-private.h>.
|
||||||
|
* In upstream GStreamer this provides backwards-compat shims for older
|
||||||
|
* GLib versions (g_memdup2 polyfill being the load-bearing one).
|
||||||
|
* Our gst_compat.h already defines g_memdup2 as a static inline, so
|
||||||
|
* we just include the shim.
|
||||||
|
*/
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_GLIB_COMPAT_PRIVATE_STUB
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_GLIB_COMPAT_PRIVATE_STUB
|
||||||
|
#include "gst_compat.h"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/* Stub for <gst/gst.h> — redirects to the project's gst_compat shim.
|
||||||
|
* The vendored GStreamer 1.28.2 H.265 parser was originally built against
|
||||||
|
* full GStreamer; we only need the GLib type aliases + memory helpers +
|
||||||
|
* macro stubs, all provided by gst_compat.h. Original gst.h would pull
|
||||||
|
* in GObject + GstObject + the entire framework, which we don't link.
|
||||||
|
*/
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_GST_H_STUB
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_GST_H_STUB
|
||||||
|
#include "gst_compat.h"
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* gst_compat.c — GArray implementation for the vendored GStreamer parser.
|
||||||
|
*
|
||||||
|
* Scope: minimal subset of GArray API exercised by gsth265parser.c
|
||||||
|
* (g_array_new, g_array_sized_new, g_array_append_vals + the
|
||||||
|
* g_array_append_val macro, g_array_index macro, g_array_set_size,
|
||||||
|
* g_array_set_clear_func, g_array_free, g_array_unref).
|
||||||
|
*
|
||||||
|
* Non-thread-safe (matches GArray's documented semantics — GArray is
|
||||||
|
* not thread-safe in upstream GLib either, callers must serialize).
|
||||||
|
*
|
||||||
|
* License: MIT (matches backend's COPYING.MIT).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gst_compat.h"
|
||||||
|
|
||||||
|
/* ===== internal helpers ===== */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
garray_grow(GArray *array, guint new_capacity)
|
||||||
|
{
|
||||||
|
if (new_capacity <= array->capacity)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* round up to next power of two for amortized O(1) growth */
|
||||||
|
guint cap = array->capacity > 0 ? array->capacity : 4;
|
||||||
|
while (cap < new_capacity)
|
||||||
|
cap *= 2;
|
||||||
|
|
||||||
|
char *new_data = realloc(array->data, (size_t)cap * array->element_size);
|
||||||
|
if (new_data == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (array->clear) {
|
||||||
|
memset(new_data + (size_t)array->capacity * array->element_size, 0,
|
||||||
|
(size_t)(cap - array->capacity) * array->element_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
array->data = new_data;
|
||||||
|
array->capacity = cap;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== public API ===== */
|
||||||
|
|
||||||
|
GArray *
|
||||||
|
g_array_sized_new(gboolean zero_terminated, gboolean clear,
|
||||||
|
guint element_size, guint reserved_size)
|
||||||
|
{
|
||||||
|
/* zero_terminated is GLib-specific (appends a zero-element sentinel
|
||||||
|
* for trailing-NULL semantics). The vendored parser does not use it;
|
||||||
|
* we ignore the flag. */
|
||||||
|
(void)zero_terminated;
|
||||||
|
|
||||||
|
GArray *a = calloc(1, sizeof(GArray));
|
||||||
|
if (a == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
a->element_size = element_size;
|
||||||
|
a->clear = clear;
|
||||||
|
|
||||||
|
if (reserved_size > 0) {
|
||||||
|
if (!garray_grow(a, reserved_size)) {
|
||||||
|
free(a);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
GArray *
|
||||||
|
g_array_new(gboolean zero_terminated, gboolean clear, guint element_size)
|
||||||
|
{
|
||||||
|
return g_array_sized_new(zero_terminated, clear, element_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GArray *
|
||||||
|
g_array_set_size(GArray *array, guint length)
|
||||||
|
{
|
||||||
|
if (length > array->capacity) {
|
||||||
|
if (!garray_grow(array, length))
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array->clear_func != NULL && length < array->len) {
|
||||||
|
for (guint i = length; i < array->len; i++)
|
||||||
|
array->clear_func(array->data + (size_t)i * array->element_size);
|
||||||
|
}
|
||||||
|
if (array->clear && length > array->len) {
|
||||||
|
memset(array->data + (size_t)array->len * array->element_size, 0,
|
||||||
|
(size_t)(length - array->len) * array->element_size);
|
||||||
|
}
|
||||||
|
array->len = length;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
GArray *
|
||||||
|
g_array_append_vals(GArray *array, gconstpointer data, guint len)
|
||||||
|
{
|
||||||
|
if (len == 0)
|
||||||
|
return array;
|
||||||
|
|
||||||
|
if (!garray_grow(array, array->len + len))
|
||||||
|
return array;
|
||||||
|
|
||||||
|
memcpy(array->data + (size_t)array->len * array->element_size,
|
||||||
|
data, (size_t)len * array->element_size);
|
||||||
|
array->len += len;
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
g_array_set_clear_func(GArray *array, void (*clear_func)(gpointer))
|
||||||
|
{
|
||||||
|
array->clear_func = clear_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
g_array_free(GArray *array, gboolean free_segment)
|
||||||
|
{
|
||||||
|
if (array == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (array->clear_func != NULL) {
|
||||||
|
for (guint i = 0; i < array->len; i++)
|
||||||
|
array->clear_func(array->data + (size_t)i * array->element_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *data = NULL;
|
||||||
|
if (free_segment) {
|
||||||
|
free(array->data);
|
||||||
|
} else {
|
||||||
|
data = array->data;
|
||||||
|
}
|
||||||
|
free(array);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
GArray *
|
||||||
|
g_array_unref(GArray *array)
|
||||||
|
{
|
||||||
|
/* simplified to free; the backend never sub-references shared GArrays */
|
||||||
|
g_array_free(array, TRUE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,463 @@
|
|||||||
|
/*
|
||||||
|
* gst_compat.h — minimal GLib/GStreamer compatibility shim for vendored
|
||||||
|
* GStreamer 1.28.2 H.265 parser + bitreader + bytereader + nalutils.
|
||||||
|
*
|
||||||
|
* Strategy: provide #defines / typedefs for the GLib API surface those
|
||||||
|
* 4 vendored files use, so they can compile against libc + libv4l2 only
|
||||||
|
* (no glib2 / gst-base linkage). Vendored .c files are NOT modified
|
||||||
|
* directly; instead this header is force-included via the Makefile's
|
||||||
|
* `-include` flag on the vendored translation units.
|
||||||
|
*
|
||||||
|
* Coverage scoped to what gsth265parser.c + nalutils.c + gstbitreader.c
|
||||||
|
* + gstbytereader.c actually call. Surveyed in
|
||||||
|
* ampere-kernel-decoders phase4 step 2 prep — see
|
||||||
|
* ~/src/ampere-kernel-decoders/phase4_plan_iter2.md and the survey
|
||||||
|
* commit message for the empirical inventory.
|
||||||
|
*
|
||||||
|
* License: this shim is original work, MIT (matching the backend's
|
||||||
|
* COPYING.MIT). The vendored .c files keep their LGPL v2.1+ headers
|
||||||
|
* verbatim.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBVA_V4L2_REQUEST_FOURIER_GST_COMPAT_H
|
||||||
|
#define LIBVA_V4L2_REQUEST_FOURIER_GST_COMPAT_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* ===== GLib type aliases ===== */
|
||||||
|
|
||||||
|
typedef bool gboolean;
|
||||||
|
typedef char gchar;
|
||||||
|
typedef unsigned char guchar;
|
||||||
|
typedef int gint;
|
||||||
|
typedef int8_t gint8;
|
||||||
|
typedef int16_t gint16;
|
||||||
|
typedef int32_t gint32;
|
||||||
|
typedef int64_t gint64;
|
||||||
|
typedef unsigned int guint;
|
||||||
|
typedef uint8_t guint8;
|
||||||
|
typedef uint16_t guint16;
|
||||||
|
typedef uint32_t guint32;
|
||||||
|
typedef uint64_t guint64;
|
||||||
|
typedef size_t gsize;
|
||||||
|
typedef ptrdiff_t gssize;
|
||||||
|
typedef void * gpointer;
|
||||||
|
typedef const void * gconstpointer;
|
||||||
|
typedef double gdouble;
|
||||||
|
typedef float gfloat;
|
||||||
|
|
||||||
|
/* GLib's gint64 / guint64 formatting is platform-conditional; for our
|
||||||
|
* aarch64 ALARM target we don't need the full G_*_FORMAT machinery, but
|
||||||
|
* gstbytereader uses G_GSIZE_FORMAT in a debug-only printf. */
|
||||||
|
#define G_GSIZE_FORMAT "zu"
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
# define TRUE true
|
||||||
|
#endif
|
||||||
|
#ifndef FALSE
|
||||||
|
# define FALSE false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ===== memory ===== */
|
||||||
|
|
||||||
|
#define g_malloc(n) malloc((size_t)(n))
|
||||||
|
#define g_malloc0(n) calloc(1, (size_t)(n))
|
||||||
|
#define g_realloc(p, n) realloc((p), (size_t)(n))
|
||||||
|
/* g_free needs to be addressable (passed as a function-pointer arg by
|
||||||
|
* nalutils.c::gst_memory_new_wrapped — even though that call site is
|
||||||
|
* dead code we don't invoke, it must compile). Plain `free` is
|
||||||
|
* compatible: signature is `void (void *)` either way. */
|
||||||
|
#define g_free free
|
||||||
|
#define g_new(type, n) ((type *)malloc(sizeof(type) * (size_t)(n)))
|
||||||
|
#define g_new0(type, n) ((type *)calloc((size_t)(n), sizeof(type)))
|
||||||
|
#define g_slice_new(type) ((type *)malloc(sizeof(type)))
|
||||||
|
#define g_slice_new0(type) ((type *)calloc(1, sizeof(type)))
|
||||||
|
#define g_slice_free(type, p) free(p)
|
||||||
|
#define g_slice_free1(size, p) free(p)
|
||||||
|
#define g_clear_pointer(pp, freefn) \
|
||||||
|
do { freefn(*(pp)); *(pp) = NULL; } while (0)
|
||||||
|
|
||||||
|
/* g_memdup2 — GLib's 64-bit-safe memdup, used by gstbytereader. */
|
||||||
|
static inline gpointer
|
||||||
|
g_memdup2(gconstpointer mem, gsize byte_size)
|
||||||
|
{
|
||||||
|
if (mem == NULL || byte_size == 0)
|
||||||
|
return NULL;
|
||||||
|
void *copy = malloc(byte_size);
|
||||||
|
if (copy != NULL)
|
||||||
|
memcpy(copy, mem, byte_size);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* g_strcmp0 — NULL-safe strcmp. Used by gsth265parser in profile-name lookup. */
|
||||||
|
static inline int
|
||||||
|
g_strcmp0(const char *a, const char *b)
|
||||||
|
{
|
||||||
|
if (a == b) return 0;
|
||||||
|
if (a == NULL) return -1;
|
||||||
|
if (b == NULL) return 1;
|
||||||
|
return strcmp(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== asserts / return-guards =====
|
||||||
|
*
|
||||||
|
* Per ampere-kernel-decoders iter2 Phase 2 §"new failure modes" #5:
|
||||||
|
* g_assert must NOT abort the process. It becomes a no-op here;
|
||||||
|
* malformed bitstream is caught by the explicit parse-result returns
|
||||||
|
* the parser already implements.
|
||||||
|
*
|
||||||
|
* g_return_if_fail / g_return_val_if_fail propagate as the original
|
||||||
|
* GLib semantics (early return with optional value). */
|
||||||
|
|
||||||
|
#define g_assert(cond) ((void)0)
|
||||||
|
#define g_assert_not_reached() __builtin_unreachable()
|
||||||
|
#define g_return_if_fail(cond) do { if (!(cond)) return; } while (0)
|
||||||
|
#define g_return_val_if_fail(cond, v) do { if (!(cond)) return (v); } while (0)
|
||||||
|
|
||||||
|
/* ===== GStreamer logging — no-ops =====
|
||||||
|
*
|
||||||
|
* The parser is heavy on debug logging. We compile all of it out;
|
||||||
|
* the backend's own logging (request_log/error_log) wraps the parser
|
||||||
|
* calls and reports parse-failure return codes from there. */
|
||||||
|
|
||||||
|
#define GST_DISABLE_GST_DEBUG 1
|
||||||
|
|
||||||
|
#define GST_DEBUG_CATEGORY_STATIC(name)
|
||||||
|
#define GST_DEBUG_CATEGORY_INIT(...) ((void)0)
|
||||||
|
#define GST_DEBUG_CATEGORY_GET(...) ((void)0)
|
||||||
|
#define GST_DEBUG(...) ((void)0)
|
||||||
|
#define GST_INFO(...) ((void)0)
|
||||||
|
#define GST_WARNING(...) ((void)0)
|
||||||
|
#define GST_ERROR(...) ((void)0)
|
||||||
|
#define GST_LOG(...) ((void)0)
|
||||||
|
#define GST_FIXME(...) ((void)0)
|
||||||
|
#define GST_MEMDUMP(...) ((void)0)
|
||||||
|
#define GST_CAT_DEFAULT (NULL)
|
||||||
|
|
||||||
|
/* ===== compiler / language helpers ===== */
|
||||||
|
|
||||||
|
#define G_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define G_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#define G_GNUC_UNUSED __attribute__((unused))
|
||||||
|
#define G_GNUC_INTERNAL
|
||||||
|
#define G_GNUC_MALLOC __attribute__((malloc))
|
||||||
|
#define G_GNUC_NORETURN __attribute__((noreturn))
|
||||||
|
#define G_GNUC_DEPRECATED
|
||||||
|
#define G_GNUC_DEPRECATED_FOR(x)
|
||||||
|
#define G_GNUC_PURE __attribute__((pure))
|
||||||
|
#define G_GNUC_CONST __attribute__((const))
|
||||||
|
#define G_GNUC_PRINTF(a, b) __attribute__((format(printf, a, b)))
|
||||||
|
#define G_BEGIN_DECLS
|
||||||
|
#define G_END_DECLS
|
||||||
|
#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
#define G_STMT_START do
|
||||||
|
#define G_STMT_END while (0)
|
||||||
|
#define G_STRINGIFY(x) G_STRINGIFY_(x)
|
||||||
|
#define G_STRINGIFY_(x) #x
|
||||||
|
|
||||||
|
/* GStreamer ABI-padding slot count; upstream uses 4 reserved gpointers
|
||||||
|
* at the end of public structs for future ABI extension. We replicate
|
||||||
|
* the size so struct layout matches what gst_byte_reader_init / friends
|
||||||
|
* write into. */
|
||||||
|
#define GST_PADDING 4
|
||||||
|
#define GST_PADDING_LARGE 20
|
||||||
|
|
||||||
|
/* Public-symbol visibility — backend's shared module uses
|
||||||
|
* -fvisibility=hidden, so we don't need to mark anything public from
|
||||||
|
* within the vendored parser. The original GST_*_API macros expand to
|
||||||
|
* extern + dllimport on Windows; on Linux ELF builds where
|
||||||
|
* fvisibility=hidden is active, they would mark public symbols. The
|
||||||
|
* vendored functions are never called from outside h265_parser/, so
|
||||||
|
* leaving these empty hides them automatically. */
|
||||||
|
#define GST_API
|
||||||
|
#define GST_API_EXPORT extern
|
||||||
|
#define GST_API_IMPORT extern
|
||||||
|
|
||||||
|
/* ===== Opaque GStreamer pipeline types =====
|
||||||
|
*
|
||||||
|
* GstBuffer + GstMemory are referenced by encoder-side dead-code
|
||||||
|
* functions in gsth265parser.c (gst_h265_parser_insert_sei_hevc).
|
||||||
|
* We never call those; declaring them as opaque structs lets the
|
||||||
|
* function pointers / declarations compile, and the linker keeps the
|
||||||
|
* dead-code .text section even though it's unreachable.
|
||||||
|
*
|
||||||
|
* If you ever need to actually USE GstBuffer in this tree, replace
|
||||||
|
* these opaque decls with the project's own buffer abstraction; do not
|
||||||
|
* try to vendor in libgst itself. */
|
||||||
|
|
||||||
|
typedef struct _GstBuffer GstBuffer;
|
||||||
|
typedef struct _GstMemory GstMemory;
|
||||||
|
typedef struct _GstMapInfo GstMapInfo; /* opaque — dead-code in gsth265parser SEI insert */
|
||||||
|
|
||||||
|
/* GLib min/max constants — dead-code unsigned-overflow guards in
|
||||||
|
* gsth265parser.c. */
|
||||||
|
#define G_MAXUINT8 ((guint8)0xFF)
|
||||||
|
#define G_MAXUINT16 ((guint16)0xFFFF)
|
||||||
|
#define G_MAXUINT32 ((guint32)0xFFFFFFFFU)
|
||||||
|
#define G_MAXUINT64 ((guint64)0xFFFFFFFFFFFFFFFFULL)
|
||||||
|
#define G_MAXINT8 ((gint8)0x7F)
|
||||||
|
#define G_MAXINT16 ((gint16)0x7FFF)
|
||||||
|
#define G_MAXINT32 ((gint32)0x7FFFFFFF)
|
||||||
|
#define G_MAXINT64 ((gint64)0x7FFFFFFFFFFFFFFFLL)
|
||||||
|
#define G_MININT8 ((gint8)(-0x80))
|
||||||
|
#define G_MININT16 ((gint16)(-0x8000))
|
||||||
|
#define G_MININT32 ((gint32)(-0x80000000))
|
||||||
|
#define G_MAXSIZE ((gsize)-1)
|
||||||
|
|
||||||
|
/* GLib function-pointer typedefs used by g_list_* APIs (which our
|
||||||
|
* gst_compat declares as abort-stubs). They show up in code paths
|
||||||
|
* we never invoke but must compile. */
|
||||||
|
typedef void (*GDestroyNotify)(gpointer data);
|
||||||
|
typedef int (*GCompareFunc)(gconstpointer a, gconstpointer b);
|
||||||
|
typedef int (*GCompareDataFunc)(gconstpointer a, gconstpointer b, gpointer user_data);
|
||||||
|
|
||||||
|
/* GstMapFlags — passed to gst_memory_map / gst_buffer_map. Dead-code. */
|
||||||
|
#define GST_MAP_READ (1 << 0)
|
||||||
|
#define GST_MAP_WRITE (1 << 1)
|
||||||
|
#define GST_MAP_READWRITE (GST_MAP_READ | GST_MAP_WRITE)
|
||||||
|
|
||||||
|
/* Dead-code stubs for buffer / memory mapping (only referenced by
|
||||||
|
* gst_h265_parser_insert_sei_hevc which we never call). The compile
|
||||||
|
* needs declarations + addressable functions; abort on call. */
|
||||||
|
static inline gboolean
|
||||||
|
gst_memory_map(GstMemory *mem G_GNUC_UNUSED, GstMapInfo *info G_GNUC_UNUSED,
|
||||||
|
int flags G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_memory_unmap(GstMemory *mem G_GNUC_UNUSED, GstMapInfo *info G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline gboolean
|
||||||
|
gst_buffer_map(GstBuffer *buf G_GNUC_UNUSED, GstMapInfo *info G_GNUC_UNUSED,
|
||||||
|
int flags G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_buffer_unmap(GstBuffer *buf G_GNUC_UNUSED, GstMapInfo *info G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline GstBuffer *
|
||||||
|
gst_buffer_new(void) { abort(); }
|
||||||
|
static inline gboolean
|
||||||
|
gst_buffer_copy_into(GstBuffer *dst G_GNUC_UNUSED, GstBuffer *src G_GNUC_UNUSED,
|
||||||
|
int flags G_GNUC_UNUSED, gsize offset G_GNUC_UNUSED,
|
||||||
|
gssize size G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_buffer_append_memory(GstBuffer *buf G_GNUC_UNUSED, GstMemory *mem G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline GstMemory *
|
||||||
|
gst_memory_ref(GstMemory *mem G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_memory_unref(GstMemory *mem G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline GstMemory *
|
||||||
|
gst_memory_copy(GstMemory *mem G_GNUC_UNUSED, gssize offset G_GNUC_UNUSED, gssize size G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void
|
||||||
|
gst_clear_buffer(GstBuffer **buf) { *buf = NULL; }
|
||||||
|
#define GST_IS_BUFFER(b) (false)
|
||||||
|
|
||||||
|
/* GstBufferCopyFlags — used only by gst_buffer_copy_into in dead code. */
|
||||||
|
#define GST_BUFFER_COPY_METADATA (1 << 0)
|
||||||
|
#define GST_BUFFER_COPY_MEMORY (1 << 1)
|
||||||
|
#define GST_BUFFER_COPY_DEEP (1 << 2)
|
||||||
|
|
||||||
|
/* gst_util_ceil_log2(n) — ceil(log2(n)) for non-zero unsigned n.
|
||||||
|
* Used by gsth265parser.c::gst_h265_slice_parse_ref_pic_list_modification.
|
||||||
|
* That function is in the slice-header parser which the libva backend
|
||||||
|
* does NOT invoke (we only call parse_sps) — but the linker still
|
||||||
|
* needs a definition. Provide a real impl: cheaper to compute than to
|
||||||
|
* justify a dead-code stub at every call site. */
|
||||||
|
static inline guint
|
||||||
|
gst_util_ceil_log2(guint32 n)
|
||||||
|
{
|
||||||
|
if (n <= 1) return 0;
|
||||||
|
/* __builtin_clz returns leading zeros for a 32-bit value;
|
||||||
|
* 32 - clz(n-1) = bits needed = ceil(log2(n)). */
|
||||||
|
return 32 - (guint)__builtin_clz(n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GstMapInfo's real definition is in <gst/gstmemory.h>; we need at
|
||||||
|
* least enough to make `info->data` / `info->size` compile. */
|
||||||
|
struct _GstMapInfo {
|
||||||
|
GstMemory *memory;
|
||||||
|
int flags;
|
||||||
|
guint8 *data;
|
||||||
|
gsize size;
|
||||||
|
gsize maxsize;
|
||||||
|
gpointer user_data[4];
|
||||||
|
gpointer _gst_reserved[GST_PADDING];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* gst_memory_new_wrapped — dead-code stub (nalutils.c calls it from
|
||||||
|
* the SEI-insertion path the libva backend never invokes). */
|
||||||
|
static inline GstMemory *
|
||||||
|
gst_memory_new_wrapped(int flags, gpointer data, gsize maxsize,
|
||||||
|
gsize offset, gsize size, gpointer user_data,
|
||||||
|
void (*notify)(gpointer))
|
||||||
|
{
|
||||||
|
(void)flags; (void)data; (void)maxsize; (void)offset; (void)size;
|
||||||
|
(void)user_data; (void)notify;
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== byte-order read / write macros =====
|
||||||
|
*
|
||||||
|
* GStreamer provides these as static-inline functions in
|
||||||
|
* <gst/gstutils.h>. We re-implement for aarch64 little-endian; the
|
||||||
|
* parser is byte-stream input, so endian-conversion is mechanical.
|
||||||
|
* The float / double variants are present in upstream but the parser
|
||||||
|
* never invokes them — provide stubs so the address-taking sites in
|
||||||
|
* gstbytereader.h's function table compile. */
|
||||||
|
|
||||||
|
#define GST_READ_UINT8(data) \
|
||||||
|
(*((const guint8 *)(data)))
|
||||||
|
|
||||||
|
#define GST_READ_UINT16_LE(data) ( \
|
||||||
|
((guint16)((const guint8 *)(data))[0]) | \
|
||||||
|
((guint16)((const guint8 *)(data))[1] << 8))
|
||||||
|
|
||||||
|
#define GST_READ_UINT16_BE(data) ( \
|
||||||
|
((guint16)((const guint8 *)(data))[0] << 8) | \
|
||||||
|
((guint16)((const guint8 *)(data))[1]))
|
||||||
|
|
||||||
|
#define GST_READ_UINT24_LE(data) ( \
|
||||||
|
((guint32)((const guint8 *)(data))[0]) | \
|
||||||
|
((guint32)((const guint8 *)(data))[1] << 8) | \
|
||||||
|
((guint32)((const guint8 *)(data))[2] << 16))
|
||||||
|
|
||||||
|
#define GST_READ_UINT24_BE(data) ( \
|
||||||
|
((guint32)((const guint8 *)(data))[0] << 16) | \
|
||||||
|
((guint32)((const guint8 *)(data))[1] << 8) | \
|
||||||
|
((guint32)((const guint8 *)(data))[2]))
|
||||||
|
|
||||||
|
#define GST_READ_UINT32_LE(data) ( \
|
||||||
|
((guint32)((const guint8 *)(data))[0]) | \
|
||||||
|
((guint32)((const guint8 *)(data))[1] << 8) | \
|
||||||
|
((guint32)((const guint8 *)(data))[2] << 16) | \
|
||||||
|
((guint32)((const guint8 *)(data))[3] << 24))
|
||||||
|
|
||||||
|
#define GST_READ_UINT32_BE(data) ( \
|
||||||
|
((guint32)((const guint8 *)(data))[0] << 24) | \
|
||||||
|
((guint32)((const guint8 *)(data))[1] << 16) | \
|
||||||
|
((guint32)((const guint8 *)(data))[2] << 8) | \
|
||||||
|
((guint32)((const guint8 *)(data))[3]))
|
||||||
|
|
||||||
|
#define GST_READ_UINT64_LE(data) ( \
|
||||||
|
((guint64)((const guint8 *)(data))[0]) | \
|
||||||
|
((guint64)((const guint8 *)(data))[1] << 8) | \
|
||||||
|
((guint64)((const guint8 *)(data))[2] << 16) | \
|
||||||
|
((guint64)((const guint8 *)(data))[3] << 24) | \
|
||||||
|
((guint64)((const guint8 *)(data))[4] << 32) | \
|
||||||
|
((guint64)((const guint8 *)(data))[5] << 40) | \
|
||||||
|
((guint64)((const guint8 *)(data))[6] << 48) | \
|
||||||
|
((guint64)((const guint8 *)(data))[7] << 56))
|
||||||
|
|
||||||
|
#define GST_READ_UINT64_BE(data) ( \
|
||||||
|
((guint64)((const guint8 *)(data))[0] << 56) | \
|
||||||
|
((guint64)((const guint8 *)(data))[1] << 48) | \
|
||||||
|
((guint64)((const guint8 *)(data))[2] << 40) | \
|
||||||
|
((guint64)((const guint8 *)(data))[3] << 32) | \
|
||||||
|
((guint64)((const guint8 *)(data))[4] << 24) | \
|
||||||
|
((guint64)((const guint8 *)(data))[5] << 16) | \
|
||||||
|
((guint64)((const guint8 *)(data))[6] << 8) | \
|
||||||
|
((guint64)((const guint8 *)(data))[7]))
|
||||||
|
|
||||||
|
/* Float / double readers — dead-code, abort if called. The function
|
||||||
|
* table in gstbytereader.h takes the address of the underlying inline
|
||||||
|
* which we don't need to be functional, only addressable. */
|
||||||
|
static inline gfloat
|
||||||
|
GST_READ_FLOAT_LE(const guint8 *data) { (void)data; abort(); }
|
||||||
|
static inline gfloat
|
||||||
|
GST_READ_FLOAT_BE(const guint8 *data) { (void)data; abort(); }
|
||||||
|
static inline gdouble
|
||||||
|
GST_READ_DOUBLE_LE(const guint8 *data) { (void)data; abort(); }
|
||||||
|
static inline gdouble
|
||||||
|
GST_READ_DOUBLE_BE(const guint8 *data) { (void)data; abort(); }
|
||||||
|
|
||||||
|
/* Write side — nalutils.c writes-out SEI bytes (dead path for us but
|
||||||
|
* must compile). */
|
||||||
|
#define GST_WRITE_UINT8(data, val) do { \
|
||||||
|
((guint8 *)(data))[0] = (guint8)(val); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define GST_WRITE_UINT16_BE(data, val) do { \
|
||||||
|
((guint8 *)(data))[0] = (guint8)((val) >> 8); \
|
||||||
|
((guint8 *)(data))[1] = (guint8)((val)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define GST_WRITE_UINT24_BE(data, val) do { \
|
||||||
|
((guint8 *)(data))[0] = (guint8)((val) >> 16); \
|
||||||
|
((guint8 *)(data))[1] = (guint8)((val) >> 8); \
|
||||||
|
((guint8 *)(data))[2] = (guint8)((val)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define GST_WRITE_UINT32_BE(data, val) do { \
|
||||||
|
((guint8 *)(data))[0] = (guint8)((val) >> 24); \
|
||||||
|
((guint8 *)(data))[1] = (guint8)((val) >> 16); \
|
||||||
|
((guint8 *)(data))[2] = (guint8)((val) >> 8); \
|
||||||
|
((guint8 *)(data))[3] = (guint8)((val)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ===== GArray ===== */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *data; /* exposed via g_array_index / GArray->data */
|
||||||
|
guint len; /* element count */
|
||||||
|
guint capacity; /* allocated element slots */
|
||||||
|
guint element_size;
|
||||||
|
gboolean clear; /* zero-fill on grow */
|
||||||
|
void (*clear_func)(gpointer);
|
||||||
|
} GArray;
|
||||||
|
|
||||||
|
GArray *g_array_new(gboolean zero_terminated, gboolean clear, guint element_size);
|
||||||
|
GArray *g_array_sized_new(gboolean zero_terminated, gboolean clear,
|
||||||
|
guint element_size, guint reserved_size);
|
||||||
|
GArray *g_array_set_size(GArray *array, guint length);
|
||||||
|
GArray *g_array_append_vals(GArray *array, gconstpointer data, guint len);
|
||||||
|
void g_array_set_clear_func(GArray *array, void (*clear_func)(gpointer));
|
||||||
|
gchar *g_array_free(GArray *array, gboolean free_segment);
|
||||||
|
GArray *g_array_unref(GArray *array);
|
||||||
|
|
||||||
|
#define g_array_append_val(a, v) g_array_append_vals((a), &(v), 1)
|
||||||
|
#define g_array_index(a, t, i) (((t *)(void *)(a)->data)[i])
|
||||||
|
|
||||||
|
/* ===== GList — stubs that abort if reached =====
|
||||||
|
*
|
||||||
|
* Surveyed call sites: gsth265parser.c uses g_list_prepend / g_list_sort /
|
||||||
|
* g_list_free_full in code paths the libva backend does not invoke for
|
||||||
|
* basic SPS parsing (likely SEI message accumulation). Stub to abort so
|
||||||
|
* any future call surfaces immediately rather than silently corrupting. */
|
||||||
|
|
||||||
|
/* GList — full struct (not opaque) so callers can do `list->data`.
|
||||||
|
* The functions still abort because we never construct a GList. */
|
||||||
|
typedef struct _GList GList;
|
||||||
|
struct _GList {
|
||||||
|
gpointer data;
|
||||||
|
GList *next;
|
||||||
|
GList *prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline GList *g_list_prepend(GList *list G_GNUC_UNUSED, gpointer data G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline GList *g_list_sort(GList *list G_GNUC_UNUSED, int (*cmp)(gconstpointer, gconstpointer) G_GNUC_UNUSED) { abort(); }
|
||||||
|
static inline void g_list_free_full(GList *list G_GNUC_UNUSED, void (*free_func)(gpointer) G_GNUC_UNUSED) { abort(); }
|
||||||
|
|
||||||
|
/* ===== g_once_init_enter / g_once_init_leave =====
|
||||||
|
*
|
||||||
|
* GLib's lazy-init guards. The parser uses these for one-shot static
|
||||||
|
* initialization (e.g. profile-name table). Our backend is single-
|
||||||
|
* threaded at the parser-init site (driver_init), so we can simplify
|
||||||
|
* to a plain run-once gate. */
|
||||||
|
|
||||||
|
#define g_once_init_enter(loc) (*(loc) == 0)
|
||||||
|
#define g_once_init_leave(loc, val) (*(loc) = (val))
|
||||||
|
|
||||||
|
/* ===== conversions ===== */
|
||||||
|
|
||||||
|
#define GINT_TO_POINTER(i) ((gpointer)(uintptr_t)(gint)(i))
|
||||||
|
#define GPOINTER_TO_INT(p) ((gint)(uintptr_t)(p))
|
||||||
|
|
||||||
|
#endif /* LIBVA_V4L2_REQUEST_FOURIER_GST_COMPAT_H */
|
||||||
+28
-3
@@ -51,7 +51,16 @@ sources = [
|
|||||||
'vp8.c',
|
'vp8.c',
|
||||||
'vp9.c',
|
'vp9.c',
|
||||||
'codec.c',
|
'codec.c',
|
||||||
'nv15.c'
|
'nv15.c',
|
||||||
|
|
||||||
|
# Vendored GStreamer 1.28.2 H.265 parser + utilities (LGPL v2.1+,
|
||||||
|
# see src/h265_parser/gst_compat.h for sourcing notes + per-iter2
|
||||||
|
# adaptation strategy).
|
||||||
|
'h265_parser/gst_compat.c',
|
||||||
|
'h265_parser/gst/base/gstbitreader.c',
|
||||||
|
'h265_parser/gst/base/gstbytereader.c',
|
||||||
|
'h265_parser/gst/codecparsers/nalutils.c',
|
||||||
|
'h265_parser/gst/codecparsers/gsth265parser.c'
|
||||||
]
|
]
|
||||||
|
|
||||||
headers = [
|
headers = [
|
||||||
@@ -78,11 +87,27 @@ headers = [
|
|||||||
'vp8.h',
|
'vp8.h',
|
||||||
'vp9.h',
|
'vp9.h',
|
||||||
'codec.h',
|
'codec.h',
|
||||||
'nv15.h'
|
'nv15.h',
|
||||||
|
|
||||||
|
# Vendored GStreamer + project shim headers (see sources above).
|
||||||
|
'h265_parser/gst_compat.h',
|
||||||
|
'h265_parser/gst/gst.h',
|
||||||
|
'h265_parser/gst/glib-compat-private.h',
|
||||||
|
'h265_parser/gst/base/base-prelude.h',
|
||||||
|
'h265_parser/gst/base/gstbitreader.h',
|
||||||
|
'h265_parser/gst/base/gstbytereader.h',
|
||||||
|
'h265_parser/gst/base/gstbitwriter.h',
|
||||||
|
'h265_parser/gst/codecparsers/codecparsers-prelude.h',
|
||||||
|
'h265_parser/gst/codecparsers/gsth265parser.h',
|
||||||
|
'h265_parser/gst/codecparsers/nalutils.h'
|
||||||
]
|
]
|
||||||
|
|
||||||
includes = [
|
includes = [
|
||||||
include_directories('../include')
|
include_directories('../include'),
|
||||||
|
# Vendored GStreamer parser tree — the parser's #include <gst/base/...>
|
||||||
|
# style references resolve here via stub headers that redirect to
|
||||||
|
# gst_compat.h.
|
||||||
|
include_directories('h265_parser')
|
||||||
]
|
]
|
||||||
|
|
||||||
cflags = [
|
cflags = [
|
||||||
|
|||||||
Reference in New Issue
Block a user