| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | 
							- // SPDX-FileCopyrightText: 2023 David Rosca <[email protected]>
 
- //
 
- // 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;
 
- }
 
- // Pass a static 10 byte buffer in. The max size for a leb128.
 
- static inline void encode_uleb128(uint64_t val, uint8_t *out_buf, size_t *len_out)
 
- {
 
- 	size_t num_bytes = 0;
 
- 	uint8_t b = val & 0x7f;
 
- 	val >>= 7;
 
- 	while (val > 0) {
 
- 		out_buf[num_bytes] = b | 0x80;
 
- 		++num_bytes;
 
- 		b = val & 0x7f;
 
- 		val >>= 7;
 
- 	}
 
- 	out_buf[num_bytes] = b;
 
- 	++num_bytes;
 
- 	*len_out = num_bytes;
 
- }
 
- /* metadata_obu_itu_t35() is a public symbol. Maintain the function
 
-  * and make it call the more general metadata_obu() function.
 
-  */
 
- void metadata_obu_itu_t35(const uint8_t *itut_t35_buffer, size_t itut_bufsize, uint8_t **out_buffer,
 
- 			  size_t *outbuf_size)
 
- {
 
- 	metadata_obu(itut_t35_buffer, itut_bufsize, out_buffer, outbuf_size, METADATA_TYPE_ITUT_T35);
 
- }
 
- // Create an OBU to carry AV1 metadata types, including captions and user private data
 
- void metadata_obu(const uint8_t *source_buffer, size_t source_bufsize, uint8_t **out_buffer, size_t *outbuf_size,
 
- 		  uint8_t metadata_type)
 
- {
 
- 	/* From the AV1 spec: 5.3.2 OBU Header Syntax
 
- 	 * -------------
 
- 	 * obu_forbidden_bit   (1)
 
- 	 * obu_type            (4)  // In this case OBS_OBU_METADATA
 
- 	 * obu_extension_flag  (1)
 
- 	 * obu_has_size_field  (1)  // Must be set, size of OBU is variable
 
- 	 * obu_reserved_1bit   (1)
 
- 	 * if(obu_extension_flag == 1)
 
- 	 *   // skip, because we aren't setting this
 
- 	 */
 
- 	uint8_t obu_header_byte = (OBS_OBU_METADATA << 3) | (1 << 1);
 
- 	/* From the AV1 spec: 5.3.1 General OBU Syntax
 
- 	 * if (obu_has_size_field)
 
- 	 * 	obu_size    leb128()
 
- 	 * else
 
- 	 * 	obu_size = sz - 1 - obu_extension_flag
 
- 	 *
 
- 	 * 	// Skipping portions unrelated to this OBU type	
 
- 	 *
 
- 	 * if (obu_type == OBU_METADATA)
 
- 	 * 	metdata_obu()
 
- 	 * 5.8.1 General metadata OBU Syntax
 
- 	 *	// leb128(metadatatype) should always be 1 byte +1 for trailing bits
 
- 	 * 	metadata_type                     leb128()
 
- 	 * 5.8.2 Metadata ITUT T35 syntax
 
- 	 * 	if (metadata_type == METADATA_TYPE_ITUT_T35)
 
-          * 		// add ITUT T35 payload
 
- 	 * 5.8.1 General metadata OBU Syntax
 
- 	 * 	// trailing bits will always be 0x80 because
 
- 	 *	// everything in here is byte aligned
 
- 	 * 	trailing_bits( obu_size * 8 - payloadBits )
 
- 	 */
 
- 	int64_t size_field = 1 + source_bufsize + 1;
 
- 	uint8_t size_buf[10];
 
- 	size_t size_buf_size = 0;
 
- 	encode_uleb128(size_field, size_buf, &size_buf_size);
 
- 	// header + obu_size + metadata_type + metadata_payload + trailing_bits
 
- 	*outbuf_size = 1 + size_buf_size + 1 + source_bufsize + 1;
 
- 	*out_buffer = bzalloc(*outbuf_size);
 
- 	size_t offset = 0;
 
- 	(*out_buffer)[0] = obu_header_byte;
 
- 	++offset;
 
- 	memcpy((*out_buffer) + offset, size_buf, size_buf_size);
 
- 	offset += size_buf_size;
 
- 	(*out_buffer)[offset] = metadata_type;
 
- 	++offset;
 
- 	memcpy((*out_buffer) + offset, source_buffer, source_bufsize);
 
- 	offset += source_bufsize;
 
- 	/* From AV1 spec: 6.2.1 General OBU semantics
 
- 	 * ... Trailing bits are always present, unless the OBU consists of only
 
- 	 * the header. Trailing bits achieve byte alignment when the payload of
 
- 	 * an OBU is not byte aligned. The trailing bits may also used for
 
- 	 * additional byte padding, and if used are taken into account in the
 
- 	 * sz value. In all cases, the pattern used for the trailing bits
 
- 	 * guarantees that all OBUs (except header-only OBUs) end with the same
 
- 	 * pattern: one bit set to one, optionally followed by zeros. */
 
- 	(*out_buffer)[offset] = 0x80;
 
- }
 
- 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;
 
- }
 
 
  |