Как добавить субтитры из файла SRT на видео и воспроизвести его с помощью Gstreamer в программе c

Я хочу воспроизвести видео с помощью программы C, используя Gstreamer и добавив субтитры из файла SRT.

Я новичок в gstreamer и каким-то образом понял, кто может заставить его работать в командной строке:

gst-launch filesrc location=video.srt ! subparse ! \
    overlay. filesrc location=video.ogv ! oggdemux name=demux \
    demux. ! queue ! vorbisdec ! audioconvert ! autoaudiosink \
    demux. ! queue ! theoradec ! ffmpegcolorspace ! subtitleoverlay name=overlay ! autovideosink;

Проблема в том, что я могу воспроизводить видео из программы на C, но я не понял, как добавить субтитры.

int main (int argc, char *argv[]) {
    GMainLoop *loop;

    GstElement *pipeline, *source, *demuxer, *audioDecoder, *videoDecoder, *audioConv, *videoConv, *videosink, 
            *audiosink, *audioQueue, *videoQueue;
    GstBus *bus;

    gst_init (&argc, &argv);

    loop = g_main_loop_new (NULL, FALSE);

    if (argc < 2 && argc > 3) {
        g_printerr ("Usage: %s <Ogg/Vorbis filename> [Srt filename]\n", argv[0]);
        return -1;
    }

    pipeline     = gst_pipeline_new ("audiovideo-player");
    source       = gst_element_factory_make ("filesrc",          "file-source");
    demuxer      = gst_element_factory_make ("oggdemux",         "ogg-demuxer");
    audioQueue   = gst_element_factory_make ("queue",            "audio-queue");
    videoQueue   = gst_element_factory_make ("queue",            "video-queue");
    audioDecoder = gst_element_factory_make ("vorbisdec",        "vorbis-decoder");
    videoDecoder = gst_element_factory_make ("theoradec",        "theora-decoder");
    audioConv    = gst_element_factory_make ("audioconvert",     "audio-converter");
    videoConv    = gst_element_factory_make ("ffmpegcolorspace", "video-converter");
    videosink    = gst_element_factory_make ("autovideosink",    "video-output");
    audiosink    = gst_element_factory_make ("autoaudiosink",    "audio-output");


    if (!pipeline || !source || !demuxer || !audioDecoder || !audioConv || !videoDecoder || !videoConv || !audioQueue 
            || !videoQueue || !audiosink || !videosink) {
        g_printerr ("One element could not be created. Exiting.\n");
        exit(-1);
    }

    g_object_set (G_OBJECT (source), "location", argv[1], NULL);

    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    gst_bus_add_watch (bus, bus_call, loop);
    gst_object_unref (bus);

    gst_bin_add_many (GST_BIN (pipeline),
                        source, demuxer, 
                        audioQueue, videoQueue, audioDecoder, videoDecoder,
                        videoConv, audioConv, videosink, audiosink, NULL);

    gst_element_link (source, demuxer);

    gst_element_link_many (videoQueue, videoDecoder, videoConv, videosink, NULL);
    g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), videoQueue);

    gst_element_link_many (audioQueue, audioDecoder, audioConv, audiosink, NULL);
    g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), audioQueue);

    g_print ("Lecture de : %s\n", argv[1]);
    gst_element_set_state (pipeline, GST_STATE_PLAYING);

    g_print ("En cours...\n");
    g_main_loop_run (loop);

    g_print ("Arret de la lecture\n");
    gst_element_set_state (pipeline, GST_STATE_NULL);
    g_print ("Suppression du pipeline\n");
    gst_object_unref (GST_OBJECT (pipeline));
    return 0;
} 

person Aleksandair    schedule 20.10.2014    source источник


Ответы (2)


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

В любом случае, видео из файла также должно быть подключено к наложению субтитров, и вы должны связать видеоприемник после наложения субтитров. И вы также свяжете дополнительный файл filesrc для файла субтитров с наложением субтитров.

Взгляните на код внутри playbin/playink для обработки субтитров, и особенно для динамической обработки этих вещей. Также обратите внимание, что playbin имеет свойство sub-uri, которое позволяет вам выбрать внешний файл субтитров, который должен быть наложен поверх видео.

person Sebastian Dröge    schedule 20.10.2014
comment
Я не получил всего этого, но я искал решение без playbin, если это возможно. - person Aleksandair; 22.10.2014
comment
Какие части вам непонятны? :) Кроме того, почему вы не хотите использовать playbin, это то, что мы рекомендуем для любых случаев использования воспроизведения (кроме супер-специальных, которые, похоже, не для вас). - person Sebastian Dröge; 22.10.2014
comment
Я не понимаю насчет колодки. Насчет плейбина, это потому, что меня попросили заставить его работать без него (иначе я бы с удовольствием им пользовался). Извините за недостаток знаний, но я только недавно начал работать с gstreamer, и самое близкое, что я нашел, это простой код без объяснений. - person Aleksandair; 23.10.2014
comment
Я изменил командную строку, эта лучше? Не могли бы вы объяснить мне, что вы имели в виду под тем, что нужно было связать и как, или ссылкой на учебник? - person Aleksandair; 24.10.2014
comment
Да, новый конвейер gst-launch у вас правильный. В качестве альтернативы вы также можете заменить subparse элементом typefind, в этом случае subtitleoverlay выберет соответствующие элементы для рендеринга субтитров на основе самого формата. Также вы можете заменить демультиплексор и декодеры на decodebin (или decodebin2, если вы используете GStreamer 0.10, как вам кажется... но на самом деле используйте 1.x). - person Sebastian Dröge; 25.10.2014
comment
И то, как вы связываете элементы сейчас, это именно то, что я имел в виду, да. - person Sebastian Dröge; 25.10.2014
comment
К сожалению, у меня нет выбора инструментов, поэтому он должен быть неполным, без плейбина и этой версии gstreamer. - person Aleksandair; 25.10.2014
comment
И я до сих пор не могу сделать то же самое в C, лучшее, что у меня есть, это то, что возвращает ошибку в потоке данных g_object_set (G_OBJECT (subSource), location, argv[2], NULL); gst_element_link (videoConv, subOverlay); gst_element_link_many (subSource, subParse, NULL); g_signal_connect (subOverlay, pad-added, G_CALLBACK (on_pad_added), subSource); - person Aleksandair; 25.10.2014
comment
В subparse есть блок ВСЕГДА, вы можете напрямую связать его, например, с помощью gst_element_link_pads(). Сигнал pad-add на subparse никогда не будет испускаться, так как pad существует с момента создания экземпляра. В вашем сценарии вам нужно использовать только добавленный сигнал для демультиплексора. Вы также всегда должны проверять, удалось ли связать элементы, и если вы получаете ошибки во время выполнения, проверьте журналы отладки GStreamer для получения дополнительной информации о том, что происходит. - person Sebastian Dröge; 25.10.2014

Большое спасибо, Себастьян Дрёдж, наконец-то я могу воспроизвести видео с субтитрами. Вот код, который я сделал.

gst_element_link_many (videoQueue, videoDecoder, videoConv, subOverlay, videosink, NULL);
g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), videoQueue);

gst_element_link_many (audioQueue, audioDecoder, audioConv, audiosink, NULL);
g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), audioQueue);


g_object_set (G_OBJECT (subSource), "location", argv[2], NULL);

Теперь я думаю использовать GTK для добавления таких функций, как приостановка видео, возможно, его нужно будет немного почистить, но пока этого достаточно.

person Aleksandair    schedule 25.10.2014