使用 gstreamer api 播放音频文件时出现问题:应用程序挂起

Trouble playing audio files using gstreamer apis: application hangs

我使用 gstreamer api 用 c++ 编写了一个简单的音频播放器应用程序。我关注了Gstreamer Hello world example。这是我的代码:

CMediaPlayer::CMediaPlayer(QString path) 
{
    gst_init(NULL, NULL);
    createElements(path);
}

createElements(QString &path)
    {
            /* Create gstreamer elements */
            m_pipeline  = gst_pipeline_new("audio-player");
            m_fileSource = gst_element_factory_make("filesrc", "file-source");
            m_audioDecoder = gst_element_factory_make("mad", "mp3-decoder");
            m_volume = gst_element_factory_make("volume", "volume-name");
            m_audioConverter = gst_element_factory_make("audioconvert", "audio-converter");
            m_sink = gst_element_factory_make("alsasink", "audio-output");


        if (!m_pipeline || !m_fileSource || !m_audioDecoder || !m_volume || !m_audioConverter || !m_sink) {
            g_printerr ("One or more elements could not be created !! \n");
            return false;
        }
        /* Set up the pipeline */
        else {
            /* set a message handler on a bus */
            GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_pipeline));
            gst_bus_add_watch(bus, bus_call, m_loop);
            gst_object_unref(bus);

            g_object_set (G_OBJECT (m_fileSource), "location", path.toLatin1().data(), NULL);

            /* add all elements into the pipeline */
            gst_bin_add_many (GST_BIN (m_pipeline), m_fileSource, m_audioDecoder, m_volume, m_audioConverter, m_sink, NULL);

            /* link the elements together */
            if(!gst_element_link_many (m_fileSource, m_audioDecoder, NULL)) {
                g_printerr("ERROR: Failed to link file-source and audio-decoder !! \n");
                return false;
            }
            if(!gst_element_link_many (m_audioDecoder, m_volume, NULL)) {
                g_printerr("ERROR: Failed to link audio-decoder and volume !! \n");
                return false;
            }
            if(!gst_element_link_many (m_volume, m_audioConverter, NULL)) {
                g_printerr("ERROR: Failed to link audio-decoder and audio-converter !! \n");
                return false;
            }
            if(!gst_element_link_many (m_audioConverter, m_sink, NULL)) {
                g_printerr("ERROR: Failed to link audio-converter and sink !! \n");
                return false;
            }
        }

    /* Prepare the pipeline */
    gst_element_set_state(m_pipeline, GST_STATE_READY);
    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);

}

bus_call(GstBus *bus, GstMessage *msg, gpointer data) {

    CMediaPlayer *ptr = (CMediaPlayer*)(data);
    switch(GST_MESSAGE_TYPE(msg))
    {
        case GST_MESSAGE_EOS:
            // Reset the position of the stream
            gst_element_set_state (ptr->m_pipeline, GST_STATE_READY);
            gst_element_set_state (ptr->m_pipeline, GST_STATE_PAUSED);
            g_message("GST_MESSAGE_EOS \n");
            break;

        case GST_MESSAGE_ERROR:
            gchar  *debug;
            GError *error;

            gst_message_parse_error (msg, &error, &debug);
            g_free (debug);

            g_printerr ("ERROR: %s\n", error->message);
            g_error_free (error);
            break;
        default:
            g_message("default \n");
            break;
    }
    bus = bus; // prevent "unused" warning
    return TRUE;
}

slot_play() {
    m_gstReturnValue = gst_element_set_state (m_pipeline, GST_STATE_PLAYING);
    if(m_gstReturnValue == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("ERROR: Cannot play !! \n");
    }
}

slot_pause() {
    m_gstReturnValue = gst_element_set_state (m_pipeline, GST_STATE_PAUSED);
    if(m_gstReturnValue == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("ERROR: Cannot pause !! \n");
    }
}

slot_stop() {
    m_gstReturnValue = gst_element_set_state (m_pipeline, GST_STATE_READY);
    m_gstReturnValue = gst_element_set_state (m_pipeline, GST_STATE_PAUSED);
    if(m_gstReturnValue == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("ERROR: Cannot stop !! \n");
    }
}

slot_setVolume(int vol_i) {
    vol_i = (vol_i > 10) ? 10 : (vol_i < 0) ? 0 : vol_i;
    g_object_set(G_OBJECT(m_volume), "volume", (gdouble(vol_i)/10), NULL);
}

当我 运行 应用程序时,它的行为很奇怪。有时播放有时不播放。这是我不播放时的信息:

