Код Gstreamer C не выполнен с остановкой потоковой передачи, причина не согласована (-4) - PullRequest
0 голосов
/ 10 мая 2019

Я изучаю Gstreamer и все, чего я достиг с помощью инструментов Gstreamer, я пытаюсь реализовать то же самое с приложением gstreamer с использованием языка Си.

Ниже команда успешно транслировала видео файл mp4: gst-launch-1.0.exe -v filesrc location = file.mp4! qtdemux! h264parse! avdec_h264! видеоконвертер! autovideosink

Я пытался сделать то же самое с кодом C, а также использовал «добавленные в пэды» сигналы элементов для создания пэдов и связывал их со следующим элементом, то есть с парсером (h264parser).

Итак, произошел сбой при остановке потоковой передачи, причина не согласована.

Полный вывод: Сейчас играет: file.mp4 Бег... Новый блок video_0 был создан для demux Элемент demux будет связан с парсером Ошибка: внутренняя ошибка потока данных. Отладочная информация: ../gst/isomp4/qtdemux.c(6607): gst_qtdemux_loop (): / GstPipeline: воспроизведение видео / GstQTDemux: demux: потоковая передача остановлена, причина не согласована (-4) Вернулся, остановка воспроизведения ... Освобождающий трубопровод ... Завершено. До свидания!

#include <gst/gst.h>
#include <stdlib.h>
#include <string.h>

#define INPUT_FILE "file.mp4"

static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *)data;

    switch (GST_MESSAGE_TYPE(msg)) {
        gchar  *debug;
        GError *error;

    case GST_MESSAGE_EOS:
        g_print("End of stream\n");
        g_main_loop_quit(loop);
        break;

    case GST_MESSAGE_ERROR:

        gst_message_parse_error(msg, &error, &debug);
        g_free(debug);

        g_printerr("Error: %s\n", error->message);
        g_printerr("Debug Information: %s\n", debug);
        g_error_free(error);

        g_main_loop_quit(loop);
        break;
    default:
        break;
    }

    return TRUE;
}


static void on_pad_added(GstElement *element, GstPad *pad, gpointer data)
{
    gchar *name;
    GstElement *parse = (GstElement *)data;

    name = gst_pad_get_name(pad);
    g_print("A new pad %s was created for %s\n", name, gst_element_get_name(element));
    g_free(name);

    g_print("element %s will be linked to %s\n",
        gst_element_get_name(element),
        gst_element_get_name(parse));

    gst_element_link(element, parse);
}

