image.png
我们添加一个变量做标记,记录当前AVPacket中是否还有AVFrame
bool readPacketFinished= true;
int HAudio::resampleAudio(void **pcmbuf) {
if(LOG_DEBUG)
{
LOGI("开始写入pcm数据");
}
while(hPlayStatus!=NULL&&!hPlayStatus->exit)
{
if(LOG_DEBUG)
{
LOGI("进入循环");
}
if(hPlayStatus->seek)
{
continue;
}
//return 0 on success
int ret=0;
if(readPacketFinished)
{
avPacket=av_packet_alloc();
if(hQueue->getAvPacket(avPacket)!=0)
{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
continue;
} else
{
}
if(LOG_DEBUG)
{
LOGI("发送一个packet");
}
ret=avcodec_send_packet(avCodecContext,avPacket);
if(ret!=0)
{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
continue;
}
}
avFrame=av_frame_alloc();
ret =avcodec_receive_frame(avCodecContext,avFrame);
if(ret==0)
{
LOGI("接收一个frame");
readPacketFinished = false;
if(avFrame->channels>0&&avFrame->channel_layout==0)
{
avFrame->channel_layout=av_get_default_channel_layout(avFrame->channels);
}
else if(avFrame->channels==0&&avFrame->channel_layout>0)
{
avFrame->channel_layout=av_get_channel_layout_nb_channels(avFrame->channel_layout);
}
SwrContext *swrContext;
swrContext=swr_alloc_set_opts(
NULL,
AV_CH_LAYOUT_STEREO,
AV_SAMPLE_FMT_S16,
avFrame->sample_rate,
avFrame->channel_layout,
(AVSampleFormat) avFrame->format,
avFrame->sample_rate,
NULL,NULL
);
if(!swrContext||swr_init(swrContext)<0)
{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket = NULL;
av_frame_free(&avFrame);
av_free(avFrame);
avFrame = NULL;
swr_free(&swrContext);
readPacketFinished = true;
continue;
}
//return number of samples output per channel
//返回每个通道输出的样本数,立体声就是2个通道
nb=swr_convert(
swrContext,
&buffer,
avFrame->nb_samples,
(const uint8_t **) avFrame->data,
avFrame->nb_samples
);
int out_channels=av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
//每个通道输出的样本数*通道数*每个样本占用的字节,感觉加上了SoundTouch后不好理解,换种写法,跟不加之前统一,主要是Enqueue这儿的代码统一
data_size=nb*out_channels*av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
// fwrite(buffer,1,data_size,outFile);
//当前AVFrame中存放的时间(比如说该Frame出现在2分钟的时候,那么它的值就是2分钟)
now_time=avFrame->pts*av_q2d(time_base);
//clock表示的是从开始播放到现在已经播放的时长
if(now_time<clock)
{
now_time=clock;
}
clock=now_time;
*pcmbuf=buffer;
if(LOG_DEBUG)
{
LOGI("总时长duration:%d 当前时长:%d ",duration,now_time);
}
//LOGI("data_size is %d", data_size);
av_packet_free(&avPacket);
av_free(avPacket);
avPacket = NULL;
av_frame_free(&avFrame);
av_free(avFrame);
avFrame = NULL;
swr_free(&swrContext);
break;
} else{
//读取玩了packet中的数据
readPacketFinished = true;
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
av_frame_free(&avFrame);
av_free(avFrame);
avFrame=NULL;
continue;
}
}
// fclose(outFile);
return data_size;
}
主要改动的地方是这块:
ret =avcodec_receive_frame(avCodecContext,avFrame);
返回0,说明已经从packet中读取完所有的AVFrame了,否则还没有读取完成
image.png
void HFFmpeg::seek(int64_t secds) {
if(duration <= 0)
{
return;
}
if(secds >= 0 && secds <= duration)
{
if(hAudio != NULL)
{
hPlayStatus->seek = true;
//记住清空队列,要不然还会播放队列中残留的数据
hAudio->hQueue->clearAvpacket();
hAudio->clock = 0;
hAudio->last_time = 0;
pthread_mutex_lock(&seek_mutex);
int64_t rel = secds * AV_TIME_BASE;
//播放ape文件时加的,清除缓存的,就是
avcodec_flush_buffers(hAudio->avCodecContext);
avformat_seek_file(avFormatContext, -1, INT64_MIN, rel, INT64_MAX, 0);
pthread_mutex_unlock(&seek_mutex);
hPlayStatus->seek = false;
}
}
}
添加代码:avcodec_flush_buffers(hAudio->avCodecContext);











网友评论