253 lines
8.1 KiB
Diff
253 lines
8.1 KiB
Diff
From 6adaff584bc42f9bdf2e22aa3dab5f3f72626c03 Mon Sep 17 00:00:00 2001
|
|
From: Hugues Fruchet <hugues.fruchet@foss.st.com>
|
|
Date: Wed, 21 Aug 2024 17:35:34 +0200
|
|
Subject: [PATCH] v4l2codecs: vp8: add webp image support
|
|
|
|
Add WebP image decoding support to stateless V4L2 VP8 decoder.
|
|
A WebP image is composed of a RIFF header followed by a VP8 chunk.
|
|
|
|
Upstream-Status: Pending
|
|
---
|
|
gst-libs/gst/codecs/gstvp8decoder.c | 10 +++
|
|
sys/v4l2codecs/gstv4l2codecvp8dec.c | 127 ++++++++++++++++++++++++++-
|
|
sys/v4l2codecs/linux/v4l2-controls.h | 1 +
|
|
3 files changed, 136 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/gst-libs/gst/codecs/gstvp8decoder.c b/gst-libs/gst/codecs/gstvp8decoder.c
|
|
index 411f272..9ef51cf 100644
|
|
--- a/gst-libs/gst/codecs/gstvp8decoder.c
|
|
+++ b/gst-libs/gst/codecs/gstvp8decoder.c
|
|
@@ -35,6 +35,8 @@
|
|
GST_DEBUG_CATEGORY (gst_vp8_decoder_debug);
|
|
#define GST_CAT_DEFAULT gst_vp8_decoder_debug
|
|
|
|
+#define WEBP_RIFF_HEADER_SIZE 20
|
|
+
|
|
struct _GstVp8DecoderPrivate
|
|
{
|
|
gint width;
|
|
@@ -376,6 +378,8 @@ gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
|
|
GstVp8Picture *picture = NULL;
|
|
GstFlowReturn ret = GST_FLOW_OK;
|
|
GstVp8DecoderOutputFrame output_frame;
|
|
+ GstCaps *webp_caps = gst_caps_intersect (gst_caps_new_empty_simple ("image/webp"),
|
|
+ self->input_state->caps);
|
|
|
|
GST_LOG_OBJECT (self,
|
|
"handle frame, PTS: %" GST_TIME_FORMAT ", DTS: %"
|
|
@@ -388,6 +392,12 @@ gst_vp8_decoder_handle_frame (GstVideoDecoder * decoder,
|
|
goto error;
|
|
}
|
|
|
|
+ if (!gst_caps_is_empty (webp_caps)) {
|
|
+ /* Drop WebP RIFF header */
|
|
+ map.data += WEBP_RIFF_HEADER_SIZE;
|
|
+ map.size -= WEBP_RIFF_HEADER_SIZE;
|
|
+ }
|
|
+
|
|
pres = gst_vp8_parser_parse_frame_header (&priv->parser,
|
|
&frame_hdr, map.data, map.size);
|
|
|
|
diff --git a/sys/v4l2codecs/gstv4l2codecvp8dec.c b/sys/v4l2codecs/gstv4l2codecvp8dec.c
|
|
index ba63a02..6cc5824 100644
|
|
--- a/sys/v4l2codecs/gstv4l2codecvp8dec.c
|
|
+++ b/sys/v4l2codecs/gstv4l2codecvp8dec.c
|
|
@@ -26,6 +26,8 @@
|
|
#include "gstv4l2codecpool.h"
|
|
#include "gstv4l2codecvp8dec.h"
|
|
#include "gstv4l2format.h"
|
|
+#include <gst/base/gstadapter.h>
|
|
+#include <gst/base/gstbytereader.h>
|
|
|
|
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
|
|
|
|
@@ -45,7 +47,8 @@ enum
|
|
static GstStaticPadTemplate sink_template =
|
|
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
|
|
GST_PAD_SINK, GST_PAD_ALWAYS,
|
|
- GST_STATIC_CAPS ("video/x-vp8")
|
|
+ GST_STATIC_CAPS ("video/x-vp8;"
|
|
+ "image/webp;")
|
|
);
|
|
|
|
static GstStaticPadTemplate alpha_template =
|
|
@@ -80,6 +83,10 @@ struct _GstV4l2CodecVp8Dec
|
|
|
|
GstMemory *bitstream;
|
|
GstMapInfo bitstream_map;
|
|
+
|
|
+ gboolean saw_header;
|
|
+ guint frame_size;
|
|
+ gboolean webp;
|
|
};
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (GstV4l2CodecVp8Dec, gst_v4l2_codec_vp8_dec,
|
|
@@ -428,7 +435,8 @@ gst_v4l2_codec_vp8_dec_fill_frame_header (GstV4l2CodecVp8Dec * self,
|
|
(frame_hdr->show_frame ? V4L2_VP8_FRAME_FLAG_SHOW_FRAME : 0) |
|
|
(frame_hdr->mb_no_skip_coeff ? V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF : 0) |
|
|
(frame_hdr->sign_bias_golden ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN : 0) |
|
|
- (frame_hdr->sign_bias_alternate ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT : 0),
|
|
+ (frame_hdr->sign_bias_alternate ? V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT : 0) |
|
|
+ (self->webp ? V4L2_VP8_FRAME_FLAG_WEBP : 0),
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
@@ -579,6 +587,7 @@ gst_v4l2_codec_vp8_dec_decode_picture (GstVp8Decoder * decoder,
|
|
static void
|
|
gst_v4l2_codec_vp8_dec_reset_picture (GstV4l2CodecVp8Dec * self)
|
|
{
|
|
+ self->saw_header = FALSE;
|
|
if (self->bitstream) {
|
|
if (self->bitstream_map.memory)
|
|
gst_memory_unmap (self->bitstream, &self->bitstream_map);
|
|
@@ -854,6 +863,7 @@ gst_v4l2_codec_vp8_dec_get_property (GObject * object, guint prop_id,
|
|
static void
|
|
gst_v4l2_codec_vp8_dec_init (GstV4l2CodecVp8Dec * self)
|
|
{
|
|
+ self->saw_header = FALSE;
|
|
}
|
|
|
|
static void
|
|
@@ -879,6 +889,116 @@ gst_v4l2_codec_vp8_dec_class_init (GstV4l2CodecVp8DecClass * klass)
|
|
{
|
|
}
|
|
|
|
+static gboolean
|
|
+gst_v4l2_codec_vp8_dec_set_format (GstVideoDecoder * decoder,
|
|
+ GstVideoCodecState * state)
|
|
+{
|
|
+ GstV4l2CodecVp8Dec *self = GST_V4L2_CODEC_VP8_DEC (decoder);
|
|
+ GstVp8Decoder *vp8dec = GST_VP8_DECODER (decoder);
|
|
+ GstCaps *webp_caps = gst_caps_intersect (gst_caps_new_empty_simple ("image/webp"),
|
|
+ state->caps);
|
|
+
|
|
+ if (vp8dec->input_state)
|
|
+ gst_video_codec_state_unref (vp8dec->input_state);
|
|
+ vp8dec->input_state = gst_video_codec_state_ref (state);
|
|
+
|
|
+ if (!gst_caps_is_empty (webp_caps)) {
|
|
+ /* WebP requires parsing for right packetization */
|
|
+ gst_video_decoder_set_packetized (decoder, FALSE);
|
|
+ self->webp = TRUE;
|
|
+ }
|
|
+
|
|
+ return TRUE;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Webp image RIFF header
|
|
+ *
|
|
+ * 52 49 46 46 f6 00 00 00 57 45 42 50 56 50 38 20 RIFF....WEBPVP8
|
|
+ * ea 00 00 00 90 09 00 9d 01 2a 30 00 30 00 3e 35 .........*0.0.>5
|
|
+ * | \______/ \______/
|
|
+ * | | \__VP8 startcode
|
|
+ * | \__VP8 frame_tag
|
|
+ * |
|
|
+ * \__End of WebP RIFF header: 20 bytes, then VP8 chunk
|
|
+ *
|
|
+ * copied from gstwebpdec.c: gst_webp_dec_parse()
|
|
+ */
|
|
+static GstFlowReturn
|
|
+gst_v4l2_codec_vp8_dec_parse (GstVideoDecoder * decoder,
|
|
+ GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
|
|
+{
|
|
+ gsize toadd = 0;
|
|
+ gsize size;
|
|
+ gconstpointer data;
|
|
+ GstByteReader reader;
|
|
+ GstV4l2CodecVp8Dec *self = (GstV4l2CodecVp8Dec *) decoder;
|
|
+
|
|
+ size = gst_adapter_available (adapter);
|
|
+ GST_DEBUG_OBJECT (decoder,
|
|
+ "parsing webp image data (%" G_GSIZE_FORMAT " bytes)", size);
|
|
+
|
|
+ if (at_eos) {
|
|
+ GST_DEBUG ("Flushing all data out");
|
|
+ toadd = size;
|
|
+
|
|
+ /* If we have leftover data, throw it away */
|
|
+ if (!self->saw_header)
|
|
+ goto drop_frame;
|
|
+ goto have_full_frame;
|
|
+ }
|
|
+
|
|
+ if (!self->saw_header) {
|
|
+ guint32 code;
|
|
+
|
|
+ if (size < 12)
|
|
+ goto need_more_data;
|
|
+
|
|
+ data = gst_adapter_map (adapter, size);
|
|
+ gst_byte_reader_init (&reader, data, size);
|
|
+
|
|
+ if (!gst_byte_reader_get_uint32_le (&reader, &code))
|
|
+ goto error;
|
|
+
|
|
+ if (code == GST_MAKE_FOURCC ('R', 'I', 'F', 'F')) {
|
|
+ if (!gst_byte_reader_get_uint32_le (&reader, &self->frame_size))
|
|
+ goto error;
|
|
+
|
|
+ if (!gst_byte_reader_get_uint32_le (&reader, &code))
|
|
+ goto error;
|
|
+
|
|
+ if (code == GST_MAKE_FOURCC ('W', 'E', 'B', 'P'))
|
|
+ self->saw_header = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!self->saw_header)
|
|
+ goto error;
|
|
+
|
|
+ if (size >= (self->frame_size + 8)) {
|
|
+ toadd = self->frame_size + 8;
|
|
+ self->saw_header = FALSE;
|
|
+
|
|
+ goto have_full_frame;
|
|
+ }
|
|
+
|
|
+need_more_data:
|
|
+ return GST_VIDEO_DECODER_FLOW_NEED_DATA;
|
|
+
|
|
+have_full_frame:
|
|
+ if (toadd)
|
|
+ gst_video_decoder_add_to_frame (decoder, toadd);
|
|
+ return gst_video_decoder_have_frame (decoder);
|
|
+
|
|
+drop_frame:
|
|
+ gst_adapter_flush (adapter, size);
|
|
+ return GST_FLOW_OK;
|
|
+
|
|
+error:
|
|
+ GST_WARNING("parsing webp GST_FLOW_ERROR");
|
|
+ return GST_FLOW_ERROR;
|
|
+}
|
|
+
|
|
static void
|
|
gst_v4l2_codec_vp8_dec_subclass_init (GstV4l2CodecVp8DecClass * klass,
|
|
GstV4l2CodecDevice * device)
|
|
@@ -906,6 +1026,9 @@ gst_v4l2_codec_vp8_dec_subclass_init (GstV4l2CodecVp8DecClass * klass,
|
|
decoder_class->open = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_open);
|
|
decoder_class->close = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_close);
|
|
decoder_class->stop = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_stop);
|
|
+ decoder_class->parse = GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_parse);
|
|
+ decoder_class->set_format =
|
|
+ GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_set_format);
|
|
decoder_class->negotiate =
|
|
GST_DEBUG_FUNCPTR (gst_v4l2_codec_vp8_dec_negotiate);
|
|
decoder_class->decide_allocation =
|
|
diff --git a/sys/v4l2codecs/linux/v4l2-controls.h b/sys/v4l2codecs/linux/v4l2-controls.h
|
|
index 7a94437..aaeaa58 100644
|
|
--- a/sys/v4l2codecs/linux/v4l2-controls.h
|
|
+++ b/sys/v4l2codecs/linux/v4l2-controls.h
|
|
@@ -1987,6 +1987,7 @@ struct v4l2_vp8_entropy_coder_state {
|
|
#define V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF 0x08
|
|
#define V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN 0x10
|
|
#define V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT 0x20
|
|
+#define V4L2_VP8_FRAME_FLAG_WEBP 0x40
|
|
|
|
#define V4L2_VP8_FRAME_IS_KEY_FRAME(hdr) \
|
|
(!!((hdr)->flags & V4L2_VP8_FRAME_FLAG_KEY_FRAME))
|
|
--
|
|
2.25.1
|
|
|