forked from marfrit/libva-v4l2-request-fourier
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',
|
||||
'vp9.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 = [
|
||||
@@ -78,11 +87,27 @@ headers = [
|
||||
'vp8.h',
|
||||
'vp9.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 = [
|
||||
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 = [
|
||||
|
||||
Reference in New Issue
Block a user