x264enc and variable rate appsrc
David J
davywj at gmail.com
Tue Sep 22 11:21:39 UTC 2020
I have created a test pipeline (see code below) using a custom appsrc that
creates an h264 stream and sends over rtp.
I am testing it with the following command line to receive and play the
video stream:
gst-launch-1.0 -v udpsrc port=5000 caps = "application/x-rtp,
media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264,
payload=(int)96" ! rtph264depay ! decodebin ! videoconvert ! autovideosink
The command-line inside the application looks like this:
appsrc name=MyAppSrc ! video/x-raw,width=640,height=360,framerate=10/1 !
videoconvert ! identity name=ident ! x264enc zerolatency=true
speed-preset=superfast ! rtph264pay ! udpsink host=127.0.0.1 port=5000
At the moment the appsrc is generating frames at precisely 10fps and I set
the buffer timestamps correctly. However, unless I also specify the
framerate (in the caps string following the appsrc) as 10/1 the client
viewer constantly complains of:
WARNING: from element
/GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstD3D11VideoSinkBin:autovideosink0-actual-sink-d3d11video/GstD3D11VideoSink:d3d11videosink0:
A lot of buffers are being dropped.
Additional debug info:
../libs/gst/base/gstbasesink.c(3134): gst_base_sink_is_too_late ():
/GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstD3D11VideoSinkBin:autovideosink0-actual-sink-d3d11video/GstD3D11VideoSink:d3d11videosink0:
There may be a timestamping problem, or this computer is too slow.
*The problem is:*
In the real application, the appsrc will produce frames at a variable rate
- between about 2 and 20 fps. How can I get this to work if I'm required to
set a fixed framerate?
Provided the buffer timestamps are set, why does the framerate property
have any bearing on the pipeine?
Here is the application code:
// NativeBasicPipeline.cpp : This file contains the 'main' function.
Program execution begins and ends there.
//
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
GTimer* timer;
GstAppSrc* appSrc;
guint sourceid = 0;
int width = 1;
int colour = 255;
bool read_data()
{
static GstClockTime time = 0;
static guint64 offset = 0;
GstFlowReturn ret;
auto ms = g_timer_elapsed(timer, NULL);
if (ms > 1.0 / 10.0) {
auto size = 640 * 3 * 360;
gpointer copy = g_malloc(size);
memset(copy, colour % 255, size);
colour += 10;
GstBuffer* buffer = gst_buffer_new_wrapped(copy, size);
//GST_BUFFER_TIMESTAMP(buffer) = pts;
GST_BUFFER_PTS(buffer) = time;
GST_BUFFER_DTS(buffer) = time;
GST_BUFFER_DURATION(buffer) = 100 * GST_MSECOND;
GST_BUFFER_OFFSET(buffer) = offset++;
GST_BUFFER_OFFSET_END(buffer) = offset;
time += 100 * GST_MSECOND;
g_signal_emit_by_name(appSrc, "push-buffer", buffer, &ret);
//ret = gst_app_src_push_buffer(appSrc, buffer);
gst_buffer_unref(buffer);
g_timer_start(timer);
return TRUE;
}
return TRUE;
}
void start_feed(GstElement* pipeline, guint size, void* unused)
{
if (sourceid == 0) {
sourceid = g_idle_add((GSourceFunc)read_data, 0);
}
}
void stop_feed(GstElement* pipeline, void* unused)
{
if (sourceid != 0) {
g_source_remove(sourceid);
sourceid = 0;
}
}
static gboolean print_field(GQuark field, const GValue* value, gpointer
pfx) {
gchar* str = gst_value_serialize(value);
g_print("%s %15s: %s\n", (gchar*)pfx, g_quark_to_string(field), str);
g_free(str);
return TRUE;
}
static void print_caps(const GstCaps* caps, const gchar* pfx) {
guint i;
g_return_if_fail(caps != NULL);
if (gst_caps_is_any(caps)) {
g_print("%sANY\n", pfx);
return;
}
if (gst_caps_is_empty(caps)) {
g_print("%sEMPTY\n", pfx);
return;
}
for (i = 0; i < gst_caps_get_size(caps); i++) {
GstStructure* structure = gst_caps_get_structure(caps, i);
g_print("%s%s\n", pfx, gst_structure_get_name(structure));
gst_structure_foreach(structure, print_field, (gpointer)pfx);
}
}
void handoff(GstElement* pipeline, GstBuffer* buffer, void* unused)
{
static int count = 0;
static GstBuffer* buffers[50];
//auto ident = gst_bin_get_by_name(GST_BIN(pipeline), "ident");
auto pads = GST_ELEMENT_PADS(pipeline);
auto pad0 = GST_PAD(pads->data);
auto pad1 = GST_PAD(pads->next->data);
auto caps = gst_pad_get_current_caps(pad1);
print_caps(caps, "");
if (count < 50)
{
GstBuffer* copy = gst_buffer_copy(buffer);
buffers[count] = copy;
++count;
}
else
{
count = 100;
}
}
int main()
{
GstElement* pipeline;
GstBus* bus;
GstMessage* msg;
timer = g_timer_new();
/* Initialize GStreamer */
gst_init(0, 0);
/* Build the pipeline */
GError* err = 0;
//auto udpPipe = "videotestsrc pattern=smpte !
video/x-raw,width=640,height=360,framerate=10/1 ! videoscale ! videoconvert
! identity name=ident ! x264enc zerolatency=true speed-preset=superfast !
rtph264pay ! udpsink host=127.0.0.1 port=5000";
//auto videoPipe = "videotestsrc pattern=smpte !
video/x-raw,width=640,height=360,framerate=10/1 ! videoscale ! videoconvert
! autovideosink";
auto appSrcPipe = "appsrc name=MyAppSrc !
video/x-raw,width=640,height=360 ! videoconvert ! identity name=ident !
x264enc zerolatency=true speed-preset=superfast ! rtph264pay ! udpsink
host=127.0.0.1 port=5000";
//auto appSrcPipeVideo = "appsrc name=MyAppSrc ! videoscale !
videoconvert ! autovideosink";
pipeline =
gst_parse_launch
(appSrcPipe,
&err);
appSrc = (GstAppSrc*)gst_bin_get_by_name(GST_BIN(pipeline), "MyAppSrc");
g_object_set(G_OBJECT(appSrc), "format", GST_FORMAT_TIME, NULL);
g_signal_connect(appSrc, "need-data", G_CALLBACK(start_feed), 0);
g_signal_connect(appSrc, "enough-data", G_CALLBACK(stop_feed), 0);
auto caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "RGB",
"bpp", G_TYPE_INT, 24,
"depth", G_TYPE_INT, 24,
"width", G_TYPE_INT, 640,
"height", G_TYPE_INT, 360,
NULL);
gst_app_src_set_caps((GstAppSrc*)appSrc, caps);
//GstPad* pad = gst_element_get_static_pad(appSrc, "src");
//auto ident = gst_bin_get_by_name(GST_BIN(pipeline), "ident");
//g_signal_connect(ident, "handoff", G_CALLBACK(handoff), 0);
/* Start playing */
gst_element_set_state(pipeline, GST_STATE_PLAYING);
auto main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(main_loop);
/* Wait until error or EOS */
bus = gst_element_get_bus(pipeline);
msg =
gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
(GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));
/* Free resources */
if (msg != NULL)
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20200922/c2a9e849/attachment-0001.htm>
More information about the gstreamer-devel
mailing list