summaryrefslogtreecommitdiff
path: root/mfx_stub
diff options
context:
space:
mode:
authorMikhail Burakov <mburakov@mailbox.org>2024-11-29 18:43:18 +0100
committerMikhail Burakov <mburakov@mailbox.org>2024-11-29 18:43:18 +0100
commit143262bdba529c83f53a5d3ae6449d27873b1ab0 (patch)
tree11d3192ecb48cfa12978b3d9fed4efbd16b0cef6 /mfx_stub
parente70354e3d504b3a1b40573b43ebf8f7cfd4b9e66 (diff)
Initial implementation on mfx stub (WIP)
Diffstat (limited to 'mfx_stub')
-rw-r--r--mfx_stub/bitstream.c89
-rw-r--r--mfx_stub/bitstream.h46
-rw-r--r--mfx_stub/include/mfxcommon.h46
-rw-r--r--mfx_stub/include/mfxdefs.h49
-rw-r--r--mfx_stub/include/mfxsession.h27
-rw-r--r--mfx_stub/include/mfxstructures.h90
-rw-r--r--mfx_stub/include/mfxvideo.h48
-rw-r--r--mfx_stub/mfxsession.c35
-rw-r--r--mfx_stub/mfxsession_impl.h41
-rw-r--r--mfx_stub/mfxvideo.c401
10 files changed, 872 insertions, 0 deletions
diff --git a/mfx_stub/bitstream.c b/mfx_stub/bitstream.c
new file mode 100644
index 0000000..058cd75
--- /dev/null
+++ b/mfx_stub/bitstream.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "bitstream.h"
+
+#include <string.h>
+
+static uint64_t BitstreamReadBit(struct Bitstream* bitstream) {
+ size_t shift = 7 - (bitstream->offset & 0x7);
+ if (shift == 7) {
+ size_t byte;
+ repeat:
+ byte = bitstream->offset >> 3;
+ if (byte >= bitstream->size) longjmp(bitstream->trap, 1);
+ bitstream->cache = (bitstream->cache << 8) | bitstream->data[byte];
+ if (bitstream->offset >= 24 && (bitstream->cache & 0xffffff) == 3) {
+ bitstream->offset += 8;
+ bitstream->epb_count++;
+ goto repeat;
+ }
+ }
+ bitstream->offset++;
+ return bitstream->cache >> shift & 0x1;
+}
+
+uint64_t BitstreamReadU(struct Bitstream* bitstream, size_t size) {
+ uint64_t result = 0;
+ for (; size; size--) {
+ result = (result << 1) | BitstreamReadBit(bitstream);
+ }
+ return result;
+}
+
+uint64_t BitstreamReadUE(struct Bitstream* bitstream) {
+ size_t size = 0;
+ while (!BitstreamReadBit(bitstream)) size++;
+ return (BitstreamReadU(bitstream, size) | (1 << size)) - 1;
+}
+
+int64_t BitstreamReadSE(struct Bitstream* bitstream) {
+ uint64_t result = BitstreamReadUE(bitstream);
+ int64_t sign = (int64_t)((result & 1) << 1) - 1;
+ return sign * (int64_t)((result + 1) >> 1);
+}
+
+void BitstreamByteAlign(struct Bitstream* bitstream) {
+ bitstream->offset = (bitstream->offset + 7) & ~(size_t)7;
+}
+
+bool BitstreamReadNalu(struct Bitstream* bitstream, struct Bitstream* output) {
+ if (bitstream->offset & 0x7) return false;
+ size_t byte_offset = bitstream->offset >> 3;
+ static const uint8_t kStartCodePrefix[] = {0, 0, 0, 1};
+ if (bitstream->size - byte_offset < sizeof(kStartCodePrefix)) {
+ return false;
+ }
+ const uint8_t* data = bitstream->data + byte_offset;
+ if (memcmp(bitstream->data + byte_offset, kStartCodePrefix,
+ sizeof(kStartCodePrefix))) {
+ return false;
+ }
+ data += sizeof(kStartCodePrefix);
+ byte_offset += sizeof(kStartCodePrefix);
+ size_t max_size = bitstream->size - byte_offset;
+ uint8_t* next =
+ memmem(data, max_size, kStartCodePrefix, sizeof(kStartCodePrefix));
+ size_t size = next ? (size_t)(next - data) : max_size;
+ bitstream->offset = (byte_offset + size) << 3;
+ *output = BitstreamCreate(data, size);
+ return true;
+}
+
+bool BitstreamAvail(const struct Bitstream* bitstream) {
+ return bitstream->offset < (bitstream->size << 3);
+}
diff --git a/mfx_stub/bitstream.h b/mfx_stub/bitstream.h
new file mode 100644
index 0000000..4a1faa2
--- /dev/null
+++ b/mfx_stub/bitstream.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_BITSTREAM_H_
+#define MFX_STUB_BITSTREAM_H_
+
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#define BitstreamCreate(a, b) \
+ (struct Bitstream) { .data = a, .size = b }
+#define BitstreamReadFailed(x) setjmp((x)->trap)
+
+struct Bitstream {
+ const uint8_t* data;
+ size_t size;
+ size_t offset;
+ size_t epb_count;
+ uint32_t cache;
+ jmp_buf trap;
+};
+
+uint64_t BitstreamReadU(struct Bitstream* bitstream, size_t size);
+uint64_t BitstreamReadUE(struct Bitstream* bitstream);
+int64_t BitstreamReadSE(struct Bitstream* bitstream);
+void BitstreamByteAlign(struct Bitstream* bitstream);
+bool BitstreamReadNalu(struct Bitstream* bitstream, struct Bitstream* output);
+bool BitstreamAvail(const struct Bitstream* bitstream);
+
+#endif // MFX_STUB_BITSTREAM_H_
diff --git a/mfx_stub/include/mfxcommon.h b/mfx_stub/include/mfxcommon.h
new file mode 100644
index 0000000..f4b1e26
--- /dev/null
+++ b/mfx_stub/include/mfxcommon.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_INCLUDE_MFXCOMMON_H_
+#define MFX_STUB_INCLUDE_MFXCOMMON_H_
+
+#include "mfxdefs.h"
+
+#define MFX_MAKEFOURCC(a, b, c, d) \
+ (((a) << 24 & 0xff000000) | ((b) << 16 & 0x00ff0000) | \
+ ((c) << 8 & 0x0000ff00) | ((d) << 0 & 0x000000ff))
+
+typedef mfxI32 mfxIMPL;
+
+enum {
+ MFX_IMPL_HARDWARE = 0x0002,
+};
+
+typedef union mfxVersion mfxVersion;
+
+typedef struct {
+ mfxI64 DecodeTimeStamp;
+ mfxU64 TimeStamp;
+ mfxU8* Data;
+ mfxU32 DataLength;
+ mfxU32 MaxLength;
+ mfxU16 DataFlag;
+} mfxBitstream;
+
+typedef struct _mfxSyncPoint* mfxSyncPoint;
+
+#endif // MFX_STUB_INCLUDE_MFXCOMMON_H_
diff --git a/mfx_stub/include/mfxdefs.h b/mfx_stub/include/mfxdefs.h
new file mode 100644
index 0000000..4589513
--- /dev/null
+++ b/mfx_stub/include/mfxdefs.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_INCLUDE_MFXDEFS_H_
+#define MFX_STUB_INCLUDE_MFXDEFS_H_
+
+#include <stdint.h>
+
+#define MFX_INFINITE 0xffffffff
+
+typedef uint8_t mfxU8;
+typedef int8_t mfxI8;
+typedef int16_t mfxI16;
+typedef uint16_t mfxU16;
+typedef uint32_t mfxU32;
+typedef int32_t mfxI32;
+typedef uint64_t mfxU64;
+typedef int64_t mfxI64;
+typedef void* mfxHDL;
+typedef mfxHDL mfxMemId;
+
+typedef enum {
+ MFX_ERR_NONE = 0,
+ MFX_ERR_UNSUPPORTED = -3,
+ MFX_ERR_MEMORY_ALLOC = -4,
+ MFX_ERR_MORE_DATA = -10,
+ MFX_ERR_MORE_SURFACE = -11,
+ MFX_ERR_DEVICE_FAILED = -17,
+ MFX_ERR_REALLOC_SURFACE = -22,
+ MFX_WRN_DEVICE_BUSY = 2,
+ MFX_WRN_VIDEO_PARAM_CHANGED = 3,
+ MFX_ERR_NONE_PARTIAL_OUTPUT = 12,
+} mfxStatus;
+
+#endif // MFX_STUB_INCLUDE_MFXDEFS_H_
diff --git a/mfx_stub/include/mfxsession.h b/mfx_stub/include/mfxsession.h
new file mode 100644
index 0000000..d39a6ac
--- /dev/null
+++ b/mfx_stub/include/mfxsession.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_INCLUDE_MFXSESSION_H_
+#define MFX_STUB_INCLUDE_MFXSESSION_H_
+
+#include "mfxcommon.h"
+
+typedef struct _mfxSession* mfxSession;
+mfxStatus MFXInit(mfxIMPL impl, mfxVersion* ver, mfxSession* session);
+mfxStatus MFXClose(mfxSession session);
+
+#endif // MFX_STUB_INCLUDE_MFXSESSION_H_
diff --git a/mfx_stub/include/mfxstructures.h b/mfx_stub/include/mfxstructures.h
new file mode 100644
index 0000000..64353c4
--- /dev/null
+++ b/mfx_stub/include/mfxstructures.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_INCLUDE_MFXSTRUCTURES_H_
+#define MFX_STUB_INCLUDE_MFXSTRUCTURES_H_
+
+#include "mfxcommon.h"
+
+typedef struct {
+ mfxU32 FourCC;
+ mfxU16 Width;
+ mfxU16 Height;
+ mfxU16 CropX;
+ mfxU16 CropY;
+ mfxU16 CropW;
+ mfxU16 CropH;
+ mfxU16 ChromaFormat;
+} mfxFrameInfo;
+
+enum {
+ MFX_FOURCC_NV12 = MFX_MAKEFOURCC('N', 'V', '1', '2'),
+};
+
+enum {
+ MFX_CHROMAFORMAT_YUV420 = 1,
+};
+
+enum {
+ MFX_TIMESTAMP_UNKNOWN = -1,
+};
+
+typedef struct {
+ mfxFrameInfo Info;
+ struct {
+ mfxMemId MemId;
+ } Data;
+} mfxFrameSurface1;
+
+typedef struct {
+ mfxU16 AsyncDepth;
+ struct {
+ mfxU32 CodecId;
+ mfxU16 DecodedOrder;
+ } mfx;
+ mfxU16 IOPattern;
+} mfxVideoParam;
+
+enum {
+ MFX_IOPATTERN_OUT_VIDEO_MEMORY = 0x10,
+};
+
+enum {
+ MFX_CODEC_HEVC = MFX_MAKEFOURCC('H', 'E', 'V', 'C'),
+};
+
+enum {
+ MFX_BITSTREAM_COMPLETE_FRAME = 0x0001,
+};
+
+typedef struct {
+ mfxU32 AllocId;
+ mfxU16 NumFrameSuggested;
+ mfxFrameInfo Info;
+} mfxFrameAllocRequest;
+
+typedef struct {
+ mfxU32 AllocId;
+ mfxMemId* mids;
+ mfxU16 NumFrameActual;
+} mfxFrameAllocResponse;
+
+typedef enum {
+ MFX_HANDLE_VA_DISPLAY = 4,
+} mfxHandleType;
+
+#endif // MFX_STUB_INCLUDE_MFXSTRUCTURES_H_
diff --git a/mfx_stub/include/mfxvideo.h b/mfx_stub/include/mfxvideo.h
new file mode 100644
index 0000000..dec1789
--- /dev/null
+++ b/mfx_stub/include/mfxvideo.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_INCLUDE_MFXVIDEO_H_
+#define MFX_STUB_INCLUDE_MFXVIDEO_H_
+
+#include "mfxsession.h"
+#include "mfxstructures.h"
+
+typedef struct {
+ mfxHDL pthis;
+ mfxStatus (*Alloc)(mfxHDL, mfxFrameAllocRequest*, mfxFrameAllocResponse*);
+ mfxStatus (*GetHDL)(mfxHDL, mfxMemId, mfxHDL*);
+ mfxStatus (*Free)(mfxHDL, mfxFrameAllocResponse*);
+} mfxFrameAllocator;
+
+mfxStatus MFXVideoCORE_SetFrameAllocator(mfxSession session,
+ mfxFrameAllocator* allocator);
+mfxStatus MFXVideoCORE_SetHandle(mfxSession session, mfxHandleType type,
+ mfxHDL hdl);
+mfxStatus MFXVideoCORE_SyncOperation(mfxSession session, mfxSyncPoint syncp,
+ mfxU32 wait);
+
+mfxStatus MFXVideoDECODE_Query(mfxSession session, mfxVideoParam* in,
+ mfxVideoParam* out);
+mfxStatus MFXVideoDECODE_DecodeHeader(mfxSession session, mfxBitstream* bs,
+ mfxVideoParam* par);
+mfxStatus MFXVideoDECODE_Init(mfxSession session, mfxVideoParam* par);
+mfxStatus MFXVideoDECODE_DecodeFrameAsync(mfxSession session, mfxBitstream* bs,
+ mfxFrameSurface1* surface_work,
+ mfxFrameSurface1** surface_out,
+ mfxSyncPoint* syncp);
+
+#endif // MFX_STUB_INCLUDE_MFXVIDEO_H_
diff --git a/mfx_stub/mfxsession.c b/mfx_stub/mfxsession.c
new file mode 100644
index 0000000..13bf8fc
--- /dev/null
+++ b/mfx_stub/mfxsession.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <mfxsession.h>
+#include <stdlib.h>
+
+#include "mfxsession_impl.h"
+
+mfxStatus MFXInit(mfxIMPL impl, mfxVersion* ver, mfxSession* session) {
+ (void)impl;
+ (void)ver;
+ mfxSession result = malloc(sizeof(struct _mfxSession));
+ if (!result) return MFX_ERR_MEMORY_ALLOC;
+ *session = result;
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXClose(mfxSession session) {
+ free(session);
+ return MFX_ERR_NONE;
+}
diff --git a/mfx_stub/mfxsession_impl.h b/mfx_stub/mfxsession_impl.h
new file mode 100644
index 0000000..5b359e1
--- /dev/null
+++ b/mfx_stub/mfxsession_impl.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef MFX_STUB_MFXSESSION_IMPL_H_
+#define MFX_STUB_MFXSESSION_IMPL_H_
+
+#include <stddef.h>
+#include <va/va.h>
+
+#include "mfxvideo.h"
+
+struct _mfxSession {
+ mfxFrameAllocator allocator;
+ VADisplay display;
+
+ VAConfigID config_id;
+ VAContextID context_id;
+ mfxMemId* mids;
+ size_t mids_count;
+
+ VAPictureParameterBufferHEVC ppb;
+ VASliceParameterBufferHEVC spb;
+ size_t global_frame_counter;
+ size_t local_frame_counter;
+};
+
+#endif // MFX_STUB_MFXSESSION_IMPL_H_
diff --git a/mfx_stub/mfxvideo.c b/mfx_stub/mfxvideo.c
new file mode 100644
index 0000000..d070755
--- /dev/null
+++ b/mfx_stub/mfxvideo.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2024 Mikhail Burakov. This file is part of receiver.
+ *
+ * receiver is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * receiver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with receiver. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <mfxvideo.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bitstream.h"
+#include "mfxsession_impl.h"
+
+// Table 7-1 – NAL unit type codes and NAL unit type classes
+enum NalUnitType {
+ TRAIL_R = 1,
+ BLA_W_LP = 16,
+ IDR_W_RADL = 19,
+ IDR_N_LP = 20,
+ CRA_NUT = 21,
+ RSV_IRAP_VCL23 = 23,
+ VPS_NUT = 32,
+ SPS_NUT = 33,
+ PPS_NUT = 34,
+ AUD_NUT = 35,
+};
+
+// 7.3.1.2 NAL unit header syntax
+static uint8_t ParseNaluHeader(struct Bitstream* nalu) {
+ assert(BitstreamReadU(nalu, 1) == 0); // forbidden_zero_bit
+ uint64_t nal_unit_type = BitstreamReadU(nalu, 6);
+ assert(BitstreamReadU(nalu, 6) == 0); // nuh_layer_id
+ assert(BitstreamReadU(nalu, 3) == 1); // nuh_temporal_id_plus1
+ return (uint8_t)nal_unit_type;
+}
+
+// 7.3.3 Profile, tier and level syntax
+static void ParseProfileTierLevel(struct Bitstream* nalu) {
+ assert(BitstreamReadU(nalu, 2) == 0); // general_profile_space
+ assert(BitstreamReadU(nalu, 1) == 0); // general_tier_flag
+ assert(BitstreamReadU(nalu, 5) == 1); // general_profile_idc
+ assert(BitstreamReadU(nalu, 32) ==
+ 3 << 29); // general_profile_compatibility_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // general_progressive_source_flag
+ assert(BitstreamReadU(nalu, 1) == 0); // general_interlaced_source_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // general_non_packed_constraint_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // general_frame_only_constraint_flag
+ assert(BitstreamReadU(nalu, 7) == 0); // general_reserved_zero_7bits
+ assert(BitstreamReadU(nalu, 1) ==
+ 0); // general_one_picture_only_constraint_flag
+ assert(BitstreamReadU(nalu, 35) == 0); // general_reserved_zero_35bits
+ assert(BitstreamReadU(nalu, 1) == 0); // general_reserved_zero_bit
+ assert(BitstreamReadU(nalu, 8) == 120); // general_level_idc
+}
+
+// 7.3.7 Short-term reference picture set syntax
+static void ParseStRefPicSet(struct Bitstream* nalu, uint64_t stRpsIdx) {
+ if (stRpsIdx != 0) {
+ assert(BitstreamReadU(nalu, 1) == 0); // inter_ref_pic_set_prediction_flag
+ }
+ assert(BitstreamReadUE(nalu) == 1); // num_negative_pics
+ assert(BitstreamReadUE(nalu) == 0); // num_positive_pics
+ assert(BitstreamReadUE(nalu) == 0); // delta_poc_s0_minus1
+ assert(BitstreamReadU(nalu, 1) == 1); // used_by_curr_pic_s0_flag
+}
+
+// E.2.1 VUI parameters syntax
+static void ParseVuiParameters(struct Bitstream* nalu) {
+ assert(BitstreamReadU(nalu, 1) == 0); // aspect_ratio_info_present_flag
+ assert(BitstreamReadU(nalu, 1) == 0); // overscan_info_present_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // video_signal_type_present_flag
+
+ // Table E.2 – Meaning of video_format
+ assert(BitstreamReadU(nalu, 3) == 5); // video_format
+ assert(BitstreamReadU(nalu, 1) == 0); // video_full_range_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // colour_description_present_flag
+
+ assert(BitstreamReadU(nalu, 8) == 2); // colour_primaries
+ assert(BitstreamReadU(nalu, 8) == 2); // transfer_characteristics
+ assert(BitstreamReadU(nalu, 8) == 6); // matrix_coeffs
+
+ assert(BitstreamReadU(nalu, 1) == 0); // chroma_loc_info_present_flag
+ assert(BitstreamReadU(nalu, 1) == 0); // neutral_chroma_indication_flag
+ assert(BitstreamReadU(nalu, 1) == 0); // field_seq_flag
+ assert(BitstreamReadU(nalu, 1) == 0); // vui_timing_info_present_flag
+
+ bool bitstream_restriction_flag = !!BitstreamReadU(nalu, 1);
+ if (bitstream_restriction_flag) {
+ assert(BitstreamReadU(nalu, 1) == 0); // tiles_fixed_structure_flag
+ assert(BitstreamReadU(nalu, 1) ==
+ 1); // motion_vectors_over_pic_boundaries_flag
+ assert(BitstreamReadU(nalu, 1) == 1); // restricted_ref_pic_lists_flag
+ assert(BitstreamReadUE(nalu) == 0); // min_spatial_segmentation_idc
+ assert(BitstreamReadUE(nalu) == 0); // max_bytes_per_pic_denom
+ assert(BitstreamReadUE(nalu) == 0); // max_bits_per_min_cu_denom
+ assert(BitstreamReadUE(nalu) == 15); // log2_max_mv_length_horizontal
+ assert(BitstreamReadUE(nalu) == 15); // log2_max_mv_length_vertical
+ }
+}
+
+// 7.3.2.2.1 General sequence parameter set RBSP syntax
+static void ParseSps(struct Bitstream* nalu, mfxSession session) {
+ assert(BitstreamReadU(nalu, 4) == 0); // sps_video_parameter_set_id
+ assert(BitstreamReadU(nalu, 3) == 0); // sps_max_sub_layers_minus1
+ assert(BitstreamReadU(nalu, 1) == 1); // sps_temporal_id_nesting_flag
+ ParseProfileTierLevel(nalu);
+ assert(BitstreamReadUE(nalu) == 0); // sps_seq_parameter_set_id
+ //
+ session->ppb.pic_fields.bits.chroma_format_idc =
+ (uint32_t)BitstreamReadUE(nalu);
+ assert(session->ppb.pic_fields.bits.chroma_format_idc == 1);
+ session->ppb.pic_width_in_luma_samples = (uint16_t)BitstreamReadUE(nalu);
+ session->ppb.pic_height_in_luma_samples = (uint16_t)BitstreamReadUE(nalu);
+ assert(BitstreamReadU(nalu, 1) == 0); // conformance_window_flag
+
+ session->ppb.bit_depth_luma_minus8 = (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.bit_depth_chroma_minus8 = (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.log2_max_pic_order_cnt_lsb_minus4 =
+ (uint8_t)BitstreamReadUE(nalu);
+ assert(BitstreamReadU(nalu, 1) ==
+ 0); // sps_sub_layer_ordering_info_present_flag
+
+ session->ppb.sps_max_dec_pic_buffering_minus1 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.pic_fields.bits.NoPicReorderingFlag =
+ !!BitstreamReadUE(nalu); // sps_max_num_reorder_pics
+ assert(BitstreamReadUE(nalu) == 0); // sps_max_latency_increase_plus1
+
+ session->ppb.log2_min_luma_coding_block_size_minus3 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.log2_diff_max_min_luma_coding_block_size =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.log2_min_transform_block_size_minus2 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.log2_diff_max_min_transform_block_size =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.max_transform_hierarchy_depth_inter =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.max_transform_hierarchy_depth_intra =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.pic_fields.bits.scaling_list_enabled_flag =
+ (uint8_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.scaling_list_enabled_flag == 0);
+
+ session->ppb.pic_fields.bits.amp_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.slice_parsing_fields.bits.sample_adaptive_offset_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.pic_fields.bits.pcm_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.pcm_enabled_flag == 0);
+
+ // vvv weird vvv
+ session->ppb.pcm_sample_bit_depth_luma_minus1 =
+ (uint8_t)((1 << (session->ppb.bit_depth_luma_minus8 + 8)) - 1);
+ session->ppb.pcm_sample_bit_depth_chroma_minus1 =
+ (uint8_t)((1 << (session->ppb.bit_depth_chroma_minus8 + 8)) - 1);
+ session->ppb.log2_min_pcm_luma_coding_block_size_minus3 = 253;
+ // ^^^ weird ^^^
+
+ session->ppb.num_short_term_ref_pic_sets = (uint8_t)BitstreamReadUE(nalu);
+ for (uint8_t i = 0; i < session->ppb.num_short_term_ref_pic_sets; i++) {
+ ParseStRefPicSet(nalu, i);
+ }
+ assert(BitstreamReadU(nalu, 1) == 0); // long_term_ref_pics_present_flag
+
+ session->ppb.slice_parsing_fields.bits.sps_temporal_mvp_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.pic_fields.bits.strong_intra_smoothing_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(BitstreamReadU(nalu, 1) == 1); // vui_parameters_present_flag
+
+ ParseVuiParameters(nalu);
+ assert(BitstreamReadU(nalu, 1) == 0); // sps_extension_present_flag
+}
+
+// 7.3.2.3.1 General picture parameter set RBSP syntax
+static void ParsePps(struct Bitstream* nalu, mfxSession session) {
+ assert(BitstreamReadUE(nalu) == 0); // pps_pic_parameter_set_id
+ assert(BitstreamReadUE(nalu) == 0); // pps_seq_parameter_set_id
+
+ session->ppb.slice_parsing_fields.bits.dependent_slice_segments_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.slice_parsing_fields.bits.output_flag_present_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.num_extra_slice_header_bits = (uint8_t)BitstreamReadU(nalu, 3);
+ assert(session->ppb.num_extra_slice_header_bits == 0);
+
+ session->ppb.pic_fields.bits.sign_data_hiding_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.slice_parsing_fields.bits.cabac_init_present_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.num_ref_idx_l0_default_active_minus1 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.num_ref_idx_l1_default_active_minus1 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.init_qp_minus26 = (int8_t)BitstreamReadSE(nalu);
+ session->ppb.pic_fields.bits.constrained_intra_pred_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.pic_fields.bits.transform_skip_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.pic_fields.bits.cu_qp_delta_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.cu_qp_delta_enabled_flag == 0);
+
+ session->ppb.pps_cb_qp_offset = (int8_t)BitstreamReadSE(nalu);
+ session->ppb.pps_cr_qp_offset = (int8_t)BitstreamReadSE(nalu);
+ session->ppb.slice_parsing_fields.bits
+ .pps_slice_chroma_qp_offsets_present_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.slice_parsing_fields.bits
+ .pps_slice_chroma_qp_offsets_present_flag == 0);
+
+ session->ppb.pic_fields.bits.weighted_pred_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.weighted_pred_flag == 0);
+ session->ppb.pic_fields.bits.weighted_bipred_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.weighted_bipred_flag == 0);
+
+ session->ppb.pic_fields.bits.transquant_bypass_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ session->ppb.pic_fields.bits.tiles_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.tiles_enabled_flag == 0);
+
+ // vvv weird vvv
+ session->ppb.pic_fields.bits.loop_filter_across_tiles_enabled_flag = 1;
+ // ^^^ weird ^^^
+
+ session->ppb.pic_fields.bits.entropy_coding_sync_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.pic_fields.bits.entropy_coding_sync_enabled_flag == 0);
+
+ session->ppb.pic_fields.bits.pps_loop_filter_across_slices_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ bool deblocking_filter_control_present_flag = !!BitstreamReadU(nalu, 1);
+ if (deblocking_filter_control_present_flag) {
+ session->ppb.slice_parsing_fields.bits
+ .deblocking_filter_override_enabled_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.slice_parsing_fields.bits
+ .deblocking_filter_override_enabled_flag == 0);
+ session->ppb.slice_parsing_fields.bits.pps_disable_deblocking_filter_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.slice_parsing_fields.bits
+ .pps_disable_deblocking_filter_flag == 0);
+ session->ppb.pps_beta_offset_div2 = (int8_t)BitstreamReadSE(nalu);
+ session->ppb.pps_tc_offset_div2 = (int8_t)BitstreamReadSE(nalu);
+ }
+
+ assert(BitstreamReadU(nalu, 1) == 0); // scaling_list_data_present_flag
+ session->ppb.slice_parsing_fields.bits.lists_modification_present_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(
+ session->ppb.slice_parsing_fields.bits.lists_modification_present_flag ==
+ 0);
+ session->ppb.log2_parallel_merge_level_minus2 =
+ (uint8_t)BitstreamReadUE(nalu);
+ session->ppb.slice_parsing_fields.bits
+ .slice_segment_header_extension_present_flag =
+ (uint32_t)BitstreamReadU(nalu, 1);
+ assert(session->ppb.slice_parsing_fields.bits
+ .slice_segment_header_extension_present_flag == 0);
+ assert(BitstreamReadU(nalu, 1) == 0); // pps_extension_present_flag
+}
+
+mfxStatus MFXVideoCORE_SetFrameAllocator(mfxSession session,
+ mfxFrameAllocator* allocator) {
+ session->allocator = *allocator;
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXVideoCORE_SetHandle(mfxSession session, mfxHandleType type,
+ mfxHDL hdl) {
+ (void)type;
+ session->display = hdl;
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXVideoCORE_SyncOperation(mfxSession session, mfxSyncPoint syncp,
+ mfxU32 wait) {
+ (void)session;
+ (void)syncp;
+ (void)wait;
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXVideoDECODE_Query(mfxSession session, mfxVideoParam* in,
+ mfxVideoParam* out) {
+ (void)session;
+ (void)in;
+ (void)out;
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXVideoDECODE_DecodeHeader(mfxSession session, mfxBitstream* bs,
+ mfxVideoParam* par) {
+ (void)par;
+ struct Bitstream bitstream = BitstreamCreate(bs->Data, bs->DataLength);
+ for (struct Bitstream nalu; BitstreamAvail(&bitstream);) {
+ if (!BitstreamReadNalu(&bitstream, &nalu)) {
+ assert(0);
+ return MFX_ERR_UNSUPPORTED;
+ }
+ if (BitstreamReadFailed(&nalu)) {
+ assert(0);
+ return MFX_ERR_UNSUPPORTED;
+ }
+ uint8_t nal_unit_type = ParseNaluHeader(&nalu);
+ switch (nal_unit_type) {
+ case SPS_NUT:
+ ParseSps(&nalu, session);
+ break;
+ case PPS_NUT:
+ ParsePps(&nalu, session);
+ bs->Data += bitstream.offset >> 3;
+ bs->DataLength -= bitstream.offset >> 3;
+ return MFX_ERR_NONE;
+ default:
+ break;
+ }
+ }
+ return MFX_ERR_NONE;
+}
+
+mfxStatus MFXVideoDECODE_Init(mfxSession session, mfxVideoParam* par) {
+ (void)par;
+ VAConfigID config_id;
+ VAStatus status = vaCreateConfig(session->display, VAProfileHEVCMain,
+ VAEntrypointVLD, NULL, 0, &config_id);
+ if (status != VA_STATUS_SUCCESS) {
+ return MFX_ERR_DEVICE_FAILED;
+ }
+
+ VAContextID context_id;
+ mfxStatus result = MFX_ERR_DEVICE_FAILED;
+ status = vaCreateContext(session->display, config_id,
+ session->ppb.pic_width_in_luma_samples,
+ session->ppb.pic_height_in_luma_samples,
+ VA_PROGRESSIVE, NULL, 0, &context_id);
+ if (status != VA_STATUS_SUCCESS) {
+ goto rollback_config_id;
+ }
+
+ mfxFrameAllocRequest request = {
+ .Info.FourCC = MFX_FOURCC_NV12,
+ .Info.Width = session->ppb.pic_width_in_luma_samples,
+ .Info.Height = session->ppb.pic_height_in_luma_samples,
+ .Info.ChromaFormat = MFX_CHROMAFORMAT_YUV420,
+ .NumFrameSuggested = 3,
+ };
+ mfxFrameAllocResponse response;
+ result =
+ session->allocator.Alloc(session->allocator.pthis, &request, &response);
+ if (result != MFX_ERR_NONE) {
+ goto rollback_context_id;
+ }
+
+ mfxMemId* mids = calloc(response.NumFrameActual, sizeof(mfxMemId));
+ if (!mids) {
+ result = MFX_ERR_MEMORY_ALLOC;
+ goto rollback_response;
+ }
+
+ session->config_id = config_id;
+ session->context_id = context_id;
+ session->mids = mids;
+ session->mids_count = response.NumFrameActual;
+ memcpy(mids, response.mids, response.NumFrameActual * sizeof(mfxMemId));
+ return MFX_ERR_NONE;
+
+rollback_response:
+ assert(session->allocator.Free(session->allocator.pthis, &response) ==
+ MFX_ERR_NONE);
+rollback_context_id:
+ assert(vaDestroyContext(session->display, context_id) == VA_STATUS_SUCCESS);
+rollback_config_id:
+ assert(vaDestroyConfig(session->display, config_id) == VA_STATUS_SUCCESS);
+ return result;
+}
+
+mfxStatus MFXVideoDECODE_DecodeFrameAsync(mfxSession session, mfxBitstream* bs,
+ mfxFrameSurface1* surface_work,
+ mfxFrameSurface1** surface_out,
+ mfxSyncPoint* syncp) {
+ assert(0);
+ return MFX_ERR_NONE;
+}