Gstreamer динамически меняет исходный элемент - PullRequest
0 голосов
/ 18 мая 2018

У меня есть конвейер GStreamer, который извлекает видео из элемента rtspsrc.Элемент rtspsrc подключается к элементу rtpjpegdepay.Я хотел бы иметь возможность изменить URL RTSP на лету.Пока что я делал:

1) отсоединение rtspsrc от элемента depay

2) создание нового исходного элемента с новым RTSP URL

3) и связывание с элементом depay.

Проблема, с которой я сталкиваюсь, заключается в том, что новый исходный элемент RTSP неправильно связывается с элементом depay, что приводит к ошибкам сегмента.Мне нужна помощь в выяснении того, как динамически изменять URL-адрес rtspsrc (пока конвейер все еще играет).

Создание конвейера:

GstBus *bus;
guint busWatchId;
GstElement *src, *depay, *parser, *decoder, *vpe, *filter, *sink;
GstCaps *vpeCaps;

m_loop = g_main_loop_new(NULL, FALSE);

//create pipeline elements
m_cameraStream = gst_pipeline_new("display_pipeline");
src = gst_element_factory_make("rtspsrc", "rtspsrc");
depay = gst_element_factory_make("rtpjpegdepay", "depay");
parser = gst_element_factory_make("jpegparse", NULL);
decoder = gst_element_factory_make("ducatijpegdec", NULL);
vpe = gst_element_factory_make("vpe", NULL);
filter = gst_element_factory_make("capsfilter", NULL);
sink = gst_element_factory_make("waylandsink", NULL);

if(!(m_cameraStream || src || depay || parser || decoder || vpe || filter || sink)){
    qFatal("could not create pipeline elements");
    exit(1);
}

g_object_set(G_OBJECT(src), "location", "rtsp://192.168.50.29/av0_1", "latency", 0, NULL);
g_signal_connect(src, "pad-added", G_CALLBACK(on_rtsp_pad_added), depay);

//add src caps?
vpeCaps = gst_caps_from_string("video/x-raw, format=NV12, width=800, height=480");  //change this when Tomas' patch hits
if(!vpeCaps){
    qFatal("cannot create caps");
    exit(1);
}

g_object_set(G_OBJECT(filter), "caps", vpeCaps, NULL);
g_object_set(G_OBJECT(sink), "sync", false, NULL);

//add and link elements to create full pipeline
gst_bin_add_many(GST_BIN(m_cameraStream), src, depay, parser, decoder, vpe, sink, NULL);
if(!gst_element_link_many(depay, parser, decoder, vpe, sink, NULL)){
    qFatal("cannot link elements");
    exit(1);
}

gst_caps_unref(vpeCaps);

bus = gst_pipeline_get_bus(GST_PIPELINE(m_cameraStream));
busWatchId = gst_bus_add_watch(bus, GstBusFunc(bus_call), m_loop);
gst_object_unref(bus);

rtsp-> Функция обратного связывания с удалением ссылок:

gchar *name;
GstElement *depay;
GstCaps *caps;

qDebug("on_rtsp_pad_added");
caps = gst_caps_from_string("application/x-rtp");
name = gst_pad_get_name(pad);
qDebug("on_rtsp_pad_added, rtspsrc pad name: %s", name);
depay = GST_ELEMENT(data);
if(!gst_element_link_pads_filtered(element, name, depay, "sink", caps)){
    qFatal("pad_added: failed to link elements");
}
g_free(name);
gst_element_set_state(m_cameraStream, GST_STATE_PLAYING);
g_main_loop_run(m_loop);

Функция изменения источника:

qDebug("slot_changeSource");
//gst_element_set_state(m_cameraStream, GST_STATE_PAUSED); //GST_STATE_NULL: segfault in pad_added
                                                         //GST_STATE_PAUSED: pauses, never returns to playing or on_rtsp_pad_added
                                                         //GST_STATE_PLAYING(left playing): same as NULL
