
这里定义了一个新锁seek_mutex,在avformat_seek_file()和av_read_frame()的时候需要加锁
看下代码实现:
native-lib.cpp
extern "C"
JNIEXPORT void JNICALL
Java_com_example_voicelib_Player_seek(JNIEnv *env, jobject instance, jint progress) {
LOGI("当前进度值:%d",progress);
if(hfFmpeg!=NULL)
{
hfFmpeg->seek(progress);
}
}
HFFmpeg.cpp
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;
avformat_seek_file(avFormatContext, -1, INT64_MIN, rel, INT64_MAX, 0);
pthread_mutex_unlock(&seek_mutex);
hPlayStatus->seek = false;
}
}
}
还需要修改的地方:
void HFFmpeg::start() {
if(hAudio==NULL)
{
LOGI("audio is NULL");
return;
}
//这儿开启新线程开始写入文件
hAudio->play();
int count=0;
while (hPlayStatus!=NULL&&!hPlayStatus->exit)
{
//如果是在seek的话,就暂停解码操作,我们在seek的时候还需要清空队列,所以就不要再解码了
if(hPlayStatus->seek)
{
continue;
}
/**
* 这个代码很关键
*/
if(hAudio->hQueue->getQueueSize() > 40)
{
continue;
}
AVPacket *avPacket=av_packet_alloc();
pthread_mutex_lock(&seek_mutex);
int ret=av_read_frame(avFormatContext,avPacket);
pthread_mutex_unlock(&seek_mutex);
//0 if OK
if(ret==0)
{
if(avPacket->stream_index==hAudio->streamIndex)
{
if(LOG_DEBUG)
{
count++;
//LOGI("解码第%d帧",count);
}
hAudio->hQueue->putAvPacket(avPacket);
} else{
av_packet_free(&avPacket);
av_free(avPacket);
}
} else{
LOGI("解码完成");
if(LOG_DEBUG)
{
LOGI("解码出现错误");
}
av_packet_free(&avPacket);
av_free(avPacket);
//清除队列中的缓存
while (hPlayStatus!=NULL&&!hPlayStatus->exit)
{
if(hAudio->hQueue->getQueueSize()>0)
{
continue;
} else{
hPlayStatus->exit=true;
break;
}
}
}
}
if(LOG_DEBUG)
{
LOGI("解码完成");
}
}
注意这儿的代码:
/**
* 这个代码很关键
*/
if(hAudio->hQueue->getQueueSize() > 40)
{
continue;
}
测试发现解码过程还是比较快的,如果在seek的时候,解码已经完成,seek我们是做了清空队列的操作的,这样的话,seek之后调用av_read_frame的时候,由于已经到了文件末尾就会返回0,最终导致hPlayStatus->exit=true;所以我们加上这个队列大小限制,不要让一直解码
HQueue.cpp
/**
清空队列
*/
void HQueue::clearAvpacket() {
pthread_cond_signal(&pthread_cond);
pthread_mutex_unlock(&pthread_mutex);
while (!queue.empty())
{
AVPacket *packet = queue.front();
queue.pop();
av_packet_free(&packet);
av_free(packet);
packet = NULL;
}
pthread_mutex_unlock(&pthread_mutex);
}
HAudio.cpp
重采样的过程中,我们也加上seek判断
int HAudio::resampleAudio() {
if(LOG_DEBUG)
{
LOGI("开始写入pcm数据");
}
while(hPlayStatus!=NULL&&!hPlayStatus->exit)
{
if(LOG_DEBUG)
{
LOGI("进入循环");
}
if(hPlayStatus->seek)
{
continue;
}
AVPacket *avPacket=av_packet_alloc();
if(hQueue->getAvPacket(avPacket)!=0)
{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
continue;
} else
{
}
//return 0 on success
int ret=0;
ret=avcodec_send_packet(avCodecContext,avPacket);
if(ret!=0)
{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
continue;
}
AVFrame *avFrame=av_frame_alloc();
ret =avcodec_receive_frame(avCodecContext,avFrame);
if(ret==0)
{
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);
continue;
}
//return number of samples output per channel
int 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);
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;
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{
av_packet_free(&avPacket);
av_free(avPacket);
avPacket=NULL;
av_frame_free(&avFrame);
av_free(avFrame);
avFrame=NULL;
continue;
}
}
// fclose(outFile);
return data_size;
}
网友评论