美文网首页
第十五节 播放ape音乐的bug

第十五节 播放ape音乐的bug

作者: 最美下雨天 | 来源:发表于2018-12-06 14:51 被阅读8次
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);

相关文章

网友评论

      本文标题:第十五节 播放ape音乐的bug

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