【问题标题】:How to create video thumbnails with Python and Gstreamer如何使用 Python 和 Gstreamer 创建视频缩略图
【发布时间】:2013-03-25 06:07:13
【问题描述】:

我想使用 Gstreamer 和 Python 为 MPEG-4 AVC 视频创建缩略图。本质上:

  1. 打开视频文件
  2. 搜索到某个时间点(例如 5 秒)
  3. 当时抢框
  4. 将帧作为 .jpg 文件保存到光盘

我一直在查看this other similar question,但我无法完全弄清楚如何在没有用户输入的情况下自动进行搜索和帧捕获。

总而言之,如何按照上述步骤使用 Gstreamer 和 Python 捕获视频缩略图?

【问题讨论】:

  • 请注意,“5 秒”可能不起作用。对于许多商业电影,您只会得到介绍/徽标。尝试找到黑框(它们表示场景变化),然后在场景中寻找几秒钟。为其中的 4-5 个用户提供易于识别的图像。
  • 这适用于所有长度超过 5 秒的个人视频。无论如何,为了示例,5 秒的数字只是任意的。它可以是 2、10 或以下任何其他值,例如 30 秒。

标签: python video gstreamer


【解决方案1】:

为了详细说明ensonic的答案,这里有一个例子:

import os
import sys

import gst

def get_frame(path, offset=5, caps=gst.Caps('image/png')):
    pipeline = gst.parse_launch('playbin2')
    pipeline.props.uri = 'file://' + os.path.abspath(path)
    pipeline.props.audio_sink = gst.element_factory_make('fakesink')
    pipeline.props.video_sink = gst.element_factory_make('fakesink')
    pipeline.set_state(gst.STATE_PAUSED)
    # Wait for state change to finish.
    pipeline.get_state()
    assert pipeline.seek_simple(
        gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, offset * gst.SECOND)
    # Wait for seek to finish.
    pipeline.get_state()
    buffer = pipeline.emit('convert-frame', caps)
    pipeline.set_state(gst.STATE_NULL)
    return buffer

def main():
    buf = get_frame(sys.argv[1])

    with file('frame.png', 'w') as fh:
        fh.write(str(buf))

if __name__ == '__main__':
    main()

这会生成一个 PNG 图像。您可以使用gst.Caps("video/x-raw-rgb,bpp=24,depth=24") 或类似的方式获取原始图像数据。

请注意,在 GStreamer 1.0(相对于 0.10)中,playbin2 已重命名为 playbinconvert-frame 信号被命名为 convert-sample

寻找的机制在this chapter of the GStreamer Application Development Manual 中有解释。 0.10 playbin2 的文档似乎不再在线,但 1.0 的文档是 here

【讨论】:

  • 那是优秀,谢谢!我试图将代码移植到 PyGI,但我发现了一个问题,gst.Caps('image/png') 不再起作用,因为新的 Gst.Caps() 不接受任何参数,而且我没有找到任何替代品(@ 987654335@ 段错误)。有什么指点吗?
  • 我创建了a gist with the PyGI version,它运行没有错误。但是,它会创建不可读的 .png 文件。如果任何 GStreamer 专家能发现错误,欢迎任何指点,谢谢!
  • 我的猜测是 str(buf) 不再像以前那样做,它现在给你像 "<GStBuffer ...>" 这样的东西。您是否尝试过查看生成的 PNG 文件?我猜你想要buf.data 之类的东西。
  • 你是对的,png文件是文本数据。我设法获得了Gst.Buffer(参见updated gist),但我仍然不知道如何从缓冲区中获取实际字节。事实证明这比我预期的要困难一些,我可能不得不提出一个新问题。
  • 好的,看来这在 GStreamer 1.0 中是不可能的,我相信我现在偶然发现了this bug:/
【解决方案2】:

Vala 中的一个示例,使用 GStreamer 1.0 :

var playbin = Gst.ElementFactory.make ("playbin", null);
playbin.set ("uri", "file:///path/to/file");
// some code here.
var caps = Gst.Caps.from_string("image/png");
Gst.Sample sample;
Signal.emit_by_name(playbin, "convert-sample", caps, out sample);
if(sample == null)
    return;
var sample_caps = sample.get_caps ();
if(sample_caps == null)
    return;
unowned Gst.Structure structure = sample_caps.get_structure(0);
int width = (int)structure.get_value ("width");
int height = (int)structure.get_value ("height");
var memory = sample.get_buffer().get_memory (0);
Gst.MapInfo info;
memory.map (out info, Gst.MapFlags.READ);
uint8[] data = info.data;

【讨论】:

  • 谢谢!但是,我仍在寻找 Python 示例。似乎由于this bug,这对于 GStreamer 1.0 和 Python 来说仍然是不可能的:/
  • 它没有回答这个问题,但它确实帮助了我。如果有人可以解释“样本”何时可能为空,那么我也许可以让它工作!
【解决方案3】:

这是一个老问题,但我仍然没有在任何地方找到它的记录。
我发现以下内容适用于使用 Gstreamer 1.0 播放的视频

import gi
import time
gi.require_version('Gst', '1.0')
from gi.repository import Gst

def get_frame():
    caps = Gst.Caps('image/png')
    pipeline = Gst.ElementFactory.make("playbin", "playbin")
    pipeline.set_property('uri','file:///home/rolf/GWPE.mp4')
    pipeline.set_state(Gst.State.PLAYING)
    #Allow time for it to start
    time.sleep(0.5)
    # jump 30 seconds
    seek_time = 30 * Gst.SECOND
    pipeline.seek(1.0, Gst.Format.TIME,(Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE),Gst.SeekType.SET, seek_time , Gst.SeekType.NONE, -1)

    #Allow video to run to prove it's working, then take snapshot
    time.sleep(1)
    buffer = pipeline.emit('convert-sample', caps)
    buff = buffer.get_buffer()
    result, map = buff.map(Gst.MapFlags.READ)
    if result:
        data = map.data
        pipeline.set_state(Gst.State.NULL)
        return data
    else:
        return

if __name__ == '__main__':
    Gst.init(None)
    image = get_frame()
    with open('frame.png', 'wb') as snapshot:
        snapshot.write(image)

代码应该在 Python2 和 Python3 上运行,我希望它对某人有所帮助。

【讨论】:

    【解决方案4】:

    使用 playbin2。将 uri 设置为媒体文件,使用 gst_element_seek_simple 寻找所需的时间位置,然后使用 g_signal_emit 调用“convert-frame”动作信号。

    【讨论】:

    • 感谢您的回答。您是否愿意用代码 sn-p 详细说明一下?我理解playbin2 的部分,但gst_element_seek_simple()gst.element_seek_simple() 似乎都不适用于Python。
    • 好了,发现Python中有gst.Element.seek_simple(),以及如何使用。尽管如此,Python sn-p 还是很有帮助的,因为现在要弄清楚的是如何使用 g_signal_emit 等效项。
    • 抱歉,python 方面我帮不上忙:/
    • 在 C 端呢?我应该能够从 C sn-p 中计算出 Python 代码。
    • 可能是gobject.GObject.emit()
    猜你喜欢
    • 2016-02-05
    • 2011-01-15
    • 1970-01-01
    • 2010-12-18
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 2015-01-24
    相关资源
    最近更新 更多