很多开发者希望Android播放端实现视频窗口的放大缩小功能,为此,我们做了个简单的demo,通过播放端回调RGB数据,直接在上层view操作处理即可,Github:https://github.com/daniulive/SmarterStreaming
无视频无真相:http://www.iqiyi.com/w_19s9sa7epp.html
基本流程如下:
1. 基础的初始化和参数设定
libPlayer = new SmartPlayerJniV2();myContext = this.getApplicationContext();sSurfaceView = (SurfaceView) this.findViewById(R.id.surface);surface_renderer = new RGBSurfaceRenderer(sSurfaceView);
private void InitAndSetConfig() {playerHandle = libPlayer.SmartPlayerOpen(myContext);if (playerHandle == 0) {Log.e(TAG, "surfaceHandle with nil..");return;}libPlayer.SetSmartPlayerEventCallbackV2(playerHandle,new EventHandeV2());libPlayer.SmartPlayerSetBuffer(playerHandle, playBuffer);// set report download speed(默认2秒一次回调 用户可自行调整report间隔)libPlayer.SmartPlayerSetReportDownloadSpeed(playerHandle, 1, 2);libPlayer.SmartPlayerSetFastStartup(playerHandle, isFastStartup ? 1 : 0);//设置RTSP超时时间int rtsp_timeout = 10;libPlayer.SmartPlayerSetRTSPTimeout(playerHandle, rtsp_timeout);//设置RTSP TCP/UDP模式自动切换int is_auto_switch_tcp_udp = 1;libPlayer.SmartPlayerSetRTSPAutoSwitchTcpUdp(playerHandle, is_auto_switch_tcp_udp);libPlayer.SmartPlayerSaveImageFlag(playerHandle, 1);// It only used when playback RTSP stream..// libPlayer.SmartPlayerSetRTSPTcpMode(playerHandle, 1);playbackUrl = "rtmp://202.69.69.180:443/webcast/bshdlive-pc";//playbackUrl = "rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov";libPlayer.SmartPlayerSetUrl(playerHandle, playbackUrl);}
2. 设置External Render,回调RGBA数据
libPlayer.SmartPlayerSetExternalRender(playerHandle, new RGBAExternalRender());
Log.i(TAG, "Start playback stream++");InitAndSetConfig();// External RenderlibPlayer.SmartPlayerSetExternalRender(playerHandle, new RGBAExternalRender());libPlayer.SmartPlayerSetAudioOutputType(playerHandle, 0);if (isMute) {libPlayer.SmartPlayerSetMute(playerHandle, isMute ? 1: 0);}if (isHardwareDecoder) {int isSupportHevcHwDecoder = libPlayer.SetSmartPlayerVideoHevcHWDecoder(playerHandle, 1);int isSupportH264HwDecoder = libPlayer.SetSmartPlayerVideoHWDecoder(playerHandle, 1);Log.i(TAG, "isSupportH264HwDecoder: " + isSupportH264HwDecoder + ", isSupportHevcHwDecoder: " + isSupportHevcHwDecoder);}libPlayer.SmartPlayerSetLowLatencyMode(playerHandle, isLowLatency ? 1: 0);libPlayer.SmartPlayerSetFlipVertical(playerHandle, is_flip_vertical ? 1 : 0);libPlayer.SmartPlayerSetFlipHorizontal(playerHandle, is_flip_horizontal ? 1 : 0);libPlayer.SmartPlayerSetRotation(playerHandle, rotate_degrees);int iPlaybackRet = libPlayer.SmartPlayerStartPlay(playerHandle);if (iPlaybackRet != 0) {Log.e(TAG, "Call SmartPlayerStartPlay failed..");return;}surface_renderer.StartRender();btnStartStopPlayback.setText("停止播放 ");isPlaying = true;Log.i(TAG, "Start playback stream--");
3. 回调RGBA数据:
class RGBAExternalRender implements NTExternalRender {// public static final int NT_FRAME_FORMAT_RGBA = 1;// public static final int NT_FRAME_FORMAT_ABGR = 2;// public static final int NT_FRAME_FORMAT_I420 = 3;private int width_ = 0;private int height_ = 0;private int row_bytes_ = 0;private ByteBuffer rgba_buffer_ = null;@Overridepublic int getNTFrameFormat() {Log.i(TAG, "RGBAExternalRender::getNTFrameFormat return "+ NT_FRAME_FORMAT_RGBA);return NT_FRAME_FORMAT_RGBA;}@Overridepublic void onNTFrameSizeChanged(int width, int height) {width_ = width;height_ = height;row_bytes_ = width_ * 4;Log.i(TAG, "RGBAExternalRender::onNTFrameSizeChanged width_:"+ width_ + " height_:" + height_);rgba_buffer_ = ByteBuffer.allocateDirect(row_bytes_ * height_);}@Overridepublic ByteBuffer getNTPlaneByteBuffer(int index) {if (index == 0) {return rgba_buffer_;} else {Log.e(TAG,"RGBAExternalRender::getNTPlaneByteBuffer index error:"+ index);return null;}}@Overridepublic int getNTPlanePerRowBytes(int index) {if (index == 0) {return row_bytes_;} else {Log.e(TAG,"RGBAExternalRender::getNTPlanePerRowBytes index error:"+ index);return 0;}}public void onNTRenderFrame(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:onNTRenderFrame w=" + width + " h="// + height + " timestamp=" + timestamp);// Log.i(TAG, "RGBAExternalRender:onNTRenderFrame rgba:" +// bytesToHexString(test_buffer));if ( surface_renderer != null){surface_renderer.SetRGBImage(width, height, rgba_buffer_);}}}
4. 对视频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(){@Overridepublic 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;}});}
5. 关闭播放:
if (isPlaying) {Log.i(TAG, "Stop playback stream++");int iRet = libPlayer.SmartPlayerStopPlay(playerHandle);if (iRet != 0) {Log.e(TAG, "Call SmartPlayerStopPlay failed..");return;}surface_renderer.StopRender();libPlayer.SmartPlayerClose(playerHandle);playerHandle = 0;isPlaying = false;btnStartStopPlayback.setText("开始播放 ");Log.i(TAG, "Stop playback stream--");}