libVLC 音频输出设备切换

04-11 779阅读


libvlc_audio_output_list_get和libvlc_audio_output_device_list_get是libVLC 库中用于处理音频输出的两个函数。

  • libvlc_audio_output_list_get函数用于获取可用的音频输出模块列表。这个列表通常包括不同的音频输出方式,例如 Pulseaudio、ALSA 等。通过这个函数,可以了解有哪些音频输出模块可供使用。
  • libvlc_audio_output_device_list_get函数则是用于获取特定音频输出模块下的音频输出设备列表。这个函数通常在选择了特定的音频输出模块后使用,用于列出该模块下的具体设备,例如特定的声卡或硬件设备。

    libvlc_audio_output_list_get用于获取音频输出模块的列表。

    libvlc_audio_output_device_list_get用于获取特定模块下的音频输出设备的列表。

    在实际应用中,需要先使用 libvlc_audio_output_list_get获取音频输出模块,然后针对每个模块使用 libvlc_audio_output_device_list_get获取其下的设备列表,以便于用户选择和配置。

    以下是VLC播放器中使用的截图界面,我们仿照这个做一个界面。 

    libVLC 音频输出设备切换

    以下是效果图。

    libVLC 音频输出设备切换

    首先程序运行起来获取音频设备列表,创建菜单项。

        QList m_lstAudioDevice;	
        m_lstAudioDevice.clear();
    	libvlc_audio_output_device_t *pDevList = nullptr;
    	libvlc_audio_output_t *pOutputList = libvlc_audio_output_list_get(vlc_base);
    	while (pOutputList)
    	{
    		//获取设备
    		pDevList = libvlc_audio_output_device_list_get(vlc_base, pOutputList->psz_name);
    		while (pDevList)
    		{
    			// 找到我想要的那个设备,跳出循环,这里使用i控制,我知道我想要的设备位置
    			if (strcmp(pOutputList->psz_name, "mmdevice") == 0)
    			{
    				QString des = QString::fromStdString(std::string(pDevList->psz_description, strlen(pDevList->psz_description)));
    				m_lstAudioDevice.append(des);
    				QAction *action = m_deviceMenu->addAction(des);
    				action->setData(pDevList->psz_device);
    				m_group->addAction(action);
    			}
    			pDevList = pDevList->p_next;
    		}
    		pOutputList = pOutputList->p_next;
    	}

    libvlc_audio_output_list_get获取音频输出模块的列表。

    libvlc_audio_output_device_list_get获取特定模块下的音频输出设备的列表。

    这里我找到名为"mmdevice"模块下的所有音频输出设备,存储到一个QList中。

    setData设置设备标识符字符串。方便我们在切换的时候使用这个标识符。

    typedef struct libvlc_audio_output_device_t
    {
        struct libvlc_audio_output_device_t *p_next; /** 
    

    因为在libvlc_audio_output_device_set这个接口中,参数device_id就是上面的设备标识符。

    LIBVLC_API void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
                                                    const char *module,
                                                    const char *device_id );

    如果需要切换音频输出模块,调用libvlc_audio_output_set。

    /**
     * Selects an audio output module.
     * \note Any change will take be effect only after playback is stopped and
     * restarted. Audio output cannot be changed while playing.
     *
     * \param p_mi media player
     * \param psz_name name of audio output,
     *               use psz_name of \see libvlc_audio_output_t
     * \return 0 if function succeeded, -1 on error
     */
    LIBVLC_API int libvlc_audio_output_set( libvlc_media_player_t *p_mi,
                                            const char *psz_name );

    官方的解释是,你需要先停止播放,设置新的音频输出设备,然后重新开始播放,以便新的设置生效。 

    示例代码:

    	libvlc_media_player_stop(vlc_mediaPlayer);
    	//设置输出waveout
    	int ret = libvlc_audio_output_set(vlc_mediaPlayer, "mmdevice");
    	//指定设备输出pDevList->psz_device
    	libvlc_audio_output_device_set(vlc_mediaPlayer, NULL, txt.toStdString().c_str());
    	libvlc_media_player_play(vlc_mediaPlayer);

    如果需要切换音频输出设备,设备在同一模块下,就不需要调用libvlc_audio_output_set,直接调用libvlc_audio_output_device_set,这个是不需要停止播放,再重新播放。

     * \param mp media player
     * \param module If NULL, current audio output module.
     *               if non-NULL, name of audio output module
                     (\see libvlc_audio_output_t)
     * \param device_id device identifier string
     * \return Nothing. Errors are ignored (this is a design bug).
     */
    LIBVLC_API void libvlc_audio_output_device_set( libvlc_media_player_t *mp,
     const char *module,
     const char *device_id );

    官方解释,参数module插入参数NULL,就使用当前的音频输出模块。 

    示例代码:

    void showWidget::slotActionTriggered(QAction *action)
    {
    	if (!vlc_mediaPlayer)
    		return;
    	
    	QString txt = action->data().toString();
    	//指定设备输出pDevList->psz_device
    	libvlc_audio_output_device_set(vlc_mediaPlayer, NULL, txt.toStdString().c_str());
    }
    

    完整源码:本示例演示同一模块下,输出设备的切换。

    #pragma once
    #include 
    #include "ui_showWidget.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    enum Rate
    {
    	Rate2X,
    	Rate1_5X,
    	Rate1_25X,
    	Rate1_0X,
    	Rate0_75X,
    	Rate0_5X
    };
    class showWidget : public QWidget
    {
        Q_OBJECT
    public:
        showWidget(QWidget *parent = nullptr);
        ~showWidget();
    private slots:
    	void slotOpenFile();
    	void slotPlay();
    	void slotPause();
    	void slotStop();
    	void slotValueChanged(int value);
    	void slotCurrentIndexChanged(int index);
    	void slotActionTriggered(QAction *action);
    protected:
    	virtual void mousePressEvent(QMouseEvent *event);
    private:
    	//事件处理回调
    	static void vlcEvents(const libvlc_event_t *ev, void *param);
    private:
        Ui::showWidgetClass ui;
    private:
    	libvlc_instance_t *vlc_base = nullptr;
    	libvlc_media_t *vlc_media = nullptr;
    	libvlc_media_player_t *vlc_mediaPlayer = nullptr;
    	QList m_lstRate;
        QList m_lstAudioDevice;
    	QMenu *m_menu = nullptr;
    	QMenu *m_deviceMenu = nullptr;
    	QAction *m_actionAudioDev = nullptr;	//音频设备
    	QActionGroup *m_group = nullptr;
    };
    

    cpp文件。 

    #include "showWidget.h"
    #include 
    #include 
    #pragma execution_character_set("utf-8")
    showWidget::showWidget(QWidget *parent)
        : QWidget(parent)
    {
        ui.setupUi(this);
    	this->setWindowTitle("视频播放器");
    	m_menu = new QMenu(this);
    	m_actionAudioDev = m_menu->addAction("音频设备");
    	m_deviceMenu = new QMenu(this);
    	m_actionAudioDev->setMenu(m_deviceMenu);
    	m_group = new QActionGroup(this);
    	connect(m_group, &QActionGroup::triggered, this, &showWidget::slotActionTriggered);
    	vlc_base = libvlc_new(0, NULL);
    	m_lstAudioDevice.clear();
    	libvlc_audio_output_device_t *pDevList = nullptr;
    	libvlc_audio_output_t *pOutputList = libvlc_audio_output_list_get(vlc_base);
    	while (pOutputList)
    	{
    		//获取设备
    		pDevList = libvlc_audio_output_device_list_get(vlc_base, pOutputList->psz_name);
    		while (pDevList)
    		{
    			// 找到我想要的那个设备,跳出循环,这里使用i控制,我知道我想要的设备位置
    			if (strcmp(pOutputList->psz_name, "mmdevice") == 0)
    			{
    				QString des = QString::fromStdString(std::string(pDevList->psz_description, strlen(pDevList->psz_description)));
    				m_lstAudioDevice.append(des);
    				QAction *action = m_deviceMenu->addAction(des);
    				action->setData(pDevList->psz_device);
    				m_group->addAction(action);
    			}
    			pDevList = pDevList->p_next;
    		}
    		pOutputList = pOutputList->p_next;
    	}
    	ui.cbxRate->setCurrentIndex(Rate1_0X);
    	m_lstRate setFocusPolicy(Qt::NoFocus);
    	connect(ui.btnOpen, &QPushButton::clicked, this, &showWidget::slotOpenFile);
    	connect(ui.btnPlay, &QPushButton::clicked, this, &showWidget::slotPlay);
    	connect(ui.btnPause, &QPushButton::clicked, this, &showWidget::slotPause);
    	connect(ui.btnStop, &QPushButton::clicked, this, &showWidget::slotStop);
    	connect(ui.hSliderVolumn, &QSlider::valueChanged, this, &showWidget::slotValueChanged);
    	connect(ui.cbxRate,SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
    }
    showWidget::~showWidget()
    {
    	libvlc_release(vlc_base); //减少libvlc实例的引用计数,并销毁
    }
    void showWidget::slotOpenFile()
    {
    	/*选择文件*/
    	QString filename = QFileDialog::getOpenFileName(this, "选择打开的文件", "D:/", tr("*.*"));
    	std::replace(filename.begin(), filename.end(), QChar('/'), QChar('\\'));
    	
    	vlc_media = libvlc_media_new_path(vlc_base, filename.toUtf8().data());
    	if (!vlc_media) {
    		return;
    	}
    	// 创建libvlc实例和媒体播放器
    	vlc_mediaPlayer = libvlc_media_player_new_from_media(vlc_media);
    	if (!vlc_mediaPlayer) {
    		return;
    	}
    	//libvlc_media_add_option(vlc_media, "--video-filter=transform");
    	//libvlc_media_add_option(vlc_media, "---transform-type=270");
    	
    	// 等待元数据加载完成
    	libvlc_media_parse(vlc_media);
    	libvlc_video_set_mouse_input(vlc_mediaPlayer, 0);
    	libvlc_video_set_key_input(vlc_mediaPlayer, 0);
    	// 获取各种元数据
    	const char *title = libvlc_media_get_meta(vlc_media, libvlc_meta_Title);
    	const char *artist = libvlc_media_get_meta(vlc_media, libvlc_meta_Artist);
    	const char *album = libvlc_media_get_meta(vlc_media, libvlc_meta_Album);
    	const char *url = libvlc_media_get_meta(vlc_media, libvlc_meta_URL);
    	const char *date = libvlc_media_get_meta(vlc_media, libvlc_meta_Date);
    	const char *lang = libvlc_media_get_meta(vlc_media, libvlc_meta_Language);
    	int duration = libvlc_media_get_duration(vlc_media);  // 获取时长(单位:毫秒)
    	qDebug("Title: %s", title ? title : "N/A");
    	qDebug("Artist: %s", artist ? artist : "N/A");
    	qDebug("Album: %s", album ? album : "N/A");
    	qDebug("Duration: %d ms", duration);
    	qDebug("url: %s", url ? url : "N/A");
    	qDebug("date: %s", date ? date : "N/A");
    	qDebug("lang: %s", lang ? lang : "N/A");
    	
    	libvlc_media_track_t **tracks;
    	int track_count = libvlc_media_tracks_get(vlc_media,&tracks);
    	for (unsigned i = 0; i psz_description);
    		// 这里可以获取到每一个轨道的信息,比如轨道类型 track->i_type
    		// 可能是 libvlc_track_video, libvlc_track_audio 或者 libvlc_track_text (字幕)
    		if (track->i_type == libvlc_track_video) {
    			// 处理视频轨道信息
    			qDebug("width = %d",track->video->i_width);
    			qDebug("height = %d", track->video->i_height);
    			qDebug("rate_num = %d", track->video->i_frame_rate_num);
    			qDebug("rate_den = %d", track->video->i_frame_rate_den);
    		}
    		else if (track->i_type == libvlc_track_audio) {
    			// 处理音频轨道信息
    			qDebug("channels = %d", track->audio->i_channels);
    			qDebug("rate = %d", track->audio->i_rate);
    		}
    		else if (track->i_type == libvlc_track_text) {
    			// 处理字幕轨道信息
    		}
    	}
    	//获取事件管理器
    	libvlc_event_manager_t *em = libvlc_media_player_event_manager(vlc_mediaPlayer);
    	// 注册事件监听器
    	libvlc_event_attach(em, libvlc_MediaPlayerTimeChanged, vlcEvents, this);
    	libvlc_event_attach(em, libvlc_MediaPlayerEndReached, vlcEvents, this);
    	libvlc_event_attach(em, libvlc_MediaPlayerStopped, vlcEvents, this);
    	libvlc_event_attach(em, libvlc_MediaPlayerPlaying, vlcEvents, this);
    	libvlc_event_attach(em, libvlc_MediaPlayerPaused, vlcEvents, this);
    	libvlc_media_player_set_hwnd(vlc_mediaPlayer, (void *)ui.widgetShow->winId());
    	libvlc_video_set_adjust_int(vlc_mediaPlayer, libvlc_adjust_Enable, 1);
    	QTimer::singleShot(1000, this, &showWidget::slotPlay);
    	libvlc_video_filter_list_get(vlc_base);
    	
    }
    void showWidget::slotPlay()
    {
    	if (vlc_mediaPlayer)
    	{
    		libvlc_media_player_play(vlc_mediaPlayer);
    	}
    	
    }
    void showWidget::slotPause()
    {
    	if (vlc_mediaPlayer)
    		libvlc_media_player_pause(vlc_mediaPlayer);
    }
    void showWidget::slotStop()
    {
    	if (vlc_mediaPlayer)
    		libvlc_media_player_stop(vlc_mediaPlayer);
    }
    void showWidget::slotValueChanged(int value)
    {
    	if (vlc_mediaPlayer)
    		libvlc_audio_set_volume(vlc_mediaPlayer, value);
    }
    void showWidget::slotCurrentIndexChanged(int index)
    {
    	if (vlc_mediaPlayer)
    		libvlc_media_player_set_rate(vlc_mediaPlayer, m_lstRate[index]);
    }
    void showWidget::slotActionTriggered(QAction *action)
    {
    	if (!vlc_mediaPlayer)
    		return;
    	
    	QString txt = action->data().toString();
    	//指定设备输出pDevList->psz_device
    	libvlc_audio_output_device_set(vlc_mediaPlayer, NULL, txt.toStdString().c_str());
    }
    void showWidget::mousePressEvent(QMouseEvent *event)
    {
    	switch (event->button())
    	{
    	case Qt::RightButton:
    		//this->setWindowState(Qt::WindowMinimized);
    		m_menu->exec(event->globalPos());
    		break;
    	default:
    		QWidget::mousePressEvent(event);
    	}
    }
    //事件回调
    void showWidget::vlcEvents(const libvlc_event_t *ev, void *param)
    {
    	showWidget *w = (showWidget*)param;
    	//处理不同的事件
    	switch (ev->type) {
    	case libvlc_MediaPlayerTimeChanged:
    	{
    		//qDebug() vlc_mediaPlayer);
    		libvlc_time_t lenSec = len / 1000;
    		libvlc_time_t totalLen = libvlc_media_player_get_length(w->vlc_mediaPlayer);
    		libvlc_time_t totalLenSec = totalLen / 1000;
    		int thh, tmm, tss;
    		thh = lenSec / 3600;
    		tmm = (lenSec % 3600) / 60;
    		tss = (lenSec % 60);
    		QTime time(thh, tmm, tss);
    		w->ui.lbCurTime->setText(time.toString("hh:mm:ss"));
    		thh = totalLenSec / 3600;
    		tmm = (totalLenSec % 3600) / 60;
    		tss = (totalLenSec % 60);
    		QTime TotalTime(thh, tmm, tss);
    		w->ui.lbTotalTime->setText(TotalTime.toString("hh:mm:ss"));
    		double pos = (double)lenSec / totalLenSec * 100;
    		w->ui.horizontalSlider->setValue(pos);
    	}
    		break;
    	case libvlc_MediaPlayerEndReached:
    		qDebug() 
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]