美文网首页
第十节 seek

第十节 seek

作者: 最美下雨天 | 来源:发表于2018-12-06 14:49 被阅读7次
image.png

这里定义了一个新锁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;
}

相关文章

网友评论

      本文标题:第十节 seek

      本文链接:https://www.haomeiwen.com/subject/amjttqtx.html