我想查看视频图像顶部的当前CPU负载(源为/dev/video0),我认为textoverlay元素对此非常合适。
我构造了一个(看似)工作的管道,除了textoverlay一直显示最初设置的值。

该管道当前如下所示:

v4l2src > qtdemux > queue > ffmpegcolorspace > textoverlay > xvimagesink


代码看起来像这样(我删除了一堆gtk窗口,线程处理代码和其他一些信号处理,只留下了相关部分):

#!/usr/bin/env python

import sys, os, time, signal
import pygtk, gtk, gobject

import pygst
pygst.require("0.10")
import gst

# For cpu load stats
import psutil
from multiprocessing import Process, Value, Lock # For starting threads

class Video:
  def __init__(self):

    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    vbox = gtk.VBox()
    window.add(vbox)
    self.movie_window = gtk.DrawingArea()
    vbox.add(self.movie_window)
    window.show_all()

    # Set up the gstreamer pipeline
    self.pipeline = gst.Pipeline("pipeline")
    self.camera = gst.element_factory_make("v4l2src","camera")
    self.camera.set_property("device","""/dev/video0""")
    self.pipeline.add(self.camera)

    # Demuxer
    self.demuxer = gst.element_factory_make("qtdemux","demuxer")

    # Create a dynamic callback for the demuxer
    self.demuxer.connect("pad-added", self.demuxer_callback)

    self.pipeline.add(self.demuxer)

    # Demuxer doesnt have static pads, but they are created at runtime, we will need a callback to link those
    self.videoqueue = gst.element_factory_make("queue","videoqueue")

    self.pipeline.add(self.videoqueue)

    self.videoconverter = gst.element_factory_make("ffmpegcolorspace","videoconverter")
    self.pipeline.add(self.videoconverter)

    ## Text overlay stuff
    self.textoverlay = gst.element_factory_make("textoverlay","textoverlay")

    self.overlay_text = "cpu load, initializing"
    self.textoverlay.set_property("text",self.overlay_text)
    self.textoverlay.set_property("halign", "left")
    self.textoverlay.set_property("valign", "top")
    self.textoverlay.set_property("shaded-background","true")
    self.pipeline.add(self.textoverlay)

    self.videosink = gst.element_factory_make("xvimagesink","videosink")
    self.pipeline.add(self.videosink)

    self.camera.link(self.videoqueue)
    gst.element_link_many(self.videoqueue,   self.videoconverter, self.textoverlay, self.videosink)


    bus = self.pipeline.get_bus()
    bus.add_signal_watch()
    bus.enable_sync_message_emission()

    # Start stream
    self.pipeline.set_state(gst.STATE_PLAYING)

    # CPU stats calculator thread
    cpu_load_thread = Process(target=self.cpu_load_calculator, args=())
    cpu_load_thread.start()

  def demuxer_callback(self, dbin, pad):

    if pad.get_property("template").name_template == "video_%02d":
      print "Linking demuxer & videopad"
      qv_pad = self.videoqueue.get_pad("sink")
      pad.link(qv_pad)


  def cpu_load_calculator(self):

    cpu_num = len( psutil.cpu_percent(percpu=True))

    while True:
      load = psutil.cpu_percent(percpu=True)
      self.parsed_load = ""

      for i in range (0,cpu_num):
        self.parsed_load = self.parsed_load + "CPU%d: %s%% " % (i, load[i])

      print self.textoverlay.get_property("text") # Correctly prints previous cycle CPU load
      self.textoverlay.set_property("text",self.parsed_load)


      time.sleep(2)

c = Video()

gtk.threads_init()
gtk.main()


cpu_load_calculator始终在后台运行,在设置新值之前,我先使用get_property()函数打印出前一个值,并且已正确设置它。但是,在实际的视频输出窗口上,它保持为初始值。
如何使textoverlay也能正确更新到视频窗口?

最佳答案

问题是您正在尝试从其他进程更新textoverlay。与线程不同的进程在单独的地址空间中运行。

您可以切换到线程:

from threading import Thread
...
# CPU stats calculator thread
cpu_load_thread = Thread(target=self.cpu_load_calculator, args=())
cpu_load_thread.start()


或者,您可以从主线程运行cpu_load_calculator循环。这将起作用,因为self.pipeline.set_state(gst.STATE_PLAYING)在后台启动它自己的线程。

这样就足够了:

# Start stream
self.pipeline.set_state(gst.STATE_PLAYING)

# CPU stats calculator loop
self.cpu_load_calculator()

07-27 14:36