private void releaseMuxer() {
    if (VERBOSE) {
      Log.v(TAG, "releasing muxer");
    }

    if (mMuxer != null) {
      mMuxer.stop();
      mMuxer.release();
      mMuxer = null;
    }
  }
  private void release() {

    if (mEncoder != null) {
      mEncoder.stop();
      mEncoder.release();
      mEncoder = null;
    }

    if (mVirtualDisplay != null) {
      mVirtualDisplay.release();
    }

    if (displayManager != null) {
      displayManager = null;
    }
    if (mediaMuxer != null) {
      mediaMuxer.stop();
      mediaMuxer.release();
      mediaMuxer = null;
    }
  }
  private void recordVideo() {
    ByteBuffer[] encodeOutputBuffers = mEncoder.getOutputBuffers();
    while (!endEncode.get()) {
      int encoderIndex = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_US);
      if (encoderIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
        if (mediaMuxerStarted) {
          throw new IllegalStateException("output format already changed");
        }
        MediaFormat newFormat = mEncoder.getOutputFormat();
        videoTrackIndex = mediaMuxer.addTrack(newFormat);
        mediaMuxer.start();
        mediaMuxerStarted = true;
      } else if (encoderIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
        try {
          Thread.sleep(10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      } else if (encoderIndex < 0) {
        Log.w(TAG, "encoderIndex 非法" + encoderIndex);
      } else if (encoderIndex >= 0) {
        ByteBuffer encodeData = encodeOutputBuffers[encoderIndex];
        if (encodeData == null) {
          throw new RuntimeException("编码数据为空");
        }
        if (mBufferInfo.size != 0) {
          if (!mediaMuxerStarted) throw new RuntimeException("混合器未开启");
          encodeData.position(mBufferInfo.offset);
          encodeData.limit(mBufferInfo.offset + mBufferInfo.size);

          mediaMuxer.writeSampleData(videoTrackIndex, encodeData, mBufferInfo);
          mEncoder.releaseOutputBuffer(encoderIndex, false);
        }
      }
    }
  }
  /**
   * Do encoding by using MediaCodec encoder, then extracts all pending data from the encoder and
   * forwards it to the muxer.
   *
   * <p>If notifyEndOfStream is not set, this returns when there is no more data to output. If it is
   * set, we send EOS to the encoder, and then iterate until we see EOS on the output. Calling this
   * with notifyEndOfStream set should be done once, before stopping the muxer.
   *
   * <p>We're just using the muxer to get a .mp4 file and audio is not included here.
   */
  private void doMediaCodecEncoding(boolean notifyEndOfStream) {
    if (VERBOSE) {
      Log.v(TAG, "doMediaCodecEncoding(" + notifyEndOfStream + ")");
    }

    if (notifyEndOfStream) {
      mEncoder.signalEndOfInputStream();
    }

    ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
    boolean notDone = true;
    while (notDone) {
      int encoderStatus = mEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
      if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
        if (!notifyEndOfStream) {
          /**
           * Break out of the while loop because the encoder is not ready to output anything yet.
           */
          notDone = false;
        } else {
          if (VERBOSE) {
            Log.v(TAG, "no output available, spinning to await EOS");
          }
        }
      } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
        // generic case for mediacodec, not likely occurs for encoder.
        encoderOutputBuffers = mEncoder.getOutputBuffers();
      } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
        /** should happen before receiving buffers, and should only happen once */
        if (mMuxerStarted) {
          throw new IllegalStateException("format changed twice");
        }
        MediaFormat newFormat = mEncoder.getOutputFormat();
        if (VERBOSE) {
          Log.v(TAG, "encoder output format changed: " + newFormat);
        }
        mTrackIndex = mMuxer.addTrack(newFormat);
        mMuxer.start();
        mMuxerStarted = true;
      } else if (encoderStatus < 0) {
        Log.w(TAG, "unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
      } else {
        // Normal flow: get output encoded buffer, send to muxer.
        ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
        if (encodedData == null) {
          throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
        }

        if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
          /**
           * The codec config data was pulled out and fed to the muxer when we got the
           * INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
           */
          if (VERBOSE) {
            Log.v(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
          }
          mBufferInfo.size = 0;
        }

        if (mBufferInfo.size != 0) {
          if (!mMuxerStarted) {
            throw new RuntimeException("muxer hasn't started");
          }

          /** It's usually necessary to adjust the ByteBuffer values to match BufferInfo. */
          encodedData.position(mBufferInfo.offset);
          encodedData.limit(mBufferInfo.offset + mBufferInfo.size);

          mMuxer.writeSampleData(mTrackIndex, encodedData, mBufferInfo);
          if (VERBOSE) {
            Log.v(TAG, "sent " + mBufferInfo.size + " bytes to muxer");
          }
        }

        mEncoder.releaseOutputBuffer(encoderStatus, false);

        if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
          if (!notifyEndOfStream) {
            Log.w(TAG, "reached end of stream unexpectedly");
          } else {
            if (VERBOSE) {
              Log.v(TAG, "end of stream reached");
            }
          }
          // Finish encoding.
          notDone = false;
        }
      }
    } // End of while(notDone)
  }