MediaCodec之H264编码

MediaCodec之H264编码MediaCodec 编码 H264

首先要实现下面的这两个接口,一个是SurfaceView必须要实现的接口,一个是相机输出数据的接口。

public class MainActivity extends Activity implements SurfaceHolder.Callback,PreviewCallback

创建相机并且开启预览

 private void startcamera(Camera mCamera){ if(mCamera != null){ try { mCamera.setPreviewCallback(this);// mCamera.setDisplayOrientation(90);//旋转90 if(parameters == null){ parameters = mCamera.getParameters(); } List 
  
    sizes = parameters.getSupportedPictureSizes(); 
   //parameters = mCamera.getParameters(); parameters.setPreviewFormat(ImageFormat.NV21); 
   //输出的格式,最好不要修改 parameters.setPreviewSize(width, height); mCamera.setParameters(parameters); mCamera.setPreviewDisplay(surfaceHolder); mCamera.startPreview(); 
   //开启预览 } 
   catch (IOException e) { e.printStackTrace(); } } } 
  

从摄像头获取数据:

 @Override public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { //data就是摄像头输出的数据,Mediacodec编码的对象就是data }
 private void initMediaCodec() { bitrate = 2 * width * height * framerate ;//码率 try { mMediaCodec = MediaCodec.createEncoderByType("video/avc"); MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", height, width); //height和width一般都是照相机的height和width。  //描述平均位速率(以位/秒为单位)的键。 关联的值是一个整数 mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate); //描述视频格式的帧速率(以帧/秒为单位)的键。 mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, framerate);//帧率,一般在15至30之内,太小容易造成视频卡顿。 mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, 19);//色彩格式,具体查看相关API,不同设备支持的色彩格式不尽相同 //关键帧间隔时间,单位是秒 mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2); mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mMediaCodec.start();//开始编码 } catch (IOException e) { e.printStackTrace(); } }

对onPreviewFrame(byte[] data, Camera camera)中的data进行编码:

 byte[] input = data; byte[] yuv420sp = new byte[width*height*3/2]; NV21ToNV12(input,yuv420sp,width,height); input = yuv420sp; if (input != null) { try { ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();//拿到输入缓冲区,用于传送数据进行编码 ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();//拿到输出缓冲区,用于取到编码后的数据  int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) { 
  //当输入缓冲区有效时,就是>=0 ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); inputBuffer.put(input);//往输入缓冲区写入数据, // //五个参数,第一个是输入缓冲区的索引,第二个数据是输入缓冲区起始索引,第三个是放入的数据大小,第四个是时间戳,保证递增就是 mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, System.nanoTime() / 1000, 0); } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);//拿到输出缓冲区的索引 while (outputBufferIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size]; outputBuffer.get(outData); //outData就是输出的h264数据 outputStream.write(outData, 0, outData.length);//将输出的h264数据保存为文件,用vlc就可以播放 mediaCodec.releaseOutputBuffer(outputBufferIndex, false); outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); } } catch (Throwable t) { t.printStackTrace(); } }

创建文件夹

 private void createfile(){ File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/test.h264"); if(file.exists()){ file.delete(); } try { outputStream = new BufferedOutputStream(new FileOutputStream(file)); } catch (Exception e){ e.printStackTrace(); } }

NV21格式转化为NV12格式

 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]; } }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/220374.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午8:39
下一篇 2026年3月17日 下午8:39


相关推荐

  • Mathjax 常用语法

    Mathjax 常用语法参考资料 REF1 Markdown 中输入数学公式 REF2 MarkdownTuto MathJax 的基本用法 REF4 为知笔记中 MathJax 多行公式插入公式行内插入 用 自成段落 用 上标与下标上标 如 x2x2x 2 下标 如 xixix i 分组 用大括号 将操作数与符号分隔开 消

    2026年3月19日
    2
  • python 0xff_正在解压缩“0xff”与“\xff”[通俗易懂]

    python 0xff_正在解压缩“0xff”与“\xff”[通俗易懂]我试图用wave库从wave文件中读取二进制数据。数据以’\x0f\x06\x0a…’的形式读取和报告,我想把十六进制数转换成整数(你知道,以10为基数)。我把这些字符当作十六进制字符来处理,但我并没有把这些字符当作十六进制字符来处理。在importwaveimportstructpath=”C:\\directory\\file.wav”file=wave.open(path,’r’)dat…

    2022年6月19日
    34
  • java实现HMACSHA256加密签名

    java实现HMACSHA256加密签名java 实现 HMACSHA256 加密签名 需要按照字典排序的朋友可以用 SortedMapmes newTreeMap 进行排序后在加密 version1 0 project autoTrade author QC 班长 date 2017 8 3 time 10 17 importjavax crypto Mac importjava

    2026年3月19日
    0
  • CPLD和FPGA的区别

    CPLD和FPGA的区别下面我们整理一下CPLD和FPGA的主要区别:1)CPLD的逻辑阵列更适合可重复编程的EEPROM或Flash技术来实现。而FPGA显然是利用SRAM技术更合适。2)由于是EEPROM或者Flash工艺决定了CPLD是有一定的擦写次数限制的。而FPGA在实际使用中几乎可以说是无配置次数限制。3)CPLD由于采用的是EEPROM或者Flash工艺所以配置掉电后不丢失,也就不需要外挂配置芯片。而FPGA采用的是SRAM工艺,配置在掉电后就没有了,因此需要一个外部配置芯片。4)CPLD的安

    2022年5月4日
    63
  • win ce 编译运行自定义控件提示:Result code: 0x80040154 错误解决

    win ce 编译运行自定义控件提示:Result code: 0x80040154 错误解决

    2021年8月8日
    56
  • pycharm 2021激活码【2021免费激活】

    (pycharm 2021激活码)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/ide…

    2022年3月20日
    65

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号