百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

「技术分享」音乐-CD播放介绍(cd播放是什么意思)

zhezhongyun 2025-05-02 14:50 3 浏览

音乐(deepin-music)是deepin自研的一款音频播放软件,能广泛支持播放本地或外部媒介中的音频文件,其中就包括对CDDA(Compact Disc-Digital Audio)标准的支持。CDDA标准主要用于光盘存储数字高保真音乐,深受音乐发烧友的喜爱。

本文将站在技术实现的角度,介绍音乐(deepin-music)应用是如何播放CD光盘中的美妙音乐的。

1. 整体流程

简单的说,音乐(deepin-music)播放CD流程整体分为三个部分:

  • 检测CD光盘;
  • 解析CD数据;
  • 播放CD;

图一 deepin-music CD光盘处理流程

2. 检测CD光盘

2.1 识别光驱设备

对光驱设备的识别,主要源于对CD光盘状态的检测。依托于 `libudisks2-qt5-dev` 开源库的DDiskManager 类,即可实现对块设备状态监控,具体使用如下:

DDiskManager diskManager;
//获取块设备状态
diskManager.setWatchChanges(true);
//初始化获取当前所有设备localPath
QStringList allDevices = diskManager.blockDevices(QVariantMap());

//根据cdrom关键字,找出光驱设备
foreach (QString tmpstr, allDevices)
{
   if (tmpstr.compare("sr0") == 0) //sr0是cdrom关键字
       return tmpstr; //localPath
}

Linux系统中, "sr0" 主要指光驱设备(s= scsi;r= rom ;数字0代表光驱设备编号)。如需判断当前光驱是否被插拔,则可通过DDiskManager 类以下信号进行监听:

void blockDeviceAdded(const QString &path);
void blockDeviceRemoved(const QString &path);

3. 解析CD数据

3.1 解析CD节点

识别到光驱设备后,接下来就是获取CD光盘的节点数据,这里可引用依赖库`libvlc-dev`和`libvlccore-dev`,具体代码实现如下:

// 将tmpstr 转化为"cdda:///dev/sr0"这种形式
QString strcda = QString("cdda: ///dev/%1").arg(tmpstr.mid(tmpstr.lastIndexOf("/") + 1, tmpstr.size() - tmpstr.lastIndexOf("/"))) ;
// 获取sr0
input_item_t *p_input =
input_item_NewExt(strcda.toUtf8().data(), "access_demux", 0, ITEM_TYPE_DISC, ITEM_LOCAL);

//打开sr0,读取流
libvlc_instance_t *_vlcInstance = vlc_new(0, nullptr); //创建libvlc_instance_t对象
libvlc_media_player_t *_vlcMediaPlayer = vlc_media_player_new(_vlcInstance); // player_t
stream_t * pstream = vlc_stream_NewURL((vlc_object_t *)_vlcMediaPlayer, strcda.toUtf8().data()); //根据sr0,获取流
//创建cda节点
input_item_node_t * p_items = input_item_node_Create(p_input);
//将数据流读到节点中
vlc_stream_ReadDir(pstream, p_items);
//释放数据流、节点
vlc_stream_Delete(pstream); //释放数据流
input_item_Release(p_input); //释放输入设备

最终产生的p_items,就包含有CD节点数据。

3.2 检索CD歌曲信息

一般而言,获取了CD节点数据已经足以支持音乐的完整播放,但在某些场景下有的用户希望知悉CD歌曲的完整信息(比如:专辑、歌曲名称、歌手),而这部分信息并不在CD光盘里,那么怎么才能获取呢?

可以考虑查询远程CD数据库(CDDB),远程CD数据库有gundb、Gracenote和微软CDDB等。这里只介绍gundb使用方法,在连接数据库时需要依赖`libcddb2-dev`库,代码实现如下:

#include <cddb/cddb.h>
#include <linux/cdrom.h>
//打开/dev/sr0设备文件
int fd=open(“/dev/sr0”, O_RDONLY | O_NONBLOCK);
//获取CD数据
int status = ioctl(fd, CDROM_DISC_STATUS, CDSL_CURRENT);
if ((CDS_AUDIO==status || CDS_MIXED==status) && 0==ioctl(fd, CDROMREADTOCHDR, &th)){
m_disc = cddb_disc_new(); //生成disc
cddb_disc_calc_discid(m_disc); //创建discid,后面的查找就是根据它
}
//创建数据库连接
QString host("gnudb.gnudb.org"); //Location
int port = 80;//port
cddb_conn_t *connection = cddb_new(); //创建cddb_conn_t 对象
cddb_cache_disable(connection);
cddb_set_server_name(connection, host.toLatin1().constData()); //设置服务名
cddb_set_server_port(connection, port); //设置端口
//创建服务
cddb_cache_disable(connection);
cddb_set_server_name(connection, QString("gnudb.gnudb.org").constData());
cddb_set_server_port(connection, 80);
//设置http服务

cddb_set_http_proxy_server_name(connection, hostName().toLatin1().constData());


cddb_set_http_proxy_server_port(connection, port());

cddb_http_proxy_enable(connection);
cddb_query(connection, m_disc); //查询
cddb_read(connection, m_disc); //读取
cddb_disc_get_title(m_disc); //读取专辑标题
cddb_disc_get_artist(m_disc); //读取专辑作者
cddb_track_t *trk=cddb_disc_get_track(m_disc, t); //获取cd中的第t首歌
cddb_track_get_title(trk); //获取歌曲标题
cddb_track_get_artist(trk); //获取歌曲作者
cddb_query_next(connection, m_disc); //查询下一条数据

