问题描述

最近在使用MediaCodec做视频播放,在小屏切换节目时,小屏就会出现闪一下的现象(黑屏->透明->视频画面。

看见这一现象后,想到了一个解决方案,就是参考tif框架中LiveTv中的遮黑处理,在停止播放时,再SurfaceView上覆盖一张黑色背景的View,再等视频画面出现时,把黑色背景的View隐藏,如此闪屏现象就消失了。

但是收到的出画消息好像不太精,准修改后出画速度好像没有以前快了,所以决定寻找一下根本原因。

原因分析:

在加了大量的debug log后,终于在SurfaceUtils.cpp找到了问题关键。
也就是在MediaCodec stop时,是调用到pushBlankBuffersToNativeWindow方法导致,SurfaceView的区域会显示黑色,又因为SurfaceView在绘画之前会是透明或者半透明,所以最终就会出现黑屏->透明->视频画面的闪一下的现象。

那怎样让MediaCodec stop不调用到pushBlankBuffersToNativeWindow呢?

在ACodec.cpp中,加log分析后,在不改动framework code 的前提下,好像并不能避免。
相关code路径:
android/frameworks/av/media/libstagefright/ACodec.cpp
android/frameworks/av/media/libstagefright/SurfaceUtils.cpp

原因如下:
MediaCodec 需要出画,MediaCodec的CodeName就需要是.secure结尾,所以mCodec->mFlags就会添加 kFlagPushBlankBuffersToNativeWindowOnShutdown flags。

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {ALOGV("onAllocateComponent");CHECK(mCodec->mOMXNode == NULL);mCodec->mFatalError = false;sp<AMessage> notify = new AMessage(kWhatOMXMessageList, mCodec);notify->setInt32("generation", mCodec->mNodeGeneration + 1);sp<RefBase> obj;CHECK(msg->findObject("codecInfo", &obj));sp<MediaCodecInfo> info = (MediaCodecInfo *)obj.get();if (info == nullptr) {ALOGE("Unexpected nullptr for codec information");mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);return false;}AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();AString componentName;CHECK(msg->findString("componentName", &componentName));sp<CodecObserver> observer = new CodecObserver(notify);sp<IOMX> omx;sp<IOMXNode> omxNode;status_t err = NAME_NOT_FOUND;OMXClient client;if (client.connect(owner.c_str()) != OK) {mCodec->signalError(OMX_ErrorUndefined, NO_INIT);return false;}omx = client.interface();pid_t tid = gettid();int prevPriority = androidGetThreadPriority(tid);androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);err = omx->allocateNode(componentName.c_str(), observer, &omxNode);androidSetThreadPriority(tid, prevPriority);if (err != OK) {ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));return false;}mDeathNotifier = new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));auto tOmxNode = omxNode->getHalInterface<IOmxNode>();if (tOmxNode && !tOmxNode->linkToDeath(mDeathNotifier, 0)) {mDeathNotifier.clear();}++mCodec->mNodeGeneration;mCodec->mComponentName = componentName;mCodec->mRenderTracker.setComponentName(componentName);mCodec->mFlags = 0;//kFlagPushBlankBuffersToNativeWindowOnShutdown  设置了遮黑的flags   if (componentName.endsWith(".secure")) {mCodec->mFlags |= kFlagIsSecure;mCodec->mFlags |= kFlagIsGrallocUsageProtected;mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;}mCodec->mOMX = omx;mCodec->mOMXNode = omxNode;mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());mCodec->changeState(mCodec->mLoadedState);return true;
}

在MediaCodec stop时,又会判断mCodec->mFlags,导致call到了pushBlankBuffersToNativeWindow。

void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() {if (mComponentNowIdle && mCodec->allYourBuffersAreBelongToUs()) {status_t err = mCodec->mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateLoaded);if (err == OK) {err = mCodec->freeBuffersOnPort(kPortIndexInput);status_t err2 = mCodec->freeBuffersOnPort(kPortIndexOutput);if (err == OK) {err = err2;}}//判断使用遮黑的flagsif ((mCodec->mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown)&& mCodec->mNativeWindow != NULL) {// We push enough 1x1 blank buffers to ensure that one of// them has made it to the display.  This allows the OMX// component teardown to zero out any protected buffers// without the risk of scanning out one of those buffers.pushBlankBuffersToNativeWindow(mCodec->mNativeWindow.get());}if (err != OK) {mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);return;}mCodec->changeState(mCodec->mIdleToLoadedState);}
}

总结

