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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3293>
This commit is contained in:
He Junyan 2024-01-30 18:10:12 +08:00 committed by GStreamer Marge Bot
parent 3d500636a9
commit 142448bbed
3 changed files with 231 additions and 0 deletions

View file

@ -0,0 +1,171 @@
/* GStreamer
* Copyright (C) 2022 Intel Corporation
* Author: He Junyan <junyan.he@intel.com>
*
* 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 <gst/base/gstbitwriter.h>
#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;
}

View file

@ -0,0 +1,59 @@
/* GStreamer
* Copyright (C) 2022 Intel Corporation
* Author: He Junyan <junyan.he@intel.com>
*
* 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 <gst/codecparsers/gstvp9parser.h>
#include <gst/codecparsers/codecparsers-prelude.h>
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__ */

View file

@ -19,6 +19,7 @@ codecparser_sources = files([
'gsth264bitwriter.c',
'gsth265bitwriter.c',
'gstav1bitwriter.c',
'gstvp9bitwriter.c',
])
codecparser_headers = [
'codecparsers-prelude.h',