MediaVideoPlay *newPlayer = nullptr;
ImageInfo lastFrameImage = {{0}};
bool hasLastFrame = false;
-
- // 如果上一次切换时保留了最后一帧视图(因为新播放器未就绪),需要先隐藏它
- // 这样才能截取到真正的视频播放器的最后一帧,而不是静态图片
- // 但只有在有正在播放的视频时才需要隐藏,如果没有播放器,应该保留它作为备用显示
- bool wasLastFrameVisible = (lastFrameView_ != nullptr && lastFrameView_->IsVisible());
- if (wasLastFrameVisible && oldPlayer != nullptr && oldWasPlaying)
- {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hiding previous last frame view before capturing new frame");
- lastFrameView_->SetVisible(false);
- lastFrameView_->Invalidate();
- // 等待一小段时间确保视图已隐藏
- usleep(20000); // 20ms
- }
- else if (wasLastFrameVisible && (oldPlayer == nullptr || !oldWasPlaying))
- {
- // 如果没有正在播放的视频,保留最后一帧视图作为备用显示
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: No playing video, keeping last frame view as backup");
- }
// 步骤1:暂停旧播放器,保留最后一帧在屏幕上(如果正在播放)
if (oldPlayer != nullptr && oldWasPlaying)
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Captured last frame, size: %dx%d",
lastFrameImage.header.width, lastFrameImage.header.height);
- // 更新最后一帧视图的位置和内容(视图已在初始化时创建,只需刷新)
+ // 创建或更新临时视图显示最后一帧
+ if (lastFrameView_ == nullptr)
+ {
+ lastFrameView_ = new UIImageView();
+ if (lastFrameView_ != nullptr)
+ {
+ lastFrameView_->SetPosition(surfaceRect.GetX(), surfaceRect.GetY(),
+ surfaceRect.GetWidth(), surfaceRect.GetHeight());
+ lastFrameView_->SetAutoEnable(false);
+ lastFrameView_->SetResizeMode(UIImageView::COVER);
+ // 将临时视图添加到surfaceView_的父容器中,并放在surfaceView_上方
+ if (ScrollView_ != nullptr)
+ {
+ ScrollView_->Add(lastFrameView_);
+ }
+ }
+ }
+
if (lastFrameView_ != nullptr)
{
- // 更新位置和大小
- lastFrameView_->SetPosition(surfaceRect.GetX(), surfaceRect.GetY(),
- surfaceRect.GetWidth(), surfaceRect.GetHeight());
- // 更新图片内容
lastFrameView_->SetSrc(&lastFrameImage);
- // 显示视图
lastFrameView_->SetVisible(true);
lastFrameView_->Invalidate();
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Last frame view displayed");
}
- else
- {
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: lastFrameView_ is null, cannot display last frame");
- hasLastFrame = false;
- }
}
else
{
- // 截图失败,直接切换视频(不显示最后一帧)
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to capture last frame, switching video directly");
- hasLastFrame = false;
+ WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to capture last frame");
}
}
- // 步骤2:创建新播放器(不销毁旧播放器,保留作为备用)
+ // 步骤2:在创建新播放器前,停止并销毁旧播放器
+ // 静态图片会遮挡整个过程,所以可以安全地销毁旧播放器
+ if (oldPlayer != nullptr)
+ {
+ // 先停止播放
+ if (oldWasEntered || oldWasPlaying)
+ {
+ oldPlayer->StopVideoPlay();
+ }
+ // 等待旧播放器完全停止
+ usleep(50000); // 50ms,确保旧播放器完全停止
+ delete oldPlayer;
+ oldPlayer = nullptr;
+ videoPlay_ = nullptr; // 清除指针
+ g_videoPlay = nullptr;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Old player stopped and destroyed before creating new player");
+ }
+
+ // 步骤3:创建新播放器
newPlayer = new MediaVideoPlay(surface, nullptr, targetPath, true);
if (newPlayer == nullptr)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to create MediaVideoPlay");
- // 创建失败,恢复旧播放器,
- if (oldPlayer != nullptr && oldWasPlaying)
- {
- oldPlayer->ResumeVideoPlay();
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player creation failed, resumed old player");
- if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
- {
- lastFrameView_->SetVisible(false);
- lastFrameView_->Invalidate();
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, old player resumed");
- }
- }
g_isSwitchingVideo = false;
return false;
}
- // 步骤3:启动新播放器
+ // 步骤4:立即启动新播放器
int32_t ret = newPlayer->StartVideoPlay();
if (ret != 0)
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to start video play, ret=%d", ret);
delete newPlayer;
- newPlayer = nullptr;
-
- // 启动失败,恢复旧播放器
- if (oldPlayer != nullptr && oldWasPlaying)
- {
- oldPlayer->ResumeVideoPlay();
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player start failed, resumed old player");
- // 隐藏最后一帧视图,因为旧播放器会继续播放
- if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
- {
- lastFrameView_->SetVisible(false);
- lastFrameView_->Invalidate();
- }
- // 释放截图内存(视图已隐藏,不再需要)
- if (hasLastFrame && lastFrameImage.data != nullptr)
- {
- ImageCacheFree(lastFrameImage);
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (start failed)");
- }
- }
- else if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
- {
- // 如果没有旧播放器,保持lastFrameView可见,避免黑屏
- // 此时不释放内存,因为视图还在使用
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player failed to start, keeping last frame view visible to avoid black screen");
- }
- else
- {
- // 如果没有视图显示,释放内存
- if (hasLastFrame && lastFrameImage.data != nullptr)
- {
- ImageCacheFree(lastFrameImage);
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (no view visible)");
- }
- }
-
g_isSwitchingVideo = false;
return false;
}
- // 步骤4:等待并检查新播放器是否正常播放
- int checkCount = 0;
- const int maxCheckCount = 50; // 50 * 20ms = 1000ms
- bool newPlayerPlaying = false;
- bool newPlayerError = false;
+ // 步骤5:立即切换指针到新播放器
+ videoPlay_ = newPlayer;
+ g_videoPlay = videoPlay_;
- while (checkCount < maxCheckCount)
- {
- // 检查新播放器是否真正开始播放
- if (newPlayer != nullptr && newPlayer->isEntered_ && newPlayer->isPlayed_ && !newPlayer->isPause_)
- {
- newPlayerPlaying = true;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player confirmed playing after %d ms", checkCount * 20);
- break;
- }
- // 检查新播放器是否发生错误
- if (newPlayer != nullptr && newPlayer->playError_)
+ // 步骤5.5:同步等待新播放器渲染第一帧后再隐藏最后一帧视图
+ // 静态图片会一直遮挡,直到新播放器的第一帧真正渲染到屏幕
+ // 通过检查Surface的buffer状态来判断第一帧是否已渲染
+ if (lastFrameView_ != nullptr && lastFrameView_->IsVisible() && surface != nullptr)
+ {
+ // 等待新播放器开始播放
+ int checkCount = 0;
+ const int maxCheckCount = 50; // 50 * 20ms = 1000ms
+ bool playerConfirmed = false;
+
+ while (checkCount < maxCheckCount)
{
- newPlayerError = true;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player error detected after %d ms", checkCount * 20);
- break;
+ // 检查新播放器是否真正开始播放
+ if (newPlayer != nullptr && newPlayer->isEntered_ && newPlayer->isPlayed_ && !newPlayer->isPause_)
+ {
+ playerConfirmed = true;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player confirmed playing after %d ms", checkCount * 20);
+ break;
+ }
+ usleep(20000); // 等待20ms
+ checkCount++;
}
- usleep(20000); // 等待20ms
- checkCount++;
- }
-
- // 步骤5:根据新播放器状态决定后续操作
- if (newPlayerPlaying && !newPlayerError)
- {
- // 新播放器正常播放,检查第一帧是否已输出
- bool firstFrameReady = false;
- LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(surface);
- if (liteSurface != nullptr)
+
+ // 如果新播放器已开始播放,检查Surface是否有新的buffer(表示第一帧已输出)
+ if (playerConfirmed)
{
- int bufferCheckCount = 0;
- const int maxBufferCheckCount = 30; // 30 * 50ms = 1500ms
-
- while (bufferCheckCount < maxBufferCheckCount)
+ // 检查Surface是否有新的buffer被flush(表示第一帧已经输出到Surface)
+ // 通过检查GetBackBuf()来判断是否有新的buffer
+ LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(surface);
+ if (liteSurface != nullptr)
{
- SurfaceBuffer* backBuf = liteSurface->GetBackBuf();
- if (backBuf != nullptr)
+ int bufferCheckCount = 0;
+ const int maxBufferCheckCount = 30; // 30 * 50ms = 1500ms
+ bool firstFrameReady = false;
+
+ while (bufferCheckCount < maxBufferCheckCount)
+ {
+ // 检查Surface是否有新的buffer(GetBackBuf返回非null表示有新的buffer)
+ SurfaceBuffer* backBuf = liteSurface->GetBackBuf();
+ if (backBuf != nullptr)
+ {
+ // 有新的buffer,说明第一帧已经输出到Surface
+ firstFrameReady = true;
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer ready after %d ms", bufferCheckCount * 50);
+ // 再等待一小段时间确保第一帧已经渲染到屏幕
+ usleep(50000); // 50ms,确保第一帧已渲染到屏幕
+ break;
+ }
+ usleep(50000); // 等待50ms
+ bufferCheckCount++;
+ }
+
+ if (!firstFrameReady)
{
- firstFrameReady = true;
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer ready after %d ms", bufferCheckCount * 50);
- usleep(50000); // 50ms,确保第一帧已渲染到屏幕
- break;
+ WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: First frame buffer not ready after %d ms, proceeding anyway", maxBufferCheckCount * 50);
}
- usleep(50000); // 等待50ms
- bufferCheckCount++;
}
- }
- else
- {
- // 如果不是LiteSurface,使用固定等待时间
- usleep(300000); // 300ms
- firstFrameReady = true;
- }
-
- // 新播放器正常播放,停止并销毁旧播放器
- if (oldPlayer != nullptr)
- {
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player playing successfully, destroying old player");
- if (oldWasEntered || oldWasPlaying)
+ else
{
- oldPlayer->StopVideoPlay();
+ // 如果不是LiteSurface,使用固定等待时间
+ usleep(300000); // 300ms
}
- // 等待旧播放器完全停止
- usleep(50000); // 50ms,确保旧播放器完全停止
- delete oldPlayer;
- oldPlayer = nullptr;
}
- // 更新指针到新播放器
- videoPlay_ = newPlayer;
- g_videoPlay = videoPlay_;
-
- // 更新当前播放的视频路径
- currentVideoPath_ = targetPath;
- // 清除切换视频标志
- g_isSwitchingVideo = false;
-
- // 隐藏最后一帧视图(放到最后,确保新播放器已经完全接管显示)
- if (firstFrameReady && lastFrameView_ != nullptr && lastFrameView_->IsVisible())
+ // 隐藏最后一帧视图(此时新播放器的第一帧应该已经渲染到屏幕)
+ // 静态图片会一直遮挡,直到这里才隐藏
+ if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
{
-
- //异步隐藏最后一帧视图
GraphicService::GetInstance()->PostGraphicEvent([this]() {
- usleep(200000); // 100ms
lastFrameView_->SetVisible(false);
lastFrameView_->Invalidate();
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, new player first frame rendered");
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Hidden last frame view, new player first frame should be rendered");
});
}
- // 释放最后一帧截图的内存
+ // 释放最后一帧截图的内存(在隐藏静态图片后释放)
if (hasLastFrame && lastFrameImage.data != nullptr)
{
ImageCacheFree(lastFrameImage);
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory");
}
-
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Successfully switched to video: %s", uri);
- return true;
}
- else
+ else if (hasLastFrame && lastFrameImage.data != nullptr)
{
- // 新播放器未正常播放,销毁新播放器并恢复旧播放器
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: New player not playing correctly, destroying new player and resuming old player");
-
- // 停止并销毁新播放器
- if (newPlayer != nullptr)
- {
- if (newPlayer->isEntered_)
- {
- newPlayer->StopVideoPlay();
- }
- usleep(50000); // 50ms,确保新播放器完全停止
- delete newPlayer;
- newPlayer = nullptr;
- }
-
- // 恢复旧播放器
- if (oldPlayer != nullptr && oldWasPlaying)
- {
- oldPlayer->ResumeVideoPlay();
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Resumed old player");
- // 隐藏最后一帧视图,因为旧播放器会继续播放
- if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
- {
- lastFrameView_->SetVisible(false);
- lastFrameView_->Invalidate();
- }
- // 释放截图内存(视图已隐藏,不再需要)
- if (hasLastFrame && lastFrameImage.data != nullptr)
- {
- ImageCacheFree(lastFrameImage);
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (resumed old player)");
- }
- }
- else if (lastFrameView_ != nullptr && lastFrameView_->IsVisible())
- {
- // 如果没有旧播放器,保持lastFrameView可见,避免黑屏
- // 此时不释放内存,因为视图还在使用
- WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: No old player to resume, keeping last frame view visible");
- }
- else
- {
- // 如果没有视图显示,释放内存
- if (hasLastFrame && lastFrameImage.data != nullptr)
- {
- ImageCacheFree(lastFrameImage);
- WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Released last frame image memory (no view visible)");
- }
- }
-
- // 清除切换视频标志
- g_isSwitchingVideo = false;
-
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Failed to switch video, old player resumed: %s", uri);
- return false;
+ // 如果没有静态图片视图,直接释放截图内存
+ ImageCacheFree(lastFrameImage);
}
+
+ // 更新当前播放的视频路径
+ currentVideoPath_ = targetPath;
+
+ // 清除切换视频标志
+ g_isSwitchingVideo = false;
+
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "ThunderBirdMainView::SwitchVideo: Successfully switched to video: %s", uri);
+ return true;
}
void ThunderBirdMainView::CloseVideo() // 关闭表情接口