当前位置: 首页 > wzjs >正文

php网站开发意思网站页面的优化

php网站开发意思,网站页面的优化,山东钢结构建设局网站,网站不公开简历做家教目录 一,目标 二,核心流程 三,设计到的技术点 4,MediaCodec编码原理 5,核心代码实现 5.1 自定义GLSurfaceView 5.2 设置录制特效模式 5.3 自定义渲染模式GLSurfaceView.Renderer 5.4 自定义视频编码器MediaRecorder 一,目标 使用Android的相机拍摄视频,在…

目录

一,目标

二,核心流程

三,设计到的技术点

4,MediaCodec编码原理

5,核心代码实现

5.1 自定义GLSurfaceView

5.2 设置录制特效模式

5.3 自定义渲染模式GLSurfaceView.Renderer

5.4 自定义视频编码器MediaRecorder


一,目标

使用Android的相机拍摄视频,在相机预览的同时,可以做一些极快,极慢,大眼,瘦脸的效果,需要在录制过程中高性能,如果直接使用 SufaceView 并不方便美颜滤镜和加水印贴图,以及对录制过程中视频操作

二,核心流程

三,设计到的技术点

3.1 OpenGL ES 预览相机(Fbo)

Frame Buffer Object

​    帧缓冲对象:FBO。默认情况下,我们在`GLSurfaceView`中绘制的结果是显示到屏幕上,然而实际中有很多情况并不需要渲染到屏幕上,这个时候使用FBO就可以很方便的实现这类需求。FBO可以让我们的渲染不渲染到屏幕上,而是渲染到离屏Buffer中。

3.2 MediaCodec 编码相机数据

MediaCodec是Android 4.1.2(API 16)提供的一套编解码API。它的使用非常简单,它存在一个输入缓冲区与一个输出缓冲区,在编码时我们将数据塞入输入缓冲区,然后从输出缓冲区取出编码完成后的数据就可以了
3.3 MediaMuxer 合成输出视频文件

4,MediaCodec编码原理

4.1

除了直接操作输入缓冲区之外,还有另一种方式来告知MediaCodec需要编码的数据,那就是:

public native final Surface createInputSurface();

使用此接口创建一个`Surface`,然后我们在这个`Surface`中"作画",`MediaCodec`就能够自动的编码`Surface`中的“画作”,我们只需要从输出缓冲区取出编码完成之后的数据即可。

​  此外,我们使用OpenGL进行绘画显示在屏幕上,然而想要复制屏幕图像到内存中却不是一件非常轻松的事情。但是现在我们可以直接将OpenGL显示到屏幕中的图像,同时绘制到`MediaCodec#createInputSurface`当中去,这样子操作就会更加简单高效

4.2
 录制我们在另外一个线程中进行(**录制现场**),所以录制的EGL环境和显示的EGL环境(`GLSurfaceView`,**显示线程**)是两个独立的工作环境,他们又能够共享上下文资源:显示线程中使用的texture等,需要能够在录制线程中操作(通过录制线程中使用OpenGL绘制到MediaCodec的Surface)。


4.3
 在这个线程中我们需要自己来:
1)、配置录制使用的EGL环境(参照GLSurfaceView是怎么配置的)

 2)、完成将显示的图像绘制到MediaCodec的Surface中

 3)、编码(H.264)与复用(封装mp4)的工作

5,核心代码实现

5.1 自定义GLSurfaceView

配置egl版本和设置自定义渲染器,以及渲染模式

public TigerView(Context context, AttributeSet attrs) {super(context, attrs);/*** 设置egl版本*/setEGLContextClientVersion(2);/*** 设置渲染器*/mTigerRender = new TigerRender(this);setRenderer(mTigerRender);/*** 设置按需渲染,当我们调用requestRender()的时候就会调用GlThread回调一次onDrawFrame()*/setRenderMode(RENDERMODE_WHEN_DIRTY);}

5.2 设置录制特效模式

public void startRecord() {float speed = 1.f;switch (mSpeed) {case MODE_EXTRA_SLOW:speed = 0.3f;break;case MODE_SLOW:speed = 0.5f;break;case MODE_NORMAL:speed = 1.f;break;case MODE_FAST:speed = 1.5f;break;case MODE_EXTRA_FAST:speed = 3.f;break;}mTigerRender.startRecord(speed);}

5.3 自定义渲染模式GLSurfaceView.Renderer

