python 网站视频快进_python gstreamer实现视频快进/快退/循环播放功能

Gstreamer到底是个啥?

GStreamer 是一个 基于pipeline的多媒体框架,基于GObject,以C语言写成。

应用GStreamer这个这个多媒体框架,你可以写出任意一种流媒体的应用来如:meidaplayer、音视频编辑器、VOIP、流媒体服务器、音视频编码等等。

关于视频快进/快退/循环播放的知识总结:

1.本地视频时长获取:

Gst.Pad.query_duration官方函数介绍:

def Gst.Pad.query_duration (self, format):

#python wrapper for 'gst_pad_query_duration'

Queries a pad for the total stream duration.

Parameters:

pad ( Gst.Pad ) –a Gst.Pad to invoke the duration query on.

format ( Gst.Format ) –the Gst.Format requested

Returns a tuple made of:

( gboolean ) –TRUE (not introspectable) if the query could be performed.

duration ( gint64 ) –TRUE (not introspectable) if the query could be performed.

使用如下:

pipeline.query_duration(Gst.Format.TIME)[1]

其中pipeline为播放本地视频的管道,query_duration()函数返回一个元组,元组的形式为[Ture,duration:******],******为以ns为单位的视频时长。

2.视频播放当前位置获取:

Gst.Pad.query_position官方函数介绍:

def Gst.Pad.query_position (self, format):

#python wrapper for 'gst_pad_query_position'

Queries a pad for the stream position.

Parameters:

pad ( Gst.Pad ) –a Gst.Pad to invoke the position query on.

format ( Gst.Format ) –the Gst.Format requested

Returns a tuple made of:

( gboolean ) –TRUE (not introspectable) if the query could be performed.

cur ( gint64 ) –TRUE (not introspectable) if the query could be performed.

使用方法与时长获取函数query_duration()相同。

3.播放跳转函数:

Gst.Element.seek_simple官方函数介绍:

def Gst.Element.seek_simple (self, format, seek_flags, seek_pos):

#python wrapper for 'gst_element_seek_simple'

Parameters:

element ( Gst.Element ) –a Gst.Element to seek on

format ( Gst.Format ) –a Gst.Format to execute the seek in, such as Gst.Format.TIME

seek_flags ( Gst.SeekFlags ) –seek options; playback applications will usually want to use GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT here

seek_pos ( gint64 ) –position to seek to (relative to the start); if you are doing a seek in Gst.Format.TIME this value is in nanoseconds - multiply with Gst.SECOND to convert seconds to nanoseconds or with Gst.MSECOND to convert milliseconds to nanoseconds.

Returns ( gboolean ) :

TRUE (not introspectable) if the seek operation succeeded. Flushing seeks will trigger a preroll, which will emit Gst.MessageType.ASYNC_DONE.

函数使用样例:

pipeline.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, time)

其中time的单位为nanoseconds。

有视频快进/快退/循环播放功能的小播放器.

import os, _thread, time

import gi

gi.require_version("Gst", "1.0")

gi.require_version('Gtk', '3.0')

from gi.repository import Gst, GObject, Gtk, Gdk

class GTK_Main:

def __init__(self):

window = Gtk.Window(Gtk.WindowType.TOPLEVEL)

window.set_title("Vorbis-Player")

window.set_default_size(500, -1)

window.connect("destroy", Gtk.main_quit, "WM destroy")

vbox = Gtk.VBox()

window.add(vbox)

self.entry = Gtk.Entry()

vbox.pack_start(self.entry, False, False, 0)

hbox = Gtk.HBox()

vbox.add(hbox)

buttonbox = Gtk.HButtonBox()

hbox.pack_start(buttonbox, False, False, 0)

rewind_button = Gtk.Button("Rewind")

rewind_button.connect("clicked", self.rewind_callback)

buttonbox.add(rewind_button)

self.button = Gtk.Button("Start")

self.button.connect("clicked", self.start_stop)

buttonbox.add(self.button)

forward_button = Gtk.Button("Forward")

