// Find the first video streamvideoStream=-1;audioStream=-1;for(i=0;i<pFormatCtx->nb_streams;i++){if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO&&videoStream<0){videoStream=i;}if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO&&audioStream<0){audioStream=i;}}if(videoStream==-1)return-1;//Didn't find a video streamif(audioStream==-1)return-1;
while(av_read_frame(pFormatCtx,&packet)>=0){if(packet.stream_index==videoStream){//Decode video frame}elseif(packet.stream_index==audioStream){packet_queue_put(&audioq,&packet);}else{av_free_packet(&packet);}}
注意,此处将数据包packet放到队列后,并没有立即释放。该packet会在稍后的解码时释放掉。
Fetching Packets
最后,让我们完成audio_callback函数来从队列中拉取数据包。回调函数必须是如下格式void callback(void *userdata, Uint8 *stream, int len),此处的userdata是我们给 SDL 的指针,stream是将音频数据写到的缓存,len是缓存的长度。代码如下:
voidaudio_callback(void*userdata,Uint8*stream,intlen){AVCodecContext*aCodecCtx=(AVCodecContext*)userdata;intlen1,audio_size;staticuint8_taudio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE*3)/2];staticunsignedintaudio_buf_size=0;staticunsignedintaudio_buf_index=0;while(len>0){if(audio_buf_index>=audio_buf_size){/*we have already sent all our data; get more*/audio_size=audio_decode_frame(aCodecCtx,audio_buf,sizeof(audio_buf));if(audio_size<0){/*If error, output silence*/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;}}
intaudio_decode_frame(AVCodecContext*aCodecCtx,uint8_t*audio_buf,intbuf_size){staticAVPacketpkt;staticuint8_t*audio_pkt_data=NULL;staticintaudio_pkt_size=0;staticAVFrameframe;intlen1,data_size=0;for(;;){while(audio_pkt_size>0){intgo_frame=0;len1=avcodec_decode_audio4(aCodecCtx,$frame,&got_frame,&pkt);if(len1<0){/*if error, skip frame*/audio_pkt_size=0;break;}audio_pkt_data+=len1;audio_pkt_size-=len1;data_size=0;if(got_frame){data_size=av_samples_get_buffer_size(NULL,aCodecCtx->channels,frame.nb_samples,aCodecCtx->sample_fmt,1);assert(data_size<=buf_size);memcpy(audio_buf,frame_data[0],data_size);}if(data_size<=0){/*No data yet, get more frames*/continue;}/*we have data, return it and come back for more later*/returndata_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;}}