我以前写过一篇修改ExoPlayer源码,获取帧时间,只是简单的获取帧时间,这次升个级,添加滤镜,获取帧时间功能保留,并且用来刷新画面,这样就可以实现某些基于帧时间来实现的滤镜功能了,比如动画效果,当然我这边还是简单的用黑白滤镜来演示

效果就不贴了,和我以前写的黑白滤镜播放器一样的。

还是基于修改ExoPlayer源码,获取帧时间来修改

在VideoTimeListener内添加onSurface和onRelease函数

public interface VideoTimeListener {void onVideoTimeChanged(long time);Surface onSurface(Surface surface, int width, int height);void onRelease();
}

在SimpleExoPlayer内的ComponentListener内也添加onSurface和onRelease函数

@Override
public void onVideoTimeChanged(long time) {for (VideoTimeListener videoTimeListener : videoTimeListeners) {videoTimeListener.onVideoTimeChanged(time);}
}
@Override
public Surface onSurface(Surface surface,int width,int height) {for (VideoTimeListener videoTimeListener : videoTimeListeners) {return videoTimeListener.onSurface(surface,width,height);}return surface;
}@Override
public void onRelease() {for (VideoTimeListener videoTimeListener : videoTimeListeners) {videoTimeListener.onRelease();}
}

在MediaCodecVideoRenderer内添加变量

private long timeUsIndex;
private long timeIndex;
private long timeUs;

在函数configureCodec内修改代码变为

@Override
protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,MediaCrypto crypto) throws DecoderQueryException {codecMaxValues = getCodecMaxValues(codecInfo, format, streamFormats);MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround,tunnelingAudioSessionId);if (surface == null) {Assertions.checkState(shouldUseDummySurface(codecInfo));if (dummySurface == null) {dummySurface = DummySurface.newInstanceV17(context, codecInfo.secure);}surface = dummySurface;}timeUsIndex = timeIndex = 0;Surface s = surface;if(timeListener != null){s = timeListener.onSurface(surface,mediaFormat.getInteger(MediaFormat.KEY_WIDTH),mediaFormat.getInteger(MediaFormat.KEY_HEIGHT));}codec.configure(mediaFormat, s, crypto, 0);if (Util.SDK_INT >= 23 && tunneling) {tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);}
}

在函数releaseCodec内添加代码变为

@CallSuper
@Override
protected void releaseCodec() {try {super.releaseCodec();} finally {buffersInCodecCount = 0;if (dummySurface != null) {if (surface == dummySurface) {surface = null;}dummySurface.release();dummySurface = null;}if(timeListener != null){timeListener.onRelease();}}
}

再添加函数,timeUs是微秒级的,可根据自己需求除以1000变毫秒级或者再除以1000变为秒

@Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {while (timeIndex < timeUsIndex){timeIndex++;if(timeListener != null && timeIndex == timeUsIndex){timeListener.onVideoTimeChanged(timeUs);}}super.render(positionUs, elapsedRealtimeUs);
}

最后修改renderOutputBufferV21和renderOutputBuffer

protected void renderOutputBuffer(MediaCodec codec, int index, long presentationTimeUs) {maybeNotifyVideoSizeChanged();TraceUtil.beginSection("releaseOutputBuffer");codec.releaseOutputBuffer(index, true);TraceUtil.endSection();lastRenderTimeUs = SystemClock.elapsedRealtime() * 1000;decoderCounters.renderedOutputBufferCount++;consecutiveDroppedFrameCount = 0;maybeNotifyRenderedFirstFrame();timeUsIndex++;timeUs = presentationTimeUs;
}

这样整个流程就走通了

接下来就贴Activity代码了