就MediaCodec会闪一下的问题,希望有大神路过时指点一二。也希望遇见同样问题的朋友,可以一起交流心得。谢谢!

视频切换SurfaceView 会闪一下相关推荐

  1. jquery点击缩略图切换视频播放的视频切换焦点图效果

    一款由jquery实现的视频切换特效,可以像图片切换那样切换所选择的视频来播放,图片切换相对来说较简单,但视频切换的话就需要播放插件的支持,选择视频缩略图后,上边原来显示大图片的地方是显示一个播放器, ...

  2. vue+videojs视频播放、视频切换、视频断点分段上传

    "本次需求是做一个视频列表,点击视频列表播放对应视频:同时要求实现断点分段上传大文件(视频)的功能 . videojs文档:Getting Started with Video.js - V ...

  3. 希沃白板如何解决手机端播放课件内视频出现黑屏闪退

    使用希沃白板的手机端或微信小程序端播放视频时,会受到手机和微信浏览器的限制,能播放的视频格式有限,请在制作课件时转换好视频格式才进行直播等 我最近在使用希沃白板的云直播功能,希沃白板的云直播功能十分好 ...

  4. 一个解决视频切换花屏的方案

    问题: 最近在开发一个项目,该项目需要在主被叫视频通话过程中对主叫播放视频彩铃,当视频彩铃播放完成后,再切回到主被叫视频通话. 开发完成后,进行测试中发现存在一个问题.视频彩铃切换到视频通话后,存在画 ...

  5. 关于Unity VideoPlayer组件 视频切换第一帧卡顿

    关于Unity VideoPlay组件 视频切换第一帧卡顿的问题 1.问题: 在做项目时,发现VideoPlayer组件在多个视频切换时,会在第一帧重复上个视频的结束时的画面. 2.原因: 因为Vid ...

  6. TypeC切换芯片ASW3410|HDMI视频切换芯片ASW3642|PCIE切换ASW3810

    目前切换开关方案芯片主要分三类: TYPEC接口切换开关芯片 HDMI视频输出切换开关芯片 PCIE串口切换开关芯片 下面主要讲解一下这三类的切换方案的参数特性与封装方式和应用途径: 1.ASW341 ...

  7. 实现app直播源代码开发,完成短视频切换功能

    讲下大概思路,app直播源代码使用recycleview配合自定义LinearLayoutManager来实现这个功能,这里着重说下自定义LinearLayoutManager的实现 可以看到每当下一 ...

  8. 仿抖音 APP 视频切换和点赞效果

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:Yun丶Lei 链接:https://www.jianshu.com/p/c43c75303174 声明:本文已 ...

  9. 微信小程序——仿抖音短视频切换效果

    一直以为抖音短视频切换假如用小程序做的话应该是比较简单的,直接用swiper实现就好,但在实际写的过程中才发现没那么简单,要控制的逻辑还是挺多的. 还是先看效果 体验路径 自定义组件系列>> ...

最新文章

  1. PHP文件操作常用函数总结
  2. 目标检测带标签样本增广工具
  3. React学习:ref调用、组件封装调用-学习笔记
  4. Java面试题整理,docker可视化监控工具
  5. 计算机网络(十二)-信道划分介质访问控制-信道复用
  6. 二叉树的公共祖先(递归)
  7. VMware vSphere Documentation(产品文档)
  8. Flutter基础—常用控件之容器
  9. 如何解决“指定的服务已被标记为删除”错误
  10. Linux 搭建 KMS 服务器
  11. 计算机软考中级合格标准,中级软考多少分及格
  12. html动态显示背景颜色,js动态修改背景颜色方法汇总
  13. 基于java嗖嗖移动业务大厅
  14. Android 给图片加边框
  15. java 封包_封包和解包简介
  16. 清理掉大流氓:2345
  17. signal信号值对应表
  18. php数据库内容在漂亮表格呈现
  19. 课程笔记-三维点云处理01 ——Introduction and Basic Algorithms
  20. 字符串format拼接格式化

热门文章

  1. 芝麻信用分SDK接入,显示芝麻信用授权界面(Android)
  2. RFC 请求评议 潇湘博客
  3. python调用crt自动登录_Python 脚本实现 SecureCRT 命令自动化
  4. StrictMode使用详解
  5. Python骚操作 自动抢火车票 逢年过节就不要去抢
  6. WordPress分类目录绑定二级域名插件WP Subdomains
  7. 数据库中如何制作表数据
  8. ServletFileUpload使用方法
  9. Olympiad (奥林匹克信息赛) Visual Judge (Set3)
  10. 3555: [Ctsc2014]企鹅QQ