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; }
接收数据 static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block) { AVPacketList *pkt1; int ret; SDL_LockMutex(q->mutex);//锁定mutex for(;;) { if(quit) { ret =-1; 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 = 1; break; } else if (!block) { ret = 0; break; } else { SDL_CondWait(q->cond, q->mutex); } } SDL_UnlockMutex(q->mutex); return ret; } SDL_CondWait先检测是否满足条件,若不满足,解锁mutex,wait,直至被SDL_CondSignal()函数或者SDL_CondBroadcast()函数通知,则锁定mutex并返回
void SDL_PauseAudio(int pause_on) 控制播放与暂停,当pause_on为0时,播放数据,若数据未准备,则播放静音
播放的回调函数,格式必须为void callback(void *userdata, Uint8 *stream, int len),这里的userdata就是我们给到SDL的指针,stream是我们要把声音数据写入的缓冲区指针,len是缓冲区的大小。 void audio_callback(void *userdata, Uint8 *stream, int len) {
struct mydata *data=(struct mydata*)userdata; AVCodecContext *aCodecCtx = (AVCodecContext *)data->pFormatCtx; PacketQueue *audioq=data->audioq; int len1, audio_size; //静态的数据为了可以多次调用回调函数,而每次不一定处理完了数据 static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; //audio_buf的大小为1.5倍的声音帧的大小以便于有一个比较好的缓冲 static unsigned int audio_buf_size = 0; static unsigned int audio_buf_index = 0;
while(len > 0) { if(audio_buf_index >= audio_buf_size) { audio_size = audio_decode_frame(aCodecCtx, audio_buf, sizeof(audio_buf)); if(audio_size < 0) { audio_buf_size = 1024; memset(audio_buf, 0, audio_buf_size); } else { audio_buf_size = audio_size; } audio_buf_index = 0; } 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; } }
对音频数据进行解码,被解码的数据存在audio_buf中,buf_size告诉函数audio_buf缓冲区多大,返回值为解码的数据数量,结束时返回-1,否则返回被解码的bytes数。 int audio_decode_frame(AVCodecContext *aCodecCtx, uint8_t *audio_buf, int buf_size,PacketQueue *audioq) {
static AVPacket pkt; static uint8_t *audio_pkt_data = NULL; static int audio_pkt_size = 0; int len1, data_size; for(;;) { while(audio_pkt_size > 0) { //该循环从末尾开始 data_size = buf_size; //avcodec_decode_audio2必须先指定输出缓冲大小 len1 = avcodec_decode_audio2(aCodecCtx, (int16_t *)audio_buf, &data_size, audio_pkt_data, audio_pkt_size);
//对数据进行解码 if(len1 < 0) { audio_pkt_size = 0; break; } audio_pkt_data += len1; audio_pkt_size -= len1; //静态数据,可能包里面有多个帧,故下次调用继续 if(data_size <= 0) { continue; } return data_size; } if(pkt.data) av_free_packet(&pkt); if(quit) { return -1; } if(packet_queue_get(&audioq, &pkt, 1) < 0) { return -1; } audio_pkt_data = pkt.data; audio_pkt_size = pkt.size; } }
int avcodec_decode_audio2(AVCodecContext *avctx, int16_t *samples, int *frame_size_ptr, uint8_t *buf, int buf_size) 输出为samples,如果没有可以解码的frame_size_ptr返回0,否则其为被解码的大小。你必须分配frame_size_ptr为samples的缓存大小在你调用该函数时。 返回负数为错误,返回解码的字节数或0指示没有被解码的。 The input buffer must be FF_INPUT_BUFFER_PADDING_SIZE larger than the actual read bytes because some optimized bitstream readers read 32 or 64 bits at once and could read over the end. The end of the input buffer buf should be set to 0 to ensure that no overreading happens for damaged MPEG streams. Note:You might have to align the input buffer buf and output buffer samples. The alignment requirements depend on the CPU: on some CPUs it isn't necessary at all, on others it won't work at all if not aligned and on others it will work but it will have an impact on performance. In practice, the bitstream should have 4 byte alignment at minimum and all sample data should be 16 byte aligned unless the CPU doesn't need it (AltiVec and SSE do). If the linesize is not a multiple of 16 then there's no sense in aligning the start of the buffer to 16.
|