public class MainActivity extends AppCompatActivity {private View videoPlayerView;private TextureView textureView;private SimpleExoPlayer player;private Handler mainHandler;private EGLUtils mEglUtils;private GLFramebuffer mFramebuffer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);videoPlayerView = findViewById(R.id.video_player);mainHandler = new Handler();textureView = findViewById(R.id.texture_view);textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {init(new Surface(surface));}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}});}private void init(Surface surface){Uri url = Uri.parse(Environment.getExternalStorageDirectory().getAbsolutePath() +"/HMSDK/video/1531383835814.mp4");DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);player = ExoPlayerFactory.newSimpleInstance(this, trackSelector);DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this,Util.getUserAgent(this, "ExoPlayerTime"), bandwidthMeter);MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(url, mainHandler,null);player.addVideoTiemListener(new VideoTimeListener() {@Overridepublic Surface onSurface(Surface surface,int width,int height) {mEglUtils = new EGLUtils();mEglUtils.initEGL(surface);mFramebuffer = new GLFramebuffer();mFramebuffer.initFramebuffer(textureView.getWidth(),textureView.getHeight(),width,height);return new Surface(mFramebuffer.getSurfaceTexture());}@Overridepublic void onVideoTimeChanged(long time) {mFramebuffer.drawFrame();mEglUtils.swap();}@Overridepublic void onRelease() {if(mEglUtils != null){mEglUtils.release();}}});player.setVideoSurface(surface);player.prepare(videoSource);}public void playVideo(View view){if(player.getContentPosition() >= player.getDuration()){player.seekTo(0);}player.setPlayWhenReady(true);videoPlayerView.setVisibility(View.INVISIBLE);isPlayEnd();}private Handler seekBarHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);if(player.getPlayWhenReady() && player.getContentPosition() < player.getDuration()){isPlayEnd();}else{if(!isPlayer){player.setPlayWhenReady(false);videoPlayerView.setVisibility(View.VISIBLE);}}}};private void isPlayEnd(){seekBarHandler.removeMessages(100);Message message = seekBarHandler.obtainMessage();message.what = 100;seekBarHandler.sendMessageDelayed(message,100);}@Overrideprotected void onResume() {super.onResume();if(player != null){if(isPlayer){player.setPlayWhenReady(true);isPlayer = false;isPlayEnd();}}}private boolean isPlayer = false;@Overrideprotected void onPause() {super.onPause();if(player != null){if(player.getPlayWhenReady()){player.setPlayWhenReady(false);isPlayer = true;}}}@Overrideprotected void onDestroy() {super.onDestroy();if(player != null){player.stop();player.release();player = null;}}
}

贴demo

下载:百度云

密码:dbl0

为啥研究这个,因为公司想要做类似简影app的功能,所以研究视频编辑,音频编辑,还有研究播放器把每一帧都取出来进行处理,简影的原理很简单,主要是滤镜特效开发太麻烦,简影团队应该有专门搞滤镜特效的吧,我要自己搞,好惨

