<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF125%3AGStreamer</id>
		<title>LXF125:GStreamer - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF125%3AGStreamer"/>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF125:GStreamer&amp;action=history"/>
		<updated>2026-05-13T21:00:06Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.11.1</generator>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF125:GStreamer&amp;diff=11171&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF125:GStreamer&amp;diff=11171&amp;oldid=prev"/>
				<updated>2010-11-19T09:06:31Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''''GStreamer''''' Надежный каркас для ваших мультимедиа-приложений&lt;br /&gt;
&lt;br /&gt;
==''GStreamer'': Ваш видеоплейер==&lt;br /&gt;
&lt;br /&gt;
:Пусть Linux и не испытывает недостатка в таких настольных приложениях, как проигрыватели мультимедиа – '''Дмитрий Мусаев''' все равно покажет вам,&lt;br /&gt;
как написать еще один, свой собственный.&lt;br /&gt;
&lt;br /&gt;
Не возникало ли у вас когда-нибудь желания написать свой собственный медиа-плейер? Дело не только в том, чтобы почить на лаврах ''Totem'' и ''Kaffeine'' – это еще и прекрасный повод познакомиться с мультимедиа-каркасом ''GStreamer'' (http://gstreamer.freedesktop.org). Он написан на ''С'' и имеет интерфейсы для многих других языков программирования, таких как ''С++'', ''Python'' и ''C#''. На данный момент для него существует более 150 модулей расширения ('''plugin'''), позволяющих декодировать практически все аудио- и видеоформаты (полный список доступен по адресу http://gstreamer.freedesktop.org/documentation/plugins.html). С помощью этих модулей можно не только просматривать или прослушивать аудио- и видеофайлы, но и перекодировать их; например, вы сможете легко написать скрипт для конвертации фильма в формат, понимаемый вашим сотовым телефоном, если последний вообще умеет воспроизводить видео. Можно получать и отправлять медиа-потоки через сеть – в списке модулей вы найдете реализацию нескольких протоколов. Например, чтобы получить видео с web-камеры, достаточно набрать в терминале команду ''gst-launch v4l2src! xvimagesink''.&lt;br /&gt;
&lt;br /&gt;
Впечатляет? Тогда давайте перейдем от слов к делу.&lt;br /&gt;
&lt;br /&gt;
===Немного теории===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_80_1.jpg|300px|Рис. 1.]]   Рис. 1. Архитектура каркаса ''GStreamer'': как видно, он имеет три уровня.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Общая архитектура каркаса ''GStreamer'' представлена на рис. 1. Как можно видеть, он состоит из базового ядра, утилит и подключаемых модулей. Давайте введем некоторые понятия. &lt;br /&gt;
&lt;br /&gt;
'''Элемент''' [element] – наиболее важный компонент в ''GStreamer''. Мы будем создавать цепочки связанных между собой элементов и направлять через них поток данных. Элементы соединяются '''коннекторами''' [pads]; это не вполне точный перевод, но мне кажется, он удобнее, чем «пады» или «подушки».&lt;br /&gt;
Коннекторы бывают '''входными''' [sink pad] и '''выходными''' [source pad]. Элемент может иметь различное количество коннекторов: одни присутствуют всегда, другие создаются в зависимости от типа медиа-данных, которые проходят через элемент. Посмотреть, какие именно коннекторы доступны у данного элемента, можно при помощи утилиты ''gst-inspect''. Выполните команду ''gst-inspect decodebin'', и вы получите много интересной информации.&lt;br /&gt;
&lt;br /&gt;
 Pad Templates:&lt;br /&gt;
  SRC template: 'src%d'&lt;br /&gt;
   Availability: Sometimes&lt;br /&gt;
   Capabilities:&lt;br /&gt;
    ANY&lt;br /&gt;
  SINK template: 'sink'&lt;br /&gt;
   Availability: Always&lt;br /&gt;
   Capabilities:&lt;br /&gt;
    ANY&lt;br /&gt;
