使用 gstreamer 和 gst-launch 循环播放视频?

发布于 2024-11-26 10:48:53 字数 295 浏览 2 评论 0原文

我可以使用 gstreamer 的 gst-launch 在命令行上播放视频,如下所示:

gst-launch gnlfilesource location=file:///tmp/myfile.mov start=0 duration=2000000000 ! autovideosink

这将播放 /tmp/myfile.mov 中文件的前 2 秒,然后视频播放停止。有没有办法让它重复循环?即将2秒长的gnlfilesource变成一个无限长度的视频,一遍又一遍地播放这2秒?

I am able to play a video on the command line with gstreamer's gst-launch like this:

gst-launch gnlfilesource location=file:///tmp/myfile.mov start=0 duration=2000000000 ! autovideosink

This plays the first 2 seconds of the file in /tmp/myfile.mov, afterwards the video playback stops. Is there anyway to get this to loop repeatidly? i.e. turn the 2 second long gnlfilesource into an infinite length video that plays those 2 seconds again and again and again?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

柳絮泡泡 2024-12-03 10:48:53

如果使用 gst-launch 那么你可能必须使用 while true;执行[你的命令];正如 Fredrik 所说,已完成。但是,如果对 C 代码感兴趣,我编写的代码可能会对您有所帮助。在第一次运行的流末尾,从文件开头开始每 2 秒循环播放一次视频。

  //(c) 2011 enthusiasticgeek
  // This code is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

#include <gst/gst.h>

gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
    GstElement *play = GST_ELEMENT(data);
    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
        /* restart playback if at end */
        if (!gst_element_seek(play, 
                    1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
                    GST_SEEK_TYPE_SET,  2000000000, //2 seconds (in nanoseconds)
                    GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
            g_print("Seek failed!\n");
        }
        break;
    default:
        break;
    }
    return TRUE;
}

gint
main (gint   argc,
      gchar *argv[])
{
  GMainLoop *loop;
  GstElement *play;
  GstBus *bus;

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

  /* make sure we have a URI */
  if (argc != 2) {
    g_print ("Usage: %s <URI>\n", argv[0]);
    return -1;
  }

  /* set up */
  play = gst_element_factory_make ("playbin", "play");
  g_object_set (G_OBJECT (play), "uri", argv[1], NULL);

  bus = gst_pipeline_get_bus (GST_PIPELINE (play));
  gst_bus_add_watch (bus, bus_callback, play);
  gst_object_unref (bus);

  gst_element_set_state (play, GST_STATE_PLAYING);

  /* now run */
  g_main_loop_run (loop);

  /* also clean up */
  gst_element_set_state (play, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (play));

  return 0;
}

更新:
请参阅以下链接
http://gstreamer.freedesktop.org/data /doc/gstreamer/head/manual/html/chapter-dataaccess.html

[第 19.1.2 节。播放媒体文件的某个区域]。这可以与我的代码结合使用。

If using gst-launch then you may have to use while true; do [your command]; done as Fredrik has stated. However if interested in C code, I have written a code which may help you. Looping of video every 2 seconds from the beginning of the file at the end of the stream of first run.

  //(c) 2011 enthusiasticgeek
  // This code is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

#include <gst/gst.h>

gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
    GstElement *play = GST_ELEMENT(data);
    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
        /* restart playback if at end */
        if (!gst_element_seek(play, 
                    1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
                    GST_SEEK_TYPE_SET,  2000000000, //2 seconds (in nanoseconds)
                    GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
            g_print("Seek failed!\n");
        }
        break;
    default:
        break;
    }
    return TRUE;
}

gint
main (gint   argc,
      gchar *argv[])
{
  GMainLoop *loop;
  GstElement *play;
  GstBus *bus;

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

  /* make sure we have a URI */
  if (argc != 2) {
    g_print ("Usage: %s <URI>\n", argv[0]);
    return -1;
  }

  /* set up */
  play = gst_element_factory_make ("playbin", "play");
  g_object_set (G_OBJECT (play), "uri", argv[1], NULL);

  bus = gst_pipeline_get_bus (GST_PIPELINE (play));
  gst_bus_add_watch (bus, bus_callback, play);
  gst_object_unref (bus);

  gst_element_set_state (play, GST_STATE_PLAYING);

  /* now run */
  g_main_loop_run (loop);

  /* also clean up */
  gst_element_set_state (play, GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (play));

  return 0;
}