GstElement* rtspsrc = gst_bin_get_by_name(GST_BIN(m_cameraStream), "rtspsrc");
if(rtspsrc){
    qDebug("rtspsrc found");
    GstElement* depay = gst_bin_get_by_name(GST_BIN(m_cameraStream), "depay");
    if(depay){
        qDebug("depay found");
        gst_element_unlink(rtspsrc, depay);
        gst_bin_remove(GST_BIN(m_cameraStream), rtspsrc);
        GstElement* newSource = gst_element_factory_make("rtspsrc", "rtspsrc");
        g_object_set(G_OBJECT(newSource), "location", "rtsp://192.168.50.29/av0_1", "latency", 0, NULL);
        g_signal_connect(newSource, "pad-added", G_CALLBACK(on_rtsp_pad_added), depay); //needed in the same way as the previous rtspsrc
        gst_bin_add(GST_BIN(m_cameraStream), newSource);
        gst_element_sync_state_with_parent(newSource);
        //gst_element_set_state(m_cameraStream, GST_STATE_PLAYING);
    }
    gst_element_set_state(rtspsrc, GST_STATE_NULL);
    gst_object_unref(rtspsrc);
}

Другие вещи, которые я пробовал:

1) Зондирование площадки src элемента rtsp, чтобы убедиться, что нетлюбые данные в элементе.Это казалось плохой идеей, поскольку элемент rtsp был бы только что создан на этом этапе.

2) Установите конвейер на PAUSED или NULL, затем измените исходный элемент.Это приводит к тому, что конвейер временно останавливается.

Ссылки:

Список рассылки Gstreamer

Документация

1 Ответ

0 голосов
/ 23 мая 2018

Хорошо, так что я думаю, что нашел ответ, и я собираюсь опубликовать его здесь, чтобы спасти кого-нибудь, кто когда-нибудь наткнется на это.

Ответ - создать пару зондов для обработки очистка данных от конвейера.Я сделал это, создав два обратных вызова пробного зонда: один для перехвата конвейера, чтобы начать процесс сброса, и другой для обработки воссоздания элемента rtspsrc после сброса конвейера.Первый пробник может быть помещен куда угодно, поэтому я положил его на элемент удаления.Второй контактный датчик должен находиться на источнике последнего элемента обработки данных .Так что не последний элемент мойки.Для вышеприведенного конвейера это элемент 'vpe'.

Я делаю это, передавая сигнал End of Stream (EOS) в элемент depay, затем получаю обратный вызов pad pad на панели src vpe.элемент, чтобы поймать EOS, когда он выходит из VPE.Если EOS доберется до промежуточной полосы, конвейер просто закроется, и вам придется перезапустить все это.

vpe = gst_bin_get_by_name(GST_BIN(data), "vpe");
srcPad = gst_element_get_static_pad(vpe, "src");
gst_pad_add_probe(srcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, event_probe, data, NULL);

//push EOS into the element, wait for the EOS to appear on the srcpad
depay = gst_bin_get_by_name(GST_BIN(data), "depay");
sinkPad = gst_element_get_static_pad(depay, "sink");
gst_pad_send_event(sinkPad, gst_event_new_eos());    

return GST_PAD_PROBE_OK;

И обратный вызов для обработки этого EOS:

static GstPadProbeReturn event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data){
    GstElement *rtspsrcOld, *rtspsrcNew, *depay;

    qDebug("event_probe");
    if(GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS){
        return GST_PAD_PROBE_PASS;
    }

    gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));

    rtspsrcOld = gst_bin_get_by_name(GST_BIN(data), "rtspsrc");
    if(rtspsrcOld){
        qDebug("found rtspsrcOld");
        depay = gst_bin_get_by_name(GST_BIN(data), "depay");
        gst_element_unlink(rtspsrcOld, depay);
        gst_bin_remove(GST_BIN(data), rtspsrcOld); //remove old rtspsrc from pipeline, should unlink from depay automatically.
        rtspsrcNew = gst_element_factory_make("rtspsrc", "rtspsrc");
        g_object_set(rtspsrcNew, "location", NEW_URI, "latency", 0, NULL);
        g_signal_connect(G_OBJECT(rtspsrcNew), "pad-added", G_CALLBACK(on_rtsp_pad_added), data);

        gst_bin_add(GST_BIN(data), rtspsrcNew);
        gst_element_set_state(GST_ELEMENT(data), GST_STATE_PLAYING);

        return GST_PAD_PROBE_DROP;
    }
    return GST_PAD_PROBE_DROP;
}
...