Как возобновить игру после паузы с помощью gstreamer?

Я написал оболочку C++ для каждого типа Gstreamer. Они просты и интуитивно понятны, поэтому я не думаю, что их реализация должна быть размещена здесь (хотя я мог бы опубликовать их (возможно, на github), если возникнет такая необходимость).

Проблема, с которой я сталкиваюсь, заключается в том, что я начинаю воспроизводить видео (и одновременно сохраняю его в файл, используя элемент gst tee).... и пока оно воспроизводится, я делаю паузу (из другого потока), которая прекрасно работает. Однако, когда я хочу возобновить это, это не работает:

void pause()
{
    _pipeline.state(GST_STATE_PAUSED)
}

void resume()
{
    _pipeline.state(GST_STATE_PLAYING);
}

А вот и play() функция, в которой я создаю конвейер и устанавливаю его состояние в GST_STATE_PLAYING.

int play(std::string const & source_path, std::string const & save_as_file)
{
    gst::element source(source_path.substr(0,4) == "http" ? "souphttpsrc" : "filesrc", "media-source");
    gst::element demuxer("decodebin", "decoder");
    gst::element vconv("videoconvert",  "vconverter");
    gst::element vsink("autovideosink", "video-output");
    gst::element aconv("audioconvert",  "aconverter");
    gst::element asink("autoaudiosink", "audio-output");
    gst::element filesink("filesink", "file-sink");
    gst::element fq("queue", "file-queqe");
    gst::element tee("tee", "media-tee");
    gst::element aq("queue", "audio-queue");
    gst::element vq("queue", "video-queue");

    source.set("location", source_path.c_str());

    gst::bus bus = _pipeline.bus();
    guint bus_watch_id = _session.add_watch(bus);


    _pipeline.add(source, demuxer, vconv, vsink, aconv, asink, filesink, tee,fq, aq, vq);

    gst::element::link(source, tee); 

    gst::element::link(vq, vconv, vsink);
    gst::element::link(aq, aconv, asink);

    gst::pad tee_src_pad = tee.request_pad("src_%u");
    gst::pad demuxer_sink_pad = demuxer.static_pad("sink");

    gst::pad::link(tee_src_pad, demuxer_sink_pad);

    filesink.set("location",  save_as_file.c_str());

    gst::element::link(fq, filesink);

    gst::pad tee_src_pad2 = tee.request_pad("src_%u");
    gst::pad fq_pad = fq.static_pad ("sink");
    gst::pad::link(tee_src_pad2, fq_pad);

    gst::element::dynamic_link(demuxer, aq);
    gst::element::dynamic_link(demuxer, vq);

    g_print ("Now playing: %s\n", source_path.c_str());
    _pipeline.state(GST_STATE_PLAYING);

    //code
    _session.run()

    //cleanup
}

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

Я играю видео на виджете Qt, используя его дескриптор и передаю его в оверлей видео gstreamer.

2 ответа

Решение

Есть ли у вас элементы очереди на каждой ветви, которая идет от тройника? Один для файла и один для декодирования? Вы также можете попробовать поэкспериментировать со свойством "sync" на fileink. Может быть, установите его в true.


Под редакцией Nawaz.

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

gst::element filesink("filesink", "file-sink");
filesink.set("async", gboolean(FALSE));

Надеюсь, что это помогает и другим.

Я нашел ответ сам. Я попытался напечатать статус всех элементов как:

void print_status_of_all()
{
    auto it  = gst_bin_iterate_elements(GST_BIN(_pipeline.raw()));
    GValue value = G_VALUE_INIT;
    for(GstIteratorResult r = gst_iterator_next(it, &value); r != GST_ITERATOR_DONE; r = gst_iterator_next(it, &value))
    {
         if ( r == GST_ITERATOR_OK )
         {
             GstElement *e = static_cast<GstElement*>(g_value_peek_pointer(&value));
             GstState  current, pending;
             auto ret = gst_element_get_state(e, &current, &pending, 100000);
             g_print("%s(%s), status = %s, pending = %s\n", G_VALUE_TYPE_NAME(&value), gst_element_get_name(e), gst_element_state_get_name(current), gst_element_state_get_name(pending));
         }
    }
}

А потом это помогло мне выяснить, что статус всех элементов менялся с PLAYING на PAUSED и PAUSED на PLAYING, без какого-либо состояния ожидания, кроме filesink элемент, состояние которого остается в состоянии PLAYING и в состоянии ожидания PAUSED (которое происходит потому, что он пытается изменить его асинхронно) - что в конечном итоге привело меня к async собственность GstBaseSink который является базовым классом filesink, Я просто установил это FALSE как:

gst::element filesink("filesink", "file-sink");
filesink.set("async", gboolean(FALSE));

Вот и все. Теперь пауза и возобновление работают отлично - статус всех элементов меняется на PLAYING на PAUSED и PAUSED на PLAYING, без какого-либо состояния ожидания!

Другие вопросы по тегам