注:CDDB(光盘数据库)服务器,是可以被 CD翻录器和CD 播放器等应用程序查询,提供给定CD 的作者、专辑、曲目列表和其他信息。

4. 播放CD

音频播放会沿用3.1章节的相关依赖库,使用`libvlc_instance_t` 和 `libvlc_media_player_t `等接口播放CD音频文件。

//在3.1节中,已经初始化得到libvlc_instance_t *_vlcInstance、
//libvlc_media_player_t *_vlcMediaPlayer
//location路径“cdda:///dev/sr0”
libvlc_media_t* _vlcMedia = libvlc_media_new_location(_vlcInstance, path.toUtf8().data());
//设置与libvlc_media_player_t关联的媒体描述

libvlc_media_player_set_media(_vlcMediaPlayer, _vlcMedia);

//track为CD中歌曲的编号,可以自定义指定,cdda-track为CD标识
config_PutInt((vlc_object_t *)_vlcMediaPlayer, "cdda-track", track);
//播放
libvlc_media_player_play(_vlcMediaPlayer);

以上便是deepin-music播放CD光盘的完整处理流程,希望此篇文章能对感兴趣的朋友起到抛砖引玉的作用。

相关推荐

「魔兽世界怀旧服」精简界面,简化操作,简单实用的宏分享

前言大家好,我是涵叔,期待内涵。今天给大家带来一些比较实用的入门级宏分享及简单讲解。宏是什么呢,简单理解就是可以通过一些代码将多个技能通过某种逻辑或者附加按键的方式绑定到一个按键之上,以此来简化操作,...

微信小程序学习笔记:Page()(微信小程序page中的data)

Page()用来注册小程序中的一个页面,接受一个Object类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。Page方法的object参数主要构成如下:属性说明datadata是页面渲染...

iOS开发之--监听事件全攻略(一)协议代理

2016年才开始没几天,IT业界大事件快播庭审,最近两天看了快播庭审,真是精彩,王欣辩护人金嘴真是绝了,话说快播辩护人的金嘴,句句金腔,我很赞同辩护人道出当今互联网业界的一些不合规矩或者不合法律的...

软网推荐:数据安全清除 要快还要狠

数据安全不仅是要保护数据不被窃取或删除,另一方面还包括清理掉的数据不能被恢复。因此,简单地删除文件或格式化磁盘的做法是不安全的。借助于两款小软件,便可做到快速而安全地清除任意文件、文件夹或磁盘分区、整...

Axure高保真教程:通过文本框维护下拉列表选项

常见的用户界面元素之一是下拉列表(DropdownList),提供一组可选项供用户选择。该元素通常显示为展开的列表形式,用户可以通过单击或选择列表中的选项。对于下拉列表的选项,一般由系统代码组成,因...

IT技工专用装备:ORICO奥睿科SATA3.0高速双硬盘底座开箱

作为一句长期战斗在电脑维修第一线的艺术家,来几件很Bigger的装备是非常必要的!比如这一样,就非常上档次:我买的时候259,强哥为了双12,把价格调成358了?说说奥睿科的产品,个人用过一些,感觉...

用markdown语法制作一个好看的网址导航页面(markdown-web-nav)

之前为了让谷歌浏览器里的书签放到博客markdown文件下,写过一个书签和markdown互转的小工具parse-bookmark,当初也是为了能直接在博客中生成一个网址导航的页面,方便随时...

Apple Watch应用开发:从再造墨迹天气谈起

编者按:本文作者刘超在2012年加入墨迹天气,主要负责iOS平台软件开发工作。在今年年初,墨迹天气团队针对AppleWatch的硬件与交互特点,对应用做了重新设计与开发。作者从软件开发角度,分享了墨...

WXML开发指南及最佳实践(wxml技术)

以下是关于WXML(WeiXinMarkupLanguage)的开发指南,涵盖基础语法、核心功能及最佳实践,帮助开发者高效构建微信小程序界面。一、WXML基础什么是WXML?OWXML...

「杰控软件」A045. 倍福_TCADSDLL

A045.倍福_TCADSDLL□支持倍福CX1000通讯,可读写变量(%Var)、%I、%Q、%M;□计算机中需先安装TwinCAT软件;□确认或修改CX1000的IP地址:...

WPF使用基础教程(wpf教程入门系列)

一、WPF简介WPF:WPF即WindowsPresentationFoundation,翻译为中文“Windows呈现基础”,是微软推出的基于WindowsVista的用户界面框架,属于.NE...

源码推荐(01.05):自适应边界的散开按钮,Swift仿斗鱼TV

自适应边界的散开按钮(上传者:SnowCheng)无聊写的,接口已经留好,主要方法也注释了,大家有用就拿去。Swift仿斗鱼TV(上传者:静听雨落)感谢chenqi777提供的源码和接口在学习Swi...

HTML DOM Form 对象(html对象方法)

Form对象Form对象代表一个HTML表单。在HTML文档中<form>每出现一次,Form对象就会被创建。表单用户通常用于收集用户数据,包含了input元素如:...

金山文档全新升级-界面篇(金山文档更新后如何恢复)

产品背景ProductStory云服务时代的到来万物上云、智慧互联,百万级服务器组成的云端计算时代已经到来,过去困扰个人电脑的效率、安全及规模化问题已不复存在。链接各端数据的金山文档万物皆可上云,...

iOS开发中两个常见问题的处理(ios开发案例)

一、“UnknownclassXXViewControllerinInterfaceBuilderfile.”问题处理最近在静态库中写了一个XXViewController类,然后在主工程...