首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

基于ARM的嵌入式流媒体播放器的实现

基于ARM的嵌入式流媒体播放器的实现

硬件:博创的ARM9的实验平台,芯片为S3C2410
系统:PC上使用Redhat Enterprise Linux5ARM上使用的是Linux 2.6内核编译的镜像。
实现语言:CC++C是我自己亲自做出来的,C++其实就是Qt编程,我没去具体实现,但是觉得比C复杂一点,后面我会具体解释的)。

实现步骤:
1. 深入理解流媒体的概念。
2. 搭建实验平台,移植linux-2.6,配置Sambanfs系统。
3. 了解Linux下音频文件播放原理,编写简单播放程序。
4. 初步了解http协议和TCP/IP的知识,学会编写简单的网络通信程序。
5. 整合播放程序和网络通信程序,编译调试。

简单播放程序的开发
* /dev/dsp
  声卡驱动程序提供的/dev/dsp是用于数字采样(sampling)和数字录音(recording)的设备文件,它对于Linux下的音频编程来讲特别重要:向该设备写数据即意味着激活声卡上的D/A转换器实行放音,而向该设备读数据则意味着激活声卡上的A/D转换器实行录音。当前许多声卡都提供有多个数字采样装备。

DSP是数字信号处理器(Digital Signal Processor)的简称,它是用来实行数字信号处理的特殊芯片,声卡运用它来实现模拟信号和数字信号的转换。声卡中的DSP设备实际上包含两个组成部分:在以只读形式打开时,能够运用A/D转换器实行声音的输入;而在以只写形式打开时,则能够运用D/A转换器实行声音的输出。严格说来,Linux下的使用程序要么以只读形式打开/dev/dsp输入声音,要么以只写形式打开/dev/dsp输出声音,但事实上某些声卡驱动程序仍准许以读写的形式打开/dev/dsp,以便同时实行声音的输入和输出。
在从DSP设备读取数据时,从声卡输入的模拟信号经历A/D转换器变成数字采样后的样本(sample),保存在声卡驱动程序的内核缓冲区中,当使用程序从声卡读取数据时,保存在内核缓冲区中的数字采样结果将被复制到使用程序所指定的用户缓冲区中。须要指出的是,声卡采样频率是由内核中的驱动程序所决定的,而不取决于使用程序从声卡读取数据的速度。假如使用程序读取数据的速度过慢,以致低于声卡的采样频率,那么多余的数据将会被丢弃;假如读取数据的速度过快,以致高于声卡的采样频率,那么声卡驱动程序将会阻塞那些请求数据的使用程序,直到新的数据到来为止。
基于以上对DSP的理解以后,可以开始编写sound.c程序了,看看附录里面的一些有用的C函数,在编程中会用到。
        直接使用DSP编程播放器尽管很简单,但是还是必须有一个比较清晰的思路,首先应该是打开/dev/dsp设备,用如下代码实现:
dsp_fd=open(dsp,O_RDWR);
if(dsp_fd<0)
  {printf("open device error\n");
   return -1;
   goto  end;
}
然后应该是打开一个wav格式的音乐文件,实现代码如下:
file_fd=fopen(file_name,"r");
if(file_fd==NULL)
  {close(dsp_fd);
   printf("open file error\n");
   goto  end;
}
然后就是从文件中读取数据,写入到dsp设备中,代码如下:
while(feof(file_fd)==0)
{ getnum=fread(buf,1,num,file_fd);
    write(dsp_fd,buf,getnum);
    if(getnum!=num)
    { goto  end1;}
}
这里说一下feof这个函数是用来检测文件是否到末尾了,如果到了就返回-1,如果没有就返回0。这里用一个while循环来控制对文件的读和对设备的写。这里是对buf进行两步操作,这样返回内存是可靠的,高效的,如果对内存进行同步读写,这样是非法操作,后面我会具体介绍这种现象,给出解决方式。

网络通讯的实现首先应该学习一下HTTPTCP/IP方面的相关知识,点击进入HTTP协议详解点击进入TCP/IP详解。这里由于时间关系就不做详细讲解了,需要注意的几点,我顺便说一下,HTTP协议是一个网络通讯的通用的基本协议,所以了解它是很必要的,当然做不同的方向,了解的东西也就不一样。这里,流媒体主要关注的是文件请求,需要对request这一部分有点了解,比如请求头应该如何写才能下载文件?具体的通过代码来解释。
sprintf(request, "GET /%s HTTP/1.1\r\nAccept: *
上一段是一个基本的代码,包含了HTTP1.1协议的文件请求,有文件名,有主机地址,有端口号。
当然在发送请求前,必须得确认网络服务器端是否存在这个主机地址。这里就需要引入TCP/IP的概念了,TCP/IP封装了很多层,有传输层,有网络层,有应用层,但是我们必要深入了解那么多。这里我们只需要知道数据在网络间是如何传输的就行,实际上这里TCP/IP起到的主要作用就是创建一个管道,在clientserver间进行通信。
  
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
    fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));
    exit(1);
}

  
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(portnumber);
server_addr.sin_addr=*((struct in_addr*)host->h_addr);

  
if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(structsockaddr))==-1)
{
    fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));
    exit(1);
}
以上代码创建一个socketsocket是一个接口,一般只针对IP进行通讯,如果只有socket,没有HTTP协议的话,那也算不上流媒体。
然后就开始通过这个管道来发送HTTP请求了,代码如下:
  
   send= 0;totalsend = 0;
  nbytes=strlen(request);
  while(totalsend < nbytes) {
    send = write(sockfd, request + totalsend, nbytes -totalsend);
    if(send==-1)  {printf("send error!%s\n", strerror(errno));exit(0);}
    totalsend+=send;
    printf("%d bytes send OK!\n", totalsend);
  }
继承事业,薪火相传
返回列表