Update:
See the following link
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/manual/html/chapter-dataaccess.html

[Section 19.1.2. Play a region of a media file]. This could be used in conjugation with my code.

醉南桥 2024-12-03 10:48:53

这似乎可以通过 multifilesrc 实现 插件,

gst-launch-1.0 multifilesrc location=alien-age.mpg loop=true ! decodebin ! autovideosink

似乎是在 2011 年 6 月添加的。

This seems to be possible with multifilesrc plugin,

gst-launch-1.0 multifilesrc location=alien-age.mpg loop=true ! decodebin ! autovideosink

Seems to be added back in June 2011.

秋日私语 2024-12-03 10:48:53

multifilesrc 是最简单的方法,但它不适用于已知“媒体长度”的媒体文件。仅当文件没有任何有关时间或长度的信息时,您才可以循环播放任何视频文件。

使用任何媒体播放器打开您的文件,如果它显示媒体长度或者您可以向前或向后搜索文件,则意味着它知道媒体长度并且 multifilesrc 不会循环它。

如何使用 GStreamer 将视频文件转换为没有时间轨迹的文件(流文件):

您需要在命令行上运行两个管道,首先运行录制器:

gst-launch-1.0 udpsrc port=10600 ! application/x-rtp-stream ! rtpstreamdepay name=pay1 ! rtph264depay ! h264parse ! video/x-h264,alignment=nal ! filesink location=my_timeless_file.mp4

它启动并等待传入​​流。

在另一个终端上运行播放管道:

gst-launch-1.0 filesrc location=my_file_with_time_track ! queue ! decodebin ! videoconvert ! x264enc ! h264parse config-interval=-1 ! rtph264pay pt=96 ! rtpstreampay name=pay0 ! udpsink host=127.0.0.1 port=10600

播放管道在传输整个文件时启动并最终终止,现在返回到第一个命令行并使用 Ctrl+C 终止记录管道。

(您可以使用任何其他机制来制作流,而不是 udpsrc/udpsink,例如 appsrc/appsink)

现在您有了一个可以在带有循环的 multifilesrc 中使用的新文件:

gst-launch-1.0 multifilesrc location=my_timeless_file.mp4 loop=true ! queue ! decodebin ! videoconvert ! ximagesink

为什么 multifilesrc< /code> 不循环已知长度的文件?

因为当媒体长度已知时,它会向下游发送 EOS 消息并导致整个管道进入 NULL 状态,通过在到达文件末尾(字节流)时删除该信息,它会尝试找到下一个要播放的文件(记住它是 “multi”文件源,默认情况下可以接受通配符位置,例如“image_%d.png”)。当没有通配符指向下一个文件时,它将循环回仅已知的文件。

multifilesrc is the easiest way, but it won't work on media files that have "Media length" known. you can loop on any video files only if file does not have any information about the time or length.

Open your file with any media player, if it shows media length or if you can seek the file forward or backward, that means it knows the media length and multifilesrc won't loop it.

How to convert video file into file without time track (stream file) with GStreamer:

you need to run two pipelines on command line, first run the recorder:

gst-launch-1.0 udpsrc port=10600 ! application/x-rtp-stream ! rtpstreamdepay name=pay1 ! rtph264depay ! h264parse ! video/x-h264,alignment=nal ! filesink location=my_timeless_file.mp4

it starts and waits for incoming stream.

on another terminal run the play pipeline:

gst-launch-1.0 filesrc location=my_file_with_time_track ! queue ! decodebin ! videoconvert ! x264enc ! h264parse config-interval=-1 ! rtph264pay pt=96 ! rtpstreampay name=pay0 ! udpsink host=127.0.0.1 port=10600

play pipeline starts and eventually terminates when it streamed whole file, now go back to the first command line and terminate recording pipeline with Ctrl+C.

(instead of udpsrc/udpsink you can use any other mechanisms to make the stream, like appsrc/appsink)

