Android播放器实现视频窗口实时放大缩小功能

  • 2019 年 10 月 4 日
  • 筆記

很多开发者希望Android播放端实现视频窗口的放大缩小功能,为此,我们做了个简单的demo,通过播放端回调RGB数据,直接在上层view操作处理即可,相关资料 可以查看 Github

基本流程如下:

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 Render                  libPlayer.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;            @Override          public int getNTFrameFormat() {              Log.i(TAG, "RGBAExternalRender::getNTFrameFormat return "                      + NT_FRAME_FORMAT_RGBA);              return NT_FRAME_FORMAT_RGBA;          }            @Override          public 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_);          }            @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 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()              {                  @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;                  }              });            }

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--");              }