You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于TextureView播放的RTSP流录制MP4片段?

嘿,刚好我之前做过类似的需求,用Android自带的MediaRecorder就能完美实现你要的录制RTSP流片段并保存为MP4的功能,而且完全能控制开始/停止按钮触发期间的内容。下面是具体的实现方案,我帮你整合到你的现有代码里:

核心思路

我们用MediaRecorder直接绑定RTSP流数据源,通过按钮点击控制它的start()和stop()方法,就能精准录制你想要的时间段内容。如果需要边播边录,也可以把MediaPlayer的播放Surface绑定到MediaRecorder的Surface上,实现同步播放和录制。

步骤1:添加必要权限

先在AndroidManifest.xml里补上权限(Android 10+还要额外加存储权限):

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- Android 10及以上需要这个权限 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

注意:Android 6.0+ 必须动态申请WRITE_EXTERNAL_STORAGE和RECORD_AUDIO权限,不然会直接崩溃,记得在代码里做权限申请逻辑哦!

步骤2:添加全局变量

在你的Activity/Fragment里添加几个全局变量,用来管理录制状态和录制实例:

private MediaRecorder mMediaRecorder;
private boolean isRecording = false;
// 录制文件的输出路径,你可以自己调整存储目录
private String mOutputFilePath;

步骤3:封装MediaRecorder初始化方法

把录制的配置逻辑封装成一个方法,方便调用,这里要特别注意配置顺序不能乱:

private void initMediaRecorder() throws IOException {
    mMediaRecorder = new MediaRecorder();
    // 设置RTSP流数据源
    mMediaRecorder.setDataSource(String.valueOf(Uri.parse("rtsp://........./")));
    
    // 配置视频参数
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
    // 分辨率建议和RTSP流实际分辨率一致,避免拉伸或模糊
    mMediaRecorder.setVideoSize(1280, 720);
    // 帧率匹配RTSP流的实际帧率,常见的是25或30
    mMediaRecorder.setVideoFrameRate(25);
    
    // 配置音频参数(不需要录音频的话可以直接注释掉这部分)
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    mMediaRecorder.setAudioSamplingRate(44100);
    mMediaRecorder.setAudioChannels(1);
    
    // 设置输出文件路径,这里存在系统的Movies目录下
    File outputDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
    mOutputFilePath = outputDir.getAbsolutePath() + "/RTSP_Record_" + System.currentTimeMillis() + ".mp4";
    mMediaRecorder.setOutputFile(mOutputFilePath);
    
    // 准备录制
    mMediaRecorder.prepare();
}

步骤4:修改录制按钮的点击事件

替换你原来的recordVideo点击事件逻辑,实现开始/停止录制的切换:

recordVideo.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (!isRecording) {
            // 开始录制
            try {
                // 先停止当前的MediaPlayer播放(如果不需要边播边录的话)
                if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
                    mMediaPlayer.stop();
                    mMediaPlayer.release();
                    mMediaPlayer = null;
                }
                
                initMediaRecorder();
                mMediaRecorder.start();
                isRecording = true;
                recordVideo.setText("停止录制"); // 切换按钮文字
                
                // 【可选】如果需要边播边录,取消下面注释,用MediaRecorder的Surface播放
                /*
                mMediaPlayer = new MediaPlayer();
                mMediaPlayer.setDataSource(String.valueOf(Uri.parse("rtsp://........./")));
                // 将MediaPlayer的播放Surface绑定到MediaRecorder的Surface
                mMediaPlayer.setSurface(mMediaRecorder.getSurface());
                mMediaPlayer.prepareAsync();
                mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        mp.start();
                    }
                });
                */
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(getApplicationContext(), "录制初始化失败", Toast.LENGTH_SHORT).show();
            }
        } else {
            // 停止录制
            if (mMediaRecorder != null) {
                try {
                    mMediaRecorder.stop();
                    mMediaRecorder.release();
                    mMediaRecorder = null;
                    isRecording = false;
                    recordVideo.setText("开始录制"); // 切换按钮文字
                    Toast.makeText(getApplicationContext(), "录制完成!文件路径:" + mOutputFilePath, Toast.LENGTH_LONG).show();
                    
                    // 【可选】停止录制后重启MediaPlayer播放
                    restartMediaPlayer();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(), "录制停止失败", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
});

步骤5:添加重启播放的方法(可选)

如果停止录制后需要恢复RTSP流播放,可以加这个方法:

private void restartMediaPlayer() {
    if (mMediaPlayer == null) {
        mMediaPlayer = new MediaPlayer();
        try {
            mMediaPlayer.setDataSource(String.valueOf(Uri.parse("rtsp://........./")));
            mMediaPlayer.setSurface(surface);
            mMediaPlayer.setLooping(true);
            mMediaPlayer.prepareAsync();
            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mediaPlayer) {
                    mediaPlayer.start();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最后:别忘了释放资源

在Activity的onDestroy方法里,一定要释放MediaPlayer和MediaRecorder的资源,避免内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mMediaPlayer != null) {
        mMediaPlayer.stop();
        mMediaPlayer.release();
        mMediaPlayer = null;
    }
    if (mMediaRecorder != null) {
        mMediaRecorder.release();
        mMediaRecorder = null;
    }
}

内容的提问来源于stack exchange,提问作者Andrea Avesani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:25:46