Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libobs: Add AV1 parsing functions #9475

Merged
merged 1 commit into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libobs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ target_sources(
obs-audio-controls.c
obs-audio-controls.h
obs-audio.c
obs-av1.c
obs-av1.h
obs-avc.c
obs-avc.h
obs-data.c
Expand Down
2 changes: 2 additions & 0 deletions libobs/cmake/legacy.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ target_sources(
obs-audio.c
obs-audio-controls.c
obs-audio-controls.h
obs-av1.c
obs-av1.h
obs-avc.c
obs-avc.h
obs-data.c
Expand Down
123 changes: 123 additions & 0 deletions libobs/obs-av1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-FileCopyrightText: 2023 David Rosca <nowrep@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later

#include "obs-av1.h"

#include "obs.h"

static inline uint64_t leb128(const uint8_t *buf, size_t size, size_t *len)
{
uint64_t value = 0;
uint8_t leb128_byte;

*len = 0;

for (int i = 0; i < 8; i++) {
if (size-- < 1)
break;
(*len)++;
leb128_byte = buf[i];
value |= (leb128_byte & 0x7f) << (i * 7);
if (!(leb128_byte & 0x80))
break;
}

return value;
}

static inline unsigned int get_bits(uint8_t val, unsigned int n,
unsigned int count)
{
return (val >> (8 - n - count)) & ((1 << (count - 1)) * 2 - 1);
}

static void parse_obu_header(const uint8_t *buf, size_t size, size_t *obu_start,
size_t *obu_size, int *obu_type)
{
int extension_flag, has_size_field;
size_t size_len = 0;

*obu_start = 0;
*obu_size = 0;
*obu_type = 0;

if (size < 1)
return;

*obu_type = get_bits(*buf, 1, 4);
extension_flag = get_bits(*buf, 5, 1);
has_size_field = get_bits(*buf, 6, 1);

if (extension_flag)
(*obu_start)++;

(*obu_start)++;

if (has_size_field)
*obu_size = (size_t)leb128(buf + *obu_start, size - *obu_start,
&size_len);
else
*obu_size = size - 1;

*obu_start += size_len;
}

bool obs_av1_keyframe(const uint8_t *data, size_t size)
{
const uint8_t *start = data, *end = data + size;

while (start < end) {
size_t obu_start, obu_size;
int obu_type;
parse_obu_header(start, end - start, &obu_start, &obu_size,
&obu_type);

if (obu_size) {
if (obu_type == OBS_OBU_FRAME ||
obu_type == OBS_OBU_FRAME_HEADER) {
uint8_t val = *(start + obu_start);
if (!get_bits(val, 0, 1)) // show_existing_frame
return get_bits(val, 1, 2) ==
0; // frame_type
return false;
}
}

start += obu_start + obu_size;
}

return false;
}

void obs_extract_av1_headers(const uint8_t *packet, size_t size,
uint8_t **new_packet_data, size_t *new_packet_size,
uint8_t **header_data, size_t *header_size)
{
DARRAY(uint8_t) new_packet;
DARRAY(uint8_t) header;
const uint8_t *start = packet, *end = packet + size;

da_init(new_packet);
da_init(header);

while (start < end) {
size_t obu_start, obu_size;
int obu_type;
parse_obu_header(start, end - start, &obu_start, &obu_size,
&obu_type);

if (obu_type == OBS_OBU_METADATA ||
obu_type == OBS_OBU_SEQUENCE_HEADER) {
da_push_back_array(header, start, obu_start + obu_size);
}
da_push_back_array(new_packet, start, obu_start + obu_size);

start += obu_start + obu_size;
}

*new_packet_data = new_packet.array;
*new_packet_size = new_packet.num;
*header_data = header.array;
*header_size = header.num;
}
35 changes: 35 additions & 0 deletions libobs/obs-av1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: 2023 David Rosca <nowrep@gmail.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "util/c99defs.h"

#ifdef __cplusplus
extern "C" {
#endif

enum {
OBS_OBU_SEQUENCE_HEADER = 1,
OBS_OBU_TEMPORAL_DELIMITER = 2,
OBS_OBU_FRAME_HEADER = 3,
OBS_OBU_TILE_GROUP = 4,
OBS_OBU_METADATA = 5,
OBS_OBU_FRAME = 6,
OBS_OBU_REDUNDANT_FRAME_HEADER = 7,
OBS_OBU_TILE_LIST = 8,
OBS_OBU_PADDING = 15,
};

/* Helpers for parsing AV1 OB units. */

EXPORT bool obs_av1_keyframe(const uint8_t *data, size_t size);
EXPORT void obs_extract_av1_headers(const uint8_t *packet, size_t size,
uint8_t **new_packet_data,
size_t *new_packet_size,
uint8_t **header_data, size_t *header_size);

#ifdef __cplusplus
}
#endif