美文网首页
spydroid-ipcamera源码分析(二):MediaSt

spydroid-ipcamera源码分析(二):MediaSt

作者: 管弦_ | 来源:发表于2017-05-31 17:12 被阅读0次

    MediaStream类

    MediaStream作为流媒体的基类,实现了Stream接口,封装了对Srteam对象的基本操作。同时它又作为一个抽象类,抽象出更为细分的操作动作让子类进行实现。

    static {
            // We determine wether or not the MediaCodec API should be used
            try {
                Class.forName("android.media.MediaCodec");
                // Will be set to MODE_MEDIACODEC_API at some point...
                sSuggestedMode = MODE_MEDIACODEC_API;
                Log.i(TAG,"Phone supports the MediaCoded API");
            } catch (ClassNotFoundException e) {
                sSuggestedMode = MODE_MEDIARECORDER_API;
                Log.i(TAG,"Phone does not support the MediaCodec API");
            }
        }
    

    MediaStream在静态块中确定流媒体使用的编解码器。默认优先选择MediaCodec,若不支持MediaCodec才选择MediaRecorder。

    在传输流媒体的过程中,为了节约带宽和传输效率,一般都会对流媒体数据进行编解码操作。在这里编解码又分为软编解码和硬编解码。

    以视频编码举例,软编码就是使用CPU进行编码,实现直接、简单,参数调整方便,但CPU负载重,性能较硬编码低;硬编码就是使用非CP(显卡GPU、专用编解码芯片等)进行编码,这种方式性能更高,但不便于移植。在Android平台上的效果,主流配置设配在使用软编码运行几分钟后便会出现发烫、掉帧等问题,而硬编码出现上述问题的程度要轻微得多。所以在spydroid-ipcamera项目这种需要长时间运行流媒体编码的场景下,显然硬编码更合适一些。

    Android系统内部提供了两种视频编码方式:MediaCodec和MediaRecorder。他们都可以对视频进行编码,但是唯一不同的是MediaCodec更偏向原生,而MediaRecorder偏向的上层封装。MediaCodec类处理视频的时候可以接触到视频流数据,比如一些特殊需求:视频的叠加技术,添加字幕等就可以在这里处理。而MediaRecorder类相对于MediaCodec简单,且封装得更好,直接用几个接口就可以完成对视频的录入和编码,用法简单,但就是不能接触到视频流数据,处理不了原生的视频数据。

        /** Starts the stream. */
        public synchronized void start() throws IllegalStateException, IOException {
            
            if (mDestination==null)
                throw new IllegalStateException("No destination ip address set for the stream !");
    
            if (mRtpPort<=0 || mRtcpPort<=0)
                throw new IllegalStateException("No destination ports set for the stream !");
    
            mPacketizer.setTimeToLive(mTTL);
            
            if (mMode != MODE_MEDIARECORDER_API) {
                encodeWithMediaCodec();
            } else {
                encodeWithMediaRecorder();
            }
    
        }
    
        /** Stops the stream. */
        @SuppressLint("NewApi") 
        public synchronized  void stop() {
            if (mStreaming) {
                try {
                    if (mMode==MODE_MEDIARECORDER_API) {
                        mMediaRecorder.stop();
                        mMediaRecorder.release();
                        mMediaRecorder = null;
                        closeSockets();
                        mPacketizer.stop();
                    } else {
                        mPacketizer.stop();
                        mMediaCodec.stop();
                        mMediaCodec.release();
                        mMediaCodec = null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }   
                mStreaming = false;
            }
        }
    

    实现Stream接口中start()和stop()的实现。start()需要子类去实现encodeWithMediaRecorder()和encodeWithMediaCodec()方法。stop()主要是释放多媒体编码类对象。

        protected abstract void encodeWithMediaRecorder() throws IOException;
    
        protected abstract void encodeWithMediaCodec() throws IOException;
    

    MediaStream类中两个核心抽象方法,就是使用MediaCodec和MediaRecorder两种编码方式的进行实现。好比同一个目的地,两条不同的路。

        protected void createSockets() throws IOException {
    
            final String LOCAL_ADDR = "net.majorkernelpanic.streaming-";
    
            for (int i=0;i<10;i++) {
                try {
                    mSocketId = new Random().nextInt();
                    mLss = new LocalServerSocket(LOCAL_ADDR+mSocketId);
                    break;
                } catch (IOException e1) {}
            }
    
            mReceiver = new LocalSocket();
            mReceiver.connect( new LocalSocketAddress(LOCAL_ADDR+mSocketId));
            mReceiver.setReceiveBufferSize(500000);
            mReceiver.setSoTimeout(3000);
            mSender = mLss.accept();
            mSender.setSendBufferSize(500000);
        }
    
        protected void closeSockets() {
            try {
                mReceiver.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                mSender.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                mLss.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            mLss = null;
            mSender = null;
            mReceiver = null;
        }
    

    如果是通过MediaRecoder采集视频,需要再将视频流映射到LocalSocket上来实现收发。所以当使用MediaRecorder方式实现时,start()和stop()需要使用到createSockets()和closeSockets()。具体细节在后面的文章会详细分析。

    到这里我们大致了解了MediaStream,主要采用了Android的MediaCodec和MediaRecorder两种方式实现流媒体的采集和编解码,下一步我们将详细分析音频流AudioStream和它的子类,了解音频流采集和编码的主要过程。

    相关文章

      网友评论

          本文标题:spydroid-ipcamera源码分析(二):MediaSt

          本文链接:https://www.haomeiwen.com/subject/kbsjfxtx.html