&lt;br /&gt;
Мы видим, что у элемента есть постоянный входной коннектор “'''sink'''”, совместимый с любым типом медиа-данных, и иногда выходные коннекторы “'''src%d'''”, количество которых зависит от типа входных данных. Отметим также, что элемент посылает три сигнала (на них мы остановимся позже):&lt;br /&gt;
&lt;br /&gt;
 Element Signals:&lt;br /&gt;
  “new-decoded-pad” : void user_function (GstElement* object,&lt;br /&gt;
                           GstPad* arg0,&lt;br /&gt;
                           gboolean arg1,&lt;br /&gt;
                           gpointer user_data);&lt;br /&gt;
  “removed-decoded-pad” : void user_function (GstElement*object,&lt;br /&gt;
                             GstPad* arg0,&lt;br /&gt;
                             gpointer user_data);&lt;br /&gt;
  “unknown-type” : void user_function (GstElement* object,&lt;br /&gt;
                         GstPad* arg0,&lt;br /&gt;
                         GstCaps* arg1,&lt;br /&gt;
                         gpointer user_data);&lt;br /&gt;
    Контейнер [bin] – это объект для управления набором элемен-&lt;br /&gt;
&lt;br /&gt;
'''Контейнер''' [bin] – это объект для управления набором элементов. Контейнер позволяет объединять несколько связанных элементов в один логический. Все, что справедливо для элементов, справедливо и для контейнеров. Например, с помощью контейнеров можно заранее подготовить в программе наборы элементов для кодирования или декодирования различных форматов входных данных и потом, в зависимости от типа последних, использовать тот или иной контейнер.&lt;br /&gt;
&lt;br /&gt;
'''Конвейер''' [pipeline] – это специальный подтип контейнера, который позволяет управлять всеми дочерними контейнерами и элементами. Конвейер должен быть контейнером самого верхнего уровня; он присутствует во всех приложения работающих с каркасом.&lt;br /&gt;
&lt;br /&gt;
Элементы ''GStreamer'' могут находиться в одном из четырех состояний:&lt;br /&gt;
* '''GST_STATE_NULL''' Состояние по умолчанию. В этом состоянии элемент освобождает все ресурсы, которые он занимал.&lt;br /&gt;
* '''GST_STATE_READY''' В этом состоянии элемент размещает глобальные ресурсы. Поток данных закрыт, и позиция в нем выставлена в начало.&lt;br /&gt;
* '''GST_STATE_PAUSED''' В этом состоянии элемент открывает поток, данные подготавливаются для обработки. Элемент позволяет менять позицию в потоке.&lt;br /&gt;
* '''GST_STATE_PLAYING''' В этом состоянии запускается обработка данных.&lt;br /&gt;
&lt;br /&gt;
''GStreamer'' является многопоточным каркасом, и чтобы упростить взаимодействие приложения и конвейера, в нем введена простая система передачи сообщений '''Bus''' (шина сообщений). Каждый конвейер автоматически создает шину сообщений – приложению остается только назначить обработчики сигналов и реагировать на интересующие его события. Обработчики могут быть синхронными и асинхронными; мы будем использовать оба типа. Асинхронный обработчик сигналов вызывается в контексте главного цикла ''Gtk''-приложения.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_81_1.jpg|300px|Рис. 2.]] Рис. 2. Схема разрабатываемого нами медиа-плейера.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
''GStreamer ''предоставляет два высокоуровневых контейнера – это '''Playbin''' и '''Decodebin'''. Они обеспечивают всю рутинную работу по определению типа медиа-данных и их декодированию. '''Playbin''' – готовый медиа-плейер, которому нужно указать лишь источник данных и дескриптор окна (что, впрочем, не обязательно – он может создать и свое собственное), куда будет выводиться видео. Но мы будем использовать '''Decodebin''', так как он поддается более тонкой настройке.&lt;br /&gt;
&lt;br /&gt;
Исходя из вышесказанного, давайте составим схему нашего будущего медиа-плейера. Графически она представлена на рис. 2, а в текстовом виде может выглядеть так:&lt;br /&gt;
&lt;br /&gt;
 gst-launch filesrc location=bubble_dancer.wmv !decodebin&lt;br /&gt;
 name=decoder decoder. !queue !videoscale !xvimagesink&lt;br /&gt;
 decoder. ! queue !audioconvert !alsasink&lt;br /&gt;