Now you have a new file which can be used in multifilesrc with loop:

gst-launch-1.0 multifilesrc location=my_timeless_file.mp4 loop=true ! queue ! decodebin ! videoconvert ! ximagesink

Why multifilesrc does not loop files with known length?

Because when length of media is known it sends EOS message downstream and causes whole pipeline going to state NULL, by removing that information when it reaches end of file (byte stream) it tries to find next file to play (remember it is "multi" file source, and by default can accept wildcard location like "image_%d.png"). When there is no wildcard to point to the next file, it loops back to only known file.

只怪假的太真实 2024-12-03 10:48:53

根据 #gstreamer IRC 频道上的人员的说法,您无法使用 gstreamer 本身来执行此操作,您需要 gstreamer 管道之外的某些东西来循环它。

According to folks on the #gstreamer IRC channel, you can't do this with gstreamer itself, you'd need something outside the gstreamer pipeline to loop it.

悟红尘 2024-12-03 10:48:53

它不是在 gstreamer 上的流中循环文件,但我可以使用 ffmpeg -stream_loop 选项来做到这一点。
https://ffmpeg.org/ffmpeg.html#Main-options

$ ffmpeg -re -stream_loop -1 -i /tmp/sample.mp4 -f rtsp rtsp://localhost:8554/stream

It's not looping file in stream on gstreamer, but I was able to do it with ffmpeg -stream_loop option.
https://ffmpeg.org/ffmpeg.html#Main-options

$ ffmpeg -re -stream_loop -1 -i /tmp/sample.mp4 -f rtsp rtsp://localhost:8554/stream
隐诗 2024-12-03 10:48:53

假设 bash...

将其包装在 while 循环中?

while true; do [your command]; done

其中 true 没有成功执行任何操作,即

true: true
    Return a successful result.

    Exit Status:
    Always succeeds.

它允许您创建无限循环,例如

$ while true; do echo "run..."; sleep 1; done
run...
run...
run...
run...
run...
...

Assuming bash...

Wrap it in a while-loop?

while true; do [your command]; done

where true does nothing sucessfully, i.e.

true: true
    Return a successful result.

    Exit Status:
    Always succeeds.

It allows you to create infinite loops, e.g.

$ while true; do echo "run..."; sleep 1; done
run...
run...
run...
run...
run...
...
简美 2024-12-03 10:48:53

您可以在 C++ 中使用 gstreamermm lib。请注意,这只是一个示例。

剪切视频的示例:

#include <gstreamermm.h>
#include <glibmm/main.h>
#include <glibmm/convert.h>
#include <iostream>
#include <stdlib.h>
#include <gstreamermm/playbin.h>

namespace
{

    Glib::RefPtr<Glib::MainLoop> mainloop;
    Glib::RefPtr<Gst::PlayBin> playbin;
    gboolean bus_callback(const Glib::RefPtr<Gst::Bus>& bus ,
        const Glib::RefPtr<Gst::Message>& message)
    {
        switch (message->get_message_type()) {
        case Gst::MESSAGE_EOS:
        {
            playbin->seek(1.0, Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH, Gst::SEEK_TYPE_SET, 0
                , Gst::SEEK_TYPE_NONE, 0);
            return true;
        }
        case Gst::MESSAGE_ERROR:
        {
            Glib::RefPtr<Gst::MessageError> msgError =
                Glib::RefPtr<Gst::MessageError>::cast_static(message);

            if (msgError)
            {
                Glib::Error err;
                err = msgError->parse_error();
                std::cerr << "Error: " << err.what() << std::endl;
            }
            else
                std::cerr << "Error." << std::endl;

            mainloop->quit();
            return false;
        }
        default:
            break;
        }

        return true;
    }
}

