From 142448bbedd0d3c5964fd92546afe28148489e11 Mon Sep 17 00:00:00 2001 From: He Junyan Date: Tue, 30 Jan 2024 18:10:12 +0800 Subject: [PATCH] vp9bitwriter: Add the VP9 bit writer helper functions In this first version, we only implement the "show existing frame" and super frame writting. Other frame header types writting can be added when needed. Part-of: --- .../gst/codecparsers/gstvp9bitwriter.c | 171 ++++++++++++++++++ .../gst/codecparsers/gstvp9bitwriter.h | 59 ++++++ .../gst-libs/gst/codecparsers/meson.build | 1 + 3 files changed, 231 insertions(+) create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.c create mode 100644 subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.h diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.c b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.c new file mode 100644 index 0000000000..7e0e60d24b --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.c @@ -0,0 +1,171 @@ +/* GStreamer + * Copyright (C) 2022 Intel Corporation + * Author: He Junyan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the0 + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstvp9bitwriter.h" +#include + +#define WRITE_BITS_UNCHECK(bw, val, nbits) \ + (nbits <= 8 ? gst_bit_writer_put_bits_uint8 (bw, val, nbits) : \ + (nbits <= 16 ? gst_bit_writer_put_bits_uint16 (bw, val, nbits) : \ + (nbits <= 32 ? gst_bit_writer_put_bits_uint32 (bw, val, nbits) : \ + FALSE))) + +#define WRITE_BITS(bw, val, nbits) \ + if (!WRITE_BITS_UNCHECK (bw, val, nbits)) { \ + g_warning ("Unsupported bit size: %u", nbits); \ + have_space = FALSE; \ + goto error; \ + } + +/** + * gst_vp9_bit_writer_frame_header: + * @frame_hdr: the frame header of #GstVp9FrameHdr to write + * @data: (out): the stream generated by the frame header + * @size: (inout): the size in bytes of the input and output + * + * Generating the according VP9 bit stream by providing the frame header. + * + * Returns: a #GstVp9BitWriterResult + * + * Since: 1.24 + **/ +GstVp9BitWriterResult +gst_vp9_bit_writer_frame_header (const GstVp9FrameHdr * frame_hdr, + guint8 * data, guint * size) +{ + gboolean have_space = TRUE; + GstBitWriter bw; + + g_return_val_if_fail (frame_hdr != NULL, GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (data != NULL, GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (size != NULL, GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (*size > 0, GST_VP9_BIT_WRITER_ERROR); + + gst_bit_writer_init_with_data (&bw, data, *size, FALSE); + + WRITE_BITS (&bw, GST_VP9_FRAME_MARKER, 2); + /* profile_low_bit */ + WRITE_BITS (&bw, frame_hdr->profile & 0x01, 1); + /* profile_high_bit */ + WRITE_BITS (&bw, (frame_hdr->profile & 0x02) >> 1, 1); + if (frame_hdr->profile == 3) + WRITE_BITS (&bw, 0, 1); + + if (frame_hdr->show_existing_frame) { + WRITE_BITS (&bw, frame_hdr->show_existing_frame, 1); + WRITE_BITS (&bw, frame_hdr->frame_to_show, 3); + gst_bit_writer_align_bytes (&bw, 0); + } else { + GST_WARNING ("Frame header writing is not implemented."); + goto error; + } + + g_assert (gst_bit_writer_get_size (&bw) % 8 == 0); + *size = gst_bit_writer_get_size (&bw) / 8; + + gst_bit_writer_reset (&bw); + + return GST_VP9_BIT_WRITER_OK; + +error: + gst_bit_writer_reset (&bw); + *size = 0; + return have_space ? GST_VP9_BIT_WRITER_INVALID_DATA : + GST_VP9_BIT_WRITER_NO_MORE_SPACE; +} + +/** + * gst_vp9_bit_writer_superframe_info: + * @frame_num: the frame number to composite this super frame + * @frame_size: the size of each frame + * @data: (inout): the stream data of this super frame + * @size: (inout): the size in bytes of the input and output + * + * Appending the super frame info at the end of this stream. + * Note: the input @data should already contain all frames' data in + * the same order of @frame_size. + * + * Returns: a #GstVp9BitWriterResult + * + * Since: 1.24 + **/ +GstVp9BitWriterResult +gst_vp9_bit_writer_superframe_info (guint frame_num, const gint * frame_size, + guint8 * data, guint * size) +{ + GstBitWriter bw; + GstVp9BitWriterResult ret = GST_VP9_BIT_WRITER_OK; + guint data_sz = 0; + guint i, j; + + g_return_val_if_fail (frame_num <= GST_VP9_MAX_FRAMES_IN_SUPERFRAME, + GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (frame_size != NULL, GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (data != NULL, GST_VP9_BIT_WRITER_ERROR); + g_return_val_if_fail (size != NULL, GST_VP9_BIT_WRITER_ERROR); + + for (i = 0; i < frame_num; i++) + data_sz += frame_size[i]; + + if (*size < data_sz + 1 /* superframe_header */ + + 4 * frame_num /* superframe_index */ + 1 /* superframe_header */ ) { + ret = GST_VP9_BIT_WRITER_NO_MORE_SPACE; + goto out; + } + + memset (data + data_sz, 0, 1 + 4 * frame_num + 1); + gst_bit_writer_init_with_data (&bw, data + data_sz, + 1 + 4 * frame_num + 1, FALSE); + + /* superframe_header() */ + gst_bit_writer_put_bits_uint8 (&bw, GST_VP9_SUPERFRAME_MARKER, 3); + /* bytes_per_framesize_minus_1 */ + gst_bit_writer_put_bits_uint8 (&bw, 4 - 1, 2); + /* frames_in_superframe_minus_1 */ + gst_bit_writer_put_bits_uint8 (&bw, frame_num - 1, 3); + + for (i = 0; i < frame_num; i++) { + guint32 value = frame_size[i]; + for (j = 0; j < 4; j++) + gst_bit_writer_put_bits_uint8 (&bw, (value >> j * 8) & 0xff, 8); + } + + /* superframe_header() again */ + gst_bit_writer_put_bits_uint8 (&bw, GST_VP9_SUPERFRAME_MARKER, 3); + /* bytes_per_framesize_minus_1 */ + gst_bit_writer_put_bits_uint8 (&bw, 4 - 1, 2); + /* frames_in_superframe_minus_1 */ + gst_bit_writer_put_bits_uint8 (&bw, frame_num - 1, 3); + + g_assert (gst_bit_writer_get_size (&bw) % 8 == 0); + *size = data_sz + gst_bit_writer_get_size (&bw) / 8; + +out: + gst_bit_writer_reset (&bw); + + if (ret != GST_VP9_BIT_WRITER_OK) + *size = 0; + + return ret; +} diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.h b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.h new file mode 100644 index 0000000000..3dd8fed62e --- /dev/null +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/gstvp9bitwriter.h @@ -0,0 +1,59 @@ +/* GStreamer + * Copyright (C) 2022 Intel Corporation + * Author: He Junyan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the0 + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_VP9_BIT_WRITER_H__ +#define __GST_VP9_BIT_WRITER_H__ + +#include +#include + +G_BEGIN_DECLS + +/** + * GstVp9BitWriterResult: + * @GST_VP9_BIT_WRITER_OK: The writing succeeded + * @GST_VP9_BIT_WRITER_INVALID_DATA: The input data to write is invalid + * @GST_VP9_BIT_WRITER_NO_MORE_SPACE: The output does not have enough size + * @GST_VP9_BIT_WRITER_ERROR: An general error occurred when writing + * + * The result of writing VP9 data into bit stream. + * + * Since: 1.24 + */ +typedef enum +{ + GST_VP9_BIT_WRITER_OK, + GST_VP9_BIT_WRITER_INVALID_DATA, + GST_VP9_BIT_WRITER_NO_MORE_SPACE, + GST_VP9_BIT_WRITER_ERROR +} GstVp9BitWriterResult; + +GST_CODEC_PARSERS_API +GstVp9BitWriterResult gst_vp9_bit_writer_frame_header (const GstVp9FrameHdr * frame_hdr, + guint8 * data, + guint * size); +GST_CODEC_PARSERS_API +GstVp9BitWriterResult gst_vp9_bit_writer_superframe_info (guint frame_num, + const gint * frame_size, + guint8 * data, + guint * total_size); + +G_END_DECLS +#endif /* __GST_VP9_BIT_WRITER_H__ */ diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/meson.build b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/meson.build index 7e968354a8..5865b373ef 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/meson.build +++ b/subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/meson.build @@ -19,6 +19,7 @@ codecparser_sources = files([ 'gsth264bitwriter.c', 'gsth265bitwriter.c', 'gstav1bitwriter.c', + 'gstvp9bitwriter.c', ]) codecparser_headers = [ 'codecparsers-prelude.h',