BPlay1.0系列(10:项目优化)

目前BPlay1.0的功能已经全部完成,但是在使用时还存在许多缺陷,后面会继续优化这些点,使体验更加舒适。

花屏

在播放视频时,如果不拖动滑块变更播放进度,视频基本可以流畅的放完,但是一旦使用进度条后,大概率会出现花屏的现象:
在这里插入图片描述
这个主要是因为我们在根据进度条位置跳转视频时,使用av_seek_frame(FormatContext, -1, (int64_t)Time * AV_TIME_BASE, AVSEEK_FLAG_ANY),它最后一个入参是 AVSEEK_FLAG_ANY,即跳转到指定帧,假如跳转处是视频I帧,则不会出现花屏现象,但是视频绝大部分帧都是B帧和P帧,跳转到这些位置时其预测关键帧就会出现问题,此处需要优化。
ffmpeg对av_seek_frame最后一个参数提供了下面这些选择:

#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward
#define AVSEEK_FLAG_BYTE     2 ///< seeking based on position in bytes
#define AVSEEK_FLAG_ANY      4 ///< seek to any frame, even non-keyframes
#define AVSEEK_FLAG_FRAME    8 ///< seeking based on frame number

其中 AVSEEK_FLAG_BACKWARDAVSEEK_FLAG_FRAME 都是用来找I帧的,前者是从往当前找,而后者是往后找,如果我们之间使用这两个参数来替代 AVSEEK_FLAG_ANY 的话,视频每次跳转的位置可能会和我们指定的实际位置有区别,这样显然是不可取的。但是我们却可以借助这两个参数来解决花屏问题,重新实现的 Bffmpeg::ResetTime(int Time) 如下:

/********************************
 * double Bffmpeg::GetTimeAll()
 * 功能:重设视频播放时间(进度)
 * *****************************/
void Bffmpeg::ResetTime(int Time)
{
    StopPlay();
    Bffmpeg::GetInstance()->GetAudioQue().que.clear();
    Bffmpeg::GetInstance()->GetVideoQue().que.clear();

    if (!FormatContext)
    {
        BLOG("FormatContext NULL");
        return;
    }

    /* 1、找到前面的关键帧 */
    av_seek_frame(FormatContext, -1, (int64_t)Time * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);

    /* 2、向后找播放点 */
    AVPacket pkt;
    while (1) {
        av_read_frame(FormatContext, &pkt);
        if (pkt.stream_index == Video_index) {
            if (Time < pkt.pts * av_q2d(FormatContext->streams[Video_index]->time_base)) {
                break;
            }

            /* 解码 */
            AVFrame* frame = Decode(&pkt);
            av_packet_unref(&pkt);
        }
    }

    StartPlay();
    return;
}

我们将 av_seek_frame 的最后一个参数改成了 AVSEEK_FLAG_BACKWARD,即每次先定位到预期位置前面的一个I帧,然后根据 pts 和定位处的差距,解码到定位处在继续播放。此时播放出来的视频不再有花屏现象,但是每次跳转后瞬间都会有一点卡顿的感觉,这个主要是I帧到目标帧解码的消耗造成的。
我后来尝试用 VLC 去验证视频跳转的效果,发现其不同的播放点跳转时会有不同程度的卡顿,卡顿程度和距离前一个I帧距离成正比(个人体验),但是整体丝滑程度比BPlay1.0好太多了,这么看 VLC 有可能也是利用了类似向前找关键帧的方法来解决花屏,但是在解码时应该做了优化,以后可以看看源码研究一下。

进度条跳转

当前视频进度改变只能通过拖动滑块来实现,点击进度条其他位置无法实现滑块的跳转,在使用时极其的不方便。
对于这个问题,我们只要为进度条注册事件过滤器(鼠标点击进度条任意处可准确修改滑块位置):

ui->BPlaySlider->installEventFilter(this);

BPlaySlider 鼠标事件重新处理:

/********************************
 * bool MainWindow::eventFilter(QObject *obj, QEvent *event)
 * 功能:事件过滤器
 * *****************************/
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == ui->BPlaySlider) {
        if (event->type() == QEvent::MouseButtonPress) {
            /* 滑动条事件过滤 */
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            int value = QStyle::sliderValueFromPosition(ui->BPlaySlider->minimum(), ui->BPlaySlider->maximum(), mouseEvent->pos().x(), ui->BPlaySlider->width());
            ui->BPlaySlider->setValue(value);
            Bffmpeg::GetInstance()->ResetTime(ui->BPlaySlider->value());
        }
    }
    
    return QObject::eventFilter(obj,event);
}

最后,BPlay1.0的功能已经全部开发,项目开源到了GitHub上: BPlay1.0
欢迎大家提出宝贵的优化意见,敬请期待BPlay2.0

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值