欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-11-07 17:20:40
gstreamer到底是个啥?gstreamer 是一个 基于pipeline的多媒体框架,基于gobject,以c语言写成。应用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()

总结

到此这篇关于python gstreamer 实现视频快进/快退/循环播放功能的文章就介绍到这了,更多相关python gstreamer 实现视频快进/快退/循环播放内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!