public void onSurfaceCreated(GL10 gl, EGLConfig config) {mCameraHelper = new CameraHelper(Camera.CameraInfo.CAMERA_FACING_BACK);//准备好摄像头绘制的画布//通过open gl创建一个纹理idmTextures = new int[1];GLES20.glGenTextures(mTextures.length, mTextures, 0);mSurfaceTexture = new SurfaceTexture(mTextures[0]);//设置有一帧新的数据到来的时候,回调监听mSurfaceTexture.setOnFrameAvailableListener(this);//必须要在GlThread里面创建着色器程序mCameraFilter = new CameraFilter(mView.getContext());mScreeFilter = new ScreeFilter(mView.getContext());EGLContext eglContext = EGL14.eglGetCurrentContext();mMediaRecorder = new MediaRecorder(mView.getContext(), "/mnt/sdcard/test.mp4", CameraHelper.HEIGHT, CameraHelper.WIDTH, eglContext);}/*** 画布发生改变** @param gl     the GL interface. Use <code>instanceof</code> to*               test if the interface supports GL11 or higher interfaces.* @param width* @param height*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {mCameraHelper.startPreview(mSurfaceTexture);mCameraFilter.onReady(width, height);mScreeFilter.onReady(width, height);}/*** 画画** @param gl the GL interface. Use <code>instanceof</code> to*           test if the interface supports GL11 or higher interfaces.*/@Overridepublic void onDrawFrame(GL10 gl) {//告诉open gl需要把屏幕清理成 什么样子的颜色GLES20.glClearColor(0, 0, 0, 0);//开始真正的屏幕颜色清理,也就是上一次设置的屏幕颜色GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//把摄像头采集的数据输出出来//更新纹理,然后我们才可以使用opengl从SurfaceTexure当中获取数据,进行渲染mSurfaceTexture.updateTexImage();//mSurfaceTexture比较特殊,在设置坐标的时候,需要一个变换矩阵,使用的是特殊的采样器samplerExternalOES//这种采样器,正常的是sample2DmSurfaceTexture.getTransformMatrix(mtx);mCameraFilter.setMatrix(mtx);int id = mCameraFilter.onDrawFrame(mTextures[0]);//在这里添加各种效果,相当于责任链//开始画画mScreeFilter.onDrawFrame(id);mMediaRecorder.encodeFrame(id, mSurfaceTexture.getTimestamp());}

1)通过在onSurfaceCreated设置相机录制功能,同时准备好相机预览的画布,通过open gl创建一个纹理id,给后续预览各种特效使用

2)给SurfaceTexture设置设置有一帧新的数据到来的时候,回调监听,mSurfaceTexture.setOnFrameAvailableListener(this)

3)onSurfaceChanged里面进行画布大小的设定和纹理绑定

4)onDrawFrame里面进行绘画,同时使用MediaCodc在单独的进程里面进行视频编码encodeFrame

5)在onFrameAvailable中

有新的一帧数据过来以后,有一帧新的图像,就开始调用GLSurfaceView的onDrawFrame进行绘制

5.4 自定义视频编码器MediaRecorder

