mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
add refresh message
Add a new refresh message to request a keyframe from the pinos server. pinospay: pass the refresh-request message upstream pinossink: turn refresh-request messages into events pinossrc: turn a keyframe event into a refresh-request message
This commit is contained in:
parent
833168c3cf
commit
d5e333ac4b
7 changed files with 212 additions and 3 deletions
|
|
@ -332,5 +332,25 @@ Types:
|
||||||
message length is end
|
message length is end
|
||||||
|
|
||||||
|
|
||||||
|
7: refresh request
|
||||||
|
|
||||||
|
Request a new refresh point
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| last-id |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| request-type |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| PTS ... |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| .... |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
<last-id> : the last seen id
|
||||||
|
<request-type> : the type of request
|
||||||
|
0 = keyframe
|
||||||
|
1 = keyframe+full headers
|
||||||
|
<PTS> : the timestamp when the refresh should be,
|
||||||
|
0 for as soon as possible
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ libpinos_@PINOS_MAJORMINOR@_la_SOURCES = \
|
||||||
|
|
||||||
libpinos_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GST_CFLAGS)
|
libpinos_@PINOS_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(GST_CFLAGS)
|
||||||
libpinos_@PINOS_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
libpinos_@PINOS_MAJORMINOR@_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
|
||||||
libpinos_@PINOS_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV) $(GST_LIBS)
|
libpinos_@PINOS_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) $(LTLIBICONV) $(GST_LIBS) $(GST_BASE_LIBS) -lgstvideo-1.0
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Daemon core library #
|
# Daemon core library #
|
||||||
|
|
|
||||||
|
|
@ -721,3 +721,55 @@ pinos_buffer_builder_add_format_change (PinosBufferBuilder *builder,
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pinos_buffer_iter_parse_refresh_request:
|
||||||
|
* @iter: a #PinosBufferIter
|
||||||
|
* @payload: a #PinosPacketRefreshRequest
|
||||||
|
*
|
||||||
|
* Parse a #PINOS_PACKET_TYPE_REFRESH_REQUEST packet from @iter into @payload.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
pinos_buffer_iter_parse_refresh_request (PinosBufferIter *iter,
|
||||||
|
PinosPacketRefreshRequest *payload)
|
||||||
|
{
|
||||||
|
struct stack_iter *si = PPSI (iter);
|
||||||
|
|
||||||
|
g_return_val_if_fail (is_valid_iter (iter), FALSE);
|
||||||
|
g_return_val_if_fail (si->type == PINOS_PACKET_TYPE_REFRESH_REQUEST, FALSE);
|
||||||
|
|
||||||
|
if (si->size < sizeof (PinosPacketRefreshRequest))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
memcpy (payload, si->data, sizeof (*payload));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pinos_buffer_builder_add_refresh_request:
|
||||||
|
* @builder: a #PinosBufferBuilder
|
||||||
|
* @payload: a #PinosPacketRefreshRequest
|
||||||
|
*
|
||||||
|
* Add a #PINOS_PACKET_TYPE_REFRESH_REQUEST payload in @payload to @builder.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
pinos_buffer_builder_add_refresh_request (PinosBufferBuilder *builder,
|
||||||
|
PinosPacketRefreshRequest *payload)
|
||||||
|
{
|
||||||
|
struct stack_builder *sb = PPSB (builder);
|
||||||
|
PinosPacketRefreshRequest *p;
|
||||||
|
|
||||||
|
g_return_val_if_fail (is_valid_builder (builder), FALSE);
|
||||||
|
|
||||||
|
p = builder_add_packet (sb,
|
||||||
|
PINOS_PACKET_TYPE_REFRESH_REQUEST,
|
||||||
|
sizeof (PinosPacketRefreshRequest));
|
||||||
|
memcpy (p, payload, sizeof (*payload));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ gpointer pinos_buffer_steal (PinosBuffer *buffer,
|
||||||
* that a previously received fd-payload is no longer in use.
|
* that a previously received fd-payload is no longer in use.
|
||||||
* @PINOS_PACKET_TYPE_FORMAT_CHANGE: a format change.
|
* @PINOS_PACKET_TYPE_FORMAT_CHANGE: a format change.
|
||||||
* @PINOS_PACKET_TYPE_PROPERTY_CHANGE: one or more property changes.
|
* @PINOS_PACKET_TYPE_PROPERTY_CHANGE: one or more property changes.
|
||||||
|
* @PINOS_PACKET_TYPE_REFRESH_REQUEST: ask for a new keyframe
|
||||||
*
|
*
|
||||||
* The possible packet types.
|
* The possible packet types.
|
||||||
*/
|
*/
|
||||||
|
|
@ -77,6 +78,7 @@ typedef enum {
|
||||||
PINOS_PACKET_TYPE_RELEASE_FD_PAYLOAD = 4,
|
PINOS_PACKET_TYPE_RELEASE_FD_PAYLOAD = 4,
|
||||||
PINOS_PACKET_TYPE_FORMAT_CHANGE = 5,
|
PINOS_PACKET_TYPE_FORMAT_CHANGE = 5,
|
||||||
PINOS_PACKET_TYPE_PROPERTY_CHANGE = 6,
|
PINOS_PACKET_TYPE_PROPERTY_CHANGE = 6,
|
||||||
|
PINOS_PACKET_TYPE_REFRESH_REQUEST = 7,
|
||||||
} PinosPacketType;
|
} PinosPacketType;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -215,5 +217,25 @@ gboolean pinos_buffer_iter_parse_property_change (PinosBufferIter
|
||||||
gboolean pinos_buffer_builder_add_property_change (PinosBufferBuilder *builder,
|
gboolean pinos_buffer_builder_add_property_change (PinosBufferBuilder *builder,
|
||||||
PinosPacketPropertyChange *payload);
|
PinosPacketPropertyChange *payload);
|
||||||
|
|
||||||
|
/* refresh request packets */
|
||||||
|
/**
|
||||||
|
* PinosPacketRefreshRequest:
|
||||||
|
* @last_id: last frame seen frame id
|
||||||
|
* @request_type: the type of the request
|
||||||
|
* @pts: the timestamp of the requested key frame, 0 = as soon as possible
|
||||||
|
*
|
||||||
|
* A refresh request packet. This packet is sent to trigger a new keyframe.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
guint32 last_id;
|
||||||
|
guint32 request_type;
|
||||||
|
gint64 pts;
|
||||||
|
} PinosPacketRefreshRequest;
|
||||||
|
|
||||||
|
gboolean pinos_buffer_iter_parse_refresh_request (PinosBufferIter *iter,
|
||||||
|
PinosPacketRefreshRequest *payload);
|
||||||
|
gboolean pinos_buffer_builder_add_refresh_request (PinosBufferBuilder *builder,
|
||||||
|
PinosPacketRefreshRequest *payload);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __PINOS_BUFFER_H__ */
|
#endif /* __PINOS_BUFFER_H__ */
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@
|
||||||
#include "gsttmpfileallocator.h"
|
#include "gsttmpfileallocator.h"
|
||||||
|
|
||||||
#include <gst/net/gstnetcontrolmessagemeta.h>
|
#include <gst/net/gstnetcontrolmessagemeta.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
#include <gio/gunixfdmessage.h>
|
#include <gio/gunixfdmessage.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
@ -198,13 +200,19 @@ client_buffer_received (GstPinosPay *pay, GstBuffer *buffer,
|
||||||
{
|
{
|
||||||
PinosBuffer pbuf;
|
PinosBuffer pbuf;
|
||||||
PinosBufferIter it;
|
PinosBufferIter it;
|
||||||
|
PinosBufferBuilder b;
|
||||||
GstMapInfo info;
|
GstMapInfo info;
|
||||||
const gchar *client_path;
|
const gchar *client_path;
|
||||||
|
gboolean have_out = FALSE;
|
||||||
|
|
||||||
client_path = g_object_get_data (obj, "pinos-client-path");
|
client_path = g_object_get_data (obj, "pinos-client-path");
|
||||||
if (client_path == NULL)
|
if (client_path == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (pay->pinos_input) {
|
||||||
|
pinos_buffer_builder_init (&b);
|
||||||
|
}
|
||||||
|
|
||||||
gst_buffer_map (buffer, &info, GST_MAP_READ);
|
gst_buffer_map (buffer, &info, GST_MAP_READ);
|
||||||
pinos_buffer_init_data (&pbuf, info.data, info.size, NULL);
|
pinos_buffer_init_data (&pbuf, info.data, info.size, NULL);
|
||||||
pinos_buffer_iter_init (&it, &pbuf);
|
pinos_buffer_iter_init (&it, &pbuf);
|
||||||
|
|
@ -224,12 +232,54 @@ client_buffer_received (GstPinosPay *pay, GstBuffer *buffer,
|
||||||
pinos_fd_manager_remove (pay->fdmanager, client_path, id);
|
pinos_fd_manager_remove (pay->fdmanager, client_path, id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PINOS_PACKET_TYPE_REFRESH_REQUEST:
|
||||||
|
{
|
||||||
|
PinosPacketRefreshRequest p;
|
||||||
|
|
||||||
|
if (!pinos_buffer_iter_parse_refresh_request (&it, &p))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GST_LOG ("refresh request");
|
||||||
|
if (!pay->pinos_input) {
|
||||||
|
gst_pad_push_event (pay->sinkpad,
|
||||||
|
gst_video_event_new_upstream_force_key_unit (p.pts,
|
||||||
|
p.request_type == 1, 0));
|
||||||
|
} else {
|
||||||
|
pinos_buffer_builder_add_refresh_request (&b, &p);
|
||||||
|
have_out = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gst_buffer_unmap (buffer, &info);
|
gst_buffer_unmap (buffer, &info);
|
||||||
pinos_buffer_clear (&pbuf);
|
pinos_buffer_clear (&pbuf);
|
||||||
|
|
||||||
|
if (pay->pinos_input) {
|
||||||
|
GstBuffer *outbuf;
|
||||||
|
GstEvent *ev;
|
||||||
|
gsize size;
|
||||||
|
gpointer data;
|
||||||
|
|
||||||
|
if (have_out) {
|
||||||
|
pinos_buffer_builder_end (&b, &pbuf);
|
||||||
|
|
||||||
|
data = pinos_buffer_steal (&pbuf, &size, NULL);
|
||||||
|
|
||||||
|
outbuf = gst_buffer_new_wrapped (data, size);
|
||||||
|
ev = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
|
||||||
|
gst_structure_new ("GstNetworkMessage",
|
||||||
|
"object", G_TYPE_OBJECT, pay,
|
||||||
|
"buffer", GST_TYPE_BUFFER, outbuf, NULL));
|
||||||
|
gst_buffer_unref (outbuf);
|
||||||
|
|
||||||
|
gst_pad_push_event (pay->sinkpad, ev);
|
||||||
|
} else {
|
||||||
|
pinos_buffer_builder_clear (&b);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -264,9 +314,10 @@ gst_pinos_pay_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||||
client_buffer_received (pay, buf, obj);
|
client_buffer_received (pay, buf, obj);
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
g_object_unref (obj);
|
g_object_unref (obj);
|
||||||
|
|
||||||
}
|
}
|
||||||
gst_event_unref (event);
|
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
|
gst_event_unref (event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
|
|
||||||
#include <gio/gunixfdmessage.h>
|
#include <gio/gunixfdmessage.h>
|
||||||
#include <gst/allocators/gstfdmemory.h>
|
#include <gst/allocators/gstfdmemory.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
#include "gsttmpfileallocator.h"
|
#include "gsttmpfileallocator.h"
|
||||||
|
|
||||||
|
|
@ -290,7 +291,19 @@ on_new_buffer (GObject *gobject,
|
||||||
g_hash_table_remove (pinossink->fdids, GINT_TO_POINTER (p.id));
|
g_hash_table_remove (pinossink->fdids, GINT_TO_POINTER (p.id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PINOS_PACKET_TYPE_REFRESH_REQUEST:
|
||||||
|
{
|
||||||
|
PinosPacketRefreshRequest p;
|
||||||
|
|
||||||
|
if (!pinos_buffer_iter_parse_refresh_request (&it, &p))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
GST_LOG ("refresh request");
|
||||||
|
gst_pad_push_event (GST_BASE_SINK_PAD (pinossink),
|
||||||
|
gst_video_event_new_upstream_force_key_unit (p.pts,
|
||||||
|
p.request_type == 1, 0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include <gio/gunixfdmessage.h>
|
#include <gio/gunixfdmessage.h>
|
||||||
#include <gst/net/gstnetclientclock.h>
|
#include <gst/net/gstnetclientclock.h>
|
||||||
#include <gst/allocators/gstfdmemory.h>
|
#include <gst/allocators/gstfdmemory.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
|
||||||
|
|
||||||
static GQuark fdpayload_data_quark;
|
static GQuark fdpayload_data_quark;
|
||||||
|
|
@ -84,6 +85,7 @@ static gboolean gst_pinos_src_unlock (GstBaseSrc * basesrc);
|
||||||
static gboolean gst_pinos_src_unlock_stop (GstBaseSrc * basesrc);
|
static gboolean gst_pinos_src_unlock_stop (GstBaseSrc * basesrc);
|
||||||
static gboolean gst_pinos_src_start (GstBaseSrc * basesrc);
|
static gboolean gst_pinos_src_start (GstBaseSrc * basesrc);
|
||||||
static gboolean gst_pinos_src_stop (GstBaseSrc * basesrc);
|
static gboolean gst_pinos_src_stop (GstBaseSrc * basesrc);
|
||||||
|
static gboolean gst_pinos_src_event (GstBaseSrc * src, GstEvent * event);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_pinos_src_set_property (GObject * object, guint prop_id,
|
gst_pinos_src_set_property (GObject * object, guint prop_id,
|
||||||
|
|
@ -245,7 +247,7 @@ gst_pinos_src_class_init (GstPinosSrcClass * klass)
|
||||||
gstbasesrc_class->unlock_stop = gst_pinos_src_unlock_stop;
|
gstbasesrc_class->unlock_stop = gst_pinos_src_unlock_stop;
|
||||||
gstbasesrc_class->start = gst_pinos_src_start;
|
gstbasesrc_class->start = gst_pinos_src_start;
|
||||||
gstbasesrc_class->stop = gst_pinos_src_stop;
|
gstbasesrc_class->stop = gst_pinos_src_stop;
|
||||||
|
gstbasesrc_class->event = gst_pinos_src_event;
|
||||||
gstpushsrc_class->create = gst_pinos_src_create;
|
gstpushsrc_class->create = gst_pinos_src_create;
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (pinos_src_debug, "pinossrc", 0,
|
GST_DEBUG_CATEGORY_INIT (pinos_src_debug, "pinossrc", 0,
|
||||||
|
|
@ -724,6 +726,55 @@ gst_pinos_src_unlock_stop (GstBaseSrc * basesrc)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_pinos_src_event (GstBaseSrc * src, GstEvent * event)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
GstPinosSrc *pinossrc;
|
||||||
|
|
||||||
|
pinossrc = GST_PINOS_SRC (src);
|
||||||
|
|
||||||
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
|
case GST_EVENT_CUSTOM_UPSTREAM:
|
||||||
|
if (gst_video_event_is_force_key_unit (event)) {
|
||||||
|
GstClockTime running_time;
|
||||||
|
gboolean all_headers;
|
||||||
|
guint count;
|
||||||
|
PinosPacketRefreshRequest refresh;
|
||||||
|
PinosBufferBuilder b;
|
||||||
|
PinosBuffer pbuf;
|
||||||
|
|
||||||
|
gst_video_event_parse_upstream_force_key_unit (event,
|
||||||
|
&running_time, &all_headers, &count);
|
||||||
|
|
||||||
|
refresh.last_id = 0;
|
||||||
|
refresh.request_type = all_headers ? 1 : 0;
|
||||||
|
refresh.pts = running_time;
|
||||||
|
|
||||||
|
pinos_buffer_builder_init (&b);
|
||||||
|
pinos_buffer_builder_add_refresh_request (&b, &refresh);
|
||||||
|
pinos_buffer_builder_end (&b, &pbuf);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (pinossrc);
|
||||||
|
if (pinossrc->stream_state == PINOS_STREAM_STATE_STREAMING) {
|
||||||
|
GST_DEBUG_OBJECT (pinossrc, "send refresh request");
|
||||||
|
pinos_stream_send_buffer (pinossrc->stream, &pbuf);
|
||||||
|
}
|
||||||
|
GST_OBJECT_UNLOCK (pinossrc);
|
||||||
|
|
||||||
|
pinos_buffer_clear (&pbuf);
|
||||||
|
res = TRUE;
|
||||||
|
} else {
|
||||||
|
res = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = GST_BASE_SRC_CLASS (parent_class)->event (src, event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
|
gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue