Знакомство с GStreamer: Источники данных

в 11:36, , рубрики: gstreamer, мультимедиа, разработка, разработка программного обеспечения, метки: , ,

Здравствуй, читатель, интересующийся фреймворком GStreamer! Сегодня мы поговорим о источниках медиа-данных (sources), и тем самым продолжим курс статей посвященный GStreamer.

Предыдущая статья: Знакомство с GStreamer: Введение.

Вступление

Знакомство с GStreamer: Источники данных
Источники данных — это класс плагинов GStreamer который позволяет читать медиаданные из различных источников, таких как файловая система или аудио-входы звуковой карты. Также, они позволяют получать медиапоток с различных серверов потокового вещания, такие как HTTP (ICECast, ShoutCast), RTSP, RTMP, TCP и UDP. А еще имеется возможность читать данные с DVB карт, CDDA-дисков (народе известных просто как «компакт-диски»), и еще много всего, при помощи различных плагинов, которых на данный момент около 30.
Примечание: как говорилось в прошлой статье, источники данных имеют только один pad с названием src, так как его можно подключить к другому элементу, но к нему подключить ничего нельзя.

В этой статье мы разберем некоторые (пожалуй, наиболее востребованные) источники данных, напишем немного кода на Python и узнаем много нового.

Поехали

0. gst-launch-1.0

Утилита gst-launch-1.0 позволяет запускать GStreamer pipeline без написания единой строчки кода. Я буду ее использовать для запуска небольших примеров, и что нам требуется знать сегодня — так это то, что запуск pipeline имеет примерно такой вид:

gst-launch-1.0 описание-pipeline

а описание pipeline, в свою очередь, делится на описание элементов вида

element1 property1=value1 property2=value2 ! element2 

Вроде в этой схеме все понятно, есть элемент типа element1 с свойствами property1 и property2 которые имеют значения value1 и value2 соответственно, и есть элемент типа element2. Символ «!» указывает на то, что выход element1 необходимо соединить с входом element2.
На этом возможности gst-launch не ограничиваются, просто в сегодняшней статье они нам не пригодятся и будут рассмотрены в дальнейшем.

1. filesrc

filesrc — на мой взгляд, это самый часто используемый источник мультимедийных данных. Как можно понять из его названия, он является элементом для чтения данных из файлов. В прошлой статье мы рассматривали схему примитивного плеера, в котором фигурировал filesrc как источник данных.
Элемент filesrc имеет несколько параметров. Рассмотрим некоторые из них.

location

Свойство location должно содержать путь к файлу, из которого необходимо производить чтение.
Пример: /foo/bar.mp3

blocksize

Данный параметр устанавливает размер буфера чтения. Значение должно быть описано беззнаковым числом.

num-buffers

Количество блоков, после прочтения которых будет отправлено сообщение EOS.
Свойства blocksize и num-buffers можно не указывать. В этом случае будут использованы значения по умолчанию. А еще указанные свойства имеются у всех источников данных, и далее рассматриваться не будут.

Пример использования источника filesrc возьмем из предыдущей статьи:

gst-launch-1.0 filesrc location=/foo/bar.mp3 ! decodebin ! autoaudiosink

2. souphttpsrc

Элемент souphttpsrc предоставляет возможность чтения данных поверх HTTP (HTTPS) протокола. Чтение может производиться как из обычного файла, доступного через HTTP протокол, так и с ICECast/ShoutCast сервера. Также данный элемент позволяет производить чтение данных поверх протоколов ICY и ICYX. По данным протоколам я никакой информации найти не смог.
souphttpsrc имеет чуть больше параметров чем filesrc, рассмотрим наиболее важные.

location

Данный параметр аналогичен одноименному параметру элемента filesrc, за исключением того, что поддерживаются только схемы URI http, https, icy или icyx.

user-agent

Название говорит само за себя — данный параметр устанавливает, какой использовать User-Agent при отправке HTTP-запросов.

automatic-redirect

