mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 03:19:40 +00:00
validate: Check all buffers when we have the info from MediaDescriptor
We now check that each buffer is the expected one for each buffer that come into the decoder. + Fix some minor leaks in test-utils https://bugzilla.gnome.org/show_bug.cgi?id=736138
This commit is contained in:
parent
cd9a3640b2
commit
bb93dbb9fb
8 changed files with 555 additions and 16 deletions
|
@ -1471,6 +1471,94 @@ mark_pads_eos (GstValidatePadMonitor *pad_monitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
_should_check_buffers (GstValidatePadMonitor * pad_monitor,
|
||||||
|
gboolean force_checks)
|
||||||
|
{
|
||||||
|
GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
|
||||||
|
GstValidateMonitor *monitor = GST_VALIDATE_MONITOR (pad_monitor);
|
||||||
|
|
||||||
|
if (pad_monitor->first_buffer || force_checks) {
|
||||||
|
if (pad_monitor->segment.rate != 1.0) {
|
||||||
|
GST_INFO_OBJECT (pad_monitor, "We do not support buffer checking"
|
||||||
|
" for trick modes");
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (!PAD_PARENT_IS_DECODER (pad_monitor)) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "Not on a decoder => no buffer checking");
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (GST_PAD_DIRECTION (pad) != GST_PAD_SINK) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "Not a sinkpad => no buffer checking");
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (!pad_monitor->caps_is_video) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "Not working with video => no buffer checking");
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (monitor->media_descriptor == NULL) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "No media_descriptor set => no buffer checking");
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (!gst_media_descriptor_detects_frames (monitor->media_descriptor)) {
|
||||||
|
GST_DEBUG_OBJECT (pad, "No frame detection media descriptor "
|
||||||
|
"=> not buffer checking");
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else if (pad_monitor->all_bufs == NULL &&
|
||||||
|
!gst_media_descriptor_get_buffers (monitor->media_descriptor, pad, NULL,
|
||||||
|
&pad_monitor->all_bufs)) {
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (monitor,
|
||||||
|
"The MediaInfo is marked as detecting frame, but getting frames"
|
||||||
|
" from pad %" GST_PTR_FORMAT " did not work (some format conversion"
|
||||||
|
" might be happening)", pad);
|
||||||
|
|
||||||
|
pad_monitor->check_buffers = FALSE;
|
||||||
|
} else {
|
||||||
|
if (!pad_monitor->current_buf)
|
||||||
|
pad_monitor->current_buf = pad_monitor->all_bufs;
|
||||||
|
pad_monitor->check_buffers = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pad_monitor->check_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_validate_monitor_find_next_buffer (GstValidatePadMonitor * pad_monitor)
|
||||||
|
{
|
||||||
|
GList *tmp;
|
||||||
|
gboolean passed_start = FALSE;
|
||||||
|
|
||||||
|
if (!_should_check_buffers (pad_monitor, TRUE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (tmp = g_list_last (pad_monitor->all_bufs); tmp; tmp = tmp->prev) {
|
||||||
|
GstBuffer *cbuf = tmp->data;
|
||||||
|
GstClockTime ts =
|
||||||
|
GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DTS (cbuf)) ? GST_BUFFER_DTS (cbuf)
|
||||||
|
: GST_BUFFER_PTS (cbuf);
|
||||||
|
|
||||||
|
if (!GST_CLOCK_TIME_IS_VALID (ts))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ts <= pad_monitor->segment.start)
|
||||||
|
passed_start = TRUE;
|
||||||
|
|
||||||
|
if (!passed_start)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!GST_BUFFER_FLAG_IS_SET (cbuf, GST_BUFFER_FLAG_DELTA_UNIT)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp == NULL)
|
||||||
|
pad_monitor->current_buf = pad_monitor->all_bufs;
|
||||||
|
else
|
||||||
|
pad_monitor->current_buf = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
|
gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
|
||||||
pad_monitor, GstObject * parent, GstEvent * event,
|
pad_monitor, GstObject * parent, GstEvent * event,
|
||||||
|
@ -1582,6 +1670,7 @@ gst_validate_pad_monitor_downstream_event_check (GstValidatePadMonitor *
|
||||||
}
|
}
|
||||||
gst_segment_copy_into (segment, &pad_monitor->segment);
|
gst_segment_copy_into (segment, &pad_monitor->segment);
|
||||||
pad_monitor->has_segment = TRUE;
|
pad_monitor->has_segment = TRUE;
|
||||||
|
gst_validate_monitor_find_next_buffer (pad_monitor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_EVENT_CAPS:{
|
case GST_EVENT_CAPS:{
|
||||||
|
@ -1685,6 +1774,90 @@ gst_validate_pad_monitor_src_event_check (GstValidatePadMonitor * pad_monitor,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_validate_pad_monitor_check_right_buffer (GstValidatePadMonitor *
|
||||||
|
pad_monitor, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
gchar *checksum;
|
||||||
|
GstBuffer *wanted_buf;
|
||||||
|
GstMapInfo map, wanted_map;
|
||||||
|
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
GstPad *pad = GST_VALIDATE_PAD_MONITOR_GET_PAD (pad_monitor);
|
||||||
|
|
||||||
|
if (_should_check_buffers (pad_monitor, FALSE) == FALSE)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (pad_monitor->current_buf == NULL) {
|
||||||
|
GST_INFO_OBJECT (pad, "No current buffer one pad, Why?");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
wanted_buf = pad_monitor->current_buf->data;
|
||||||
|
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (wanted_buf)) &&
|
||||||
|
GST_CLOCK_TIME_IS_VALID (GST_BUFFER_PTS (buffer)) &&
|
||||||
|
GST_BUFFER_PTS (wanted_buf) != GST_BUFFER_PTS (buffer)) {
|
||||||
|
|
||||||
|
GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
|
||||||
|
"buffer %" GST_PTR_FORMAT " PTS %ld"
|
||||||
|
" different than expected: %ld", buffer,
|
||||||
|
GST_BUFFER_PTS (buffer), GST_BUFFER_PTS (wanted_buf));
|
||||||
|
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_BUFFER_DTS (wanted_buf) != GST_BUFFER_DTS (buffer)) {
|
||||||
|
GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
|
||||||
|
"buffer %" GST_PTR_FORMAT " DTS %" GST_TIME_FORMAT
|
||||||
|
" different than expected: %" GST_TIME_FORMAT, buffer,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DTS (buffer)),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DTS (wanted_buf)));
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_BUFFER_DURATION (wanted_buf) != GST_BUFFER_DURATION (buffer)) {
|
||||||
|
GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
|
||||||
|
"buffer %" GST_PTR_FORMAT " DURATION %" GST_TIME_FORMAT
|
||||||
|
" different than expected: %" GST_TIME_FORMAT, buffer,
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_DURATION (wanted_buf)));
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GST_BUFFER_FLAG_IS_SET (wanted_buf, GST_BUFFER_FLAG_DELTA_UNIT) !=
|
||||||
|
GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
|
||||||
|
GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
|
||||||
|
"buffer %" GST_PTR_FORMAT " Delta unit is set to %s but expected %s",
|
||||||
|
buffer, GST_BUFFER_FLAG_IS_SET (buffer,
|
||||||
|
GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False",
|
||||||
|
GST_BUFFER_FLAG_IS_SET (wanted_buf,
|
||||||
|
GST_BUFFER_FLAG_DELTA_UNIT) ? "True" : "False");
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (gst_buffer_map (wanted_buf, &wanted_map, GST_MAP_READ));
|
||||||
|
g_assert (gst_buffer_map (buffer, &map, GST_MAP_READ));
|
||||||
|
|
||||||
|
checksum = g_compute_checksum_for_data (G_CHECKSUM_MD5,
|
||||||
|
(const guchar *) map.data, map.size);
|
||||||
|
|
||||||
|
if (g_strcmp0 ((gchar *) wanted_map.data, checksum)) {
|
||||||
|
GST_VALIDATE_REPORT (pad_monitor, WRONG_BUFFER,
|
||||||
|
"buffer %" GST_PTR_FORMAT " checksum %s different from expected: %s",
|
||||||
|
buffer, checksum, wanted_map.data);
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_buffer_unmap (wanted_buf, &wanted_map);
|
||||||
|
gst_buffer_unmap (buffer, &map);
|
||||||
|
g_free (checksum);
|
||||||
|
|
||||||
|
pad_monitor->current_buf = pad_monitor->current_buf->next;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
|
gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
|
||||||
GstBuffer * buffer)
|
GstBuffer * buffer)
|
||||||
|
@ -1696,6 +1869,7 @@ gst_validate_pad_monitor_chain_func (GstPad * pad, GstObject * parent,
|
||||||
GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
|
GST_VALIDATE_PAD_MONITOR_PARENT_LOCK (pad_monitor);
|
||||||
GST_VALIDATE_MONITOR_LOCK (pad_monitor);
|
GST_VALIDATE_MONITOR_LOCK (pad_monitor);
|
||||||
|
|
||||||
|
gst_validate_pad_monitor_check_right_buffer (pad_monitor, buffer);
|
||||||
gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
|
gst_validate_pad_monitor_check_first_buffer (pad_monitor, buffer);
|
||||||
gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
|
gst_validate_pad_monitor_update_buffer_data (pad_monitor, buffer);
|
||||||
gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
|
gst_validate_pad_monitor_check_eos (pad_monitor, buffer);
|
||||||
|
|
|
@ -29,6 +29,7 @@ typedef struct _GstValidatePadMonitor GstValidatePadMonitor;
|
||||||
typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass;
|
typedef struct _GstValidatePadMonitorClass GstValidatePadMonitorClass;
|
||||||
|
|
||||||
#include <gst/validate/gst-validate-monitor.h>
|
#include <gst/validate/gst-validate-monitor.h>
|
||||||
|
#include <gst/validate/media-descriptor-parser.h>
|
||||||
#include <gst/validate/gst-validate-element-monitor.h>
|
#include <gst/validate/gst-validate-element-monitor.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
@ -110,6 +111,12 @@ struct _GstValidatePadMonitor {
|
||||||
*/
|
*/
|
||||||
GstClockTime timestamp_range_start;
|
GstClockTime timestamp_range_start;
|
||||||
GstClockTime timestamp_range_end;
|
GstClockTime timestamp_range_end;
|
||||||
|
|
||||||
|
/* GstMediaCheck related fields */
|
||||||
|
GList *all_bufs;
|
||||||
|
/* The GstBuffer that should arrive next in a GList */
|
||||||
|
GList *current_buf;
|
||||||
|
gboolean check_buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -130,6 +130,12 @@ gst_validate_report_load_issues (void)
|
||||||
REGISTER_VALIDATE_ISSUE (WARNING, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
|
REGISTER_VALIDATE_ISSUE (WARNING, FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
|
||||||
_("first buffer's running time isn't 0"),
|
_("first buffer's running time isn't 0"),
|
||||||
_("the first buffer's received running time is expected to be 0"));
|
_("the first buffer's received running time is expected to be 0"));
|
||||||
|
REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER,
|
||||||
|
_("Received buffer does not correspond to wanted one."),
|
||||||
|
_("When checking playback of a file against a MediaInfo file"
|
||||||
|
" all buffers coming into the decoders might be checked"
|
||||||
|
" and should have the exact expected metadatas and hash of the"
|
||||||
|
" content"));
|
||||||
REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN,
|
REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN,
|
||||||
_("flow return from pad push doesn't match expected value"),
|
_("flow return from pad push doesn't match expected value"),
|
||||||
_("flow return from a 1:1 sink/src pad element is as simple as "
|
_("flow return from a 1:1 sink/src pad element is as simple as "
|
||||||
|
|
|
@ -77,6 +77,7 @@ typedef enum {
|
||||||
#define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4)
|
#define GST_VALIDATE_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 4)
|
||||||
#define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5)
|
#define GST_VALIDATE_ISSUE_ID_WRONG_FLOW_RETURN (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 5)
|
||||||
#define GST_VALIDATE_ISSUE_ID_BUFFER_AFTER_EOS (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 6)
|
#define GST_VALIDATE_ISSUE_ID_BUFFER_AFTER_EOS (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 6)
|
||||||
|
#define GST_VALIDATE_ISSUE_ID_WRONG_BUFFER (((GstValidateIssueId) GST_VALIDATE_AREA_BUFFER) << GST_VALIDATE_ISSUE_ID_SHIFT | 7)
|
||||||
|
|
||||||
#define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
#define GST_VALIDATE_ISSUE_ID_CAPS_IS_MISSING_FIELD (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 1)
|
||||||
#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2)
|
#define GST_VALIDATE_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((GstValidateIssueId) GST_VALIDATE_AREA_CAPS) << GST_VALIDATE_ISSUE_ID_SHIFT | 2)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <gst/validate/validate.h>
|
#include <gst/validate/validate.h>
|
||||||
#include <gst/validate/gst-validate-pad-monitor.h>
|
#include <gst/validate/gst-validate-pad-monitor.h>
|
||||||
|
#include <gst/validate/media-descriptor-parser.h>
|
||||||
#include <gst/check/gstcheck.h>
|
#include <gst/check/gstcheck.h>
|
||||||
#include "test-utils.h"
|
#include "test-utils.h"
|
||||||
|
|
||||||
|
@ -545,6 +546,260 @@ GST_START_TEST (issue_concatenation)
|
||||||
check_destroyed (sink, sinkpad, NULL);
|
check_destroyed (sink, sinkpad, NULL);
|
||||||
check_destroyed (runner, NULL, NULL);
|
check_destroyed (runner, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
static const gchar * media_info =
|
||||||
|
"<file duration='10031000000' frame-detection='1' uri='file:///I/am/so/fake.fakery' seekable='true'>"
|
||||||
|
" <streams caps='video/quicktime'>"
|
||||||
|
" <stream type='video' caps='video/x-fake'>"
|
||||||
|
" <frame duration='1' id='0' is-keyframe='true' offset='18446744073709551615' offset-end='18446744073709551615' pts='0' dts='0' checksum='cfeb9b47da2bb540cd3fa84cffea4df9'/>" /* buffer1 */
|
||||||
|
" <frame duration='1' id='1' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='1' dts='1' checksum='e40d7cd997bd14462468d201f1e1a3d4'/>" /* buffer2 */
|
||||||
|
" <frame duration='1' id='2' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='2' dts='2' checksum='4136320f0da0738a06c787dce827f034'/>" /* buffer3 */
|
||||||
|
" <frame duration='1' id='3' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='3' dts='3' checksum='sure my dear'/>" /* gonna fail */
|
||||||
|
" <frame duration='1' id='4' is-keyframe='true' offset='18446744073709551615' offset-end='18446744073709551615' pts='4' dts='4' checksum='569d8927835c44fd4ff40b8408657f9e'/>" /* buffer4 */
|
||||||
|
" <frame duration='1' id='5' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='5' dts='5' checksum='fcea4caed9b2c610fac1f2a6b38b1d5f'/>" /* buffer5 */
|
||||||
|
" <frame duration='1' id='6' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='6' dts='6' checksum='c7536747446a1503b1d9b02744144fa9'/>" /* buffer6 */
|
||||||
|
" <frame duration='1' id='7' is-keyframe='false' offset='18446744073709551615' offset-end='18446744073709551615' pts='7' dts='7' checksum='sure my dear'/>" /* gonna fail */
|
||||||
|
" <tags>"
|
||||||
|
" </tags>"
|
||||||
|
" </stream>"
|
||||||
|
" </streams>"
|
||||||
|
"</file>";
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
typedef struct _BufferDesc
|
||||||
|
{
|
||||||
|
const gchar *content;
|
||||||
|
GstClockTime pts;
|
||||||
|
GstClockTime dts;
|
||||||
|
GstClockTime duration;
|
||||||
|
gboolean keyframe;
|
||||||
|
|
||||||
|
gint num_issues;
|
||||||
|
} BufferDesc;
|
||||||
|
|
||||||
|
static GstBuffer *
|
||||||
|
_create_buffer (BufferDesc * bdesc)
|
||||||
|
{
|
||||||
|
gchar *tmp = g_strdup (bdesc->content);
|
||||||
|
GstBuffer *buffer =
|
||||||
|
gst_buffer_new_wrapped (tmp, strlen (tmp) * sizeof (gchar));
|
||||||
|
|
||||||
|
GST_BUFFER_DTS (buffer) = bdesc->dts;
|
||||||
|
GST_BUFFER_PTS (buffer) = bdesc->pts;
|
||||||
|
GST_BUFFER_DURATION (buffer) = bdesc->duration;
|
||||||
|
|
||||||
|
if (bdesc->keyframe)
|
||||||
|
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
else
|
||||||
|
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_check_media_info (GstSegment * segment, BufferDesc * bufs)
|
||||||
|
{
|
||||||
|
GList *reports;
|
||||||
|
GstEvent *segev;
|
||||||
|
GstBuffer *buffer;
|
||||||
|
GstElement *decoder;
|
||||||
|
GstPad *srcpad, *sinkpad;
|
||||||
|
GstValidateReport *report;
|
||||||
|
GstValidateMonitor *monitor;
|
||||||
|
GstValidateRunner *runner;
|
||||||
|
GstMediaDescriptor *mdesc;
|
||||||
|
|
||||||
|
GError *err = NULL;
|
||||||
|
gint i, num_issues = 0;
|
||||||
|
|
||||||
|
fail_unless (g_setenv ("GST_VALIDATE_REPORT_LEVEL", "all", TRUE));
|
||||||
|
runner = gst_validate_runner_new ();
|
||||||
|
|
||||||
|
mdesc = (GstMediaDescriptor *)
|
||||||
|
gst_media_descriptor_parser_new_from_xml (runner, media_info, &err);
|
||||||
|
|
||||||
|
decoder = fake_decoder_new ();
|
||||||
|
monitor = gst_validate_monitor_factory_create (GST_OBJECT (decoder),
|
||||||
|
runner, NULL);
|
||||||
|
gst_validate_monitor_set_media_descriptor (monitor, mdesc);
|
||||||
|
|
||||||
|
srcpad = gst_pad_new ("src", GST_PAD_SRC);
|
||||||
|
sinkpad = decoder->sinkpads->data;
|
||||||
|
ASSERT_OBJECT_REFCOUNT (sinkpad, "decoder ref", 1);
|
||||||
|
fail_unless (gst_pad_activate_mode (srcpad, GST_PAD_MODE_PUSH, TRUE));
|
||||||
|
fail_unless_equals_int (gst_element_set_state (decoder, GST_STATE_PLAYING),
|
||||||
|
GST_STATE_CHANGE_SUCCESS);
|
||||||
|
|
||||||
|
assert_equals_string (gst_pad_link_get_name (gst_pad_link (srcpad, sinkpad)),
|
||||||
|
gst_pad_link_get_name (GST_PAD_LINK_OK));
|
||||||
|
|
||||||
|
gst_check_setup_events_with_stream_id (srcpad, decoder,
|
||||||
|
gst_caps_from_string ("video/x-fake"), GST_FORMAT_TIME, "the-stream");
|
||||||
|
|
||||||
|
|
||||||
|
if (segment) {
|
||||||
|
segev = gst_event_new_segment (segment);
|
||||||
|
fail_unless (gst_pad_push_event (srcpad, segev));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; bufs[i].content != NULL; i++) {
|
||||||
|
BufferDesc *buf = &bufs[i];
|
||||||
|
buffer = _create_buffer (buf);
|
||||||
|
|
||||||
|
assert_equals_string (gst_flow_get_name (gst_pad_push (srcpad, buffer)),
|
||||||
|
gst_flow_get_name (GST_FLOW_OK));
|
||||||
|
reports = gst_validate_runner_get_reports (runner);
|
||||||
|
|
||||||
|
num_issues += buf->num_issues;
|
||||||
|
assert_equals_int (g_list_length (reports), num_issues);
|
||||||
|
|
||||||
|
if (buf->num_issues) {
|
||||||
|
GList *tmp = g_list_nth (reports, num_issues - buf->num_issues);
|
||||||
|
|
||||||
|
while (tmp) {
|
||||||
|
report = tmp->data;
|
||||||
|
|
||||||
|
fail_unless_equals_int (report->level,
|
||||||
|
GST_VALIDATE_REPORT_LEVEL_WARNING);
|
||||||
|
fail_unless_equals_int (report->issue->issue_id,
|
||||||
|
GST_VALIDATE_ISSUE_ID_WRONG_BUFFER);
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
fail_unless (gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, FALSE));
|
||||||
|
fail_unless_equals_int (gst_element_set_state (decoder, GST_STATE_NULL),
|
||||||
|
GST_STATE_CHANGE_SUCCESS);
|
||||||
|
|
||||||
|
gst_object_unref (srcpad);
|
||||||
|
check_destroyed (decoder, sinkpad, NULL);
|
||||||
|
check_destroyed (runner, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (check_media_info)
|
||||||
|
{
|
||||||
|
GstSegment segment;
|
||||||
|
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
_check_media_info (NULL,
|
||||||
|
(BufferDesc []) {
|
||||||
|
{
|
||||||
|
.content = "buffer1",
|
||||||
|
.pts = 0,
|
||||||
|
.dts = 0,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = TRUE,
|
||||||
|
.num_issues = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.content = "buffer2",
|
||||||
|
.pts = 1,
|
||||||
|
.dts = 1,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = FALSE,
|
||||||
|
.num_issues = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.content = "buffer3",
|
||||||
|
.pts = 2,
|
||||||
|
.dts = 2,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = FALSE,
|
||||||
|
.num_issues = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.content = "fail please",
|
||||||
|
.pts = 3,
|
||||||
|
.dts = 3,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = FALSE,
|
||||||
|
.num_issues = 1
|
||||||
|
},
|
||||||
|
{ NULL}
|
||||||
|
});
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||||
|
/* Segment start is 2, the first buffer is expected (first Keyframe) */
|
||||||
|
segment.start = 2;
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
_check_media_info (&segment,
|
||||||
|
(BufferDesc []) {
|
||||||
|
{
|
||||||
|
.content = "buffer2", /* Wrong checksum */
|
||||||
|
.pts = 0,
|
||||||
|
.dts = 0,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = TRUE,
|
||||||
|
.num_issues = 1
|
||||||
|
},
|
||||||
|
{ NULL}
|
||||||
|
});
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||||
|
/* Segment start is 2, the first buffer is expected (first Keyframe) */
|
||||||
|
segment.start = 2;
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
_check_media_info (&segment,
|
||||||
|
(BufferDesc []) {
|
||||||
|
{ /* The right first buffer */
|
||||||
|
.content = "buffer1",
|
||||||
|
.pts = 0,
|
||||||
|
.dts = 0,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = TRUE,
|
||||||
|
.num_issues = 0
|
||||||
|
},
|
||||||
|
{ NULL}
|
||||||
|
});
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||||
|
/* Segment start is 6, the 4th buffer is expected (first Keyframe) */
|
||||||
|
segment.start = 6;
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
_check_media_info (&segment,
|
||||||
|
(BufferDesc []) {
|
||||||
|
{ /* The right fourth buffer */
|
||||||
|
.content = "buffer4",
|
||||||
|
.pts = 4,
|
||||||
|
.dts = 4,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = TRUE,
|
||||||
|
.num_issues = 0
|
||||||
|
},
|
||||||
|
{ NULL}
|
||||||
|
});
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||||
|
/* Segment start is 6, the 4th buffer is expected (first Keyframe) */
|
||||||
|
segment.start = 6;
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
_check_media_info (&segment,
|
||||||
|
(BufferDesc []) {
|
||||||
|
{ /* The sixth buffer... all wrong! */
|
||||||
|
.content = "buffer6",
|
||||||
|
.pts = 6,
|
||||||
|
.dts = 6,
|
||||||
|
.duration = 1,
|
||||||
|
.keyframe = FALSE,
|
||||||
|
.num_issues = 1
|
||||||
|
},
|
||||||
|
{ NULL}
|
||||||
|
});
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
}
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
@ -562,6 +817,7 @@ gst_validate_suite (void)
|
||||||
tcase_add_test (tc_chain, first_buffer_running_time);
|
tcase_add_test (tc_chain, first_buffer_running_time);
|
||||||
tcase_add_test (tc_chain, flow_aggregation);
|
tcase_add_test (tc_chain, flow_aggregation);
|
||||||
tcase_add_test (tc_chain, issue_concatenation);
|
tcase_add_test (tc_chain, issue_concatenation);
|
||||||
|
tcase_add_test (tc_chain, check_media_info);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,18 +102,8 @@ GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_STATIC_CAPS ("something")
|
GST_STATIC_CAPS ("something")
|
||||||
);
|
);
|
||||||
|
|
||||||
static void
|
|
||||||
fake_demuxer_dispose (FakeDemuxer * self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fake_demuxer_finalize (FakeDemuxer * self)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
_chain (GstPad * pad, GstObject * self, GstBuffer * buffer)
|
_demuxer_chain (GstPad * pad, GstObject * self, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
gst_buffer_unref (buffer);
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
@ -146,18 +136,14 @@ fake_demuxer_init (FakeDemuxer * self, gpointer * g_class)
|
||||||
|
|
||||||
self->return_value = GST_FLOW_OK;
|
self->return_value = GST_FLOW_OK;
|
||||||
|
|
||||||
gst_pad_set_chain_function (pad, _chain);
|
gst_pad_set_chain_function (pad, _demuxer_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fake_demuxer_class_init (FakeDemuxerClass * self_class)
|
fake_demuxer_class_init (FakeDemuxerClass * self_class)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (self_class);
|
|
||||||
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class);
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class);
|
||||||
|
|
||||||
object_class->dispose = (void (*)(GObject * object)) fake_demuxer_dispose;
|
|
||||||
object_class->finalize = (void (*)(GObject * object)) fake_demuxer_finalize;
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (gstelement_class,
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
gst_static_pad_template_get (&fake_demuxer_src_template));
|
gst_static_pad_template_get (&fake_demuxer_src_template));
|
||||||
gst_element_class_add_pad_template (gstelement_class,
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
@ -222,3 +208,91 @@ free_element_monitor (GstElement *element)
|
||||||
|
|
||||||
g_object_unref (G_OBJECT(monitor));
|
g_object_unref (G_OBJECT(monitor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstStaticPadTemplate fake_decoder_src_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
|
GST_PAD_SRC,
|
||||||
|
GST_PAD_SOMETIMES,
|
||||||
|
GST_STATIC_CAPS ("video/x-fake")
|
||||||
|
);
|
||||||
|
|
||||||
|
static GstStaticPadTemplate fake_decoder_sink_template =
|
||||||
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
GST_PAD_SINK,
|
||||||
|
GST_PAD_ALWAYS,
|
||||||
|
GST_STATIC_CAPS ("video/x-fake")
|
||||||
|
);
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
_decoder_chain (GstPad * pad, GstObject * self, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
gst_buffer_unref (buffer);
|
||||||
|
|
||||||
|
return FAKE_DECODER (self)->return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fake_decoder_init (FakeDecoder * self, gpointer * g_class)
|
||||||
|
{
|
||||||
|
GstPad *pad;
|
||||||
|
GstElement *element = GST_ELEMENT (self);
|
||||||
|
GstPadTemplate *pad_template;
|
||||||
|
|
||||||
|
pad_template =
|
||||||
|
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
|
||||||
|
pad = gst_pad_new_from_template (pad_template, "src");
|
||||||
|
gst_element_add_pad (element, pad);
|
||||||
|
|
||||||
|
pad_template =
|
||||||
|
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
|
||||||
|
pad = gst_pad_new_from_template (pad_template, "sink");
|
||||||
|
gst_element_add_pad (element, pad);
|
||||||
|
|
||||||
|
self->return_value = GST_FLOW_OK;
|
||||||
|
|
||||||
|
gst_pad_set_chain_function (pad, _decoder_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fake_decoder_class_init (FakeDecoderClass * self_class)
|
||||||
|
{
|
||||||
|
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (self_class);
|
||||||
|
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&fake_decoder_src_template));
|
||||||
|
gst_element_class_add_pad_template (gstelement_class,
|
||||||
|
gst_static_pad_template_get (&fake_decoder_sink_template));
|
||||||
|
gst_element_class_set_static_metadata (gstelement_class,
|
||||||
|
"Fake Decoder", "Decoder", "Some decoder", "Thibault Saunier");
|
||||||
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
fake_decoder_get_type (void)
|
||||||
|
{
|
||||||
|
static volatile gsize type = 0;
|
||||||
|
|
||||||
|
if (g_once_init_enter (&type)) {
|
||||||
|
GType _type;
|
||||||
|
static const GTypeInfo info = {
|
||||||
|
sizeof (FakeDecoderClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(GClassInitFunc) fake_decoder_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (FakeDecoder),
|
||||||
|
0,
|
||||||
|
(GInstanceInitFunc) fake_decoder_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
_type = g_type_register_static (GST_TYPE_ELEMENT, "FakeDecoder", &info, 0);
|
||||||
|
g_once_init_leave (&type, _type);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstElement *
|
||||||
|
fake_decoder_new (void)
|
||||||
|
{
|
||||||
|
return GST_ELEMENT (g_object_new (FAKE_DECODER_TYPE, NULL));
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,25 @@ typedef struct {
|
||||||
GType fake_demuxer_get_type (void);
|
GType fake_demuxer_get_type (void);
|
||||||
GstElement * fake_demuxer_new (void);
|
GstElement * fake_demuxer_new (void);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GstElement parent;
|
||||||
|
|
||||||
|
GstFlowReturn return_value;
|
||||||
|
} FakeDecoder;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GstElementClass parent;
|
||||||
|
} FakeDecoderClass;
|
||||||
|
|
||||||
|
#define FAKE_DECODER_TYPE (fake_decoder_get_type ())
|
||||||
|
#define FAKE_DECODER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FAKE_DECODER_TYPE, FakeDecoder))
|
||||||
|
#define FAKE_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), FAKE_DECODER_TYPE, FakeDecoderClass))
|
||||||
|
#define IS_FAKE_DECODER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FAKE_DECODER_TYPE))
|
||||||
|
#define IS_FAKE_DECODER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FAKE_DECODER_TYPE))
|
||||||
|
#define FAKE_DECODER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), FAKE_DECODER_TYPE, FakeDecoderClass))
|
||||||
|
|
||||||
|
GType fake_decoder_get_type (void);
|
||||||
|
GstElement * fake_decoder_new (void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -294,6 +294,8 @@ class GstValidateLaunchTest(GstValidateTest):
|
||||||
def build_arguments(self):
|
def build_arguments(self):
|
||||||
GstValidateTest.build_arguments(self)
|
GstValidateTest.build_arguments(self)
|
||||||
self.add_arguments(self.pipeline_desc)
|
self.add_arguments(self.pipeline_desc)
|
||||||
|
if self.media_descriptor is not None:
|
||||||
|
self.add_arguments("--set-media-info", self.media_descriptor.get_path())
|
||||||
|
|
||||||
def get_current_value(self):
|
def get_current_value(self):
|
||||||
if self.scenario:
|
if self.scenario:
|
||||||
|
|
Loading…
Reference in a new issue