int main(int argc, char** argv)
{
    Gst::init(argc, argv);
    if (argc < 2)
    {
        std::cout << "Usage: " << argv[0] << " <media file or uri>" << std::endl;
        return EXIT_FAILURE;
    }
#ifndef GSTREAMERMM_DISABLE_DEPRECATED
    playbin = Gst::PlayBin::create();
#else
    Glib::RefPtr<Gst::Element> playbin = Gst::ElementFactory::create_element("playbin");
#endif

    if (!playbin)
    {
        std::cerr << "The playbin2 element could not be created." << std::endl;
        return EXIT_FAILURE;
    }

    Glib::ustring uri;

    if (gst_uri_is_valid(argv[1]))
        uri = argv[1];
    else
        uri = Glib::filename_to_uri(argv[1]);

    
    mainloop = Glib::MainLoop::create();

    playbin->set_property("uri", uri);

    Glib::RefPtr<Gst::Bus> bus = playbin->get_bus();

    bus->add_watch(sigc::ptr_fun(&bus_callback));

    playbin->set_state(Gst::STATE_PLAYING);

    mainloop->run();
    std::cout << "Returned. Setting state to NULL." << std::endl;
    playbin->set_state(Gst::STATE_NULL);
    return EXIT_SUCCESS;
}

或者您可以使用经典的 C lib gst。
剪辑视频示例:

#include <gst/gst.h>
#include <glib-object.h>

typedef struct _CustomData {
    GstElement* playbin;
    GMainLoop* loop;
} CustomData;


gboolean bus_callback(GstBus* bus, GstMessage* msg, CustomData* data)
{
    GstElement* play = GST_ELEMENT(data->playbin);
    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
    {
        gboolean ret = gst_element_seek(play,
            1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
            GST_SEEK_TYPE_SET, 0,
            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
        if (!ret)
        {
            g_print("Seek failed!\n");
            return FALSE;
        }
        return TRUE;
    }
    case GST_MESSAGE_ERROR:
    {
        GError* err;
        gchar* debug;
        gst_message_parse_error(msg, &err, &debug);
        g_print("Error: %s\n", err->message);
        g_error_free(err);
        g_free(debug);
        g_main_loop_quit(data->loop);
        return FALSE;
    }
    default:
        break;
    }
    return TRUE;
}

gint main(gint argc, gchar** argv)
{
    GMainLoop* main_loop;
    GstElement* playbin;
    GstBus* bus;
    GstStateChangeReturn ret;
    CustomData data;
    if (argc < 2)
    {
        g_print("Usage: %s <URI>\n", argv[0]);
        return EXIT_FAILURE;
    }
    gst_init(&argc, &argv);
    playbin = gst_element_factory_make("playbin", "playbin");

    gchar* uri;
    if (gst_uri_is_valid(argv[1]))
        uri = argv[1];
    else
        uri = gst_filename_to_uri(argv[1], NULL);
    g_object_set(G_OBJECT(playbin), "uri", uri, NULL);
    bus = gst_element_get_bus(playbin);
    ret = gst_element_set_state(playbin, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(playbin);
        return EXIT_FAILURE;
    }
    main_loop = g_main_loop_new(NULL, FALSE);
    data.loop = main_loop;
    data.playbin = playbin;
    gst_bus_add_watch(bus, (GstBusFunc)bus_callback, &data);

    g_main_loop_run(main_loop);
    
    g_main_loop_unref(main_loop);
    gst_element_set_state(playbin, GST_STATE_NULL);
    gst_object_unref(playbin);
    gst_object_unref(bus);
    return EXIT_SUCCESS;
}

You can use gstreamermm lib in C++. Note it's just an example.

Example of lopping video:

#include <gstreamermm.h>
#include <glibmm/main.h>
#include <glibmm/convert.h>
#include <iostream>
#include <stdlib.h>
#include <gstreamermm/playbin.h>

namespace
{

    Glib::RefPtr<Glib::MainLoop> mainloop;
    Glib::RefPtr<Gst::PlayBin> playbin;
    gboolean bus_callback(const Glib::RefPtr<Gst::Bus>& bus ,
        const Glib::RefPtr<Gst::Message>& message)
    {
        switch (message->get_message_type()) {
        case Gst::MESSAGE_EOS:
        {
            playbin->seek(1.0, Gst::FORMAT_TIME, Gst::SEEK_FLAG_FLUSH, Gst::SEEK_TYPE_SET, 0
                , Gst::SEEK_TYPE_NONE, 0);
            return true;
        }
        case Gst::MESSAGE_ERROR:
        {
            Glib::RefPtr<Gst::MessageError> msgError =
                Glib::RefPtr<Gst::MessageError>::cast_static(message);

            if (msgError)
            {
                Glib::Error err;
                err = msgError->parse_error();
                std::cerr << "Error: " << err.what() << std::endl;
            }
            else
                std::cerr << "Error." << std::endl;

            mainloop->quit();
            return false;
        }
        default:
            break;
        }

        return true;
    }
}