forward_button.connect("clicked", self.forward_callback)

buttonbox.add(forward_button)

self.time_label = Gtk.Label()

self.time_label.set_text("00:00 / 00:00")

hbox.add(self.time_label)

window.show_all()

self.player = Gst.Pipeline.new("player")

source = Gst.ElementFactory.make("filesrc", "file-source")

demuxer = Gst.ElementFactory.make("decodebin", "demuxer")

videoconv = Gst.ElementFactory.make("videoconvert", "converter")

videosink = Gst.ElementFactory.make("xvimagesink", "video-output")

demuxer.connect("pad-added", self.demuxer_callback, videoconv)

for ele in [source, demuxer, videoconv, videosink]:

self.player.add(ele)

source.link(demuxer)

videoconv.link(videosink)

bus = self.player.get_bus()

bus.add_signal_watch()

bus.connect("message", self.on_message)

def start_stop(self, w):

if self.button.get_label() == "Start":

filepath = self.entry.get_text().strip()

if os.path.isfile(filepath):

filepath = os.path.realpath(filepath)

self.button.set_label("Stop")

self.player.get_by_name("file-source").set_property("location", filepath)

self.player.set_state(Gst.State.PLAYING)

self.play_thread_id = _thread.start_new_thread(self.play_thread, ())

else:

self.play_thread_id = None

self.player.set_state(Gst.State.NULL)

self.button.set_label("Start")

self.time_label.set_text("00:00 / 00:00")

def play_thread(self):

play_thread_id = self.play_thread_id

Gdk.threads_enter()

self.time_label.set_text("00:00 / 00:00")

Gdk.threads_leave()

print(play_thread_id)

print(self.play_thread_id)

while play_thread_id == self.play_thread_id:

time.sleep(0.2)

dur_int = self.player.query_duration(Gst.Format.TIME)[1]

if dur_int == -1:

continue

dur_str = self.convert_ns(dur_int)

Gdk.threads_enter()

self.time_label.set_text("00:00 / " + dur_str)

Gdk.threads_leave()

break

time.sleep(0.2)

while play_thread_id == self.play_thread_id:

pos_int = self.player.query_position(Gst.Format.TIME)[1]

pos_str = self.convert_ns(pos_int)

if play_thread_id == self.play_thread_id:

Gdk.threads_enter()

self.time_label.set_text(pos_str + " / " + dur_str)

Gdk.threads_leave()

time.sleep(1)

def on_message(self, bus, message):

t = message.type

if t == Gst.MessageType.EOS:

self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, 0000000000)

elif t == Gst.MessageType.ERROR:

err, debug = message.parse_error()

print ("Error: %s" % err, debug)

self.play_thread_id = None

self.player.set_state(Gst.State.NULL)

self.button.set_label("Start")

self.time_label.set_text("00:00 / 00:00")

def demuxer_callback(self, demuxer, pad, dst):

caps = Gst.Pad.get_current_caps(pad)

structure_name = caps.to_string()

if structure_name.startswith("video"):

videorate_pad = dst.get_static_pad("sink")

pad.link(videorate_pad)

def rewind_callback(self, w):

rc, pos_int = self.player.query_position(Gst.Format.TIME)

seek_ns = pos_int - 10 * 1000000000

if seek_ns < 0:

seek_ns = 0

print ('Backward: %d ns -> %d ns' % (pos_int, seek_ns))

self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)

def forward_callback(self, w):

rc, pos_int = self.player.query_position(Gst.Format.TIME)

seek_ns = pos_int + 10 * 1000000000

print ('Forward: %d ns -> %d ns' % (pos_int, seek_ns))

self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)

def convert_ns(self, t):

s,ns = divmod(t, 1000000000)

m,s = divmod(s, 60)

if m < 60:

return "%02i:%02i" %(m,s)

else:

h,m = divmod(m, 60)

return "%i:%02i:%02i" %(h,m,s)

GObject.threads_init()

Gst.init(None)

GTK_Main()

Gtk.main()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值