很多开发者希望我们的Android平台RTSP/RTMP播放端实现视频窗口的放大缩小功能,为此,我们做了个简单的demo,通过播放端回调RGB数据,直接在上层view操作处理即可,Github:https://github.com/daniulive/SmarterStreaming

无视频无真相:http://www.iqiyi.com/w_19s9sa7epp.html

基本流程如下:

  1. 基础的初始化和参数设定

        libP  = new SmartP JniV2();    myContext = this.getApplicationContext();    sSurfaceView = (SurfaceView) this.findViewById(R.id.surface);    surface_renderer = new RGBSurfaceRenderer(sSurfaceView);

private void InitAndSetConfig() {

    p Handle = libP .SmartP Open(myContext);    if (p Handle == 0) {        Log.e(TAG, "surfaceHandle with nil..");        return;    }    libP .SetSmartP EventCallbackV2(p Handle,            new EventHandeV2());    libP .SmartP SetBuffer(p Handle, playBuffer);    // set report download speed(默认2秒一次回调 用户可自行调整report间隔)    libP .SmartP SetReportDownloadSpeed(p Handle, 1, 2);    libP .SmartP SetFastStartup(p Handle, isFastStartup ? 1 : 0);    //设置RTSP超时时间    int rtsp_timeout = 10;    libP .SmartP SetRTSPTimeout(p Handle, rtsp_timeout);    //设置RTSP TCP/UDP模式自动切换    int is_auto_switch_tcp_udp = 1;    libP .SmartP SetRTSPAutoSwitchTcpUdp(p Handle, is_auto_switch_tcp_udp);    libP .SmartP SaveImageFlag(p Handle, 1);    // It only used when playback RTSP stream..    // libP .SmartP SetRTSPTcpMode(p Handle, 1);    playbackUrl = "rtmp://202.69.69.180:443/webcast/bshdlive-pc";    //playbackUrl = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov";    libP .SmartP SetUrl(p Handle, playbackUrl);}

2.  设置External Render,回调RGBA数据

libP .SmartP SetExternalRender(p Handle, new RGBAExternalRender());

Log.i(TAG, "Start playback stream++");

            InitAndSetConfig();            // External Render            libP .SmartP SetExternalRender(p Handle, new RGBAExternalRender());            libP .SmartP SetAudioOutputType(p Handle, 0);            if (isMute) {                libP .SmartP SetMute(p Handle, isMute ? 1                        : 0);            }            if (isHardwareDecoder) {                int isSupportHevcHwDecoder = libP .SetSmartP VideoHevcHWDecoder(p Handle, 1);                int isSupportH264HwDecoder = libP                         .SetSmartP VideoHWDecoder(p Handle, 1);                Log.i(TAG, "isSupportH264HwDecoder: " + isSupportH264HwDecoder + ", isSupportHevcHwDecoder: " + isSupportHevcHwDecoder);            }            libP .SmartP SetLowLatencyMode(p Handle, isLowLatency ? 1                    : 0);            libP .SmartP SetFlipVertical(p Handle, is_flip_vertical ? 1 : 0);            libP .SmartP SetFlipHorizontal(p Handle, is_flip_horizontal ? 1 : 0);            libP .SmartP SetRotation(p Handle, rotate_degrees);            int iPlaybackRet = libP                     .SmartP StartPlay(p Handle);            if (iPlaybackRet != 0) {                Log.e(TAG, "Call SmartP StartPlay failed..");                return;            }            surface_renderer.StartRender();            btnStartStopPlayback.setText("停止播放 ");            isPlaying = true;            Log.i(TAG, "Start playback stream--");
  1. 回调RGBA数据:

class RGBAExternalRender implements NTExternalRender {

    // public static final int NT_ _FORMAT_RGBA = 1;    // public static final int NT_ _FORMAT_ABGR = 2;    // public static final int NT_ _FORMAT_I420 = 3;    private int width_ = 0;    private int height_ = 0;    private int row_bytes_ = 0;    private ByteBuffer rgba_buffer_ = null;    @Override    public int getNT Format() {        Log.i(TAG, "RGBAExternalRender::getNT Format return "                + NT_ _FORMAT_RGBA);        return NT_ _FORMAT_RGBA;    }    @Override    public void onNT SizeChanged(int width, int height) {        width_ = width;        height_ = height;        row_bytes_ = width_ * 4;        Log.i(TAG, "RGBAExternalRender::onNT SizeChanged width_:"                + width_ + " height_:" + height_);        rgba_buffer_ = ByteBuffer.allocateDirect(row_bytes_ * height_);    }    @Override    public ByteBuffer getNTPlaneByteBuffer(int index) {        if (index == 0) {            return rgba_buffer_;        } else {            Log.e(TAG,                    "RGBAExternalRender::getNTPlaneByteBuffer index error:"                            + index);            return null;        }    }    @Override    public int getNTPlanePerRowBytes(int index) {        if (index == 0) {            return row_bytes_;        } else {            Log.e(TAG,                    "RGBAExternalRender::getNTPlanePerRowBytes index error:"                            + index);            return 0;        }    }    public void onNTRender (int width, int height, long timestamp) {        if (rgba_buffer_ == null)            return;       // rgba_buffer_.rewind();        // copy buffer        // test        // byte[] test_buffer = new byte[16];        // rgba_buffer_.get(test_buffer);        //Log.i(TAG, "RGBAExternalRender:onNTRender  w=" + width + " h="        //        + height + " timestamp=" + timestamp);        // Log.i(TAG, "RGBAExternalRender:onNTRender  rgba:" +        // bytesToHexString(test_buffer));        if ( surface_renderer != null)        {            surface_renderer.SetRGBImage(width, height, rgba_buffer_);        }    }}
  1. 对视频view进行放大缩小等状态处理:

    @SuppressLint("ClickableViewAccessibility")
    public RGBSurfaceRenderer(SurfaceView view)
    {

    surface_holder_ = view.getHolder();if (surface_holder_ == null){    Log.e(TAG, "RGBSurfaceRenderer, surfaceHolder with null..");    return;}surface_holder_.addCallback(this);view.setOnTouchListener(new View.OnTouchListener(){    @Override    public boolean onTouch(View v, MotionEvent event)    {        Log.e(TAG, "onTouch called..");        switch (event.getAction() & MotionEvent.ACTION_MASK) {            case MotionEvent.ACTION_DOWN:                start_point_.set(event.getX(), event.getY());                status_ = DRAG;                break;            case MotionEvent.ACTION_POINTER_DOWN:                float distance = spacing(event);                if (distance > 10f) {                    status_ = ZOOM;                    start_distance_ = distance;                }                break;            case MotionEvent.ACTION_MOVE:                if (status_ == DRAG) {                    dragAction(event);                } else {                    if (event.getPointerCount() == 1)                        return true;                    zoomAcition(event);                }                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_POINTER_UP:                status_ = NONE;                break;            default:                break;        }        return true;    }});

    }

  2. 关闭播放:

if (isPlaying) {

            Log.i(TAG, "Stop playback stream++");            int iRet = libP .SmartP StopPlay(p Handle);            if (iRet != 0) {                Log.e(TAG, "Call SmartP StopPlay failed..");                return;            }            surface_renderer.StopRender();            libP .SmartP Close(p Handle);            p Handle = 0;            isPlaying = false;            btnStartStopPlayback.setText("开始播放 ");            Log.i(TAG, "Stop playback stream--");        } 
收藏 打印