2021年3月27日星期六

Connecting to a tee that's playing

I'm using gstreamer to stream video from a camera to an HLS sink and to also record that video to the filesystem as an MP4. I use a tee to split the video into the two paths. I wrote some code and got it working if I connect it all up and switch state to "play". But when I start the streaming and try to connect the splitmuxsink dynamically to the tee, the video files I record aren't valid (at least VLC won't play them). (The web stream continues to work just fine)

I've reduced my code to a simple version (below) where I start with one splimuxsink, sleep a while and then add a second one. Although the first splitmuxsink works great, the new one never generates usable video. To make the transitions, I switch the playing pipeline to pause, add the new elements (all in the paused state) and switch everything to play.

Following the gstream manual, I've tried more complicated switching procedures; adding a probe to block the new branch of the tee, etc. but the results are the same.

#include <stdio.h>  #include <stdlib.h>  #include <unistd.h>  #include <ctype.h>  #include <gst/gst.h>  #include <assert.h>    using namespace std;    int main()  {      // Create a pipeline to write a file      printf("starting\n");        gst_init(NULL, NULL);        // Create the pipeline to host the elements      GstElement* pipeline = gst_pipeline_new("pipeline");      assert(pipeline != nullptr);            GstElement* camera = gst_element_factory_make("v4l2src", "v4l2src");      assert(camera != nullptr);      g_object_set(G_OBJECT(camera),                   "device", "/dev/video2",                   NULL);            GstElement* caps = gst_element_factory_make("capsfilter", "capsfilter");      assert(caps != nullptr);      g_object_set(G_OBJECT(caps),                   "caps", gst_caps_from_string("video/x-h264,width=640,height=480,framerate=30/1"),                   NULL);        GstElement* tee = gst_element_factory_make("tee", "tee");      GstElement* queue1 = gst_element_factory_make("queue", "queue1");      GstElement* h264parse1 = gst_element_factory_make("h264parse", "h264parse1");      GstElement* splitmux1 = gst_element_factory_make("splitmuxsink", "splitmux1");      g_object_set(G_OBJECT(splitmux1),                   "location", "file%03d.mp4",                   "max-size-time", 10000000000,                   NULL);      assert(tee != nullptr && queue1 != nullptr && h264parse1 != nullptr && splitmux1 != nullptr);        // Attach them all to the pipeline      gst_bin_add_many(GST_BIN (pipeline), camera, caps, tee, queue1, h264parse1, splitmux1, NULL);        // Link the pieces      assert(true == gst_element_link_many(camera, caps, tee, NULL));      GstPad* srcpad = gst_element_get_request_pad(tee, "src_%u");      assert(srcpad != nullptr);      GstPad* dstpad = gst_element_get_static_pad (queue1, "sink");      assert(dstpad != nullptr);      assert(GST_PAD_LINK_OK == gst_pad_link(srcpad, dstpad));      assert(true == gst_element_link_many (queue1, h264parse1, splitmux1, NULL));        assert(GST_STATE_CHANGE_ASYNC == gst_element_set_state (pipeline, GST_STATE_PLAYING));        sleep(35);        printf("Attach the splitmuxsink\n");      // Now attach another sink      GstElement* queue2 = gst_element_factory_make("queue", "queue2");      assert(nullptr != queue2);      GstElement* h264parse2 = gst_element_factory_make("h264parse", "h264parse2");      assert(nullptr != h264parse2);      GstElement* splitmux2 = gst_element_factory_make("splitmuxsink", "splitmux2");      assert(nullptr != splitmux2);      g_object_set(G_OBJECT(splitmux2),                   "location", "alt%03d.mp4",                   "max-size-time", 10000000000,                   NULL);        // Set all the states to paused before attaching      assert(GST_STATE_CHANGE_ASYNC == gst_element_set_state (splitmux2, GST_STATE_PAUSED));      assert(GST_STATE_CHANGE_SUCCESS == gst_element_set_state (h264parse2, GST_STATE_PAUSED));      assert(GST_STATE_CHANGE_SUCCESS == gst_element_set_state (queue2, GST_STATE_PAUSED));      assert(GST_STATE_CHANGE_NO_PREROLL == gst_element_set_state (pipeline, GST_STATE_PAUSED));        gst_bin_add_many (GST_BIN (pipeline), queue2, h264parse2, splitmux2, NULL);      assert(true == gst_element_link_many (queue2, h264parse2, splitmux2, NULL));      GstPad* srcpad2 = gst_element_get_request_pad(tee, "src_%u");      assert(nullptr != srcpad2);      GstPad* dstpad2 = gst_element_get_static_pad (queue2, "sink");      assert(nullptr != dstpad2);      assert(GST_PAD_LINK_OK == gst_pad_link(srcpad2, dstpad2));        assert(GST_STATE_CHANGE_ASYNC == gst_element_set_state (pipeline, GST_STATE_PLAYING));      sleep(65);      printf("all done\n");   }  
https://stackoverflow.com/questions/66837804/connecting-to-a-tee-thats-playing March 28, 2021 at 10:06AM

没有评论:

发表评论