public MediaRecorder(Context context, String path, int width, int height, EGLContext eglContext) {mContext = context.getApplicationContext();mPath = path;mWidth = width;mHeight = height;mEglContext = eglContext;}/*** 开始录制视频*/public void start(float speed) throws IOException {/*** 配置MediaCodec编码器,视频编码的宽,高,帧率,码率* 录制成mp4格式,视频编码格式是h264 MIMETYPE_VIDEO_AVC 高级编码*/mSpeed = speed;MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, mWidth, mHeight);//配置码率 1500kbsvideoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1500_000);//帧率videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20);//关键字间隔videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 20);//创建视频高级编码器mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);//因为是从Surface中读取的,所以不需要设置这个颜色格式videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);//配置编码器,CONFIGURE_FLAG_ENCODE,mMediaCodec.configure(videoFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);//交给虚拟屏幕,通过opengl 将预览的纹理绘制到这一个虚拟屏幕中,这样子Mediacodc 就会自动编码这一帧图像mInputSurface = mMediaCodec.createInputSurface();//mp4 播放流程  解复用--》解码 》绘制//mp4 编码流程  封装器--》编码//MUXER_OUTPUT_MPEG_4 MP4格式封装器,将h.264通过他写出到文件就可以了mMediaMuxer = new MediaMuxer(mPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);/*** 配置EGL环境,也就是配置我们的虚拟屏幕环境*/HandlerThread handlerThread = new HandlerThread("ViewoCodec");handlerThread.start();Looper looper = handlerThread.getLooper();//子线程和子线程之间的通信mHandler = new Handler(looper);//EGl的绑定线程,对我们自己创建的EGl环境,都是在这个线程里面进行mHandler.post(() -> {//创建我们的EGL环境(虚拟设备,EGL上下文 )mEglBase = new EGLBase(mContext, mWidth, mHeight, mInputSurface, mEglContext);//启动编码器mMediaCodec.start();isStart = true;});}/*** textureId 纹理id* 调用一次,就有一个新的图片需要编码*/public void encodeFrame(int textureId, long timesnap) {if (!isStart) {return;}//切换到子线程中编码mHandler.post(() -> {//把图像纹理画到虚拟屏幕里面mEglBase.draw(textureId, timesnap);//此时我们需要从编码器里面的输出缓冲区获取编码以后的数据就可以了,getCodec(false);});}private void getCodec(boolean endOfStream) {if (endOfStream) {//表示停止录制,此时我们不录制了,需要给mediacoic 通知mMediaCodec.signalEndOfInputStream();}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();//希望将已经编码完成的数据都获取到,然后写出到mp4文件中while (true) {//并不是传给mediacodec一帧数据就表示可以编码出一帧数据,有可能需要好多帧数据才可以同时编码出数据出来//输出缓冲区//传递-1表示一直等到输出缓冲区有一个编码好的有效的数据以后才会继续向下走,不然就会一直卡在127行,//10_000超时时间int status = mMediaCodec.dequeueOutputBuffer(bufferInfo, 10_000);if (status == MediaCodec.INFO_TRY_AGAIN_LATER) {//如果是停止,就继续循环,// 继续循环就表示不会接收到新的等待编码的图像了//相当于保证mediacodic中所有待编码的数据都编码完成// 标记不是停止,我们退出,下一轮接收到更多的数据才来输出编码以后的数据,我们就让继续走// 表示需要更多数据才可以编码出图像  false是继续录制,未来还有机会在调用getCodecif (!endOfStream) {//结束录制了break;}//否则继续} else if (status == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {//开始编码,就会调用一次MediaFormat outputFormat = mMediaCodec.getOutputFormat();//配置封装器,增加一路指定格式的媒体流index = mMediaMuxer.addTrack(outputFormat);//启动封装器mMediaMuxer.start();} else if (status == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {//忽略} else {//成功取出一个有效的输出ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(status);if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {//如果获取的ByteBuffer是配置信息,那么就不需要写出到mp4文件中bufferInfo.size = 0;}if (bufferInfo.size != 0) {bufferInfo.presentationTimeUs = (long) (bufferInfo.presentationTimeUs / mSpeed);//写出到 mp4文件中//根据偏移定位去获取数据,而不是从0开始outputBuffer.position(bufferInfo.offset);//设置可读可写的总长度outputBuffer.limit(bufferInfo.offset + bufferInfo.size);mMediaMuxer.writeSampleData(index, outputBuffer, bufferInfo);}//输出缓冲区使用完毕了, 此时就可以回收了,让mediacodec继续使用mMediaCodec.releaseOutputBuffer(status, false);if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {//结束了,break;}}}}public void stop() {isStart = false;mHandler.post(() -> {getCodec(true);mMediaCodec.stop();mMediaCodec.release();mMediaCodec = null;mMediaMuxer.stop();mMediaMuxer.release();mMediaMuxer = null;mEglBase.release();mEglBase = null;mInputSurface = null;mHandler.getLooper().quitSafely();mHandler = null;});}
}

http://www.dtcms.com/wzjs/333009.html

相关文章:

  • 做视频网站的公司2022网站seo
  • 电商网站构建网络营销公司哪家可靠
  • 自己做网站多少钱被忽悠去做网销了
  • asp网站和php网站电子商务推广
  • 谁有wap网站优化大师如何删掉多余的学生
  • 龙华民治网站设计公司河北seo平台
  • 深圳便宜建网站热点新闻
  • 英铭广州网站建设sem是什么电镜
  • 电子书网站 跟我学做家常菜800国外网站推广平台有哪些?
  • 专门做婚纱儿童摄影网站企业网站seo诊断工具
  • 淘客做网站seo综合查询国产
  • 怎样更新网站seo百度关键词排名
  • 网站做邮箱吗关键词排名零芯互联排名
  • 青岛做网站公司店铺推广方法
  • 做石材外贸用什么网站磁力猫官网cilimao
  • 建设网站怎么赚钱的百度官方电话人工服务电话
  • 公司做网站 手机 电脑今日国际新闻最新消息
  • 做网站 兼职今天nba新闻最新消息
  • 企业网站系统排名企业网站管理系统源码
  • 做国际物流需网站深圳百度推广公司
  • 学做网站零基础微信小程序开发一个多少钱啊
  • 程序员做交友网站举例网络营销的例子
  • App加网站什么做淘宝seo优化怎么做
  • 做qq空间的网站线上推广方案怎么做
  • 每天日常更新请广大拿笔记好seo营销方法
  • 鄱阳做网站网站公司
  • 电视剧在线观看完整版免费网站ip子域名大全
  • 商城网站建设可以吗seo搜索引擎优化课程
  • 网站没有关键词营销
  • 校园网站制作推广服务商