Устанавливает автоматический переход в случае, если сервер ответил, что ресурс был перемещен (статусы 301 и 302).

user-id и user-pw

Данные свойства устанавливают имя пользователя и пароль, на случай, если ресурс требует авторизации (HTTP Basic Authentication).

proxy, proxy-id и proxy-pw

Данные свойства устанавливают адрес прокси сервера, имя пользователя и пароль для авторизации (если необходимо). Поддерживаются HTTP и HTTPS прокси.

Использование источника souphttpsrc, ничем не отличается от использования источника filesrc:

gst-launch-1.0 souphttpsrc location=http://radio.localhost:1234 ! decodebin ! autoaudiosink

3. giosrc

В наборе плагинов GStreamer имеется интересный элемент giosrc. Это почти то же самое что и filesrc, только работает он через библиотеку GIO, и позволяет получать данные из различных источников с которыми может работать GIO. Таких источников 22, начиная от file, заканчивая mtp. Также, данный элемент поддерживает протоколы ftp, sftp, smb и webdav.
Данный элемент имеет параметры аналогичные элементу filesrc. Пример использования данного источника аналогичен использованию предыдущих:

gst-launch-1.0 giosrc location=ftp://ftp.localhost/foo/bar.mp3 ! decodebin ! autoaudiosink

4. rtspsrc

Как можно понять из названия, данный элемент позволяет читать данные с RTSP сервера. Подробно рассматривать свойства данного элемента не будем, скажу только то, что он имеет свойство location для указания адреса источника данных, proxy, proxy-id и proxy-pw для указания настроек прокси, и с десяток свойств специфичных для RTSP протокола, рассмотрение которого не входит в наши планы.
Но, у rtspsrc есть одна особенность, у него несколько pad-ов, и имеют они названия подходящие под шаблон source_%u. Это связано с тем, что сервер может транслировать несколько потоков одновременно, например, аудио и видео могут быть разбросаны по двум потокам.
Примечание:
Я не знаком c протоколом RTSP, поэтому я мог ошибиться в предположении выше.

Пример использования rtspsrc аналогичен предыдущим элементам:

gst-launch-1.0 rtspsrc location=rtsp://rtsp.localhost/movie.mp4 ! decodebin ! autoaudiosink

5. multifilesrc

Суть элемента multifilesrc такая же, как и у элемента filesrc — читать файлы с диска, но имеется одно отличие — multifilesrc читает файлы последовательно (1.mp3, 2.mp3...), в то время как filesrc может читать только по одному файлу. У данного элемента есть один недостаток — имена файлов должны различаться только числом, например, file-1.mp3, file-2.mp3 и так далее. Но такой недостаток можно списать в разряд фич, так как с помощью данного «недостатка» можно с легкостью слепить из изображений 0000.png-9999.png видеоролик из фотографий, ну или мелодию из семплов, или микс из треков.
Элемент multifilesrc имеет немного параметров, и как ни странно — они все полезные. Рассмотрим их подробнее.

location

Путь к файлу может (и должен) включать в себя управляющую последовательность %d, которая будет автоматически заменена с помощью функции sprintf() на число равное текущему индексу.
Пример: /foo/bar-%04d.mp3

index, start-index и stop-index

Данные свойства содержат в себе текущий индекс, стартовый индекс, и финальный индекс. Данные свойства содержат целочисленное число.

loop

Данное свойство может содержать булево значение, и в случае если оно равно true — чтение файлов будет зациклено. Грубо говоря, это аналог функции «Repeat All».

Пример использования элемента multifilesrc который читает файлы с именами начиная от bar-1.mp3 с включенной опцией loop:

gst-launch-1.0 multifilesrc location="/foo/bar-%d.mp3" loop=true start-index=1 ! decodebin ! autoaudiosink
6. fdsrc

На мой взгляд, самый бесполезный элемент. Читает данные из файлового дескриптора. Может применяться когда лень описывать filesrc для gst-launch.
Данный элемент имеет один параметр:

fd

