Python 在gstreamer中获取视频的高度和宽度?
我正在为linux开发一个wx Python media ctrl,它使用gstreamer(感觉wx widgets版本必须是自定义编译的)。。。我发现gstreamer要么很糟糕,要么就是没有好的文档,因为它是有史以来最令人困惑的东西。这是我当前的代码,我想我要做的是获取消息_tagtype MESSAGE并从中执行一些操作,但我现在还不确定,当我当前运行它时,我得到了一个错误 代码Python 在gstreamer中获取视频的高度和宽度?,python,linux,gstreamer,Python,Linux,Gstreamer,我正在为linux开发一个wx Python media ctrl,它使用gstreamer(感觉wx widgets版本必须是自定义编译的)。。。我发现gstreamer要么很糟糕,要么就是没有好的文档,因为它是有史以来最令人困惑的东西。这是我当前的代码,我想我要做的是获取消息_tagtype MESSAGE并从中执行一些操作,但我现在还不确定,当我当前运行它时,我得到了一个错误 代码 “” 调整GStreamer以适合wx.media.MediaCtrl 为什么? -是,wx.media.M
“”
调整GStreamer以适合wx.media.MediaCtrl
为什么?
-是,wx.media.MediaCtrl有一个gstreamer后端
但它是无用的,甚至不起作用
因为显然是WX小部件C++代码
需要使用gstreamer支持进行编译
现在他们为什么不在linux上这么做
将在Linux上运行的具有
使用gstreamer的可能原因我没有
我知道为什么,但他们不知道。
主要从wxWidgets旧代码移植。
'''
导入操作系统
导入wx
从wx.lib.newevent导入NewCommandEvent
进口商品及服务税
导入gobject
从twisted.python导入日志
#启动线程,否则观察来自其他线程的消息会给我们一个错误
gobject.threads_init()
#州
#可能不是wx.media.MediaCtrl使用的数字
MEDIASTATE_播放=0
MEDIASTATE_=1
MEDIASTATE_已停止=2
#事件
媒体加载事件,EVT\U媒体加载=事件()
媒体播放事件,EVT媒体播放=NewCommandEvent()
媒体暂停事件,EVT\U媒体暂停=事件()
媒体停止事件,EVT媒体停止=NewCommandEvent()
媒体完成事件,EVT\U媒体完成=事件()
GstreamerCtrl类(wx.面板):
定义初始化(自身、父项、id):
wx.Panel.uuuu init_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
loop=gobject.MainLoop()
self.context=loop.get_context()
#使用GetState获取新状态
self.state=gst.state_NULL#当前状态
self.no_resource=True
self.video_size=(0,0)
self.caps=[]
self.paused\u playback\u position=0
wx.CallLater(500,self.gstreamer\u循环)
self.playbin=gst.element\u factory\u make(“playbin 2”)
#代码来自http://www.majorsilence.com/pygtk_audio_and_video_playback_gstreamer
总线=self.playbin.get_总线()
总线.添加信号\u手表()
总线.启用\u同步\u消息\u发射()
总线连接(“消息”,自接通消息)
总线连接('sync-message::element',self.on\u sync\u消息)
self.Bind(wx.EVT\u WINDOW\u DESTROY、self.OnWinDestroy、self)
def on_sync_消息(自身、总线、消息):
#代码来自http://pythonide.blogspot.com/2008/03/howto-write-wxpython-video-player-with.html
#另见http://pygstdocs.berlios.de/pygst-tutorial/videomixer.html
打印“===============================”
如果message.structure为无:
返回
message\u name=message.structure.get\u name()
打印邮件名称
如果消息_name==“准备xwindow id”:
imagesink=message.src
imagesink.set_属性('force-aspect-ratio',True)
imagesink.set_xwindow_id(self.GetHandle())
def SetInitialSize(自身):
通过#与其他人进行交叉比较,但gstreamer会自动通过
def on_消息(自身、总线、消息):
如果message.type==gst.message\u STATE\u已更改:
# http://pygstdocs.berlios.de/pygst-reference/class-gstmessage.htm
state=message.parse_state_changed()#当前状态[旧状态、新状态、挂起状态]
self.state=state[1]#更新状态(如果是重复,我们不必这样做,因为它是第一次设置的)
如果self.state==gst.state_READY:#如果这是第一个加载状态(感觉它不是重复,而是状态_READY)
打印“启动EVT\u媒体加载”
自发送事件(媒体加载事件)
#获取gstreamer信息
elif message.type==gst.message_标记:
self.caps.append(消息)
#这就是我们得到尺寸的地方;为什么这么不清楚
#检测流结束并将状态设置为NULL
#代码来自http://www.majorsilence.com/pygtk_audio_and_video_playback_gstreamer
elif message.type==gst.message_EOS:
log.msg(“Gstreaner[Debug]:EOS”)
#文件结束了,停下来,在结尾说
self.Stop()
#在文件末尾
自我发送事件(媒体完成事件)
elif message.type==gst.message\u错误:
(err,debug)=message.parse_error()
打印“Gstreamer[错误]:%s”%err
打印“Gstreamer[Debug]:%s”%Debug
#某些未知错误必须设置为null,否则可能是路径名错误
self.playbin.set_state(gst.state_NULL)
自我发送事件(媒体停止事件)
自我发送事件(媒体完成事件)
def gstreamer_回路(自):
self.context.iteration(True)
wx.CallLater(500,self.gstreamer\u循环)
定义发送事件(自身、事件):
打印“触发事件”
evt=事件(self.GetId())
wx.PostEvent(自我,evt)
def加载(自身,文件路径):
self.no_resource=False
self.paused\u playback\u position=0
file\u path=os.path.abspath(file\u path)
打印“加载文件”+文件路径
打印“通过URI文件加载://”
LoadURI(“文件:/”+文件路径)
返回真值
def LoadURI(自我,uri):
self.no_resource=False
log.msg(“URI:%s”%URI)
self.paused\u playback\u position=0
self.playbin.set_state(gst.state_NULL)
self.playbin.set_属性(“uri”,uri)
打印自我状态
#开始下载
self.playbin.set_state(gst.state_PLAYING)
self.playbin.set_状态(gst.state_暂停)
返回真值
def播放(自我):
如果self.no_资源:
雷图
'''
Adapts GStreamer to fit wx.media.MediaCtrl
Why?
- Yes wx.media.MediaCtrl has a gstreamer backend
but it is useless and well doesn't even work
because apparently the wx widgets C++ code
needs to be compiled with gstreamer support
now why they don't do that for the linux
build that will be running on Linux with
a likely hood of using gstreamer I have no
clue why but they don't.
Largely Ported from wxWidgets old code.
'''
import os
import wx
from wx.lib.newevent import NewCommandEvent
import gst
import gobject
from twisted.python import log
# Start threads otherwise watching messages from other threads gives us a segfault
gobject.threads_init()
# States
# might not be the numbers wx.media.MediaCtrl uses
MEDIASTATE_PLAYING = 0
MEDIASTATE_PAUSED = 1
MEDIASTATE_STOPPED = 2
# Events
media_loaded_event , EVT_MEDIA_LOADED = NewCommandEvent()
media_play_event , EVT_MEDIA_PLAY = NewCommandEvent()
media_pause_event , EVT_MEDIA_PAUSE = NewCommandEvent()
media_stop_event , EVT_MEDIA_STOP = NewCommandEvent()
media_finished_event, EVT_MEDIA_FINISHED = NewCommandEvent()
class GstreamerCtrl(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id, size = (0,0))
loop = gobject.MainLoop()
self.context = loop.get_context()
# use GetState to get new state
self.state = gst.STATE_NULL # current state
self.no_resource = True
self.video_size = (0,0)
self.caps = []
self.paused_playback_position = 0
wx.CallLater(500, self.gstreamer_loop)
self.playbin = gst.element_factory_make("playbin2")
# Code from http://www.majorsilence.com/pygtk_audio_and_video_playback_gstreamer
bus = self.playbin.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect("message", self.on_message)
bus.connect('sync-message::element', self.on_sync_message)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnWinDestroy, self)
def on_sync_message(self, bus, message):
# Code from http://pythonide.blogspot.com/2008/03/howto-write-wxpython-video-player-with.html
# See also http://pygstdocs.berlios.de/pygst-tutorial/videomixer.html
print "===================="
if message.structure is None:
return
message_name = message.structure.get_name()
print message_name
if message_name == 'prepare-xwindow-id':
imagesink = message.src
imagesink.set_property('force-aspect-ratio', True)
imagesink.set_xwindow_id(self.GetHandle())
def SetInitialSize(self):
pass# for cross compartibilitry with others but gstreamer does it automatically
def on_message(self, bus, message):
if message.type == gst.MESSAGE_STATE_CHANGED:
# http://pygstdocs.berlios.de/pygst-reference/class-gstmessage.htm
state = message.parse_state_changed()#current state [oldstate, newstate, pendingstate]
self.state = state[1]# update the state (we don't have to do this if it is a repeat because it was set the first time around)
if self.state == gst.STATE_READY:# if this is the first load state (sense it isn't a repeat and it is a STATE_READY)
print "Firing EVT_MEDIA_LOADED"
self._send_event(media_loaded_event)
# get gstreamer information
elif message.type == gst.MESSAGE_TAG:
self.caps.append(message)
# is this where we get the size; why is it so unclear
# Detect end of stream and set state to to NULL
# Code From http://www.majorsilence.com/pygtk_audio_and_video_playback_gstreamer
elif message.type == gst.MESSAGE_EOS:
log.msg("Gstreaner [Debug]: EOS")
# end of file so stop and say at the end
self.Stop()
# at end of file
self._send_event(media_finished_event)
elif message.type == gst.MESSAGE_ERROR:
(err, debug) = message.parse_error()
print "Gstreamer [ERROR]: %s" % err
print "Gstreamer [Debug]: %s" % debug
# Some unknown error have to set to null not anything else cause could be error with path name
self.playbin.set_state(gst.STATE_NULL)
self._send_event(media_stop_event)
self._send_event(media_finished_event)
def gstreamer_loop(self):
self.context.iteration(True)
wx.CallLater(500, self.gstreamer_loop)
def _send_event(self, event):
print "Firing an event"
evt = event(self.GetId())
wx.PostEvent(self, evt)
def Load(self, file_path):
self.no_resource = False
self.paused_playback_position = 0
file_path = os.path.abspath(file_path)
print "Loading File " + file_path
print "Loading through URI file://"
self.LoadURI("file://" + file_path )
return True
def LoadURI(self, uri):
self.no_resource = False
log.msg("URI: %s" % uri)
self.paused_playback_position = 0
self.playbin.set_state(gst.STATE_NULL)
self.playbin.set_property("uri", uri)
print self.state
# Start download
self.playbin.set_state(gst.STATE_PLAYING)
self.playbin.set_state(gst.STATE_PAUSED)
return True
def Play(self):
if self.no_resource:
return False # see stop() for why false here but true for stop
self.playbin.set_state(gst.STATE_PLAYING)
print "Firing EVT_MEDIA_PLAY"
self._send_event(media_play_event)
return True
def Pause(self):
if self.no_resource:
return False # see stop() for why false here but true for stop
self.paused_playback_position = self.Tell()
self.playbin.set_state(gst.STATE_PAUSED)
print "Firing EVT_MEDIA_PAUSE"
self._send_event(media_pause_event)
return True
def Stop(self):
# it seeems that to stop on gstreamer you set the state to paused
# and then set the stream position to 0
# why not just have STOPPED state or have NULL be stopped
# What is used in wxWidgets code now set
if self.no_resource:
# confirms stop was good because we are "stopped" play pause however say they failed because not "playing" or "paused"
print "Firing EVT_MEDIA_STOPPED"
self._send_event(media_stop_event)
return True
self.paused_playback_position = 0
self.Seek(0)
self.playbin.set_state(gst.STATE_PAUSED)
print "Firing EVT_MEDIA_STOPPED"
self._send_event(media_stop_event)
return True
def GetState(self):
# Stop - 0
# Pause - 1
# Play - 2
state = self.state
# see http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-state
if state == gst.STATE_PAUSED:
if self.paused_playback_position == 0:
return MEDIASTATE_STOPPED
else:
return MEDIASTATE_PAUSED
elif state == gst.STATE_PLAYING:
return MEDIASTATE_PLAYING
else:# Other states (NULL, READY, etc)
return MEDIASTATE_STOPPED
def SetVolume(self, volume):
# wx media media ctrl takes a value between 0.0 and 1.0
# gstreamer takes a value between 0 and 10
# maybe not volume seems funny
# try setting it to * 10 again still weird setting it back
self.playbin.set_property("volume", volume)
def Tell(self):
if self.state != gst.STATE_PLAYING:
# Any other state other than playing return the paused time otherwise something strange could be returned
return self.paused_playback_position
time_format = gst.Format(gst.FORMAT_TIME) #time in nanoseconds
try:
data = self.playbin.query_position(time_format)
except gst.QueryError:
return -1
position = int(data[0] / 1000000.0)
return position
def Length(self):
time_format = gst.Format(gst.FORMAT_TIME) #time in nanoseconds
try:
data = self.playbin.query_duration(time_format)
except gst.QueryError:
return -1
length = int(data[0] / 1000000.0)
return length
def Seek(self, position):
if self.no_resource:
return False
print "Seeking to %s" % position
if position < 0 or position > self.Length():
return
self.paused_playback_position = position
position_ns = position * 1000000
self.playbin.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, position_ns)
return True
def OnWinDestroy(self, event):
self.playbin.set_state(gst.STATE_NULL)
if __name__ == "__main__":
a = wx.App(False)
f = wx.Frame(None, -1, size = (500,300))
PlayerSizer = wx.BoxSizer(wx.VERTICAL)
PlayerSizer.Add(self.player, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 10, proportion = 1)
f.d = GstreamerCtrl(f, -1)
f.Show()
wx.CallLater(10000, f.d.LoadURI, "http://www.tools4movies.com/dvd_catalyst_profile_samples/Harold%20Kumar%203%20Christmas%20bionic.mp4")
a.MainLoop()