GStreamer: отправка строки в другой конвейер через UDP - PullRequest
2 голосов
/ 29 февраля 2020

У меня есть конвейер Gstreamer в C, предназначенный для отправки файла в принимающий конвейер через udp.

Мой конвейер отправки похож на этот:

filesrc location=X.mp4 ! decodebin ! videoconvert ! x264enc ! rtph264pay ! udpsink host=X port=5000

Мой приемный конвейер похож на это:

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

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

Я понимаю, что не могу используйте textoverlay, потому что текст становится частью пикселей видео, и очевидным решением, по-видимому, является использование субтитров, но Я не могу понять, как динамически создавать поток субтитров . Просто чтобы подчеркнуть: я не могу использовать файл субтитров, потому что мне нужно иметь возможность отправлять субтитры «на лету».

Любая помощь будет с благодарностью.

1 Ответ

1 голос
/ 10 марта 2020

В конце концов мне удалось это сделать. Если в будущем это кому-нибудь поможет:

В моем конвейере отправителя я подключаю зонд к элементу rtph264pay sr c:

rtph264pay_src_pad = gst_element_get_static_pad(rtph264pay_HD, "src");
    gst_pad_add_probe (rtph264pay_src_pad, GST_PAD_PROBE_TYPE_BUFFER,
                       (GstPadProbeCallback) set_x_to_rtp_header, NULL, NULL);
    gst_object_unref (rtph264pay_src_pad);

Это обратный вызов "set_x_to_rtp_header":

static GstPadProbeReturn set_x_to_rtp_header (GstPad          *pad,
                                              GstPadProbeInfo *info,
                                              gpointer         user_data)
{
    GstBuffer *buffer;
    GstRTPBuffer rtpBuffer = GST_RTP_BUFFER_INIT;
    g_print("%s\n", __func__);

    buffer = GST_PAD_PROBE_INFO_BUFFER (info);
    buffer = gst_buffer_make_writable (buffer);

    /* Making a buffer writable can fail (for example if it
     * cannot be copied and is used more than once)
     */
    if (buffer == NULL)
        return GST_PAD_PROBE_OK;

    if (gst_rtp_buffer_map (buffer,GST_MAP_WRITE, &rtpBuffer)) {

        pthread_mutex_lock(&mutex);
        if (gst_rtp_buffer_set_extension_data(&rtpBuffer, setup_data.left_videocrop, sizeof(setup_data.left_videocrop)) != TRUE) {
            g_printerr("cannot add extension to rtp header");
        }
        pthread_mutex_unlock(&mutex);

        gst_rtp_buffer_unmap (&rtpBuffer);
    }

    return GST_PAD_PROBE_OK;
}

В моем конвейере приемника я присоединяю зонд к элементу приемника rtph264depay:

 rtph264depay_sink_pad = gst_element_get_static_pad(rtph264depay_HD, "sink");
    gst_pad_add_probe (rtph264depay_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
                       (GstPadProbeCallback) get_x_from_rtp_header, videomixer, NULL);
    gst_object_unref (rtph264depay_sink_pad);

И это обратный вызов "get_x_from_rtp_header":

static GstPadProbeReturn get_x_from_rtp_header (GstPad          *pad,
                                                GstPadProbeInfo *info,
                                                gpointer         user_data)
{
    GstBuffer *buffer;
    GstRTPBuffer rtpBuffer = GST_RTP_BUFFER_INIT;
    guint16 ret_x;
    gpointer data;
    guint wordlen;
    GstElement* videomixer = (GstElement*)user_data;
    GstPad* videomixer_HD_sink_pad;

    g_print("%s\n", __func__);

    buffer = GST_PAD_PROBE_INFO_BUFFER (info);
    buffer = gst_buffer_make_writable (buffer);

    /* Making a buffer writable can fail (for example if it
     * cannot be copied and is used more than once)
     */
    if (buffer == NULL)
        return GST_PAD_PROBE_OK;

    if (gst_rtp_buffer_map (buffer,GST_MAP_READ, &rtpBuffer)) {
        //get x from the rtp header and into ret_x variable
        if (gst_rtp_buffer_get_extension_data(&rtpBuffer, &ret_x, &data, &wordlen) != TRUE) {
            return GST_PAD_PROBE_OK;
        }

        gst_rtp_buffer_unmap (&rtpBuffer);
    }

    return GST_PAD_PROBE_OK;
}
...