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',