Android中MP4视频编码及SQLite视频存储与检索播放问题
Hey there! Let's break down your two Android questions clearly, step by step.
1. 如何在Android平台中对MP4格式视频进行编码?
在Android上编码MP4视频,常用的方案有三种,各有适用场景:
原生MediaCodec API(高性能、系统级支持)
这是Android官方推荐的底层编码方案,直接调用系统硬件编码器,性能最优。核心步骤如下:- 配置
MediaFormat,指定MP4常用的H.264编码(MIME类型为video/avc),并设置分辨率、比特率、帧率等参数:MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 1920, 1080); videoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000); // 6Mbps比特率 videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); // 每5帧生成一个关键帧 - 创建
MediaCodec实例并启动,循环处理输入的原始视频帧(比如从Camera预览的Surface获取数据),输出编码后的H.264流。 - 使用
MediaMuxer将编码后的视频流(若需要音频则同步处理音频编码)封装为MP4文件。
提示:需要注意缓冲区的操作逻辑,以及不同Android版本的兼容性差异,处理过程中要做好异常捕获。
- 配置
FFmpeg库(高灵活性、跨平台)
如果需要自定义编码逻辑或支持更多格式,可集成FFmpeg。步骤如下:- 编译FFmpeg的Android适配版本,或者使用现成的预编译库(如mobile-ffmpeg)。
- 通过JNI调用FFmpeg API,配置编码参数(指定输出格式为MP4,编码器为libx264等)。
- 输入原始视频数据,编码后写入MP4文件。
优点是功能强大,缺点是会增大APK包体积。
MediaRecorder(快速实现、低自定义)
如果你只是需要录制Camera或屏幕内容生成MP4,MediaRecorder是最简便的选择——它封装了MediaCodec和MediaMuxer,无需处理底层细节:MediaRecorder recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); recorder.setOutputFile(getExternalFilesDir(null) + "/recorded_video.mp4"); recorder.setPreviewDisplay(surfaceHolder.getSurface()); recorder.prepare(); recorder.start(); // 录制结束后释放资源 // recorder.stop(); // recorder.release();
2. 从SQLite数据库中检索视频并播放
首先要说明:SQLite并不适合存储大体积视频(会导致数据库臃肿、读写性能下降),更推荐存储视频的文件路径到数据库而非直接存字节数组。不过针对你已实现的存储逻辑,以下是检索和播放的方案:
步骤1:从数据库读取视频字节数组
// 假设db是你的SQLiteDatabase实例 Cursor cursor = db.query("tb", new String[]{"a"}, null, null, null, null, null); byte[] videoBytes = null; if (cursor.moveToFirst()) { // 读取blob类型的字段 videoBytes = cursor.getBlob(cursor.getColumnIndexOrThrow("a")); } cursor.close(); // 记得关闭Cursor释放资源
步骤2:将字节数组写入临时文件
MediaPlayer无法直接播放字节数组,所以需要先把字节数组写入一个临时文件:
File tempVideoFile = null; if (videoBytes != null) { try { // 在应用缓存目录创建临时MP4文件 tempVideoFile = File.createTempFile("temp_video", ".mp4", getCacheDir()); FileOutputStream fos = new FileOutputStream(tempVideoFile); fos.write(videoBytes); fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } }
步骤3:使用MediaPlayer播放临时文件
MediaPlayer mediaPlayer = new MediaPlayer(); if (tempVideoFile != null && tempVideoFile.exists()) { try { mediaPlayer.setDataSource(tempVideoFile.getAbsolutePath()); mediaPlayer.prepare(); mediaPlayer.start(); // 播放完成后释放资源并删除临时文件 mediaPlayer.setOnCompletionListener(mp -> { mp.release(); if (tempVideoFile.exists()) { tempVideoFile.delete(); } }); } catch (IOException e) { e.printStackTrace(); mediaPlayer.release(); // 异常时也要清理临时文件 if (tempVideoFile.exists()) { tempVideoFile.delete(); } } }
额外提示:如果视频体积较大,一次性读取字节数组可能引发OOM(内存溢出),这种情况下更不建议用SQLite存储视频,转而存储文件路径会更稳妥。
内容的提问来源于stack exchange,提问作者Amir