int main(int argc, char *argv[])
{
    GMainLoop *loop;
    GstElement *pipeline, *source, *demux, *parser, *decoder, *sink, *fpssink;
    GstBus *bus;
    guint bus_watch_id;

    const gchar *input_file = INPUT_FILE;

    /* Initialization */
    gst_init(&argc, &argv);
    loop = g_main_loop_new(NULL, FALSE);

    /* Create gstreamer elements */
    pipeline = gst_pipeline_new("video-play");
    source = gst_element_factory_make("filesrc", "file-source");
    demux = gst_element_factory_make("qtdemux", "demux");
    parser = gst_element_factory_make("h264parse", "h264-parser");
    decoder = gst_element_factory_make("avdec_h264", "decoder");
    sink = gst_element_factory_make("d3dvideosink", "video-output");

    if (!pipeline || !source || !demux || !parser || !decoder || !sink) {
        g_printerr("One element could not be created. Exiting.\n");
        return -1;
    }

    /* Set input video file for source element */
    g_object_set(G_OBJECT(source), "location", input_file, NULL);

    /* we add a message handler */
    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    bus_watch_id = gst_bus_add_watch(bus, bus_call, loop);
    gst_object_unref(bus);

    /* Add all elements into the pipeline */
    /* pipeline---[ filesrc + qtdemux + h264parse + avdec_h264 + d3dvideosink ] */
    gst_bin_add_many(GST_BIN(pipeline), source, demux, parser, decoder, sink, NULL);

    /* Link the elements filesrc->demux together */

    if (gst_element_link(source, demux) != TRUE) {
        g_printerr("Element source->demux could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }
    /* h264parse -> avdec_h264 -> d3dvideosink */

    if (gst_element_link_many(parser, decoder, sink, NULL) != TRUE) {
            g_printerr("Many Elements could not be linked.\n");
            gst_object_unref(pipeline);
            return -1;
    }

    g_signal_connect(demux, "pad-added", G_CALLBACK(on_pad_added), parser);

    /* Set the pipeline to "playing" state */
    g_print("Now playing: %s\n", input_file);
    if (gst_element_set_state(pipeline,
        GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    g_print("Running...\n");
    g_main_loop_run(loop);


    /* Free resources and change state to NULL */
    gst_object_unref(bus);
    g_print("Returned, stopping playback...\n");
    gst_element_set_state(pipeline, GST_STATE_NULL);
    g_print("Freeing pipeline...\n");
    gst_object_unref(GST_OBJECT(pipeline));
    g_print("Completed. Goodbye!\n");
    return 0;
}

Ребята, пожалуйста, дайте мне знать, как связать эти пэды с элементом h264parser для потоковой передачи видеофайла. Если возможно, объясните, как эти панели работают в инструментах и ​​приложениях Gstreamer

1 Ответ

0 голосов
/ 31 мая 2019

Ниже команды успешно транслируется видеофайл mp4: gst-launch-1.0.exe -v filesrc location = file.mp4!qtdemux!h264parse!avdec_h264!видеоконвертер!autovideosink

В идеале ваш конвейер должен быть:

gst-launch-1.0.exe -v filesrc location = file.mp4!qtdemux name = d d.video_0!очередь !h264parse!avdec_h264!видеоконвертер!autovideosink

Если вы проверите qtdemux (gst-inspect-1.0 qtdemux) , вы заметите, что пэды SINK имеют следующие заглавные буквы:

Возможности: видео / QuickTime видео / MJ2 аудио / X-M4A приложение / X-3GP

И если вы проверяете h264parse (gst-inspect-1.0 h264parse) , вы заметитечто пэды SRC имеют следующие заглавные буквы:

шаблон SRC: 'src' Доступность: всегда Возможности: video / x-h264 проанализирован: true stream-format: {(string) avc, (string)avc3, (string) byte-stream} выравнивание: {(string) au, (string) nal}

Когда вы пытаетесь связать панель приемника Qtdemux с панелью src h264parse, вы можетедля соединения с h264parse нужно собрать видео-шапки.

Я использовал приведенный ниже код для связи qtdemux с h264parse внутри сигнала «добавлено pad»:

static void pad_added_handler(GstElement *src, GstPad *new_pad, App *data) {
   GstPadLinkReturn ret;
   GstCaps *new_pad_caps = NULL;
   GstStructure *new_pad_struct = NULL;
   const gchar *new_pad_type = NULL;

   /* Check the new pad's type */
   new_pad_caps = gst_pad_get_current_caps(new_pad);
   new_pad_struct = gst_caps_get_structure(new_pad_caps, 0);
   new_pad_type = gst_structure_get_name(new_pad_struct);

   GST_PAD_NAME(new_pad), new_pad_type, gst_caps_to_string(new_pad_caps));

    if (g_str_has_prefix(new_pad_type, "video/x-h264")) {
          ret = gst_pad_link(new_pad, sink_pad_video);
     }
   }

Примечание: вы можетенужно связать фильтры шапки, чтобы отфильтровать желаемую видео возможность вашего источника видео или просто попробуйте условие как: if (g_str_has_prefix (new_pad_type, " video ")) {}

Но я не уверен, как добавление очереди решило вашу проблему.

Надеюсь, это поможет.

...