&lt;br /&gt;
'''Gst-launch''' – одна из ключевых вспомогательных утилит каркаса. Она позволяет размещать элементы на конвейере, восклицательный знак служит их разделителем: '''SRCELEMENT.PAD1!SINKELEMENT.PAD1'''. Если коннекторы не указаны, то перебираются все коннекторы и соединяются подходящие. Свойство '''name''' используется для задания имени элемента, что дает нам возможность обратиться к нему. При использовании имени элемента точка в конце обязательна – таков синтаксис команды.&lt;br /&gt;
&lt;br /&gt;
===Время кодировать===&lt;br /&gt;
&lt;br /&gt;
Перейдем к написанию кода. Я буду использовать ''C++'' и среду разработки ''Anjuta''; при желании, вы можете обойтись простым текстовым редактором. Итак, запускаем ''Anjuta'' и создаем новый проект; на вкладке'' C++'' выбираем ''GTKmm''.&lt;br /&gt;
&lt;br /&gt;
Введите имя проекта, например, '''Playermm''', и выберите его местоположение на жестком диске. Готово: мы имеем функцию '''main()''' и ''Glade''-форму нашего будущего приложения. Нажимаем '''F7''' и соглашаемся с тем, что нам надо создать проект; после завершения компиляции нажимаем '''F3'''. После запуска приложения вы должны увидеть пустое окно с заголовком &amp;quot;Hello world!&amp;quot;. Теперь внесем небольшие изменения в '''main.cc''' (выделены жирным шрифтом)&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_81_2.jpg|300px|Рис. 3.]] Рис. 3. Для написания медиа-плейера подойдет ''Anjuta'' или любая другая среда, ориентированная на GNOME.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
 int main (int argc, char *argv[]) {&lt;br /&gt;
  Gtk::Main kit(argc, argv);&lt;br /&gt;
  //Загру зить Glade-файл и соз дать его вид жеты:&lt;br /&gt;
  Glib::RefPtr&amp;lt;Gnome::Glade::Xml&amp;gt; refXml;&lt;br /&gt;
  try{&lt;br /&gt;
    refXml = Gnome::Glade::Xml::create(GLADE_FILE);&lt;br /&gt;
  } catch (const Gnome::Glade::XmlError&amp;amp; ex) {&lt;br /&gt;
    std::cerr &amp;lt;&amp;lt; ex.what() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    return 1;&lt;br /&gt;
   }&lt;br /&gt;
   '''PlayerWindow* main_win = 0;'''&lt;br /&gt;
   '''refXml-&amp;gt;get_widget_derived(“main_window”, main_win);'''&lt;br /&gt;
   if (main_win){&lt;br /&gt;
     kit.run(*main_win);&lt;br /&gt;
   }&lt;br /&gt;
   delete main_win;&lt;br /&gt;
   return 0;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Откройте файл '''playermm.glade''' двойным щелчком мыши и разместите на форме вертикальный контейнер, состоящий из трех элементов. В самый верхний добавьте меню, в следующий элемент добавьте еще один вертикальный контейнер, состоящий из четырех элементов, и назовите его '''‘playerbox’'''; в самый нижний элемент поместите строку состояния. В первый элемент контейнера '''playerbox''' поместите '''Gtk::DrawingArea''' – в эту область будет выводиться наше видео. Во второй элемент добавьте метку – '''Gtk::Label''', далее разместите горизонтальную шкалу '''Gtk::HScale'''. В самом последнем элементе располагается горизонтальная группа кнопок '''Gtk::HButtonBox''': добавьте туда шесть штук и назовите их '''btn_play, btn_pause, btn_stop, btn_rewind, btn_forward''' и '''btn_open'''. В результате должен получиться интерфейс, показанный на рис. 4.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_82_1.jpg|300px|Рис. 4.]][[Изображение:LXF125_82_2.jpg|300px|Рис. 4.]] Рис. 4. Иерархия виджетов и внешний вид окна плейера.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Создадим новый класс ('''Файл &amp;gt; Новый &amp;gt; Класс С++'''), введем название – '''PlayerWindow''', базовый класс – '''Gtk::Window'''. Далее, добавим в заголовочный файл объявления всех виджетов, что мы будем использовать согласно рис. 4 (подробности ищите на прилагаемом DVD).&lt;br /&gt;
&lt;br /&gt;
Теперь, глядя на рис. 2, создадим для каждого его элемента объявление:&lt;br /&gt;
&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::DecodeBin&amp;gt; m_decode_bin;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::VideoScale&amp;gt; m_scale;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::XvImageSink&amp;gt; m_video_sink;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::AudioConvert&amp;gt; m_conv;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::AlsaSink&amp;gt; m_audio_sink;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::Pipeline&amp;gt; m_pipeline;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::FileSrc&amp;gt; m_src;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::Queue&amp;gt; m_queuev;&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::Queue&amp;gt; m_queuea;&lt;br /&gt;
&lt;br /&gt;
Поясним, что означает каждая из этих переменных:&lt;br /&gt;
* '''FileSrc''' Источник данных, то есть файл.&lt;br /&gt;
* '''DecodeBin''' Элемент, который будет раскодировать наши медиа-данные. В зависимости от типа данных у него будут создаваться выходы для видео- и аудиопотоков, каждый из которых мы будем передавать в элемент '''Queue''' [очередь].&lt;br /&gt;
* '''Queue''' Элемент, который используется в ''GStreamer'' для создания многопоточности; наши аудио и видео будут обрабатываться в разных потоках.&lt;br /&gt;
* '''AudioConvert''' Конвертирует буфер «сырого» звука [‘raw audio’] между различными возможными форматами. Строго говоря, в нашем случае он не нужен и добавлен «для массовости», чтобы вы могли лучше представить себе структуру типового приложения ''GStreamer''. Нужно помнить, что разные входные коннекторы могут принимать разные форматы, и даже одни и те же коннекторы могут принимать разные форматы на разных машинах. Поэтому лучше добавлять в цепочки для обработки данных конвертирующие элементы, такие как ''audioconvert'' и ''audioresample'' для звука или ''ffmpegcolorspace'' для видео. Об этом, по крайней мере, предупреждает документация.&lt;br /&gt;
* '''VideoScale''' Изменяет размер изображения. По умолчанию используется билинейный алгоритм, что дает при масштабировании более приятную картинку. В нашем случае элемент также необязательный, поскольку протокол ''Xv'' пытается привлечь для масштабирования графическую карту.&lt;br /&gt;
* '''AlsaSink''' В качестве аудиовыхода используется ''ALSA'' (Advanced Linux Sound Architecture).&lt;br /&gt;
* '''XvImageSink''' Элемент транслирует видеофреймы в нечто, пригодное к выводу на локальный дисплей с использованием видеоконтроллера для преобразования цветов и размера изображения. Также может использоваться для преобразования яркости, контрастности и оттенка цветов. '''XImageSink''' для всех этих операций применяет другие элементы, например, '''VideoScale'''.&lt;br /&gt;
* '''Pipeline''' Конвейер, в который помещаются все остальные элементы и который осуществляет управление ими.&lt;br /&gt;
&lt;br /&gt;
Кроме того, в нашем заголовочном файле присутствуют конструктор, деструктор и обработчики сигналов.&lt;br /&gt;
&lt;br /&gt;
Вы, наверное, обратили внимание на использование интеллектуального указателя с подсчетом ссылок – '''Glib::RefPtr&amp;lt; t_CppObject&amp;gt;'''. Это стандартная практика управления ресурсами '''glibmm''' и '''gtkmm'''. Суффикс «mm» в конце имени библиотеки, кстати, говорит о том, что это ''С++''-обертка.&lt;br /&gt;
&lt;br /&gt;
===Свет, камера, мотор!===&lt;br /&gt;
&lt;br /&gt;
Заголовочный файл готов; приступим к реализации. Конструктор настраивает все виджеты, связывает виджеты с обработчиками сигналов и выставляет кнопки в начальное состояние, то есть блокирует все, кроме кнопки '''Открыть'''. Настройку ''GStreamer'' вынесем в отдельную функцию, которая будет вызываться из нашего конструктора.&lt;br /&gt;
&lt;br /&gt;
В методе '''GstreamInit()''' происходит инициализация ''GStreamer'' и настройка всех нужных нам элементов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 void PlayerWindow::GstreamInit() {&lt;br /&gt;
  // инициа лизация GStreamer&lt;br /&gt;
  Gst::init();&lt;br /&gt;
  //соз даем конвейер&lt;br /&gt;
  m_pipeline = Gst::Pipeline::create(“pipeline”);&lt;br /&gt;
  //шина сообщений&lt;br /&gt;
  Glib::RefPtr&amp;lt;Gst::Bus&amp;gt; bus = m_pipeline-&amp;gt;get_bus();&lt;br /&gt;
  // Разрешить син хронное извлечение сообщений&lt;br /&gt;
  bus-&amp;gt;enable_sync_message_emission();&lt;br /&gt;
  // На значить син хронный обработ чик сообщений&lt;br /&gt;
  bus-&amp;gt;signal_sync_message().connect( sigc::mem_fun(*this,&lt;br /&gt;
    &amp;amp;PlayerWindow::on_bus_message_sync));&lt;br /&gt;
  // На значить асин хронный обработ чик сообщений&lt;br /&gt;
  m_watch_id = bus-&amp;gt;add_watch(sigc::mem_fun(*this,&lt;br /&gt;
    &amp;amp;PlayerWindow::on_bus_message) );&lt;br /&gt;
  //ис точник данных&lt;br /&gt;
  m_src = Gst::FileSrc::create(“source”);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь создадим наш декодер. Выше мы рассматривали вывод команды ''gst-inspect decodebin'' и видели, что он посылает три сигнала:&lt;br /&gt;
* '''new-decoded-pad''' Создан новый коннектор. В этом обработчике мы будем связывать аудио- и видеоцепочки с выходными данными декодера, исходя из типа создаваемого коннектора (см. рис. 2).&lt;br /&gt;
* '''removed-decoded-pad''' Коннектор удален.&lt;br /&gt;
* '''unknown-type''' Неизвестный тип медиа-данных.&lt;br /&gt;
&lt;br /&gt;
Из всех этих событий нам нужно обрабатывать только создание новых коннекторов.&lt;br /&gt;
&lt;br /&gt;
 m_decode_bin = Gst::DecodeBin::create(“decodebin”);&lt;br /&gt;
 m_decode_bin-&amp;gt;signal_new_decoded_pad().&lt;br /&gt;
 connect(sigc::mem_fun(*this,&amp;amp;PlayerWindow::on_new_decoded_pad));&lt;br /&gt;
&lt;br /&gt;
Следующим шагом создаются оставшиеся элементы:&lt;br /&gt;
&lt;br /&gt;
 m_conv = Gst::AudioConvert::create();&lt;br /&gt;
 m_audio_sink = Gst::AlsaSink::create();&lt;br /&gt;
 m_scale = Gst::VideoScale::create();&lt;br /&gt;
 m_video_sink = Gst::XvImageSink::create(“ximagesink”);&lt;br /&gt;
 m_video_sink-&amp;gt;set_property(“force-aspect-ratio”, true);&lt;br /&gt;
 m_queuea = Gst::Queue::create();&lt;br /&gt;
 m_queuev = Gst::Queue::create();&lt;br /&gt;
&lt;br /&gt;
Наконец, мы размещаем все элементы на конвейере и связываем их между собой:&lt;br /&gt;
&lt;br /&gt;
 m_pipeline-&amp;gt;add(m_src)-&amp;gt;add(m_decode_bin)-&amp;gt;add(m_queuea)-&lt;br /&gt;
 &amp;gt;add(m_conv)-&amp;gt; add(m_audio_sink)-&amp;gt;add(m_queuev)-&amp;gt;add(m_scale)-&lt;br /&gt;
 &amp;gt;add(m_video_sink);&lt;br /&gt;
 m_src-&amp;gt;link(m_decode_bin);&lt;br /&gt;
 // аудиоветвь&lt;br /&gt;
 m_queuea-&amp;gt;link(m_conv)-&amp;gt;link(m_audio_sink);&lt;br /&gt;
 // видеоветвь&lt;br /&gt;
 m_queuev-&amp;gt;link(m_scale)-&amp;gt;link(m_video_sink);&lt;br /&gt;
 m_pipeline-&amp;gt;set_state(Gst::STATE_NULL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Далее, реализуем обработчик сигналов для декодера. В случае, если речь идет о создании нового коннектора, его текст представлен ниже. В имени вновь созданного коннектора мы ищем строку «'''video'''» или «'''audio'''», далее получаем входной коннектор соответствующей ветви элементов и связываем их. Наконец, мы проверяем результат связывания, и в случае неудачи сообщаем об этом на консоль программы.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 void PlayerWindow::on_new_decoded_pad(const&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::Pad&amp;gt;&amp;amp; pad,&lt;br /&gt;
                           bool arg1) {&lt;br /&gt;
   if (pad-&amp;gt;get_caps()-&amp;gt;get_structure(0).get_name().find(“video”)&lt;br /&gt;
       != Glib::ustring::npos) {&lt;br /&gt;
     Glib::RefPtr&amp;lt;Gst::Pad&amp;gt; sinkPad = m_queuev-&lt;br /&gt;
 &amp;gt;get_static_pad(“sink”);&lt;br /&gt;
     // связать только один раз&lt;br /&gt;
     if (!sinkPad-&amp;gt;is_linked()) {&lt;br /&gt;
       Gst::PadLinkReturn ret = pad-&amp;gt;link(sinkPad);&lt;br /&gt;
       if (ret != Gst::PAD_LINK_OK&lt;br /&gt;
           &amp;amp;&amp;amp; ret != Gst::PAD_LINK_WAS_LINKED) {&lt;br /&gt;
         std::cerr &amp;lt;&amp;lt; “Невозмож но на значить видеовы ход” &amp;lt;&amp;lt;&lt;br /&gt;
 std::endl;&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
   //... подключение аудиопотока осу щест в ляется точно так же&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Каждый обработчик сигналов принимает одинаковые последовательности сообщений: первым их получает синхронный обработчик, далее – асинхронный. Рассмотрим синхронный обработчик шины сообщений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 void PlayerWindow::on_bus_message_sync( const&lt;br /&gt;
 Glib::RefPtr&amp;lt;Gst::Message&amp;gt;&amp;amp; message) {&lt;br /&gt;
   // игнорировать все события кроме ‘prepare-xwindow-id’&lt;br /&gt;
   if(message-&amp;gt;get_message_type() != Gst::MESSAGE_ELEMENT&lt;br /&gt;
      &amp;amp;&amp;amp; !message-&amp;gt;get_structure().has_name(“prepare-xwindow-id”))&lt;br /&gt;
     return;&lt;br /&gt;
   Glib::RefPtr&amp;lt;Gst::Element&amp;gt; element =&lt;br /&gt;
     Glib::RefPtr&amp;lt;Gst::Element&amp;gt;::cast_dynamic(message-&amp;gt;get_source());&lt;br /&gt;
   Glib::RefPtr&amp;lt; Gst::ElementInterfaced&amp;lt;Gst::XOverlay&amp;gt; &amp;gt; xoverlay =&lt;br /&gt;
     Gst::Interface::cast &amp;lt;Gst::XOverlay&amp;gt;(element);&lt;br /&gt;
   if(xoverlay){&lt;br /&gt;
     const gulong xWindowId =&lt;br /&gt;
      GDK_WINDOW_XID(m_video_area-&amp;gt;get_window()-&amp;gt;gobj());&lt;br /&gt;
     xoverlay-&amp;gt;set_xwindow_id(xWindowId);&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Задача этого обработчика – получить контекст окна, в которое будет выводится видео. Наш асинхронный обработчик, '''on_bus_message()''', обрабатывает только два сигнала: это конец потока данных и ошибка. В любом случае обработчик вызывает метод '''on_button_stop()''', который переводит конвейер в состояние '''STATE_NULL'''.&lt;br /&gt;
&lt;br /&gt;
Вот почти и все: осталось только добавить обработчики нажатия кнопок, и приложение можно запускать. Все управление воспроизведением сводится к изменению состояния контейнера посредством шести кнопок. Также в обработчиках кнопок разместим управление таймером. Он нужен нам для обновления прогресса воспроизведения и отслеживания прошедшего времени. Например, обработчик кнопки «'''Play'''» может выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 void PlayerWindow::on_button_play() {&lt;br /&gt;
  //изменить состояние кнопок&lt;br /&gt;
  m_progress_scale-&amp;gt;set_sensitive();&lt;br /&gt;
  m_play_button-&amp;gt;set_sensitive(false);&lt;br /&gt;
  m_pause_button-&amp;gt;set_sensitive();&lt;br /&gt;
  m_stop_button-&amp;gt;set_sensitive();&lt;br /&gt;
  m_rewind_button-&amp;gt;set_sensitive();&lt;br /&gt;
  m_forward_button-&amp;gt;set_sensitive();&lt;br /&gt;
  m_open_button-&amp;gt;set_sensitive(false);&lt;br /&gt;
  m_play_button-&amp;gt;hide();&lt;br /&gt;
  m_pause_button-&amp;gt;show();&lt;br /&gt;
  // вызывать функ цию on_timeout ка ж дые 200 мс&lt;br /&gt;
  // для регулярного обнов ления по зиции в потоке&lt;br /&gt;
  m_timeout_connection = Glib::signal_timeout().connect(&lt;br /&gt;
    sigc::mem_fun(*this, &amp;amp;PlayerWindow::on_timeout), 200);&lt;br /&gt;
  // Включить режим воспроизведения&lt;br /&gt;
  m_pipeline-&amp;gt;set_state(Gst::STATE_PLAYING);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF125_83_1.jpg|300px|Рис. 5.]]  Рис. 5. Результат наших трудов: не слишком развитый, но вполне работоспособный видеоплейер.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Соответственно, постановка на паузу будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=cpp&amp;gt;&lt;br /&gt;
 void PlayerWindow::on_button_pause() {&lt;br /&gt;
   m_play_button-&amp;gt;set_sensitive();&lt;br /&gt;
   m_pause_button-&amp;gt;set_sensitive(false);&lt;br /&gt;
   m_pause_button-&amp;gt;hide();&lt;br /&gt;
   m_play_button-&amp;gt;show();&lt;br /&gt;
   // Ос тановить таймер&lt;br /&gt;
   m_timeout_connection.disconnect();&lt;br /&gt;
   // Пау за&lt;br /&gt;
   m_pipeline-&amp;gt;set_state(Gst::STATE_PAUSED);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Полный текст приложения имеется на прилагающемся к журналу диске. Кроме того, пакеты '''GStreamer''' и '''GStreamermm''' содержат примеры, которые помогают понять все тонкости использования данного каркаса. Проект активно развивается, расширяется документация (http://gstreamer.freedesktop.org/documentation/), в планах есть интеграция с KDE, что упростит обработку событий; об этом вы можете подробнее прочитать на сайте проекта.&lt;br /&gt;
&lt;br /&gt;
Ну и, прежде чем закончить статью, давайте посмотрим, что у нас получилось! Для запуска приложения скопируйте его в свою рабочую папку, запустите ''Anjuta'', откройте диалог '''Настроить проект''' ('''Сборка &amp;gt; Конфигурация проекта...''') отметьте галочку '''Пересоздать проект''' и нажмите '''Выполнить'''. Теперь ''Playermm'' можно запустить, нажав '''F3'''.&lt;br /&gt;
&lt;br /&gt;
'''LXF'''&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>