SDL_AudioSpec(转)
转贴地址:http://www.cnblogs.com/nanguabing/archive/2012/04/12/2444084.html
====================================================
这篇主要讲把视频的声音播放出来
audioStream = -;
for (i = ; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO
&& audioStream < ) {
audioStream = i;
}
}
if (audioStream == -)
return -;
上面这段代码主要是找到第一个音频流。
aCodecCtx=pFormatCtx->streams[audioStream]->codec;
记录一个音频解码器的上下文信息:
wanted_spec.freq = aCodecCtx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = aCodecCtx->channels;
wanted_spec.silence = ;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = aCodecCtx;
wanted_spec是一个SDL_AudioSpec结构体。
SDL_AudioSpec是包含音频输出格式的结构体,同时它也包含当音频设备需要更多数据时调用的回调函数。
int |
freq |
采样率 |
SDL_AudioFormat |
format |
音频数据格式;format 告诉SDL我们将要给的格式。在“S16SYS”中的S表示有符号的signed,16表示每个样本是16位长的,SYS表示大小头的顺序是与使用的系统相同的。这些格式是由avcodec_decode_audio2为我们给出来的输入音频的格式。 |
Uint8 |
channels |
声音的通道数 1 单声道, 2 立体声; |
Uint8 |
silence |
表示静音的值。因为声音采样是有符号的,所以0当然就是这个值。 |
Uint16 |
samples |
audio buffer size in samples (power of 2); 详情参考“讨论” |
Uint32 |
size |
音频缓存区大小(字节数),当我们想要更多声音的时候,我们想让SDL给出来的声音缓冲区的尺寸。一个比较合适的值在512到8192之间;ffplay使用1024。 |
SDL_AudioCallback |
callback |
当音频设备需要更多数据时调用的回调函数; |
void* |
userdata |
这个是SDL供给回调函数运行的参数。我们将让回调函数得到整个编解码的上下文信息; |
---------------
if (SDL_OpenAudio(&wanted_spec, &spec) < )
{
fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());
return -;
}
如果你的程序能够处理不同的音频格式,把一个SDL_AudioSpec的指针作为SDL_OpenAudio() 的第二个参数可以取得硬件真正的音频格式。如果第二个参数是NULL,音频数据将在运行时被转换成硬件格式。
aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
if (!aCodec) {
fprintf(stderr, "Unsupported codec!/n");
return -;
}
avcodec_find_decoder(aCodecCtx->codec_id);函数负责找到解码器。
avcodec_open(aCodecCtx, aCodec);
打开音频解码器。
下面要把音频从文件中循环的读出来:
typedef struct PacketQueue {
AVPacketList *first_pkt, *last_pkt;
int nb_packets;
int size;
SDL_mutex *mutex;
SDL_cond *cond;
} PacketQueue;
再wanted_spec.callback =audio_callback;我已经解释过了这是一个回调函数,
这个回调函数负责不断的播放声音,那么这个函数从那里取出声音呢?这时候我需要申请一块内存用来存放声音,
回调函数不断的读取数据从我申请的内存中,这块内存就是队列PacketQueue 。
PacketQueue通过小链表AVPacketList把音频帧AVPacket组成一个顺序队列。
nb_packets为AVPacket的数量
size为AVPacket.size的总大小
void packet_queue_init(PacketQueue *q) {
memset(q, , sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
q->cond = SDL_CreateCond();
}
初始化队列。
函数memset(q, 0, sizeof(PacketQueue));负责将q中前sizeof(PacketQueue)个字节替换为0并返回q;
SDL_CreateMutex函数用来创建一个互斥体的,返回类型是SDL_mutex。
SDL_CreateCond创建一个条件变量。
int packet_queue_put(PacketQueue *q, AVPacket *pkt) {
AVPacketList *pkt1;
if (av_dup_packet(pkt) < ) {
return -;
}
pkt1 = av_malloc(sizeof(AVPacketList));
if (!pkt1)
return -;
pkt1->pkt = *pkt;
pkt1->next = NULL;
SDL_LockMutex(q->mutex);
if (!q->last_pkt)
q->first_pkt = pkt1;
else
q->last_pkt->next = pkt1;
q->last_pkt = pkt1;
q->nb_packets++;
q->size += pkt1->pkt.size;
SDL_CondSignal(q->cond);
SDL_UnlockMutex(q->mutex);
return ;
}
函数SDL_LockMutex()锁定队列的互斥量以便于我们向队列中添加数据,然后函数SDL_CondSignal ()重新启动线程等待一个条件变量(如果它在等待)发出一个信号来告诉它现在已经有数据了,接着就会解锁互斥量并让队列可以自由访问。
int decode_interrupt_cb(void) { return quit; } ... main() { ... url_set_interrupt_cb(decode_interrupt_cb); ... SDL_PollEvent(&event); switch(event.type) { case SDL_QUIT: quit = ; ...
url_set_interrupt_cb函数是进行回调并检查我们是否需要退出一些被阻塞的函数。
在SDL中的,还必需要设置quit标志为1。
PacketQueue audioq; main() { ... avcodec_open(aCodecCtx, aCodec); packet_queue_init(&audioq); SDL_PauseAudio();
初始化PacketQueue队列。
函数SDL_PauseAudio()让音频设备最终开始工作。如果没有立即供给足够的数据,它会播放静音。
while(av_read_frame(pFormatCtx, &packet)>=) { // Is this a packet from the video stream? if(packet.stream_index==videoStream) { // Decode video frame .... } } else if(packet.stream_index==audioStream) { packet_queue_put(&audioq, &packet); } else { av_free_packet(&packet); }
循环读取音频流包的信息。
void audio_callback(void *userdata, Uint8 *stream, int len) {
//获得编解码器的上下文信息
AVCodecContext *aCodecCtx = (AVCodecContext *) userdata;
int len1, audio_size;
static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * ) / ];
static unsigned int audio_buf_size = ;
static unsigned int audio_buf_index = ;
while (len > ) {
if (audio_buf_index >= audio_buf_size) {
//自定义的音频解码器方法
audio_size = audio_decode_frame(aCodecCtx, audio_buf,
sizeof(audio_buf));
if (audio_size < ) {
audio_buf_size = ;
memset(audio_buf, , audio_buf_size);
} else {
audio_buf_size = audio_size;
}
audio_buf_index = ;
}
len1 = audio_buf_size - audio_buf_index;
if (len1 > len)
len1 = len;
memcpy(stream, (uint8_t *) audio_buf + audio_buf_index, len1);
len -= len1;
stream += len1;
audio_buf_index += len1;
}
}
int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf,int buf_size) {
static AVPacket pkt;
static uint8_t *audio_pkt_data = NULL;
static int audio_pkt_size = ;
int len1, data_size;
for (;;) {
while (audio_pkt_size > ) {
data_size = buf_size;
len1 = avcodec_decode_audio2(aCodecCtx, (int16_t *) audio_buf,
&data_size,
audio_pkt_data, audio_pkt_size);
if (len1 < ) {
audio_pkt_size = ;
break;
}
audio_pkt_data += len1;
audio_pkt_size -= len1;
if (data_size <= ) {
continue;
}
return data_size;
}
if (pkt.data)
av_free_packet(&pkt);
if (quit) {
return -;
}
if (packet_queue_get(&audioq, &pkt, ) < ) {
return -;
}
audio_pkt_data = pkt.data;
audio_pkt_size = pkt.size;
}
}
int quit = ;
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) {
AVPacketList *pkt1;
int ret;
SDL_LockMutex(q->mutex);
for(;;) {
if(quit) {
ret = -;
break;
}
pkt1 = q->first_pkt;
if (pkt1) {
q->first_pkt = pkt1->next;
if (!q->first_pkt)
q->last_pkt = NULL;
q->nb_packets--;
q->size -= pkt1->pkt.size;
*pkt = pkt1->pkt;
av_free(pkt1);
ret = ;
break;
} else if (!block) {
ret = ;
break;
} else {
SDL_CondWait(q->cond, q->mutex);
}
}
SDL_UnlockMutex(q->mutex);
return ret;
}
这段代码大概就是 先执行main函数,开启分线程audio_callback()不断读取音频流,然后用audio_decode_frame()解码,解码的数据从packet_queue_get()中取出来,
继续回到main函数packet_queue_put()负责把音频帧放到队列中去,以便于packet_queue_get()从队列中获取。
c文件下载
http://download.csdn.net/detail/wenwei19861106/4221053
SDL_AudioSpec(转)的更多相关文章
- FFmpeg学习5:多线程播放视音频
在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...
- FFmpeg学习3:播放音频
参考dranger tutorial,本文将介绍如何使用FFmpeg解码音频数据,并使用SDL将解码后的数据输出. 本文主要包含以下几方面的内容: 关于播放音频的需要的一些基础知识介绍 使用SDL2播 ...
- ffplay代码播放pcm数据
摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...
- ffmpeg 和 SDL 的结合使用
FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录制.转换以及流化音视 频的完整解决方案.它包含了非常先进的音频/视频编解码库 ...
- SDL播放视频
// PlayVideo.cpp : Defines the entry point for the console application. // extern "C" { #i ...
- SDL播放声音
extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> ...
- SDL2.0学习
http://www.ffmpeg.org/download.html http://doc.okbase.net/leixiaohua1020/archive/110977.html //视频 h ...
- [原]如何在Android用FFmpeg+SDL2.0解码图像线程
关于如何在Android上用FFmpeg+SDL2.0解码显示图像参考[原]如何在Android用FFmpeg+SDL2.0解码显示图像 ,关于如何在Android使用FFmpeg+SDL2.0解码声 ...
- [原]如何在Android用FFmpeg+SDL2.0解码声音
关于如何在Android上用FFmpeg+SDL2.0解码显示图像参考[原]如何在Android用FFmpeg+SDL2.0解码显示图像 ,本文是基于上述文章和[原]零基础学习视频解码之解码声音 来移 ...
随机推荐
- 用工具快速建立hibernate框架
,一.建好项目后先导入两类jar包,一类是hibernate的jar包,一类是jdbc的jar包 二.点击“窗口”--“显示视图”--“其它”-“Hibernate configurations” 三 ...
- mysql注入介绍
0. SQL注入常用的尝试语句: or 1=1--+ 'or 1=1--+ "or 1=1--+ )or 1=1--+ ')or 1=1--+ ") or 1=1--+ " ...
- 为什么这个地方用重定向会报错.只能用 服务器跳转?? 为什么我加了过滤器,还是能直接登陆 servlet
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, ...
- 【dlbook】数学基础
[代数] Moore-Penrose 伪逆 [概率信息论] 自信息,香农熵,衡量两个分布的差异:kl散度 \ 交叉熵 [数值] 溢出: softmax计算的时候要关注上溢和下溢,如果所有X都相等且为很 ...
- WebSocket 在烧瓶和龙卷风中的应用
a. 安装 pip3 install gevent-websocket 作用: - 处理Http.Websocket协议的请求 -> socket - 封装Http.Websocket相关数据 ...
- ArcGIS图例标注上标和下标
1. 插入图例 在布局视图下,从插入中选择"图例",我们获得以下的样式: 2. 转为单个图形 选择图例,点击右键,选择"转化为图形",再次点击右键,点击&quo ...
- Ubuntu中修改Terminal背景
哈哈哈哈,没什么卵用,只能是看起来舒服,有逼格! 详解参考
- (转)Android中的页面切换动画
这段时间一直在忙Android的项目,总算抽出点时间休息一下,准备把一些项目用到的Android经验分享一下. 在Android开发过程中,经常会碰到Activity之间的切换效果的问题,下面介绍一下 ...
- android中状态栏透明
设置 Acitivity 所在 window 的属性 @Override protected void onCreate(Bundle savedInstanceState) { super.onCr ...
- Unidac手工安装
Universal Data Access Components Source Code Copyright 1997-2010, Devart. All Rights ReservedThere ...