diff --git a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json index ca9963f1b7..2993a2a4ca 100644 --- a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json @@ -1715,6 +1715,44 @@ "tracers": {}, "url": "Unknown package origin" }, + "basedebug": { + "description": "elements for testing and debugging", + "elements": { + "fakevideodec": { + "author": "Julien Isorce ", + "description": "Fake video decoder", + "hierarchy": [ + "GstFakeVideoDec", + "GstVideoDecoder", + "GstElement", + "GstObject", + "GInitiallyUnowned", + "GObject" + ], + "klass": "Codec/Decoder/Video", + "pad-templates": { + "sink": { + "caps": "video/x-h264:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\n parsed: true\nvideo/x-h263:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\n parsed: true\nvideo/x-theora:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-vp6:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-vp6-flash:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-vp8:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-vp9:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-divx:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-msmpeg:\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/mpeg:\n mpegversion: { (int)1, (int)2, (int)4 }\n systemstream: false\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-flash-video:\n flvversion: 1\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-raw:\n format: { RGBA, RGBx, BGRA, BGRx, RGB16 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\nvideo/x-wmv:\n wmvversion: { (int)1, (int)2, (int)3 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 1/1, 2147483647/1 ]\n", + "direction": "sink", + "presence": "always" + }, + "src": { + "caps": "video/x-raw:\n format: { RGBA, RGBx, BGRA, BGRx, RGB16 }\n width: [ 1, 2147483647 ]\n height: [ 1, 2147483647 ]\n framerate: [ 0/1, 2147483647/1 ]\n", + "direction": "src", + "presence": "always" + } + }, + "rank": "none" + } + }, + "filename": "gstbasedebug", + "license": "LGPL", + "other-types": {}, + "package": "GStreamer Base Plug-ins", + "source": "gst-plugins-base", + "tracers": {}, + "url": "Unknown package origin" + }, "cdparanoia": { "description": "Read audio from CD in paranoid mode", "elements": { diff --git a/subprojects/gst-plugins-base/gst/debugutils/gstdebug.c b/subprojects/gst-plugins-base/gst/debugutils/gstdebug.c new file mode 100644 index 0000000000..15c9b0c44e --- /dev/null +++ b/subprojects/gst-plugins-base/gst/debugutils/gstdebug.c @@ -0,0 +1,53 @@ +/* GStreamer + * Copyright (C) 2004 Benjamin Otte + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * @Author: Stéphane Cerveau + * + * 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 the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +/** + * plugin-basedebug: + * @short_description: elements for testing and debugging + * + * This plugin contains elements that are useful for debugging and testing + * purposes. + * + * Since: 1.24 + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include "gstdebugutilselements.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret = FALSE; + + ret |= GST_ELEMENT_REGISTER (fakevideodec, plugin); + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + basedebug, + "elements for testing and debugging", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/subprojects/gst-plugins-base/gst/debugutils/gstdebugutilselements.h b/subprojects/gst-plugins-base/gst/debugutils/gstdebugutilselements.h new file mode 100644 index 0000000000..03c3232d4a --- /dev/null +++ b/subprojects/gst-plugins-base/gst/debugutils/gstdebugutilselements.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004 Benjamin Otte + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * @Author: Stéphane Cerveau + * + * 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 the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_DEBUGUTILS_ELEMENTS_H__ +#define __GST_DEBUGUTILS_ELEMENTS_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +G_BEGIN_DECLS + +GST_ELEMENT_REGISTER_DECLARE (fakevideodec); + +G_END_DECLS + +#endif /* __GST_DEBUGUTILS_ELEMENTS_H__ */ diff --git a/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.c b/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.c new file mode 100644 index 0000000000..cebb2f1607 --- /dev/null +++ b/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.c @@ -0,0 +1,474 @@ +/* GStreamer + * Copyright (C) 2019 Julien Isorce + * Copyright (C) 2023 Thibault Saunier + * + * 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 the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ +/** + * element-fakevideodec: + * + * The fake video decoder ignores input bitstream except + * to enforce caps restrictions. It reads video `width`, + * `height` and `framerate` from caps. Then it just pushes + * video frames without doing any decoding. It can Also + * handle raw frames decoding them as they come, faking + * that it is decoding them. + * + * When faking decoding encoded data, it draws a snake moving from + * left to right in the middle of the frame. This is a + * light weight drawing while it still provides an idea + * about how smooth is the rendering. + * + * The fake video decoder inherits from GstVideoDecoder. + * It is useful to measure how smooth will be the whole + * rendering pipeline if you had the most efficient video + * decoder. Also useful to bisect issues for example when + * suspecting issues in a specific video decoder. + * + * It is also useful to to use it to test the #GstVideoDecoder base + * class. + * + * ## Examples: + * + * ### Fake decoding raw frames + * + * ``` + * $ gst-launch-1.0 videotestsrc ! fakevideodec ! videoconvert ! autovideosink + * ``` + * + * ### False decoding encoded framers + * + * ``` + * $ GST_PLUGIN_FEATURE_RANK=fakevideodec:1000 gstdump gst-launch-1.0 playbin3 uri=file:///path/to/video + * + * ``` + * Since: 1.24 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstfakevideodec.h" + +#include +#include + +#include +#include + + +GST_DEBUG_CATEGORY_STATIC (gst_fake_videodec_debug); +#define GST_CAT_DEFAULT gst_fake_videodec_debug + +static gboolean gst_fake_video_dec_start (GstVideoDecoder * decoder); +static gboolean gst_fake_video_dec_stop (GstVideoDecoder * decoder); +static gboolean gst_fake_video_dec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state); +static gboolean gst_fake_video_dec_negotiate (GstVideoDecoder * decoder); +static gboolean gst_fake_video_dec_flush (GstVideoDecoder * decoder); +static GstFlowReturn gst_fake_video_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame); +static gboolean gst_fake_video_dec_decide_allocation (GstVideoDecoder * decoder, + GstQuery * query); + +#define FAKE_VIDEO_DEC_CAPS_COMMON ", width=(int) [1, MAX], height=(int) [1, MAX], framerate=(fraction) [1, MAX]" +#define FAKE_VIDEO_DEC_CAPS_COMMON_PARSED FAKE_VIDEO_DEC_CAPS_COMMON ", parsed = (boolean) true" +#define FAKE_VIDEO_DEC_CAPS "video/x-h264" FAKE_VIDEO_DEC_CAPS_COMMON_PARSED ";" \ + "video/x-h263" FAKE_VIDEO_DEC_CAPS_COMMON_PARSED ";" \ + "video/x-theora" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-vp6" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-vp6-flash" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-vp8" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-vp9" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-divx" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-msmpeg" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/mpeg, mpegversion=(int) {1, 2, 4}, systemstream=(boolean) false" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-flash-video, flvversion=(int) 1" FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-raw,format={ RGBA, RGBx, BGRA, BGRx, RGB16} " FAKE_VIDEO_DEC_CAPS_COMMON ";" \ + "video/x-wmv, wmvversion=(int) {1, 2, 3}" FAKE_VIDEO_DEC_CAPS_COMMON + +static GstStaticPadTemplate gst_fake_video_dec_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (FAKE_VIDEO_DEC_CAPS) + ); + +static GstStaticPadTemplate gst_fake_video_dec_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGBx, BGRA, BGRx, RGB16}")) + ); + +#define parent_class gst_fake_video_dec_parent_class +G_DEFINE_TYPE (GstFakeVideoDec, gst_fake_video_dec, GST_TYPE_VIDEO_DECODER); +GST_ELEMENT_REGISTER_DEFINE (fakevideodec, "fakevideodec", + GST_RANK_NONE, gst_fake_video_dec_get_type ()); + +static void +gst_fake_video_dec_class_init (GstFakeVideoDecClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstVideoDecoderClass *base_video_decoder_class = + GST_VIDEO_DECODER_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_fake_video_dec_src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_fake_video_dec_sink_template)); + + gst_element_class_set_static_metadata (element_class, + "Fake Video Decoder", + "Codec/Decoder/Video", + "Fake video decoder", "Julien Isorce "); + + base_video_decoder_class->start = + GST_DEBUG_FUNCPTR (gst_fake_video_dec_start); + base_video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_fake_video_dec_stop); + base_video_decoder_class->flush = + GST_DEBUG_FUNCPTR (gst_fake_video_dec_flush); + base_video_decoder_class->set_format = + GST_DEBUG_FUNCPTR (gst_fake_video_dec_set_format); + base_video_decoder_class->negotiate = + GST_DEBUG_FUNCPTR (gst_fake_video_dec_negotiate); + base_video_decoder_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_fake_video_dec_handle_frame); + base_video_decoder_class->decide_allocation = + gst_fake_video_dec_decide_allocation; + + GST_DEBUG_CATEGORY_INIT (gst_fake_videodec_debug, "fakevideodec", 0, + "Fake Video Decoder"); +} + +static void +gst_fake_video_dec_init (GstFakeVideoDec * dec) +{ + GstVideoDecoder *bdec = GST_VIDEO_DECODER (dec); + + GST_DEBUG_OBJECT (dec, "Initialize fake video decoder"); + + gst_video_decoder_set_packetized (bdec, TRUE); + dec->min_buffers = 0; + dec->snake_current_step = 0; + dec->snake_max_steps = 0; + dec->snake_length = 0; +} + +static gboolean +gst_fake_video_dec_start (GstVideoDecoder * decoder) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (decoder); + + GST_DEBUG_OBJECT (dec, "start"); + + dec->min_buffers = 0; + dec->snake_current_step = 0; + + return TRUE; +} + +static gboolean +gst_fake_video_dec_stop (GstVideoDecoder * base_video_decoder) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (base_video_decoder); + + GST_DEBUG_OBJECT (dec, "stop"); + + if (dec->output_state) { + gst_video_codec_state_unref (dec->output_state); + dec->output_state = NULL; + } + + if (dec->input_state) { + gst_video_codec_state_unref (dec->input_state); + dec->input_state = NULL; + } + + return TRUE; +} + +static gboolean +gst_fake_video_dec_set_format (GstVideoDecoder * decoder, + GstVideoCodecState * state) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (decoder); + GstCaps *templ_caps = NULL; + GstCaps *intersection = NULL; + GstVideoInfo info; + gdouble fps = 0; + + GST_DEBUG_OBJECT (dec, "set format"); + + /* select what downstream want of support the best */ + + templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (dec)); + intersection = + gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (dec), templ_caps); + gst_caps_unref (templ_caps); + + GST_DEBUG_OBJECT (dec, "Allowed downstream caps: %" GST_PTR_FORMAT, + intersection); + + intersection = gst_caps_truncate (intersection); + intersection = gst_caps_fixate (intersection); + + gst_video_info_init (&info); + if (!gst_video_info_from_caps (&info, intersection)) { + GST_WARNING_OBJECT (dec, + "failed to parse intersection with downstream caps %" GST_PTR_FORMAT, + intersection); + gst_caps_unref (intersection); + return FALSE; + } + gst_caps_unref (intersection); + intersection = NULL; + + if (dec->input_state) + gst_video_codec_state_unref (dec->input_state); + dec->input_state = gst_video_codec_state_ref (state); + + dec->output_state = + gst_video_decoder_set_output_state (GST_VIDEO_DECODER (dec), + GST_VIDEO_INFO_FORMAT (&info), dec->input_state->info.width, + dec->input_state->info.height, dec->input_state); + gst_video_decoder_negotiate (GST_VIDEO_DECODER (dec)); + + gst_util_fraction_to_double (dec->output_state->info.fps_n, + dec->output_state->info.fps_d, &fps); + + if (fps < 1 || fps > 60) { + GST_ERROR_OBJECT (dec, "unsupported framerate %d / %d", + dec->output_state->info.fps_n, dec->output_state->info.fps_d); + return FALSE; + } + + dec->snake_max_steps = (guint) fps; + dec->snake_length = dec->output_state->info.width / fps; + + if (dec->snake_length == 0) { + GST_ERROR_OBJECT (dec, + "unsupported framerate %d / %d or frame width too small %d", + dec->output_state->info.fps_n, dec->output_state->info.fps_d, + dec->output_state->info.width); + return FALSE; + } + + GST_DEBUG_OBJECT (dec, + "width: %d, height: %d, fps_n: %d, fps_d: %d, snake length %d", + dec->output_state->info.width, dec->output_state->info.height, + dec->output_state->info.fps_n, dec->output_state->info.fps_d, + dec->snake_length); + + return TRUE; +} + +static GstFlowReturn +gst_fake_video_dec_init_buffer (GstFakeVideoDec * dec, GstBuffer * buffer) +{ + GstMapInfo minfo; + + if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) { + GST_ERROR_OBJECT (dec, "Failed to map input buffer"); + return GST_FLOW_ERROR; + } + + /* Make the frames entirely black just once. */ + memset (minfo.data, 0, minfo.maxsize); + + gst_buffer_unmap (buffer, &minfo); + + return GST_FLOW_OK; +} + +static gboolean +gst_fake_video_dec_negotiate (GstVideoDecoder * decoder) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (decoder); + GstVideoCodecFrame *frame = NULL; + gboolean ret = TRUE; + guint i = 0; + + if (!GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) + return FALSE; + + GST_DEBUG_OBJECT (dec, "negotiate"); + + frame = g_slice_new0 (GstVideoCodecFrame); + + for (i = 0; i < dec->min_buffers; ++i) { + ret = + gst_video_decoder_allocate_output_frame (decoder, frame) == GST_FLOW_OK; + if (!ret) + break; + gst_fake_video_dec_init_buffer (dec, frame->output_buffer); + gst_buffer_replace (&frame->output_buffer, NULL); + } + + g_slice_free (GstVideoCodecFrame, frame); + + return ret; +} + +static gboolean +gst_fake_video_dec_flush (GstVideoDecoder * decoder) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (decoder); + + GST_DEBUG_OBJECT (dec, "flush"); + + return TRUE; +} + +static void +gst_fake_video_dec_snake_next_step (GstFakeVideoDec * dec) +{ + if (dec->snake_current_step < dec->snake_max_steps) { + ++dec->snake_current_step; + return; + } + + dec->snake_current_step = 0; +} + +static GstFlowReturn +gst_fake_video_dec_fill_buffer (GstFakeVideoDec * dec, GstBuffer * buffer) +{ + gint height = 0; + guint offset = 0; + gint stride = 0; + guint depth = 0; + guint8 *data = NULL; + GstVideoFrame frame; + GstVideoInfo *info = &dec->output_state->info; + + if (!gst_video_frame_map (&frame, info, buffer, GST_MAP_WRITE)) { + GST_ERROR_OBJECT (dec, "Could not map video buffer"); + return GST_FLOW_ERROR; + } + + if (GST_VIDEO_FRAME_N_PLANES (&frame) != 1) { + GST_ERROR_OBJECT (dec, "Currently only support one video frame plane"); + gst_video_frame_unmap (&frame); + return GST_FLOW_ERROR; + } + + height = GST_VIDEO_FRAME_HEIGHT (&frame); + data = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0); + offset = GST_VIDEO_FRAME_PLANE_OFFSET (&frame, 0); + stride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0); + depth = GST_VIDEO_FRAME_COMP_DEPTH (&frame, 0); + + switch (GST_VIDEO_FRAME_FORMAT (&frame)) { + case GST_VIDEO_FORMAT_BGRA: + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_RGB16: + { + /* Erase the entire line where the snake is drawn. */ + memset (data + offset + (height / 2) * stride, 0, stride * depth); + /* Draw a snake moving from left to right. */ + memset (data + offset + (height / 2) * stride + + dec->snake_current_step * dec->snake_length * depth, 0xff, + dec->snake_length * depth); + break; + } + default: + GST_WARNING_OBJECT (dec, "Not supported video format %s", + gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (&frame))); + break; + } + + gst_video_frame_unmap (&frame); + + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_fake_video_dec_handle_frame (GstVideoDecoder * decoder, + GstVideoCodecFrame * frame) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (decoder); + GstFlowReturn ret = GST_FLOW_OK; + GstMapInfo minfo; + + GST_DEBUG_OBJECT (dec, "handle frame"); + + if (dec->input_state->info.finfo->format == GST_VIDEO_FORMAT_ENCODED) { + if (!gst_buffer_map (frame->input_buffer, &minfo, GST_MAP_READ)) { + GST_ERROR_OBJECT (dec, "Failed to map input buffer"); + return GST_FLOW_ERROR; + } + + GST_DEBUG_OBJECT (dec, + "input data size %" G_GSIZE_FORMAT ", PTS: %" GST_TIME_FORMAT, + minfo.size, GST_TIME_ARGS (frame->pts)); + + gst_buffer_unmap (frame->input_buffer, &minfo); + + gst_fake_video_dec_snake_next_step (dec); + ret = gst_video_decoder_allocate_output_frame (decoder, frame); + if (ret != GST_FLOW_OK) + goto drop; + ret = gst_fake_video_dec_fill_buffer (dec, frame->output_buffer); + if (ret != GST_FLOW_OK) + goto drop; + } else { + frame->output_buffer = gst_buffer_ref (frame->input_buffer); + } + + ret = gst_video_decoder_finish_frame (decoder, frame); + return ret; + +drop: + gst_video_decoder_drop_frame (decoder, frame); + return ret; +} + +static gboolean +gst_fake_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) +{ + GstFakeVideoDec *dec = GST_FAKE_VIDEO_DEC (bdec); + GstBufferPool *pool = NULL; + GstStructure *config = NULL; + guint min_buffers = 0; + + if (!GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation (bdec, query)) + return FALSE; + + GST_DEBUG_OBJECT (dec, "decide allocation"); + + g_assert (gst_query_get_n_allocation_pools (query) > 0); + gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, &min_buffers, + NULL); + g_assert (pool != NULL); + + /* Initialize at least 2 buffers. */ + dec->min_buffers = MIN (min_buffers, 2); + + config = gst_buffer_pool_get_config (pool); + if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { + gst_buffer_pool_config_add_option (config, + GST_BUFFER_POOL_OPTION_VIDEO_META); + } + gst_buffer_pool_set_config (pool, config); + gst_object_unref (pool); + + return TRUE; +} diff --git a/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.h b/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.h new file mode 100644 index 0000000000..72deebf157 --- /dev/null +++ b/subprojects/gst-plugins-base/gst/debugutils/gstfakevideodec.h @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) 2019 Julien Isorce + * + * 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 the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + +#ifndef __GST_FAKE_VIDEO_DEC_H__ +#define __GST_FAKE_VIDEO_DEC_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "gstdebugutilselements.h" + +G_BEGIN_DECLS +#define GST_TYPE_FAKE_VIDEO_DEC \ + (gst_fake_video_dec_get_type()) +#define GST_FAKE_VIDEO_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FAKE_VIDEO_DEC,GstFakeVideoDec)) +#define GST_FAKE_VIDEO_DEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FAKE_VIDEO_DEC,GstFakeVideoDecClass)) +#define GST_IS_FAKE_VIDEO_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FAKE_VIDEO_DEC)) +#define GST_IS_FAKE_VIDEO_DEC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FAKE_VIDEO_DEC)) +typedef struct _GstFakeVideoDec GstFakeVideoDec; +typedef struct _GstFakeVideoDecClass GstFakeVideoDecClass; + +struct _GstFakeVideoDec +{ + GstVideoDecoder base_video_decoder; + + GstVideoCodecState *input_state; + GstVideoCodecState *output_state; + + guint min_buffers; + guint snake_current_step; + guint snake_max_steps; + guint snake_length; +}; + +struct _GstFakeVideoDecClass +{ + GstVideoDecoderClass base_video_decoder_class; +}; + +GType gst_fake_video_dec_get_type (void); + +G_END_DECLS +#endif /* __GST_FAKE_VIDEO_DEC_H__ */ diff --git a/subprojects/gst-plugins-base/gst/debugutils/meson.build b/subprojects/gst-plugins-base/gst/debugutils/meson.build new file mode 100644 index 0000000000..48d04bf360 --- /dev/null +++ b/subprojects/gst-plugins-base/gst/debugutils/meson.build @@ -0,0 +1,11 @@ +gstdebug = library('gstbasedebug', + 'gstdebug.c', + 'gstfakevideodec.c', + c_args: gst_plugins_base_args, + include_directories : [configinc], + dependencies : [gst_dep, gst_base_dep, video_dep], + install : true, + install_dir : plugins_install_dir, +) +plugins += [gstdebug] + diff --git a/subprojects/gst-plugins-base/gst/meson.build b/subprojects/gst-plugins-base/gst/meson.build index 0dc44cd519..185cc493d2 100644 --- a/subprojects/gst-plugins-base/gst/meson.build +++ b/subprojects/gst-plugins-base/gst/meson.build @@ -1,5 +1,5 @@ foreach plugin : ['adder', 'app', 'audioconvert', 'audiomixer', 'audiorate', 'audioresample', - 'audiotestsrc', 'compositor', 'dsd', 'encoding', 'gio', 'overlaycomposition', + 'audiotestsrc', 'compositor', 'dsd', 'debugutils', 'encoding', 'gio', 'overlaycomposition', 'pbtypes', 'playback', 'rawparse', 'subparse', 'tcp', 'typefind', 'videoconvertscale', 'videorate', 'videotestsrc', 'volume'] if not get_option(plugin).disabled() diff --git a/subprojects/gst-plugins-base/meson_options.txt b/subprojects/gst-plugins-base/meson_options.txt index 45d0fed0aa..0f307b21dc 100644 --- a/subprojects/gst-plugins-base/meson_options.txt +++ b/subprojects/gst-plugins-base/meson_options.txt @@ -36,6 +36,7 @@ option('audiorate', type : 'feature', value : 'auto') option('audioresample', type : 'feature', value : 'auto') option('audiotestsrc', type : 'feature', value : 'auto') option('compositor', type : 'feature', value : 'auto') +option('debugutils', type : 'feature', value : 'auto') option('drm', type : 'feature', value : 'auto') option('dsd', type : 'feature', value : 'auto') option('encoding', type : 'feature', value : 'auto')