0:01:12.000176325 31988   0x5e3000 INFO               GST_EVENT gstevent.c:1244:gst_event_new_latency: creating latency event 0:00:00.000000000
0:01:12.000953562 31988   0x5e3000 INFO                     bin gstbin.c:2502:gst_bin_do_latency_func:<audio-player> configured latency of 0:00:00.000000000
0:01:12.001444706 31988   0x5e3000 INFO              GST_STATES gstbin.c:2230:gst_bin_element_set_state:<audio-output> current PAUSED pending VOID_PENDING, desired next PLAYING
0:01:12.004258709 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<audio-output> completed state change to PLAYING
0:01:12.004433239 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<audio-output> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)
0:01:12.004624124 31988   0x5e3000 INFO              GST_STATES gstbin.c:2673:gst_bin_change_state_func:<audio-player> child 'audio-output' changed state to 4(PLAYING) successfully
0:01:12.004783134 31988   0x5e3000 INFO              GST_STATES gstbin.c:2230:gst_bin_element_set_state:<audio-converter> current PAUSED pending VOID_PENDING, desired next PLAYING
0:01:12.004904644 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<audio-converter> completed state change to PLAYING
0:01:12.004990634 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<audio-converter> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)
0:01:12.005134540 31988   0x5e3000 INFO              GST_STATES gstbin.c:2673:gst_bin_change_state_func:<audio-player> child 'audio-converter' changed state to 4(PLAYING) successfully
0:01:12.005267925 31988   0x5e3000 INFO              GST_STATES gstbin.c:2230:gst_bin_element_set_state:<volume-name> current PAUSED pending VOID_PENDING, desired next PLAYING
0:01:12.005386310 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<volume-name> completed state change to PLAYING
0:01:12.005483653 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<volume-name> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)
0:01:12.005634851 31988   0x5e3000 INFO              GST_STATES gstbin.c:2673:gst_bin_change_state_func:<audio-player> child 'volume-name' changed state to 4(PLAYING) successfully
0:01:12.005785006 31988   0x5e3000 INFO              GST_STATES gstbin.c:2230:gst_bin_element_set_state:<mp3-decoder> current PAUSED pending VOID_PENDING, desired next PLAYING
0:01:12.005916673 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<mp3-decoder> completed state change to PLAYING
0:01:12.006004329 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<mp3-decoder> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)
0:01:12.006142245 31988   0x5e3000 INFO              GST_STATES gstbin.c:2673:gst_bin_change_state_func:<audio-player> child 'mp3-decoder' changed state to 4(PLAYING) successfully
0:01:12.006259484 31988   0x5e3000 INFO              GST_STATES gstbin.c:2230:gst_bin_element_set_state:<file-source> current PAUSED pending VOID_PENDING, desired next PLAYING
0:01:12.006381567 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<file-source> completed state change to PLAYING
0:01:12.006465942 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<file-source> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)
0:01:12.006599379 31988   0x5e3000 INFO              GST_STATES gstbin.c:2673:gst_bin_change_state_func:<audio-player> child 'file-source' changed state to 4(PLAYING) successfully
0:01:12.006726983 31988   0x5e3000 INFO              GST_STATES gstelement.c:2328:gst_element_continue_state:<audio-player> completed state change to PLAYING
0:01:12.006812868 31988   0x5e3000 INFO              GST_STATES gstelement.c:2233:_priv_gst_element_state_changed:<audio-player> notifying about state-changed PAUSED to PLAYING (VOID_PENDING pending)

根据日志,管道状态更改为 PLAYING。但我什么也没听到。当我尝试停止或暂停或更改音量时,应用程序挂起。

我提到了这个 link。但是没有用。

我错过了什么?我是 gstreamer 的新手。任何指点都会很有帮助。

好的,这对我来说很好,一直在玩..

#include <gst/gst.h>
#include <glib.h>

int createElements(char *path)
{

    /* Create gstreamer elements */
    GstElement *m_pipeline  = gst_pipeline_new("audio-player");
    GstElement *m_fileSource = gst_element_factory_make("filesrc", "file-source");
    GstElement *m_audioDecoder = gst_element_factory_make("mad", "mp3-decoder");
    GstElement *m_volume = gst_element_factory_make("volume", "volume-name");
    GstElement *m_audioConverter = gst_element_factory_make("audioconvert", "audio-converter");
    GstElement *m_sink = gst_element_factory_make("alsasink", "audio-output");

    if (!m_pipeline || !m_fileSource || !m_audioDecoder || !m_volume || !m_audioConverter || !m_sink) {
            g_printerr ("One or more elements could not be created !! \n");
            return 0;
    } else {
            g_object_set (G_OBJECT (m_fileSource), "location", path, NULL);

            gst_bin_add_many (GST_BIN (m_pipeline), m_fileSource, m_audioDecoder, m_volume, m_audioConverter, m_sink, NULL);

            if(!gst_element_link_many (m_fileSource, m_audioDecoder, NULL)) {
                    g_printerr("ERROR: Failed to link file-source and audio-decoder !! \n");
                    return 0;
            }
            if(!gst_element_link_many (m_audioDecoder, m_volume, NULL)) {
                    g_printerr("ERROR: Failed to link audio-decoder and volume !! \n");
                    return 0;
            }
            if(!gst_element_link_many (m_volume, m_audioConverter, NULL)) {
                    g_printerr("ERROR: Failed to link audio-decoder and audio-converter !! \n");
                    return 0;
            }
            if(!gst_element_link_many (m_audioConverter, m_sink, NULL)) {
                    g_printerr("ERROR: Failed to link audio-converter and sink !! \n");
                    return 0;
            }
    }

    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
    sleep(3);
    gst_element_set_state(m_pipeline, GST_STATE_PLAYING);
    sleep(1);
    gst_element_set_state(m_pipeline, GST_STATE_PAUSED);
    sleep(2);
    gst_element_set_state(m_pipeline, GST_STATE_PLAYING);

    return 1;
}


int main(int argc, char **argv) {
    GMainLoop *loop = g_main_loop_new (NULL, FALSE);
    gst_init(&argc, &argv);
    createElements(argv[1]);
    g_main_loop_run (loop);
    return 0;
}

更新: 添加了多个过渡暂停/播放

在 Linux 编译

gcc -Wall alsa_player.c -o alsa_player $(pkg-config --cflags --libs gstreamer-1.0)

运行 与 ./alsa_player file.mp3

我正在使用 gstreamer 1.6,但我认为这段代码 运行 非常适合任何 1.x gstreamer。

更新 2: 您也可以尝试使用 gst-play 命令通过指定 alsasink 来完成相同的任务:

gst-play-1.0 japaka.mp3 --audiosink=alsasink

使用SPACE暂停和播放..