mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-09 05:38:58 +00:00
The default behaviour of rtponviftimestamp is to drop buffers outside the segment. This creates obvious problems for reverse playback. The ONVIF specification unfortunately doesn't describe how to handle that specific use case, but we can expose a property to let the user disable the dropping behaviour, and forward these buffers with a G_MAXUINT64 ONVIF timestamp. Also modify rtponvifparse to handle such timestamps appropriately.
179 lines
4.9 KiB
C
179 lines
4.9 KiB
C
/*
|
|
* gstrtponviftimestamp-parse.c
|
|
*
|
|
* Copyright (C) 2014 Axis Communications AB
|
|
* Author: Guillaume Desmottes <guillaume.desmottes@collabora.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <gst/rtp/gstrtpbuffer.h>
|
|
|
|
#include "gstrtponvifparse.h"
|
|
|
|
static GstFlowReturn gst_rtp_onvif_parse_chain (GstPad * pad,
|
|
GstObject * parent, GstBuffer * buf);
|
|
|
|
static GstStaticPadTemplate sink_template_factory =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("application/x-rtp")
|
|
);
|
|
|
|
static GstStaticPadTemplate src_template_factory =
|
|
GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("application/x-rtp")
|
|
);
|
|
|
|
G_DEFINE_TYPE (GstRtpOnvifParse, gst_rtp_onvif_parse, GST_TYPE_ELEMENT);
|
|
|
|
static void
|
|
gst_rtp_onvif_parse_class_init (GstRtpOnvifParseClass * klass)
|
|
{
|
|
GstElementClass *gstelement_class;
|
|
|
|
gstelement_class = GST_ELEMENT_CLASS (klass);
|
|
|
|
/* register pads */
|
|
gst_element_class_add_static_pad_template (gstelement_class,
|
|
&sink_template_factory);
|
|
gst_element_class_add_static_pad_template (gstelement_class,
|
|
&src_template_factory);
|
|
|
|
gst_element_class_set_static_metadata (gstelement_class,
|
|
"ONVIF NTP timestamps RTP extension", "Effect/RTP",
|
|
"Add absolute timestamps and flags of recorded data in a playback "
|
|
"session", "Guillaume Desmottes <guillaume.desmottes@collabora.com>");
|
|
}
|
|
|
|
static void
|
|
gst_rtp_onvif_parse_init (GstRtpOnvifParse * self)
|
|
{
|
|
self->sinkpad =
|
|
gst_pad_new_from_static_template (&sink_template_factory, "sink");
|
|
gst_pad_set_chain_function (self->sinkpad, gst_rtp_onvif_parse_chain);
|
|
gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
|
|
GST_PAD_SET_PROXY_CAPS (self->sinkpad);
|
|
|
|
self->srcpad =
|
|
gst_pad_new_from_static_template (&src_template_factory, "src");
|
|
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
|
|
}
|
|
|
|
#define EXTENSION_ID 0xABAC
|
|
#define EXTENSION_SIZE 3
|
|
|
|
static gboolean
|
|
handle_buffer (GstRtpOnvifParse * self, GstBuffer * buf, gboolean * send_eos)
|
|
{
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 *data;
|
|
guint16 bits;
|
|
guint wordlen;
|
|
guint8 flags;
|
|
guint64 timestamp_seconds;
|
|
guint64 timestamp_fraction;
|
|
guint64 timestamp_nseconds;
|
|
/*
|
|
guint8 cseq;
|
|
*/
|
|
|
|
if (!gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp)) {
|
|
GST_ELEMENT_ERROR (self, STREAM, FAILED,
|
|
("Failed to map RTP buffer"), (NULL));
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check if the ONVIF RTP extension is present in the packet */
|
|
if (!gst_rtp_buffer_get_extension_data (&rtp, &bits, (gpointer) & data,
|
|
&wordlen))
|
|
goto out;
|
|
|
|
if (bits != EXTENSION_ID || wordlen != EXTENSION_SIZE)
|
|
goto out;
|
|
|
|
timestamp_seconds = GST_READ_UINT32_BE (data);
|
|
timestamp_fraction = GST_READ_UINT32_BE (data + 4);
|
|
timestamp_nseconds =
|
|
(timestamp_fraction * G_GINT64_CONSTANT (1000000000)) >> 32;
|
|
|
|
if (timestamp_seconds == G_MAXUINT32 && timestamp_fraction == G_MAXUINT32) {
|
|
GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
|
|
} else {
|
|
GST_BUFFER_PTS (buf) =
|
|
timestamp_seconds * GST_SECOND + timestamp_nseconds * GST_NSECOND;
|
|
}
|
|
|
|
flags = GST_READ_UINT8 (data + 8);
|
|
/* cseq = GST_READ_UINT8 (data + 9); TODO */
|
|
|
|
/* C */
|
|
if (flags & (1 << 7))
|
|
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
|
else
|
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
|
|
|
|
/* E */
|
|
/* if (flags & (1 << 6)); TODO */
|
|
|
|
/* D */
|
|
if (flags & (1 << 5))
|
|
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
|
|
else
|
|
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
|
|
|
|
/* T */
|
|
if (flags & (1 << 4))
|
|
*send_eos = TRUE;
|
|
|
|
out:
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
return TRUE;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_rtp_onvif_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
|
{
|
|
GstRtpOnvifParse *self = GST_RTP_ONVIF_PARSE (parent);
|
|
GstFlowReturn ret;
|
|
gboolean send_eos = FALSE;
|
|
|
|
if (!handle_buffer (self, buf, &send_eos)) {
|
|
gst_buffer_unref (buf);
|
|
return GST_FLOW_ERROR;
|
|
}
|
|
|
|
ret = gst_pad_push (self->srcpad, buf);
|
|
|
|
if (ret == GST_FLOW_OK && send_eos) {
|
|
GstEvent *event;
|
|
|
|
event = gst_event_new_eos ();
|
|
gst_pad_push_event (self->srcpad, event);
|
|
ret = GST_FLOW_EOS;
|
|
}
|
|
|
|
return ret;
|
|
}
|