android硬编码h264-MediaCodec
16lz
2021-01-24
分类:笔记音视频学习过程音视频 2013-12-26 15:40 5623人阅读 评论(13) 收藏 举报
本人对android已无大爱,更新太快,就h264编码先后实现了 ffmpeg+x264软编 Mediarecoder提取,还没能稳定的又出了MediaCodec,更新太快。更新快也是好事,说明android生命力旺盛。
既然瞅了几眼,就发出来个测试版本吧。android编码h264, 用udp发送到vlc播放测试。代码上传至:http://download.csdn.net/detail/liuhongxiangm/6772629
上代码:
[java] view plain copy
- <spanstyle="font-size:18px;">packagecom.encode.androidencode;
- importjava.nio.ByteBuffer;
- importandroid.annotation.SuppressLint;
- importandroid.media.MediaCodec;
- importandroid.media.MediaCodecInfo;
- importandroid.media.MediaFormat;
- importandroid.util.Log;
- publicclassAvcEncoder
- {
- privateMediaCodecmediaCodec;
- intm_width;
- intm_height;
- byte[]m_info=null;
- privatebyte[]yuv420=null;
- @SuppressLint("NewApi")
- publicAvcEncoder(intwidth,intheight,intframerate,intbitrate){
- m_width=width;
- m_height=height;
- yuv420=newbyte[width*height*3/2];
- mediaCodec=MediaCodec.createEncoderByType("video/avc");
- MediaFormatmediaFormat=MediaFormat.createVideoFormat("video/avc",width,height);
- mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,bitrate);
- mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,framerate);
- mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
- mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1);//关键帧间隔时间单位s
- mediaCodec.configure(mediaFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
- mediaCodec.start();
- }
- @SuppressLint("NewApi")
- publicvoidclose(){
- try{
- mediaCodec.stop();
- mediaCodec.release();
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- @SuppressLint("NewApi")
- publicintofferEncoder(byte[]input,byte[]output)
- {
- intpos=0;
- swapYV12toI420(input,yuv420,m_width,m_height);
- try{
- ByteBuffer[]inputBuffers=mediaCodec.getInputBuffers();
- ByteBuffer[]outputBuffers=mediaCodec.getOutputBuffers();
- intinputBufferIndex=mediaCodec.dequeueInputBuffer(-1);
- if(inputBufferIndex>=0)
- {
- ByteBufferinputBuffer=inputBuffers[inputBufferIndex];
- inputBuffer.clear();
- inputBuffer.put(yuv420);
- mediaCodec.queueInputBuffer(inputBufferIndex,0,yuv420.length,0,0);
- }
- MediaCodec.BufferInfobufferInfo=newMediaCodec.BufferInfo();
- intoutputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,0);
- while(outputBufferIndex>=0)
- {
- ByteBufferoutputBuffer=outputBuffers[outputBufferIndex];
- byte[]outData=newbyte[bufferInfo.size];
- outputBuffer.get(outData);
- if(m_info!=null)
- {
- System.arraycopy(outData,0,output,pos,outData.length);
- pos+=outData.length;
- }
- else//保存ppssps只有开始时第一个帧里有,保存起来后面用
- {
- ByteBufferspsPpsBuffer=ByteBuffer.wrap(outData);
- if(spsPpsBuffer.getInt()==0x00000001)
- {
- m_info=newbyte[outData.length];
- System.arraycopy(outData,0,m_info,0,outData.length);
- }
- else
- {
- return-1;
- }
- }
- mediaCodec.releaseOutputBuffer(outputBufferIndex,false);
- outputBufferIndex=mediaCodec.dequeueOutputBuffer(bufferInfo,0);
- }
- if(output[4]==0x65)//keyframe编码器生成关键帧时只有0000000165没有ppssps,要加上
- {
- System.arraycopy(output,0,yuv420,0,pos);
- System.arraycopy(m_info,0,output,0,m_info.length);
- System.arraycopy(yuv420,0,output,m_info.length,pos);
- pos+=m_info.length;
- }
- }catch(Throwablet){
- t.printStackTrace();
- }
- returnpos;
- }
- //yv12转yuv420pyvu->yuv
- privatevoidswapYV12toI420(byte[]yv12bytes,byte[]i420bytes,intwidth,intheight)
- {
- System.arraycopy(yv12bytes,0,i420bytes,0,width*height);
- System.arraycopy(yv12bytes,width*height+width*height/4,i420bytes,width*height,width*height/4);
- System.arraycopy(yv12bytes,width*height,i420bytes,width*height+width*height/4,width*height/4);
- }
- }
- </span>
- <spanstyle="font-size:18px;">packagecom.interfaces.androidencode;
- importjava.io.IOException;
- importjava.net.DatagramPacket;
- importjava.net.DatagramSocket;
- importjava.net.InetAddress;
- importjava.net.SocketException;
- importjava.net.UnknownHostException;
- importjava.util.List;
- importandroid.graphics.ImageFormat;
- importandroid.hardware.Camera;
- importandroid.hardware.Camera.PreviewCallback;
- importandroid.os.Bundle;
- importandroid.os.StrictMode;
- importandroid.annotation.SuppressLint;
- importandroid.app.Activity;
- importandroid.util.Log;
- importandroid.view.Menu;
- importandroid.view.SurfaceHolder;
- importandroid.view.SurfaceHolder.Callback;
- importandroid.view.SurfaceView;
- importcom.encode.androidencode.AvcEncoder;
- publicclassMainActivityextendsActivity
- implementsSurfaceHolder.Callback,PreviewCallback
- {
- DatagramSocketsocket;
- InetAddressaddress;
- AvcEncoderavcCodec;
- publicCameram_camera;
- SurfaceViewm_prevewview;
- SurfaceHolderm_surfaceHolder;
- intwidth=1280;
- intheight=720;
- intframerate=20;
- intbitrate=2500000;
- byte[]h264=newbyte[width*height*3/2];
- @SuppressLint("NewApi")
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder()
- .detectDiskReads()
- .detectDiskWrites()
- .detectAll()//or.detectAll()foralldetectableproblems
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder()
- .detectLeakedSqlLiteObjects()
- .detectLeakedClosableObjects()
- .penaltyLog()
- .penaltyDeath()
- .build());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- avcCodec=newAvcEncoder(width,height,framerate,bitrate);
- m_prevewview=(SurfaceView)findViewById(R.id.SurfaceViewPlay);
- m_surfaceHolder=m_prevewview.getHolder();//绑定SurfaceView,取得SurfaceHolder对象
- m_surfaceHolder.setFixedSize(width,height);//预览大小設置
- m_surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- m_surfaceHolder.addCallback((Callback)this);
- try{
- socket=newDatagramSocket();
- address=InetAddress.getByName("192.168.12.124");
- }catch(SocketExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }catch(UnknownHostExceptione){
- //TODOAuto-generatedcatchblock
- e.printStackTrace();
- }
- }
- @Override
- publicbooleanonCreateOptionsMenu(Menumenu){
- //Inflatethemenu;thisaddsitemstotheactionbarifitispresent.
- getMenuInflater().inflate(R.menu.main,menu);
- returntrue;
- }
- @Override
- publicvoidsurfaceChanged(SurfaceHolderarg0,intarg1,intarg2,intarg3)
- {
- }
- @SuppressLint("NewApi")
- @SuppressWarnings("deprecation")
- @Override
- publicvoidsurfaceCreated(SurfaceHolderarg0)
- {
- try
- {
- m_camera=Camera.open();
- m_camera.setPreviewDisplay(m_surfaceHolder);
- Camera.Parametersparameters=m_camera.getParameters();
- parameters.setPreviewSize(width,height);
- parameters.setPictureSize(width,height);
- parameters.setPreviewFormat(ImageFormat.YV12);
- m_camera.setParameters(parameters);
- m_camera.setPreviewCallback((PreviewCallback)this);
- m_camera.startPreview();
- }catch(IOExceptione)
- {
- e.printStackTrace();
- }
- }
- @Override
- publicvoidsurfaceDestroyed(SurfaceHolderarg0)
- {
- m_camera.setPreviewCallback(null);//!!这个必须在前,不然退出出错
- m_camera.stopPreview();
- m_camera.release();
- m_camera=null;
- avcCodec.close();
- }
- @Override
- publicvoidonPreviewFrame(byte[]data,Cameracamera)
- {
- Log.v("h264","h264start");
- intret=avcCodec.offerEncoder(data,h264);
- if(ret>0)
- {
- try{
- DatagramPacketpacket=newDatagramPacket(h264,ret,address,5000);
- socket.send(packet);
- }catch(IOExceptione)
- {
- }
- }
- Log.v("h264","h264end");
- }
- }
- </span>
vlc的设置:设置里面的去复用器设置成H264的就好了,然后打开网络串流:udp://@:5000 就好了
更多相关文章
- android基本动画,代码构建动画
- Android(安卓)6.0 运行时权限处理完全解析
- android实现在横竖屏切换时页面信息不被重置的示例分享
- android之逐帧动画
- Android(安卓)Shape控件美化实现代码
- ViewDragHelper与Transition的示例代码
- 【译】Android:更好的自定义字体方案
- 利用Bundle实现Android(安卓)Activity间消息的传递
- Android(安卓)数据库操作 以及命令行上操作sqlite