上篇博客是使用MediaCodec编码摄像头预览数据成h264数据,并用rtp发送实时数据流。这篇博客是接收h264数据流MediaCodec解码并显示。
先上代码的结构图:
eclipse的工程,接收端比较简单只有两个类
直接上解码部分的代码:
public class ClientTextureView extends TextureView implements TextureView.SurfaceTextureListener{ private static final String MIME_TYPE = "video/avc"; private static final String TAG = "ClientTextureView" ; private MediaCodec decode; byte[] rtpData = new byte[80000]; byte[] h264Data = new byte[80000]; int timestamp = 0; DatagramSocket socket; public ClientTextureView(Context context, AttributeSet attrs) { super(context, attrs); setSurfaceTextureListener(this); try { socket = new DatagramSocket(5004);//端口号 socket.setReuseAddress(true); socket.setBroadcast(true); } catch (SocketException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { new PreviewThread(new Surface(surface),800,480);//手机的分辨率 } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { if (socket != null){ socket.close(); socket = null; } return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } private class PreviewThread extends Thread { DatagramPacket datagramPacket = null; public PreviewThread(Surface surface, int width , int height){ Log.e(TAG, "PreviewThread: gou zhao"); decode = MediaCodec.createDecoderByType(MIME_TYPE); final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE,width,height); format.setInteger(MediaFormat.KEY_BIT_RATE, 40000); format.setInteger(MediaFormat.KEY_FRAME_RATE, 20); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); byte[] header_sps = {0, 0, 0, 1, 103, 66, 0 , 41, -115, -115, 64, 80 , 30 , -48 , 15 ,8,-124, 83, -128}; byte[] header_pps = {0,0 ,0, 1, 104, -54, 67, -56}; format.setByteBuffer("csd-0", ByteBuffer.wrap(header_sps)); format.setByteBuffer("csd-1", ByteBuffer.wrap(header_pps)); decode.configure(format,surface,null,0); decode.start(); start(); } @Override public void run() { byte[] data = new byte[80000]; int h264Length = 0; while (true){ if (socket != null){ try { datagramPacket = new DatagramPacket(data,data.length); socket.receive(datagramPacket);//接收数据 } catch (IOException e) { e.printStackTrace(); } } rtpData = datagramPacket.getData(); if (rtpData != null ){ if (rtpData[0] == -128 && rtpData[1] == 96){ Log.e(TAG, "run:xxx"); int l1 = (rtpData[12]<<24)& 0xff000000; int l2 = (rtpData[13]<<16)& 0x00ff0000; int l3 = (rtpData[14]<= 0) { ByteBuffer inputBuffer = inputBuffers[inputBufferIndex]; inputBuffer.clear(); try{ inputBuffer.put(input, 0, length); }catch (Exception e){ e.printStackTrace(); } decode.queueInputBuffer(inputBufferIndex, 0, length, 0, 0); } MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = decode.dequeueOutputBuffer(bufferInfo, 0); while (outputBufferIndex >= 0) { //If a valid surface was specified when configuring the codec, //passing true renders this output buffer to the surface. decode.releaseOutputBuffer(outputBufferIndex, true); outputBufferIndex = decode.dequeueOutputBuffer(bufferInfo, 0); } } catch (Throwable t) { t.printStackTrace(); } } }
MainActivity的代码:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
源码已经放到GitHub,地址:https://github.com/xmc1715499699/MediaCodec_rtp_receive,欢迎下载star。
作者:阿德0307