ExoPlayer添加滤镜功能相关推荐

  1. 安卓实现为图片添加滤镜功能

    相机中有一个功能:滤镜. 我们一点击某种样式(怀旧色.反色.暖色等等)那么这个功能是如何实现的呢? 想要实现这个功能我们首先要了解什么是滤镜?现实中如何实现滤镜? 带着这个问题,我们开始思考. 在实际 ...

  2. IOS美图秀秀(滤镜和涂鸦)和 添加阴影功能

    如今对个人图片的美化可所谓,天花乱醉.今天,就和大家一起进入一个美丽的世界. 第一步:首先,了解一个重要的知识,如下: UIImage和UIView使用的是左上原点坐标,Core Image和Core ...

  3. ExoPlayer添加Ffmpeg扩展实现软解功能

    一.准备环境 有时候Exoplayer自带的解码器不支持一些特殊的格式或者编码,此时我们可以通过给Exoplayer添加Ffmpeg扩展实现软解来支持这些编码. 工具版本 系统:Ubuntu 20.0 ...

  4. 阅读软件怎么添加书源_相册视频制作软件怎么用?怎么添加滤镜?

    最近,我和朋友因为工作出差,顺道在某个旅游城市逗留了几天,开开心心地放松了一回.旅行中,我们拍下了很多沿途的风景.美食.人文等有纪念意义的照片,结束旅行后,想用这些照片制作一个视频分享到朋友圈,该怎么 ...

  5. 从零开始开发Android相机app(三)简单介绍图像滤镜功能

    目前章节 1.从零开始安卓端相机功能开发(一)了解用什么去开发以及流程 2.从零开始安卓端相机功能开发(二)让我们来开发一个相机 3.从零开始开发Android相机app(三)简单介绍图像滤镜功能 文 ...

  6. 用Java实现相机滤镜功能(一)

    今天我们来用java实现相机滤镜功能.显然首先要有一个窗体,所以我们创建类来设置窗体,类名取为VideoCapture,这里我们简写一下,让VideoCapture类继承JFrame,作为它的子类,然 ...

  7. android mp4添加滤镜,Android 视频外部滤镜:挂件、贴纸,或美颜效果

    视频外部滤镜 1 使用场景 当 SDK 自带的美颜无法满足需求,例如需要做挂件.贴纸,或者美颜效果无法达到预期时,建议开发者使用外部滤镜功能. 对于比较复杂的场景,例如想要用摄像头画面做图层混合,建议 ...

  8. Android使用GpuImage给图片、视频、相机添加滤镜

    网上关于GpuImage使用的资料较少,我在使用的过程中整理出一个Demo,分享出来,希望帮助到有需要的人 Demo比较简单 首先是给图片加滤镜,这个比较简单,网上也有现成的例子 给视频添加滤镜,这里 ...

  9. php实现图片液化,ps液化滤镜怎么用 ps液化滤镜功能教程

    ps液化滤镜主要是用来实现图像的各种特殊效果.滤镜的操作是非常简单的,但是真正用起来却很难恰到好处它在Photoshop 具有神奇的作用.ps液化滤镜可用于推.拉.旋转.反射.折叠和膨胀图像的任意区域 ...

最新文章

  1. php删除数组中指定值的元素
  2. RxJava Timer:代替handler
  3. Disable auto select after clicking magnifier
  4. Collections.toMap 报错 空指针 key重复
  5. LeetCode刷题(5)
  6. sybase_isql命令
  7. 系统学习机器学习之神经网络(一)--MLP及局部模型,RBF综述
  8. 第九章 限制性图谱和正则表达式
  9. [转]软件开发的“三重门”
  10. python三位数数字求和_Python定义函数实现累计求和操作
  11. DeepFace人脸检测(python实现)
  12. 如何提高电路工作频率
  13. 如何用adb命令启动安装的APK
  14. vue实现上传图片识别文字
  15. 【期望】几何分布的期望
  16. Mobileye超详细研报:高逼格ADAS的内在修养
  17. autocad2014点击保存闪退_win10下autocad2014闪退怎么解决?-解决win10下autocad2014闪退的方法 - 河东软件园...
  18. SYN8086语音合成芯片(TTS语音芯片)各项指标测试已完成,正式批量化生产
  19. 华为USG6380与安达通包过滤防火墙建立ipsec隧道后丢包
  20. 隐藏在Windows XP中的28个秘密武器(黑客防线)

热门文章

  1. 第八章:ogg初始化datapump
  2. CSS怎么控制行高?
  3. html数字时钟免费代码,html5 canvas js(数字时钟)实例代码
  4. C语言API接口开发,腾讯云服务器 API C语言接口
  5. Virtualbox使用U盘
  6. ClickHouse 在有赞的实践
  7. php网页游戏学习之xnova(ogame)源码解读,PHP网页游戏学习之Xnova(ogame)源码解读(十六)...
  8. bandicom录屏音画不同步_bendicam新人求助!音画不同步!
  9. Slog78_本地Markdown编辑器--ArthurSLogMD!
  10. 签入职合同还是自由顾问工作协议