Данный параметр должен содержать число, равное открытому файловому дескриптору. По умолчанию равняется нулю.

Пример использования:

cat /foo/bar.mp3 | gst-launch-1.0 fdsrc ! decodebin ! autoaudiosink

7. fakesrc

Как следует из названия, данный элемент ничего не делает — он просто является dummy-источником пустых буферов.

8. alsasrc, pulsesrc, osssrc, jackaudiosrc, autoaudiosrc

Данные элементы предназначены для получения потока с микрофонного входа звуковой карты. Из названий следует, что они используются для работы с различными звуковыми подсистемами, такими, как Alsa, PulseAudio, OSS, Jack. Элемент autoaudiosrc является «оберткой» над остальными элементами, и упрощает разработку, забирая на свои плечи всю работу по выбору источника звука.
Свойств у данных элементов не очень много. Основным свойством является device, оно присутствует в первых трех элементах и должно содержать название девайса (hw:0, hw:1...). Остальные свойства используются специфичны для каждой звуковой подсистемы, и рассматривать мы их не будем.

9. v4l2src

Этот элемент предназначен для открытия видеопотока через интерфейс Video4Linux2. Интерфейс V4L2 поддерживает большинство веб-камер, ТВ-тюнеры, DVB-карточки и карточки видеозахвата.
Рассмотрим наиболее важные параметры:

device

Указывает имя устройства с которого нужно производить захват. Узнать список доступных устройств можно с помощью

ls -l /dev/v4l/by-id

В качестве значения этого параметра должен быть указан полный путь к устройству.
Пример: device=/dev/video0

hue, saturation, contrast. brightness

Данные параметры отвечают за цветовой баланс, насыщенность, контраст и яркость соответственно. Конечно же, если устройство видеозахвата не поддерживает данные параметры, то изображение будет таким, каким его отдает устройство. Значения этих свойств должны находиться в диапазоне от -2147483648 до 2147483647.

Пример использования элемента:

gst-launch-1.0 v4l2src ! xvimagesink

Пояснения

Выше мы рассмотрели 13 основных источников данных, это где-то половина от всех имеющихся плагинов из категории source. Остальные плагины не были рассмотрены по двум причинам:

  • Они узкоспециализированные;
  • У меня отсутствуют необходимые «железки» для проверки того или иного плагина.

При рассмотрении плагинов были опущены многие параметры, так как в основном все они используются для «тонкой настройки», а у нас, как вы помните, идет знакомство с GStreamer. Или же данные параметры доступны только для чтения. Чтобы получить список всех доступных свойств, а так же допустимые для них значения, достаточно выполнить gst-inspect-1.0 <имя_элемента>, например:

gst-inspect-1.0 filesrc

и в секции «Element Properties» вы можете наблюдать все свойства (в том числе и унаследованные).

Примеры

Сегодня мы рассмотрим один простой пример использования GStreamer. В примере я буду использовать Python 2.7, GStreamer 1.0 и GObject Introspection.
Сразу оговорюсь, код может быть не идеальным, и может быть даже так называемым «говнокодом», но его единственное назначение показать, как использовать GStreamer, не более.

Простой плеер

Данный пример показывает, как проводится связывание элементов, как обрабатываются сообщения и изменяются свойства элементов.

Код плеера

#env python2
# coding=utf-8

import gi
gi.require_version("Gst", "1.0")
gi.require_version("Gtk", "3.0")
from gi.repository import Gst
from gi.repository import Gtk
from gi.repository import GObject

import os
import signal
import argparse

Gst.init("")
signal.signal(signal.SIGINT, signal.SIG_DFL)
GObject.threads_init()


def parse_args():
    parser = argparse.ArgumentParser(prog='example1.py')
    parser.add_argument('--volume', help='Указать громкость (0-100)', type=int, default=100)
    parser.add_argument('location')
    args = parser.parse_args()
    return args


