Пытаюсь формировать видео поток.
Для этого написал пример, который берет поток с камеры, кодирует в vp8, передает в ручной слив appsink. Слив напрямую передает данные ручному источнику appsrc (в дальнейшем здесь будет передача через сеть). appsrc передает на раскодировщик, затем в окно.
Проблема в том, что когда я передаю буфер из appsink в appsrc напрямую, конвейеры работают, картинка «живет». Когда же я передаю самодельный буфер - картинка замирает на первом кадре.
Может второй конвейер застопоривается, может первичные буферы не подчищаются, может вторичными забиваются... Все выходные прое$%лся, перечитал весь интернет, про буферы написано очень скудно.
Вопрос: как правильно формировать буфер Gst.Buffer чтобы очередь работала безостановочно?
Код на ruby:
require 'gtk2'
require 'gst'
pipeline1 = Gst::Pipeline.new
pipeline2 = Gst::Pipeline.new
webcam = Gst::ElementFactory.make('v4l2src')
webcam.decimate=3
capsfilter = Gst::ElementFactory.make('capsfilter')
capsfilter.caps = Gst::Caps.parse('video/x-raw-rgb,width=320,height=240')
ffmpegcolorspace1 = Gst::ElementFactory.make('ffmpegcolorspace')
vp8enc = Gst::ElementFactory.make('vp8enc')
vp8enc.max_latency=1
appsink = Gst::ElementFactory.make('appsink')
appsrc = Gst::ElementFactory.make('appsrc')
appsrc.caps = Gst::Caps.parse('caps=video/x-vp8,width=320,height=240,framerate=30/1,pixel-aspect-ratio=1/1')
appsrc.signal_connect('need-data') { |src, length|
buf1 = appsink.pull_buffer
if buf1 != nil
buf2 = Gst::Buffer.new(buf1.size)
buf2.data = String.new(buf1.data)
#src.push_buffer(buf1) #it works
src.push_buffer(buf2) #freezing!
end
}
vp8dec = Gst::ElementFactory.make('vp8dec')
ffmpegcolorspace2 = Gst::ElementFactory.make('ffmpegcolorspace')
ximagesink = Gst::ElementFactory.make('ximagesink');
ximagesink.sync = false
pipeline1.add(webcam, capsfilter, ffmpegcolorspace1, vp8enc, appsink)
webcam >> capsfilter >> ffmpegcolorspace1 >> vp8enc >> appsink
pipeline2.add(appsrc, vp8dec, ffmpegcolorspace2, ximagesink)
appsrc >> vp8dec >> ffmpegcolorspace2 >> ximagesink
window = Gtk::Window.new
window.signal_connect('expose-event') do
ximagesink.xwindow_id = window.window.xid
end
window.signal_connect("destroy") { pipeline1.stop; pipeline2.stop; Gtk.main_quit }
window.set_default_size(320, 240)
window.show_all
pipeline1.play
pipeline2.play
Gtk.main
Тот же код на python:
import pygtk
pygtk.require('2.0')
import pygst
pygst.require("0.10")
import gtk, gst
def needdata(src, length):
buf1 = appsink.emit('pull-buffer')
if not (buf1 is None):
buf2 = gst.Buffer(buf1.data)
#src.emit('push-buffer', buf1) #it works
src.emit('push-buffer', buf2) #freezing!
def expose_event(window, event):
ximagesink.set_xwindow_id(window.window.xid)
pipeline1 = gst.Pipeline()
pipeline2 = gst.Pipeline()
webcam = gst.element_factory_make('v4l2src')
webcam.decimate=3
capsfilter = gst.element_factory_make('capsfilter')
capsfilter.set_property('caps', gst.caps_from_string('video/x-raw-rgb,width=320,height=240'))
ffmpegcolorspace1 = gst.element_factory_make('ffmpegcolorspace')
vp8enc = gst.element_factory_make('vp8enc')
vp8enc.max_latency=1
appsink = gst.element_factory_make('appsink')
appsrc = gst.element_factory_make('appsrc')
appsrc.set_property('caps', gst.caps_from_string('caps=video/x-vp8,width=320,height=240,framerate=30/1,pixel-aspect-ratio=1/1'))
appsrc.connect('need-data', needdata)
vp8dec = gst.element_factory_make('vp8dec')
ffmpegcolorspace2 = gst.element_factory_make('ffmpegcolorspace')
ximagesink = gst.element_factory_make('ximagesink');
ximagesink.sync = False
pipeline1.add(webcam, capsfilter, ffmpegcolorspace1, vp8enc, appsink)
gst.element_link_many(webcam, capsfilter, ffmpegcolorspace1, vp8enc, appsink)
pipeline2.add(appsrc, vp8dec, ffmpegcolorspace2, ximagesink)
gst.element_link_many(appsrc, vp8dec, ffmpegcolorspace2, ximagesink)
window = gtk.Window()
window.connect('expose-event', expose_event)
window.connect("destroy", gtk.main_quit, "WM destroy")
window.set_default_size(320, 240)
window.show_all()
pipeline1.set_state(gst.STATE_PLAYING)
pipeline2.set_state(gst.STATE_PLAYING)
gtk.main()