android硬编码h264数据,并使用rtp推送数据流,实现一个简单的直播-MediaCodec(二)

上篇博客是使用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]<<8) & 0x0000ff00;
                        int l4 = rtpData[15]&0x000000FF;
                        h264Length = l1+l2+l3+l4;
                        Log.e(TAG, "run: h264Length="+h264Length);
                        System.arraycopy(rtpData,16, h264Data,0,h264Length);
                        Log.e(TAG, "run:h264Data[0]="+h264Data[0]+","+h264Data[1]+","+h264Data[2]+","+h264Data[3]
                                +","+h264Data[4]+","+h264Data[5]+","+h264Data[6]+","+h264Data[7]
                                +","+h264Data[8]+","+h264Data[9]+","+h264Data[10]
                                +","+h264Data[11]+","+h264Data[12]+","+h264Data[13]
                                +","+h264Data[14]+","+h264Data[15]+","+h264Data[16]
                                +","+h264Data[17]+","+h264Data[18]+","+h264Data[19]
                                +","+h264Data[20]+","+h264Data[21]+","+h264Data[22]);//打印sps、pps
                        offerDecoder(h264Data,h264Data.length);
                        Log.e(TAG, "run: offerDecoder=");
                    }
                }
            }
        }
    }

    //解码h264数据
    private void offerDecoder(byte[] input, int length) {
         Log.d(TAG, "offerDecoder: ");
        try {
            ByteBuffer[] inputBuffers = decode.getInputBuffers();
            int inputBufferIndex = decode.dequeueInputBuffer(0);
            if (inputBufferIndex >= 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();
        }
    }
}
  • 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]<<8) & 0x0000ff00;
                            int l4 = rtpData[15]&0x000000FF;
                            h264Length = l1+l2+l3+l4;
                            Log.e(TAG, "run: h264Length="+h264Length);
                            System.arraycopy(rtpData,16, h264Data,0,h264Length);
                            Log.e(TAG, "run:h264Data[0]="+h264Data[0]+","+h264Data[1]+","+h264Data[2]+","+h264Data[3]
                                    +","+h264Data[4]+","+h264Data[5]+","+h264Data[6]+","+h264Data[7]
                                    +","+h264Data[8]+","+h264Data[9]+","+h264Data[10]
                                    +","+h264Data[11]+","+h264Data[12]+","+h264Data[13]
                                    +","+h264Data[14]+","+h264Data[15]+","+h264Data[16]
                                    +","+h264Data[17]+","+h264Data[18]+","+h264Data[19]
                                    +","+h264Data[20]+","+h264Data[21]+","+h264Data[22]);//打印sps、pps
                            offerDecoder(h264Data,h264Data.length);
                            Log.e(TAG, "run: offerDecoder=");
                        }
                    }
                }
            }
        }

        //解码h264数据
        private void offerDecoder(byte[] input, int length) {
             Log.d(TAG, "offerDecoder: ");
            try {
                ByteBuffer[] inputBuffers = decode.getInputBuffers();
                int inputBufferIndex = decode.dequeueInputBuffer(0);
                if (inputBufferIndex >= 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);
    }
}
  • 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。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值