class Player():

    def __init__(self, args):
        self.pipeline = self.create_pipeline(args)

        ## получаем шину по которой рассылаются сообщения
        ## и вешаем на нее обработчик
        message_bus = self.pipeline.get_bus()
        message_bus.add_signal_watch()
        message_bus.connect('message', self.message_handler)

        ## устанавливаем громкость
        self.pipeline.get_by_name('volume').set_property('volume', args.volume / 100.)

    def create_source(self, location):
        """create_source(str) -> Gst.Element"""
        if not args.location.startswith('http') and not os.path.exists(args.location):
            raise IOError("File %s doesn't exists" % args.location)

        if location.startswith('http'):
            source = Gst.ElementFactory.make('souphttpsrc', 'source')
        else:
            source = Gst.ElementFactory.make('filesrc', 'source')
        source.set_property('location', location)
        return source

    def create_pipeline(self, args):
        """create_pipeline() -> Gst.Pipeline"""

        pipeline = Gst.Pipeline()
        ## Создаем нужные элементы для плеера
        source = self.create_source(args.location)
        decodebin = Gst.ElementFactory.make('decodebin', 'decodebin')
        audioconvert = Gst.ElementFactory.make('audioconvert', 'audioconvert')
        volume = Gst.ElementFactory.make('volume', 'volume')
        audiosink = Gst.ElementFactory.make('autoaudiosink', 'autoaudiosink')

        ## decodebin имеет динамические pad'ы, которые так же динамически
        ## необходимо линковать
        def on_pad_added(decodebin, pad):
            pad.link(audioconvert.get_static_pad('sink'))
        decodebin.connect('pad-added', on_pad_added)

        ## добавляем все созданные элементы в pipeline
        [pipeline.add(k) for k in [source, decodebin, audioconvert, volume, audiosink]]

        ## линкуем элементы между собой по схеме:
        ## *src* -> (decodebin + audioconvert) -> volume -> autoaudiosink
        source.link(decodebin)
        audioconvert.link(volume)
        volume.link(audiosink)
        return pipeline

    def play(self):
        self.pipeline.set_state(Gst.State.PLAYING)

    def message_handler(self, bus, message):
        """Обработчик сообщений"""
        struct = message.get_structure()
        if message.type == Gst.MessageType.EOS:
            print('Воспроизведение окончено.')
            Gtk.main_quit()
        elif message.type == Gst.MessageType.TAG and message.parse_tag() and struct.has_field('taglist'):
            print('GStreamer обнаружил в потоке мета-теги')
            taglist = struct.get_value('taglist')
            for x in range(taglist.n_tags()):
                name = taglist.nth_tag_name(x)
                print('  %s: %s' % (name, taglist.get_string(name)[1]))
        else:
            pass


if __name__ == "__main__":
    args = parse_args()
    player = Player(args)
    player.play()
    Gtk.main()

Примеры запуска этого скрипта:

python2 ./example1.py /foo/bar.mp3
python2 ./example1.py --volume 50 /foo/bar.mp3
python2 ./example1.py http://myradio.localhost:5678/foo.mp3

В случае, если все пойдет как нужно — вы услышите нужный вам трек и увидите список ID3 тегов, если таковые имеются.
Пример доступен на GitHub.

Ну вот и все

Сегодня мы рассмотрели около половины имеющихся источников данных которые доступны «из коробки», рассмотрели примеры запуска этих элементов, а также рассмотрели пример простого плеера основанного на GStreamer. В следующих статьях мы будем рассматривать остальные классы плагинов, рассмотрим еще больше примеров использования GStreamer, и конечно же, напишем больше кода.
До встречи через неделю!

Литература

  1. GStreamer Application Development Manual
  2. GStreamer Core Plugins Reference Manual
  3. GStreamer Base Plugins Reference Manual
  4. GStreamer Good Plugins Reference Manual
  5. Video4Linux
  6. GIO Reference Manual
  7. The ID3v2/Shoutcast standart
  8. SHOUTCast

Автор: POPSuL

Источник

Поделиться

* - обязательные к заполнению поля