gcc -o tutorial03 tutorial03.c -lavutil -lavformat -lavcodec -lz -lm \
`sdl-config --cflags --libs`
AUDIO名词解释:
samples:采样,通过PCM来采样,通常样本16bit,PCM的采样精度从14-bit发展到16-bit、18-bit、20-bit直到24-bit
Samples rate:采样率,22.05KHz and 44.1KHz,每秒从连续信号中提取并组成离散信号的采样个数
位速:采样率*样本bit*通道数,CD上未经压缩的音频位速是1411.2 kbit/s(16 位/采样点 × 44100 采样点/秒 × 2 通道)
pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO , 在for循环找找到audiostream的索引i
AVCodecContext *aCodecCtx=pFormatCtx->streams[audioStream]->codec; 得到音频编码的信息
SDL_AudioSpec wanted_spec,spec;
wanted_spec.freq = aCodecCtx->sample_rate; //采样率
wanted_spec.format = AUDIO_S16SYS;
//告诉SDL使用什么格式,S指代signed,16为样本16bit,SYS指代大小端由系统决定
wanted_spec.channels = aCodecCtx->channels; //有多少个通道
wanted_spec.silence = 0; //silence值,由于为signed,故为0
wanted_spec.samples =1024; //缓存大小
wanted_spec.callback = audio_callback; //音频的回调函数
wanted_spec.userdata = aCodecCtx; //给回调函数处理的数据
SDL_OpenAudio(&wanted_spec, &spec)
返回-1则打开失败,spec为NULL则以wanted_spec指定的方式播放,若spec不为NULL,则使用根据硬件改变的spec指定的方式播放,而wanted_spec可以删除
VCodec *aCodec = 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;
我们自己创建的用于构建Packet队列的数据结构
AVPacketList
A simple linked list for packets.
AVPacket pkt
AVPacketList * next
void packet_queue_init(PacketQueue *q)
{
memset(q,0,sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
q->cond=SDL_CreateCond();
}
对PacketQueue数据结构进行初始化
用于给PacketQueue数据结构中填入包的函数
int packet_queue_put(PacketQueue *q,AVPacket *pkt)
{
AVPacketList *pkt1;
if(av_dup_packet(pkt)<0)
{
return -1; //检查是否为NULL,为NULL则自己填充,否则返回-1
}
pkt1 = av_malloc(sizeof(AVPacketList));//给AVPacketList分配空间
if (!pkt1) return -1; pkt1->pkt = *pkt; pkt1->next = NULL; SDL_LockMutex(q->mutex); //对PacketQueue进行操作,先锁定互斥变量 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 0; } 接收数据
void SDL_PauseAudio(int pause_on) 播放的回调函数,格式必须为void callback(void *userdata, Uint8 *stream, int len),这里的userdata就是我们给到SDL的指针,stream是我们要把声音数据写入的缓冲区指针,len是缓冲区的大小。 struct mydata *data=(struct mydata*)userdata; while(len > 0) { 对音频数据进行解码,被解码的数据存在audio_buf中,buf_size告诉函数audio_buf缓冲区多大,返回值为解码的数据数量,结束时返回-1,否则返回被解码的bytes数。 static AVPacket pkt;
//对数据进行解码 int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, uint8_t *buf, int buf_size) |