OpenHarmony开发者论坛

标题: Video组件播放损坏的音视频文件导致应用卡死问题分析报告 [打印本页]

作者: Laval社区小助手    时间: 2024-1-2 16:33
标题: Video组件播放损坏的音视频文件导致应用卡死问题分析报告
[md]# 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->repare() 方法执行,导致应用卡死。

```
void VideoElement::Start()
{
    ......
   if (isStop_) {
        // 方法执行,应用卡死
       if (mediaPlayer_->repare() != 0) {
           LOGE("layer 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:layerErrorType 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->repare()方法,导致应用卡死。

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

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

```
void OnError(Media:layerErrorType 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提供的视频路径。
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5