android - 如何将原始 h.264 文件转换为 mp4
问题描述
我看到了如何使用 MediaCodec 将视频转换为 mp4。这些示例使用的是 Surface。
然后我认为h.264 => decode => Surface => encode(file),这是一个不必要的encode/decode过程。
是否可以使用 android MediaCodec / MediaMuxer 在不编码/解码的情况下制作原始 h.264 文件 mp4?
更新
我实现了一些代码引用链接(https://developer.android.com/reference/android/media/MediaMuxer)的评论。
while(!finished) {
// getInputBuffer() will fill the inputBuffer with one frame of encoded
// sample from either MediaCodec or MediaExtractor, set isAudioSample to
// true when the sample is audio data, set up all the fields of bufferInfo,
// and return true if there are no more samples.
byte[] tempBuffer = new byte[1000000];
try {
inputBuffer.clear();
int bytesRead = videoFis.read(tempBuffer, 0, inputBuffer.limit());
if(bytesRead <= -1) {
break;
}
else {
inputBuffer.put(tempBuffer, 0, bytesRead);
int currentTrackIndex = videoTrackIndex; // isAudioSample ? audioTrackIndex : videoTrackIndex;
muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);
}
} catch (IOException e) {
e.printStackTrace();
}
}
上面的代码不起作用。我没有得到一帧编码。
// getInputBuffer() will fill the inputBuffer with one frame of encoded
// sample from either MediaCodec or MediaExtractor
为了从原始 h.264 编码一帧,我应该使用 MediaCodec 吗?
更新2
bb.mark();
// read all
while(true) {
try {
int bb2 = videoFis.read(tempBuffer, 0, tempBuffer.length);
if(bb2 != -1) {
bb.put(tempBuffer, 0, bb2);
}
else {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
bb.reset();
int mata[][] = new int[5][256];
mata[0][0] = 1;
mata[1][0] = 2;
mata[2][0] = 3;
mata[3][1] = 4;
int step = 0;
// find first key frame.
while(bb.hasRemaining()) {
step = mata[step][(bb.get() & 0xFF)];
if(step < 4) {
step = mata[step][(bb.get() & 0xFF)];
}
else if(step == 4) {
byte g = bb.get();
if((g & 0x1f) == 5) {
bb.position(bb.position() - 5);
break;
}
}
}
step = 0;
while(!finished) {
int nextPosition = -1;
int offset = bb.position();
bb.get(); bb.get(); bb.get(); bb.get();
byte nalUnit = bb.get();
while(bb.hasRemaining()) {
if(step < 4) {
step = mata[step][(bb.get() & 0xFF)];
}
else if(step == 4) {
byte g = bb.get();
if((g & 0x60) != 0) {
nextPosition = bb.position() - 5;
break;
}
}
}
step = 0;
bufferInfo.flags = (nalUnit & 0x1f) == 5 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0;
bufferInfo.offset = offset;
bufferInfo.size = nextPosition - offset;
bufferInfo.presentationTimeUs += 1000 * 1000 / 15;
Log.d(",,", "offset: " + bufferInfo.offset + "..." + "size: " + bufferInfo.size + "..." + "pts: " + bufferInfo.presentationTimeUs);
muxer.writeSampleData(videoTrackIndex, inputBuffer, bufferInfo);
bb.position(nextPosition);
if(bufferInfo.presentationTimeUs >= 666660)
{
bufferInfo.size = 0;
break;
}
}
muxer.stop();
muxer.release();
像上面的实现一样,我发现 0x00 0x00 0x00 0x01 称为 NAL,我用偏移量、大小、pts 填充了 bufferInfo。但我收到了消息
...
02-23 17:59:25.131 7597-7738/com.example.ksoo.ballbotpkg I/MPEG4Writer: setStartTimestampUs: 66666
Earliest track starting time: 66666
02-23 17:59:25.131 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 284939...size: 10531...pts: 133332
02-23 17:59:25.132 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 295470...size: 15908...pts: 199998
offset: 311378...size: 20194...pts: 266664
02-23 17:59:25.133 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 331572...size: 20628...pts: 333330
offset: 352200...size: 21346...pts: 399996
02-23 17:59:25.134 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 373546...size: 21407...pts: 466662
02-23 17:59:25.134 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 394953...size: 22494...pts: 533328
02-23 17:59:25.135 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 417447...size: 23230...pts: 599994
02-23 17:59:25.135 7597-7597/com.example.ksoo.ballbotpkg D/,,: offset: 440677...size: 23820...pts: 666660
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg I/MPEG4Writer: Normal stop process
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopping. Stop source
Video track source stopping
Video track source stopped
02-23 17:59:25.136 7597-7738/com.example.ksoo.ballbotpkg I/MPEG4Writer: Received total/0-length (10/0) buffers and encoded 10 frames. - Video
02-23 17:59:25.136 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopped. Stop source
Stopping writer thread
02-23 17:59:25.137 7597-7737/com.example.ksoo.ballbotpkg D/MPEG4Writer: 0 chunks are written in the last batch
02-23 17:59:25.137 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Writer thread stopped
02-23 17:59:25.138 7597-7597/com.example.ksoo.ballbotpkg I/MPEG4Writer: The mp4 file will not be streamable.
02-23 17:59:25.138 7597-7597/com.example.ksoo.ballbotpkg D/MPEG4Writer: Video track stopping. Stop source
我犯错了吗?
解决方案
推荐阅读
- reactjs - React 原生网页分割点
- java - Java:格式化嵌套循环?
- list - 如何在可迭代列表中应用函数
- bluetooth-lowenergy - C ++如何在回调arduino之外查询值
- php - 基于其他下拉列表的 ajax 和 jQuery 动态下拉列表(来自数据库的数据)
- postgresql - 使用 EXPLAIN ANALYZE 确定是否可以进行改进时,您会寻找什么
- python - 如何在 OBS 中将 python-osc 作为脚本运行?
- godot - 不知道如何在脚本中引用其他场景
- gradle - Gradle WSL:来自 buildSrc 的未知属性
- javascript - 我如何解决 Promise.all