LINUX.ORG.RU

Замирает кадр при формировании буфера

 , ,


0

1

Пытаюсь формировать видео поток.
Для этого написал пример, который берет поток с камеры, кодирует в 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()

★★★★

Кстати, кодек «vp8» живет в пакете «libgstreamer-plugins-bad0.10-0» - не забудьте поставить, если захотите поиграться со скриптами.

Novator ★★★★ ()

Если кому интересно, победил проблему заполнением поля «timestamp»:

appsrc.signal_connect('need-data') do |src, length|
  buf1 = appsink.pull_buffer
  if buf1 != nil
    buf2 = Gst::Buffer.new
    buf2.data = String.new(buf1.data)
    #buf2.timestamp = buf1.timestamp      #original timestamp, it also works
    buf2.timestamp = Time.now.to_i * Gst::NSECOND    #simulated timestamp, better way
    src.push_buffer(buf2)
  end
end

Картинка задвигалась.

Пояснение: у пустого буфера поле timestamp=Gst::ClockTime::NONE, а надо чтобы там было осмысленное или более менее осмысленое значение, что и представлено выше.

Novator ★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.