Android使用MediaCodec将摄像头采集的视频编码为h264
本文实例为大家分享了Android使用MediaCodec将摄像头采集的视频编码为h264,供大家参考,具体内容如下
MainActivity.java
importandroid.app.Activity;
importandroid.graphics.ImageFormat;
importandroid.hardware.Camera;
importandroid.hardware.Camera.Parameters;
importandroid.hardware.Camera.PreviewCallback;
importandroid.os.Bundle;
importandroid.view.SurfaceHolder;
importandroid.view.SurfaceView;
importjava.io.IOException;
importjava.util.concurrent.ArrayBlockingQueue;
publicclassMainActivityextendsActivityimplementsSurfaceHolder.Callback,PreviewCallback{
privateSurfaceViewsurfaceview;
privateSurfaceHoldersurfaceHolder;
privateCameracamera;
privateParametersparameters;
intwidth=1280;
intheight=720;
intframerate=30;
intbiterate=8500*1000;
privatestaticintyuvqueuesize=10;
//待解码视频缓冲队列,静态成员!
publicstaticArrayBlockingQueueYUVQueue=newArrayBlockingQueue(yuvqueuesize);
privateAvcEncoderavcCodec;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceview=(SurfaceView)findViewById(R.id.surfaceview);
surfaceHolder=surfaceview.getHolder();
surfaceHolder.addCallback(this);
}
@Override
publicvoidsurfaceCreated(SurfaceHolderholder){
camera=getBackCamera();
startcamera(camera);
//创建AvEncoder对象
avcCodec=newAvcEncoder(width,height,framerate,biterate);
//启动编码线程
avcCodec.StartEncoderThread();
}
@Override
publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,intheight){
}
@Override
publicvoidsurfaceDestroyed(SurfaceHolderholder){
if(null!=camera){
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera=null;
avcCodec.StopThread();
}
}
@Override
publicvoidonPreviewFrame(byte[]data,android.hardware.Cameracamera){
//将当前帧图像保存在队列中
putYUVData(data,data.length);
}
publicvoidputYUVData(byte[]buffer,intlength){
if(YUVQueue.size()>=10){
YUVQueue.poll();
}
YUVQueue.add(buffer);
}
privatevoidstartcamera(CameramCamera){
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,必须要在拍照之前startPreview
mCamera.startPreview();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
privateCameragetBackCamera(){
Camerac=null;
try{
//获取Camera的实例
c=Camera.open(0);
}catch(Exceptione){
e.printStackTrace();
}
//获取Camera的实例失败时返回null
returnc;
}
}
2.AvcEncoder.java
importandroid.media.MediaCodec;
importandroid.media.MediaCodecInfo;
importandroid.media.MediaFormat;
importandroid.os.Environment;
importjava.io.BufferedOutputStream;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.nio.ByteBuffer;
importstaticandroid.media.MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
importstaticandroid.media.MediaCodec.BUFFER_FLAG_KEY_FRAME;
publicclassAvcEncoder
{
privatefinalstaticStringTAG="MeidaCodec";
privateintTIMEOUT_USEC=12000;
privateMediaCodecmediaCodec;
intm_width;
intm_height;
intm_framerate;
publicbyte[]configbyte;
publicAvcEncoder(intwidth,intheight,intframerate,intbitrate){
m_width=width;
m_height=height;
m_framerate=framerate;
MediaFormatmediaFormat=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(IOExceptione){
e.printStackTrace();
}
//配置编码器参数
mediaCodec.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
//启动编码器
mediaCodec.start();
//创建保存编码后数据的文件
createfile();
}
privatestaticStringpath=Environment.getExternalStorageDirectory().getAbsolutePath()+"/test1.h264";
privateBufferedOutputStreamoutputStream;
privatevoidcreatefile(){
Filefile=newFile(path);
if(file.exists()){
file.delete();
}
try{
outputStream=newBufferedOutputStream(newFileOutputStream(file));
}catch(Exceptione){
e.printStackTrace();
}
}
privatevoidStopEncoder(){
try{
mediaCodec.stop();
mediaCodec.release();
}catch(Exceptione){
e.printStackTrace();
}
}
publicbooleanisRuning=false;
publicvoidStopThread(){
isRuning=false;
try{
StopEncoder();
outputStream.flush();
outputStream.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
intcount=0;
publicvoidStartEncoderThread(){
ThreadEncoderThread=newThread(newRunnable(){
@Override
publicvoidrun(){
isRuning=true;
byte[]input=null;
longpts=0;
longgenerateIndex=0;
while(isRuning){
//访问MainActivity用来缓冲待解码数据的队列
if(MainActivity.YUVQueue.size()>0){
//从缓冲队列中取出一帧
input=MainActivity.YUVQueue.poll();
byte[]yuv420sp=newbyte[m_width*m_height*3/2];
//把待编码的视频帧转换为YUV420格式
NV21ToNV12(input,yuv420sp,m_width,m_height);
input=yuv420sp;
}
if(input!=null){
try{
longstartMs=System.currentTimeMillis();
//编码器输入缓冲区
ByteBuffer[]inputBuffers=mediaCodec.getInputBuffers();
//编码器输出缓冲区
ByteBuffer[]outputBuffers=mediaCodec.getOutputBuffers();
intinputBufferIndex=mediaCodec.dequeueInputBuffer(-1);
if(inputBufferIndex>=0){
pts=computePresentationTime(generateIndex);
ByteBufferinputBuffer=inputBuffers[inputBufferIndex];
inputBuffer.clear();
//把转换后的YUV420格式的视频帧放到编码器输入缓冲区中
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex,0,input.length,pts,0);
generateIndex+=1;
}
MediaCodec.BufferInfobufferInfo=newMediaCodec.BufferInfo();
intoutputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,TIMEOUT_USEC);
while(outputBufferIndex>=0){
//Log.i("AvcEncoder","GetH264BufferSuccess!flag="+bufferInfo.flags+",pts="+bufferInfo.presentationTimeUs+"");
ByteBufferoutputBuffer=outputBuffers[outputBufferIndex];
byte[]outData=newbyte[bufferInfo.size];
outputBuffer.get(outData);
if(bufferInfo.flags==BUFFER_FLAG_CODEC_CONFIG){
configbyte=newbyte[bufferInfo.size];
configbyte=outData;
}elseif(bufferInfo.flags==BUFFER_FLAG_KEY_FRAME){
byte[]keyframe=newbyte[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(Throwablet){
t.printStackTrace();
}
}else{
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
});
EncoderThread.start();
}
privatevoidNV21ToNV12(byte[]nv21,byte[]nv12,intwidth,intheight){
if(nv21==null||nv12==null)return;
intframesize=width*height;
inti=0,j=0;
System.arraycopy(nv21,0,nv12,0,framesize);
for(i=0;i
3.activity_main.xml
4.添加权限
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。