积分582 / 贡献0

提问0答案被采纳0文章52

[经验分享] Video组件播放损坏的音视频文件导致应用卡死问题分析报告 原创

Laval社区小助手 显示全部楼层 发表于 2024-1-2 16:33:36

1 关键字

Video;

2 问题描述

开发板型号:rk3568

内核版本:Release 3.1

问题现象:

  • 播放损坏的音频文件,点击了 start,然后点击 stop ,然后再点击start,应用卡死。

测试步骤:

  1. 使用Video组件,设置播放的流媒体文价为损坏的的文件;
  2. 调用controller.start方法;
  3. 调用controller.stop方法;
  4. 再调用controller.start方法,应用卡死。

3 问题原因

3.1 正常机制

播放损坏的音频文件,Video组件的OnError事件可以回调,在收到OnError回调后,切换媒体资源文件。

3.2 异常机制

播放损坏的音频文件,Video组件的OnError事件没有回调,没有切换媒体资源文件,调用stop方法后,video_element.cpp 中的 isStop 变量设置为true。

void VideoElement::Stop()
{
    OnCurrentTimeChange(0);
    OnPlayerStatus(PlaybackStatus::STOPPED);
    ......
    isStop_ = true;
}

再次调用start,由于isStop 为true,mediaPlayer->Prepare() 方法执行,导致应用卡死。

void VideoElement::Start()
{
    ......
    if (isStop_) {
        // 方法执行,应用卡死
        if (mediaPlayer_->Prepare() != 0) {
            LOGE("Player prepare failed");
            return;
        }
    }
    ......
}
  • video_element.cpp 文件路径:foundation\ace\ace_engine\frameworks\core\components\video\video_element.cpp

4 解决方案

将媒体底层上报的错误回调给Video组件。

修改 media_player_callback.h,将OnError事件反馈给video_element。

using ErrorEvent = std::function<void()>;

void OnError(Media::PlayerErrorType errorType, int32_t errorCode) override
{
     LOGE("OnError callback, errorType: %{public}d, errorCode: %{public}d", errorType, errorCode);
        ContainerScope scope(instanceId_);
     if (errorEvent_) {
        errorEvent_();
     }
}

void SetErrorEvent(ErrorEvent&& errorEvent)
{
    errorEvent_ = std::move(errorEvent);
}

private:
    ......
    StateChangedEvent stateChangedEvent_;
    ErrorEvent errorEvent_;
    ......

修改 video_element.cpp,添加OnError回调。

void VideoElement::RegistMediaPlayerEvent()
{
   ......
   auto&& errorEvent = [videoElement, uiTaskExecutor]() {
       uiTaskExecutor.PostTask([&videoElement] {
           auto video = videoElement.Upgrade();
           if (video) {
              LOGD("OnError");
              video->OnError("", "");
            }
        });
    };
    mediaPlayerCallback_ = std::make_shared<MediaPlayerCallback>(ContainerScope::CurrentId());
    mediaPlayerCallback_->SetPositionUpdatedEvent(positionUpdatedEvent);
    mediaPlayerCallback_->SetStateChangedEvent(stateChangedEvent);
    // 添加回调
    mediaPlayerCallback_->SetEndOfStreamEvent(endOfStreamEvent);
    mediaPlayer_->SetPlayerCallback(mediaPlayerCallback_);
}

在前端ETS中,为Video设置onError监听,onError回调,设置下一个资源文件。

5 定位过程

为video_element.cpp中的OnStart添加日志,在调用Stop后再次调用Start,代码执行了mediaPlayer->Prepare()方法,导致应用卡死。

void VideoElement::Start()
{
    ......
    if (isStop_) {
        // 方法执行,应用卡死
        if (mediaPlayer_->Prepare() != 0) {
            LOGE("Player prepare failed");
            return;
        }
    }
    ......
}

媒体文件缓冲失败,media_player_callback.h 中的OnError会打印error日志。

 void OnError(Media::PlayerErrorType errorType, int32_t errorCode) override
    {
        LOGE("OnError callback, errorType: %{public}d, errorCode: %{public}d", errorType, errorCode);
    }

这里只回调打印了日志,没有将错误回调给Video组件。

6 知识分享

视频播放源的路径,支持本地视频路径和网络路径,使用网络视频时,需要在config或者module.json对应的"abilities"中添加网络使用权限ohos.permission.INTERNET。

支持在resources下面的video或rawfile文件夹里放置媒体资源。

支持dataability://的路径前缀,用于访问通过 DataAbility提供的视频路径。

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部