Простой аудио плеер на Gstreamer

от автора

Недавно мне понадобилось реализовать небольшой аудио плеер. Я, по различным причинам, выбрал библиотеку Gstreamer. И вот решил поделиться полученными знаниями. Надеюсь, приведенная ниже информация кому-то будет полезна.

И так начнем

Для начала немного разберемся с основными понятиями в Gstreamer

Элемент — является самым важным классом объектов в Gstreamer. Они могут объединятся в цепочку и создавать так называемый канал (pipeline). Каждый элемент имеет строго определенную функцию: чтение файла, ввод или вывод данных и т. д.

Гнезда(pads) — используются для передачи данных между элементами. В каждом элементе может быть от одного и выше гнезд.

Контейнер элементов (Bin) — объединяет цепочку элементов. С помощью данного контейнера можно управлять элементами как одним целым.

Канал (pipeline) — похож на бины, за исключением того, что место элементов он содержит контейнеры элементов.

Подробнее обо всем этом можно узнать в документации.

Теперь перейдем к реализации нашего класса.

Вот так вот выглядит класс нашего аудио плеера:

audioengine.h

#ifndef AUDIOENGINE_H #define AUDIOENGINE_H  #include <gst/gst.h> #include <glib.h> #include <QObject>  class AudioEngine : public QObject {     Q_OBJECT public:     AudioEngine(QObject *parent = 0);     ~AudioEngine();      int Init();      void MusicPlay();     void MusicPaused();     void MusicStop();     void AddFile(char *file);     void SetVolume(gdouble val);     gint64 GetMusicPosition();     gint64 GetMusicDuration();     void SetMusicPosition(gint64 pos);  private:     GstElement *pipeline;     GstElement *source;     GstElement *volume;     gint64 pos;      static void OnPadAdded(GstElement *element, GstPad *pad, gpointer data);  private slots: };  #endif // AUDIOENGINE_H 

В функции Init() мы инициализируем библиотеку Gstreamer:

gst_init(0, 0); 

данная функция принимает аргументы командной строки argv и argc, в нашем случаи их можно опустить.

Далее создаем канал:

pipeline = gst_pipeline_new("audio-player"); 

и необходимые нам элементы:

source = gst_element_factory_make("filesrc", NULL); demuxer = gst_element_factory_make("decodebin", NULL); decoder = gst_element_factory_make("audioconvert", NULL); volume = gst_element_factory_make("volume", NULL); conv = gst_element_factory_make("audioconvert",  NULL); sink = gst_element_factory_make("autoaudiosink", NULL); 

Элемент source — предназначен для чтения аудио файлов.
demuxer — используется для декодирования аудио файла.
decoder и conv — для конвертирования аудио файла в другой формат.
volume — предназначен для регулирования громкости звука.
sinc — автоматически определяет аудио устройство и выводит данные на него…

Следует заметить что demuxer создает гнезда для каждого элемента потока и нам придется установить обработчик событий для связи demuxer с decoder. В этом нам поможет функция OnPadAdded().

Обработчик событий в нашем коде выглядит так:

g_signal_connect(demuxer, "pad-added", G_CALLBACK(OnPadAdded), decoder); 

Добавляем все созданные элементы в канал:

gst_bin_add_many (GST_BIN (pipeline), source, demuxer, decoder, volume, conv, sink, NULL); 

и линкуем элементы между собой.

gst_element_link (source, demuxer); gst_element_link_many (decoder, volume, conv, sink, NULL); 

Функция для добавления файла в плеер выглядит примерно так:

void AudioEngine::AddFile(char *file) {     g_object_set(G_OBJECT(source), "location", file, NULL); } 

функция g_object_set() передает аргументы элементу source. В данном случае аргумент «location» говорит нам о том, что аудио-файл находится на локальной машине, file — путь к нашему файлу. Последний параметр NULL говорит нам о том, что элемент больше в никаких аргументах не нуждается.

Функции для запуска, остановки воспроизведения выглядят так:

void AudioEngine::AddFile(char *file) {     g_object_set(G_OBJECT(source), "location", file, NULL); } void AudioEngine::MusicPlay() {     gst_element_set_state(pipeline, GST_STATE_PLAYING); } void AudioEngine::MusicPaused() {     gst_element_set_state(pipeline, GST_STATE_PAUSED); } 

тут вроде все понятно.

Функция для регулирование громкости:

void AudioEngine::SetVolume(gdouble val) {     g_object_set(G_OBJECT(volume), "volume", val, NULL); } 

Функции для для получения продолжительности трека и текущего его положения:

gint64 AudioEngine::GetMusicDuration() {     gint64 len;     gst_element_query_duration(pipeline, GST_FORMAT_TIME, &len);     return len; } gint64 AudioEngine::GetMusicPosition() {     gint64 pos;     gst_element_query_position(pipeline, GST_FORMAT_TIME, &pos);     return pos; } 

следует иметь в виду что функции возвращают значения времени в наносекундах.

И наконец-то функция для смены позиции трека:

void AudioEngine::SetMusicPosition(gint64 pos) {     gst_element_set_state(pipeline, GST_STATE_PAUSED);     gst_element_seek_simple(pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, pos);     gst_element_set_state(pipeline, GST_STATE_PLAYING); }  

для того что бы сменить позицию нам придется остановить воспроизведение, а после смены опять его запустить.
gst_element_seek_simple() принимает в аргументы наш канал, формат времени, флаг поиска позиции, и саму позицию которая измеряется в наносекундах.

Полный код приведен ниже по ссылке в месте с небольшим GUI реализованном на Qt.
Исходники на GitHab

Всем спасибо.

ссылка на оригинал статьи http://habrahabr.ru/post/204172/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *