Limiting a RTSP recording after X seconds
Jesper Taxbøl
jesper at taxboel.dk
Wed Dec 13 09:32:42 UTC 2017
2017-12-01 12:20 GMT+01:00 Jesper Taxbøl <jesper at taxboel.dk>:
> You guys are right. My solution is not safe.
>
> The signal works but the file is messed up in such a way that when
> transcoding the file gstreamer often stalls generating much larger files
> than the input. When running ffprobe against the file duration is strange.
>
> I was thinking that the problem was that the pipeline did not have time to
> close the file properly.
>
> Therefore I found the example from https://gstreamer.freedesktop.
> org/documentation/tutorials/basic/time-management.html.I could insert my
> configuration and piggyback on the message flow.
>
>
>
>
>
>
>
> *mpegtsmux ! filesink location=two.ts \ rtspsrc
> location=rtsp://root:hest1234@192.168.130.200/axis-media/media.amp
> <http://root:hest1234@192.168.130.200/axis-media/media.amp> ntp-sync=true
> protocols=GST_RTSP_LOWER_TRANS_TCP ! \ queue ! capsfilter
> caps=\"application/x-rtp,media=video\" ! \ rtph264depay ! mpegtsmux0. \
> rtspsrc location=rtsp://root:hest1234@192.168.130.201/axis-media/media.amp
> <http://root:hest1234@192.168.130.201/axis-media/media.amp> ntp-sync=true
> protocols=GST_RTSP_LOWER_TRANS_TCP ! \ queue ! capsfilter
> caps=\"application/x-rtp,media=video\" ! \ rtph264depay ! mpegtsmux0.*
>
> In the message handler I count timeouts and stop after a given time. Full
> source added below.
>
> The approach works as such, but it still gives me funny readings. ffprobe
> says:
>
> Invalid return value 0 for stream protocol
> Input #0, mpegts, from 'two.ts':
> Duration: 00:00:11.95, start: 3600.698056, bitrate: 37229 kb/s
> Program 1
> Stream #0:0[0x41]: Video: h264 (High) (HDMV / 0x564D4448),
> yuvj420p(pc, bt709, progressive), 3840x2160 [SAR 1:1 DAR 16:9], 29.97 fps,
> 29.97 tbr, 90k tbn, 59.94 tbc
> Stream #0:1[0x42]: Video: h264 (High) (HDMV / 0x564D4448),
> yuvj420p(pc, bt709, progressive), 3840x2160 [SAR 1:1 DAR 16:9], 29.97 fps,
> 29.97 tbr, 90k tbn, 59.94 tbc
>
> I notice that duration is somewhat plausible, but start is 3600, which I
> guess could be part of the problem.
>
> Any Ideas on how to fix time in my output file.
>
> Kind regards
>
> Jesper
>
>
>
>
> #include <stdio.h>
> #include <gst/gst.h>
>
> /* Structure to contain all our information, so we can pass it around */
> typedef struct _CustomData {
> GstElement *playbin; /* Our one and only element */
> gboolean playing; /* Are we in the PLAYING state? */
> gboolean terminate; /* Should we terminate execution? */
> gboolean seek_enabled; /* Is seeking enabled for this media? */
> gboolean seek_done; /* Have we performed the seek already? */
> gint64 duration; /* How long does this media last, in nanoseconds
> */
> } CustomData;
>
> /* Forward definition of the message processing function */
> static void handle_message (CustomData *data, GstMessage *msg);
>
> int main(int argc, char *argv[]) {
> CustomData data;
> GstBus *bus;
> GstMessage *msg;
> GstStateChangeReturn ret;
>
> data.playing = FALSE;
> data.terminate = FALSE;
> data.seek_enabled = FALSE;
> data.seek_done = FALSE;
> data.duration = GST_CLOCK_TIME_NONE;
>
> /* Initialize GStreamer */
> gst_init (&argc, &argv);
>
> /* Create the elements */
> //data.playbin = gst_element_factory_make ("playbin", "playbin");
>
> char* cmd = "mpegtsmux ! filesink location=two.ts \
> rtspsrc location=rtsp://root:hest1234@192.168.130.200/axis-media/
> media.amp ntp-sync=true protocols=GST_RTSP_LOWER_TRANS_TCP ! \
> queue ! capsfilter caps=\"application/x-rtp,media=video\" ! \
> rtph264depay ! mpegtsmux0. \
> rtspsrc location=rtsp://root:hest1234@192.168.130.201/axis-media/
> media.amp ntp-sync=true protocols=GST_RTSP_LOWER_TRANS_TCP ! \
> queue ! capsfilter caps=\"application/x-rtp,media=video\" ! \
> rtph264depay ! mpegtsmux0.";
> printf(cmd);
> data.playbin = gst_parse_launch (cmd, NULL);
>
>
> if (!data.playbin) {
> g_printerr ("Not all elements could be created.\n");
> return -1;
> }
>
> /* Set the URI to play */
> //g_object_set (data.playbin, "uri", //"https://www.freedesktop.
> org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm", NULL);
>
>
>
> /* Start playing */
> ret = gst_element_set_state (data.playbin, GST_STATE_PLAYING);
> if (ret == GST_STATE_CHANGE_FAILURE) {
> g_printerr ("Unable to set the pipeline to the playing state.\n");
> gst_object_unref (data.playbin);
> return -1;
> }
>
> /* Listen to the bus */
> bus = gst_element_get_bus (data.playbin);
>
> int t = 0;
>
> do {
> msg = gst_bus_timed_pop_filtered (bus, 100 * GST_MSECOND,
> GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS |
> GST_MESSAGE_DURATION);
>
> printf("Tick: \r\n%d\r\n", t++);
> if(t == 200)
> {
> gst_element_send_event (GST_ELEMENT (data.playbin),
> gst_event_new_eos());
> }
>
> /* Parse message */
> if (msg != NULL) {
> handle_message (&data, msg);
> } else {
>
> /* We got no message, this means the timeout expired */
> if (data.playing) {
> gint64 current = -1;
>
> /* Query the current position of the stream */
> if (!gst_element_query_position (data.playbin, GST_FORMAT_TIME,
> ¤t)) {
> g_printerr ("Could not query current position.\n");
> }
>
> /* If we didn't know it yet, query the stream duration */
> if (!GST_CLOCK_TIME_IS_VALID (data.duration)) {
> if (!gst_element_query_duration (data.playbin, GST_FORMAT_TIME,
> &data.duration)) {
> g_printerr ("Could not query current duration.\n");
> }
> }
>
> /* Print current position and total duration */
> g_print ("Position %" GST_TIME_FORMAT " / %" GST_TIME_FORMAT "\r",
> GST_TIME_ARGS (current), GST_TIME_ARGS (data.duration));
>
> /* If seeking is enabled, we have not done it yet, and the time is
> right, seek */
> if (data.seek_enabled && !data.seek_done && current > 10 *
> GST_SECOND) {
> g_print ("\nReached 10s, performing seek...\n");
> gst_element_seek_simple (data.playbin, GST_FORMAT_TIME,
> GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, 30 *
> GST_SECOND);
> data.seek_done = TRUE;
> }
> }
> }
> } while (!data.terminate);
>
> /* Free resources */
> gst_object_unref (bus);
> gst_element_set_state (data.playbin, GST_STATE_NULL);
> gst_object_unref (data.playbin);
> return 0;
> }
>
> static void handle_message (CustomData *data, GstMessage *msg) {
> GError *err;
> gchar *debug_info;
>
> switch (GST_MESSAGE_TYPE (msg)) {
> case GST_MESSAGE_ERROR:
> gst_message_parse_error (msg, &err, &debug_info);
> g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME
> (msg->src), err->message);
> g_printerr ("Debugging information: %s\n", debug_info ? debug_info :
> "none");
> g_clear_error (&err);
> g_free (debug_info);
> data->terminate = TRUE;
> break;
> case GST_MESSAGE_EOS:
> g_print ("End-Of-Stream reached.\n");
> data->terminate = TRUE;
> break;
> case GST_MESSAGE_DURATION:
> /* The duration has changed, mark the current one as invalid */
> printf("...\r\n");
> data->duration = GST_CLOCK_TIME_NONE;
> break;
> case GST_MESSAGE_STATE_CHANGED: {
> GstState old_state, new_state, pending_state;
> gst_message_parse_state_changed (msg, &old_state, &new_state,
> &pending_state);
> if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->playbin)) {
> g_print ("Pipeline state changed from %s to %s:\n",
> gst_element_state_get_name (old_state),
> gst_element_state_get_name (new_state));
>
> /* Remember whether we are in the PLAYING state or not */
> data->playing = (new_state == GST_STATE_PLAYING);
>
> if (data->playing) {
> /* We just moved to PLAYING. Check if seeking is possible */
> GstQuery *query;
> gint64 start, end;
> query = gst_query_new_seeking (GST_FORMAT_TIME);
> if (gst_element_query (data->playbin, query)) {
> gst_query_parse_seeking (query, NULL, &data->seek_enabled,
> &start, &end);
> if (data->seek_enabled) {
> g_print ("Seeking is ENABLED from %" GST_TIME_FORMAT " to %"
> GST_TIME_FORMAT "\n",
> GST_TIME_ARGS (start), GST_TIME_ARGS (end));
> } else {
> g_print ("Seeking is DISABLED for this stream.\n");
> }
> }
> else {
> g_printerr ("Seeking query failed.");
> }
> gst_query_unref (query);
> }
> }
> } break;
> default:
> /* We should not reach here */
> g_printerr ("Unexpected message received.\n");
> break;
> }
> gst_message_unref (msg);
> }
>
>
>
>
>
> 2017-11-30 11:40 GMT+01:00 Tim Müller <tim at centricular.com>:
>
>> On Thu, 2017-11-30 at 10:22 +0100, Jesper Taxbøl wrote:
>>
>> > I spent some time today and figured out i can use use the following
>> > syntax in my makefile. Its actually the terminal sending a signal to
>> > kill the process.
>>
>> That'll work of course, but the file won't be finalised properly, so
>> the headers won't be updated with the duration and there won't be a
>> seektable and you might be missing the last few frames/seconds.
>>
>> Cheers
>> -Tim
>>
>> --
>> Tim Müller, Centricular Ltd - http://www.centricular.com
>> _______________________________________________
>> gstreamer-devel mailing list
>> gstreamer-devel at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
>>
>
>
>
> --
> Jesper Taxbøl
> +45 61627501 <+45%2061%2062%2075%2001>
>
>
I ended up taking the recording into a ffmpeg program I have been working
on, and I could read PTS on every frame there. I wrote a simple mechanism
to repeat frames if the frames are out of sync and that seems to work for
now.
I am still interrested though if it was possible to offset PTS to start
from zero in gstreamer with existing modules.
Kind regards
--
Jesper Taxbøl
+45 61627501
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/gstreamer-devel/attachments/20171213/25825127/attachment-0001.html>
More information about the gstreamer-devel
mailing list