gstreamer/ext/avtp/gstavtpcrfutil.c
Vedang Patel 12ad2a4bcd avtp: Introduce the CRF Sync Element
This commit introduces the AVTP Clock Reference Format (CRF) Synchronizer
element. This element implements the AVTP CRF Listener as described in IEEE
1722-2016 Section 10.

CRF is useful in synchronizing events within different systems by
distributing a common clock. This is useful in a scenario where there are
multiple talkers who are sending data to a single listener which is
processing that data. E.g.  CCTV cameras on a network sending AVTP video
streams to a base station to display on the same screen.

It is assumed that all the systems are already time-synchronized with each
other. So, the AVTP Talker essentially adjusts the AVTP Presentation Time
so it's phase-locked with the reference clock provided by the CRF stream.

There are 2 different roles of systems which participate in CRF data
exchange.  A system can either be a CRF Talker, which samples it's own
clock and generates a stream of timestamps to transmit over the network, or
a CRF Listener, the system which receives the generated timestamps and
recovers the media clock from the timestamps. It then adjusts it's own
clock to align with recovered media clock. The timestamps generated by the
talker may not be continuous and the listener might have to interpolate
some timestamps to recover the media clock. The number of timestamps to
interpolate is mentioned in the CRF stream AVTPDU (Refer IEEE 1722-2016
Section 10.4 for AVTPDU structure). Only CRF Listener has been implemented
in this commit.

The CRF Sync element will create a separate thread to listen for the CRF
stream. This thread will calculate and store the average period of the
recovered media clock. The pipeline thread will use this stored period
along with the first timestamp of the latest CRF AVTPDU received to
calculate adjustment for timestamps in the audio/video streams. In case of
CRF AVTPDUs with single timestamp, two consecutive CRF AVTPDUs will be used
to figure out the average period of the recovered media clock.

In case of H264 streams, both AVTP timestamp and H264 timestamp will be
adjusted.

In the future commits, another "CRF Checker" element will be introduced
which will validate the timestamps on the AVTP Listener side. Which is why
a lot of code has been implemented as part of the gstcrfbase class.
2020-04-30 23:31:25 +00:00

117 lines
3.3 KiB
C

/*
* GStreamer AVTP Plugin
* Copyright (C) 2019 Intel Corporation
*
* 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.
*/
#include <avtp.h>
#include <avtp_aaf.h>
#include <avtp_cvf.h>
#include <glib.h>
#include "gstavtpcrfutil.h"
#define AVTP_CVF_H264_HEADER_SIZE (sizeof(struct avtp_stream_pdu) + sizeof(guint32))
gboolean
buffer_size_valid (GstMapInfo * info)
{
struct avtp_stream_pdu *pdu;
guint64 subtype;
guint32 type;
int res;
if (info->size < sizeof (struct avtp_stream_pdu))
return FALSE;
pdu = (struct avtp_stream_pdu *) info->data;
res =
avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, &type);
g_assert (res == 0);
res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &subtype);
g_assert (res == 0);
if (type == AVTP_SUBTYPE_CVF && subtype == AVTP_CVF_FORMAT_SUBTYPE_H264
&& info->size < AVTP_CVF_H264_HEADER_SIZE)
return FALSE;
return TRUE;
}
GstClockTime
get_avtp_tstamp (GstAvtpCrfBase * avtpcrfbase, struct avtp_stream_pdu * pdu)
{
guint64 tstamp = GST_CLOCK_TIME_NONE, tstamp_valid;
guint32 type;
int res;
res =
avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, &type);
g_assert (res == 0);
switch (type) {
case AVTP_SUBTYPE_AAF:
res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_TV, &tstamp_valid);
g_assert (res == 0);
if (!tstamp_valid)
break;
res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_TIMESTAMP, &tstamp);
g_assert (res == 0);
break;
case AVTP_SUBTYPE_CVF:
res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_TV, &tstamp_valid);
g_assert (res == 0);
if (!tstamp_valid)
break;
res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_TIMESTAMP, &tstamp);
g_assert (res == 0);
break;
default:
GST_INFO_OBJECT (avtpcrfbase, "type 0x%x not supported.\n", type);
break;
}
return (GstClockTime) tstamp;
}
gboolean
h264_tstamp_valid (struct avtp_stream_pdu * pdu)
{
guint64 subtype, h264_time_valid;
guint32 type;
int res;
/*
* Validate H264 timestamp for H264 format. For more details about the
* timestamp look at IEEE 1722-2016 Section 8.5.3.1
*/
res =
avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE, &type);
g_assert (res == 0);
if (type == AVTP_SUBTYPE_CVF) {
res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_FORMAT_SUBTYPE, &subtype);
g_assert (res == 0);
res = avtp_cvf_pdu_get (pdu, AVTP_CVF_FIELD_H264_PTV, &h264_time_valid);
g_assert (res == 0);
if (subtype == AVTP_CVF_FORMAT_SUBTYPE_H264 && h264_time_valid)
return TRUE;
}
return FALSE;
}