Android如何使用MediaCodec将摄像头采集的视频编码为h264
发表于:2024-10-26 作者:千家信息网编辑
千家信息网最后更新 2024年10月26日,这篇文章主要介绍Android如何使用MediaCodec将摄像头采集的视频编码为h264,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体内容如下MainActivity.j
千家信息网最后更新 2024年10月26日Android如何使用MediaCodec将摄像头采集的视频编码为h264
这篇文章主要介绍Android如何使用MediaCodec将摄像头采集的视频编码为h264,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
具体内容如下
MainActivity.java
import android.app.Activity;import android.graphics.ImageFormat;import android.hardware.Camera;import android.hardware.Camera.Parameters;import android.hardware.Camera.PreviewCallback;import android.os.Bundle;import android.view.SurfaceHolder;import android.view.SurfaceView;import java.io.IOException;import java.util.concurrent.ArrayBlockingQueue;public class MainActivity extends Activity implements SurfaceHolder.Callback,PreviewCallback{ private SurfaceView surfaceview; private SurfaceHolder surfaceHolder; private Camera camera; private Parameters parameters; int width = 1280; int height = 720; int framerate = 30; int biterate = 8500*1000; private static int yuvqueuesize = 10; //待解码视频缓冲队列,静态成员! public static ArrayBlockingQueueYUVQueue = new ArrayBlockingQueue (yuvqueuesize); private AvcEncoder avcCodec; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceview = (SurfaceView)findViewById(R.id.surfaceview); surfaceHolder = surfaceview.getHolder(); surfaceHolder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { camera = getBackCamera(); startcamera(camera); //创建AvEncoder对象 avcCodec = new AvcEncoder(width,height,framerate,biterate); //启动编码线程 avcCodec.StartEncoderThread(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (null != camera) { camera.setPreviewCallback(null); camera.stopPreview(); camera.release(); camera = null; avcCodec.StopThread(); } } @Override public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { //将当前帧图像保存在队列中 putYUVData(data,data.length); } public void putYUVData(byte[] buffer, int length) { if (YUVQueue.size() >= 10) { YUVQueue.poll(); } YUVQueue.add(buffer); } private void startcamera(Camera mCamera){ if(mCamera != null){ try { mCamera.setPreviewCallback(this); mCamera.setDisplayOrientation(90); if(parameters == null){ parameters = mCamera.getParameters(); } //获取默认的camera配置 parameters = mCamera.getParameters(); //设置预览格式 parameters.setPreviewFormat(ImageFormat.NV21); //设置预览图像分辨率 parameters.setPreviewSize(width, height); //配置camera参数 mCamera.setParameters(parameters); //将完全初始化的SurfaceHolder传入到setPreviewDisplay(SurfaceHolder)中 //没有surface的话,相机不会开启preview预览 mCamera.setPreviewDisplay(surfaceHolder); //调用startPreview()用以更新preview的surface,必须要在拍照之前start Preview mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } } private Camera getBackCamera() { Camera c = null; try { //获取Camera的实例 c = Camera.open(0); } catch (Exception e) { e.printStackTrace(); } //获取Camera的实例失败时返回null return c; }}
2.AvcEncoder.java
import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaFormat;import android.os.Environment;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import static android.media.MediaCodec.BUFFER_FLAG_CODEC_CONFIG;import static android.media.MediaCodec.BUFFER_FLAG_KEY_FRAME;public class AvcEncoder{ private final static String TAG = "MeidaCodec"; private int TIMEOUT_USEC = 12000; private MediaCodec mediaCodec; int m_width; int m_height; int m_framerate; public byte[] configbyte; public AvcEncoder(int width, int height, int framerate, int bitrate) { m_width = width; m_height = height; m_framerate = framerate; MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width*height*5); mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); try { mediaCodec = MediaCodec.createEncoderByType("video/avc"); } catch (IOException e) { e.printStackTrace(); } //配置编码器参数 mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); //启动编码器 mediaCodec.start(); //创建保存编码后数据的文件 createfile(); } private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h364"; private BufferedOutputStream outputStream; private void createfile(){ File file = new File(path); if(file.exists()){ file.delete(); } try { outputStream = new BufferedOutputStream(new FileOutputStream(file)); } catch (Exception e){ e.printStackTrace(); } } private void StopEncoder() { try { mediaCodec.stop(); mediaCodec.release(); } catch (Exception e){ e.printStackTrace(); } } public boolean isRuning = false; public void StopThread(){ isRuning = false; try { StopEncoder(); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } int count = 0; public void StartEncoderThread(){ Thread EncoderThread = new Thread(new Runnable() { @Override public void run() { isRuning = true; byte[] input = null; long pts = 0; long generateIndex = 0; while (isRuning) { //访问MainActivity用来缓冲待解码数据的队列 if (MainActivity.YUVQueue.size() >0){ //从缓冲队列中取出一帧 input = MainActivity.YUVQueue.poll(); byte[] yuv420sp = new byte[m_width*m_height*3/2]; //把待编码的视频帧转换为YUV420格式 NV21ToNV12(input,yuv420sp,m_width,m_height); input = yuv420sp; } if (input != null) { try { long startMs = System.currentTimeMillis(); //编码器输入缓冲区 ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers(); //编码器输出缓冲区 ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { pts = computePresentationTime(generateIndex); ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); //把转换后的YUV420格式的视频帧放到编码器输入缓冲区中 inputBuffer.put(input); mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, pts, 0); generateIndex += 1; } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); while (outputBufferIndex >= 0) { //Log.i("AvcEncoder", "Get H264 Buffer Success! flag = "+bufferInfo.flags+",pts = "+bufferInfo.presentationTimeUs+""); ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size]; outputBuffer.get(outData); if(bufferInfo.flags == BUFFER_FLAG_CODEC_CONFIG){ configbyte = new byte[bufferInfo.size]; configbyte = outData; }else if(bufferInfo.flags == BUFFER_FLAG_KEY_FRAME){ byte[] keyframe = new byte[bufferInfo.size + configbyte.length]; System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length); //把编码后的视频帧从编码器输出缓冲区中拷贝出来 System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length); outputStream.write(keyframe, 0, keyframe.length); }else{ //写到文件中 outputStream.write(outData, 0, outData.length); } mediaCodec.releaseOutputBuffer(outputBufferIndex, false); outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); } } catch (Throwable t) { t.printStackTrace(); } } else { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }); EncoderThread.start(); } private void NV21ToNV12(byte[] nv21,byte[] nv12,int width,int height){ if(nv21 == null || nv12 == null)return; int framesize = width*height; int i = 0,j = 0; System.arraycopy(nv21, 0, nv12, 0, framesize); for(i = 0; i < framesize; i++){ nv12[i] = nv21[i]; } for (j = 0; j < framesize/2; j+=2) { nv12[framesize + j-1] = nv21[j+framesize]; } for (j = 0; j < framesize/2; j+=2) { nv12[framesize + j] = nv21[j+framesize-1]; } } /** * Generates the presentation time for frame N, in microseconds. */ private long computePresentationTime(long frameIndex) { return 132 + frameIndex * 1000000 / m_framerate; }}
3.activity_main.xml
4.添加权限
以上是"Android如何使用MediaCodec将摄像头采集的视频编码为h264"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!
编码
缓冲
视频
编码器
缓冲区
队列
内容
格式
配置
摄像头
摄像
参数
图像
实例
数据
文件
篇文章
输入
输出
价值
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
数据库访问资源消耗
前端软件开发 迷茫
校园网络安全教育问题
sql数据库float
明日之后夏尔镇服务器有主播吗
滴滴 软件开发 年假
python 数据库编程
腾讯2个服务器怎么登录
西悉尼大学网络安全与学位
浙江开发票安全接入服务器地址
四川从零学java软件开发
港澳台华侨生网络安全专业院校
高碑店网络安全公司
蚌埠网络安全宣传周
袋鼠主人网络技术有限公司
自动化数据库技术
怀化软件开发培训好不好
黎明觉醒有没有服务器
网络安全维护工作业绩
工信部开展摄像头网络安全整治
ios软件开发招聘
维基本地数据库
网络安全周的开幕式
威海软件开发多少钱
网络安全研究院有哪些
最新frp免费服务器
软件开发的职业寿命
玩客云一直上传数据库
数据库文件导入工具最新免费版
宿州安卓软件开发多少钱