int main(int argc, char** argv)
{
    Gst::init(argc, argv);
    if (argc < 2)
    {
        std::cout << "Usage: " << argv[0] << " <media file or uri>" << std::endl;
        return EXIT_FAILURE;
    }
#ifndef GSTREAMERMM_DISABLE_DEPRECATED
    playbin = Gst::PlayBin::create();
#else
    Glib::RefPtr<Gst::Element> playbin = Gst::ElementFactory::create_element("playbin");
#endif

    if (!playbin)
    {
        std::cerr << "The playbin2 element could not be created." << std::endl;
        return EXIT_FAILURE;
    }

    Glib::ustring uri;

    if (gst_uri_is_valid(argv[1]))
        uri = argv[1];
    else
        uri = Glib::filename_to_uri(argv[1]);

    
    mainloop = Glib::MainLoop::create();

    playbin->set_property("uri", uri);

    Glib::RefPtr<Gst::Bus> bus = playbin->get_bus();

    bus->add_watch(sigc::ptr_fun(&bus_callback));

    playbin->set_state(Gst::STATE_PLAYING);

    mainloop->run();
    std::cout << "Returned. Setting state to NULL." << std::endl;
    playbin->set_state(Gst::STATE_NULL);
    return EXIT_SUCCESS;
}

Or you can use classic C lib gst.
Example of lopping video:

#include <gst/gst.h>
#include <glib-object.h>

typedef struct _CustomData {
    GstElement* playbin;
    GMainLoop* loop;
} CustomData;


gboolean bus_callback(GstBus* bus, GstMessage* msg, CustomData* data)
{
    GstElement* play = GST_ELEMENT(data->playbin);
    switch (GST_MESSAGE_TYPE(msg))
    {
    case GST_MESSAGE_EOS:
    {
        gboolean ret = gst_element_seek(play,
            1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
            GST_SEEK_TYPE_SET, 0,
            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
        if (!ret)
        {
            g_print("Seek failed!\n");
            return FALSE;
        }
        return TRUE;
    }
    case GST_MESSAGE_ERROR:
    {
        GError* err;
        gchar* debug;
        gst_message_parse_error(msg, &err, &debug);
        g_print("Error: %s\n", err->message);
        g_error_free(err);
        g_free(debug);
        g_main_loop_quit(data->loop);
        return FALSE;
    }
    default:
        break;
    }
    return TRUE;
}

gint main(gint argc, gchar** argv)
{
    GMainLoop* main_loop;
    GstElement* playbin;
    GstBus* bus;
    GstStateChangeReturn ret;
    CustomData data;
    if (argc < 2)
    {
        g_print("Usage: %s <URI>\n", argv[0]);
        return EXIT_FAILURE;
    }
    gst_init(&argc, &argv);
    playbin = gst_element_factory_make("playbin", "playbin");

    gchar* uri;
    if (gst_uri_is_valid(argv[1]))
        uri = argv[1];
    else
        uri = gst_filename_to_uri(argv[1], NULL);
    g_object_set(G_OBJECT(playbin), "uri", uri, NULL);
    bus = gst_element_get_bus(playbin);
    ret = gst_element_set_state(playbin, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(playbin);
        return EXIT_FAILURE;
    }
    main_loop = g_main_loop_new(NULL, FALSE);
    data.loop = main_loop;
    data.playbin = playbin;
    gst_bus_add_watch(bus, (GstBusFunc)bus_callback, &data);

    g_main_loop_run(main_loop);
    
    g_main_loop_unref(main_loop);
    gst_element_set_state(playbin, GST_STATE_NULL);
    gst_object_unref(playbin);
    gst_object_unref(bus);
    return EXIT_SUCCESS;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文