Moh*_*lah 16 video android mediacodec
我正在尝试将MediaCodec一系列图像(保存为文件中的字节数组)保存到视频文件中.我已经测试了这些图像SurfaceView(在系列中播放),我可以看到它们很好.我看了很多使用的例子MediaCodec,这是我理解的(如果我错了请纠正我):
从MediaCodec对象获取InputBuffers - >用你的帧的图像数据填充它 - >将输入缓冲区排队 - >获取编码输出缓冲区 - >将其写入文件 - >增加显示时间并重复
但是,我已经对此进行了很多测试,最终我遇到了两种情况之一:
queueInputBuffer在第二次调用时导致Media服务器死机.codec.flush()在最后调用(在将输出缓冲区保存到文件之后,虽然我看到的所有示例都没有这样做)并且媒体服务器没有死,但是,我无法使用任何媒体播放器打开输出视频文件,所以出了点问题.这是我的代码:
MediaCodec codec = MediaCodec.createEncoderByType(MIMETYPE);
MediaFormat mediaFormat = null;
if(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)){
mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 1280 , 720);
} else {
mediaFormat = MediaFormat.createVideoFormat(MIMETYPE, 720, 480);
}
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 700000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
codec.start();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
boolean sawInputEOS = false;
int inputBufferIndex=-1,outputBufferIndex=-1;
BufferInfo info=null;
//loop to read YUV byte array from file
inputBufferIndex = codec.dequeueInputBuffer(WAITTIME);
if(bytesread<=0)sawInputEOS=true;
if(inputBufferIndex >= 0){
if(!sawInputEOS){
int samplesiz=dat.length;
inputBuffers[inputBufferIndex].put(dat);
codec.queueInputBuffer(inputBufferIndex, 0, samplesiz, presentationTime, 0);
presentationTime += 100;
info = new BufferInfo();
outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);
Log.i("BATA", "outputBufferIndex="+outputBufferIndex);
if(outputBufferIndex >= 0){
byte[] array = new byte[info.size];
outputBuffers[outputBufferIndex].get(array);
if(array != null){
try {
dos.write(array);
} catch (IOException e) {
e.printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex, false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
if(sawInputEOS) break;
}
}else{
codec.queueInputBuffer(inputBufferIndex, 0, 0, presentationTime, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
info = new BufferInfo();
outputBufferIndex = codec.dequeueOutputBuffer(info, WAITTIME);
if(outputBufferIndex >= 0){
byte[] array = new byte[info.size];
outputBuffers[outputBufferIndex].get(array);
if(array != null){
try {
dos.write(array);
} catch (IOException e) {
e.printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex, false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
break;
}
}
}
}
codec.flush();
try {
fstream2.close();
dos.flush();
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
codec.stop();
codec.release();
codec = null;
return true;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,如何使用MediaCodec从图像流中获取工作视频.我究竟做错了什么?
另一个问题(如果我不是太贪心),我想为这个视频添加一个音频轨道,也可以用MediaCodec完成,还是我必须使用FFmpeg?
注意:我知道MediaMux在Android 4.3中,它不适合我,因为我的应用程序必须在Android 4.1+上运行.
更新 感谢fadden回答,我能够在没有媒体服务器死亡的情况下到达EOS(上面的代码是在修改后).但是,我得到的文件正在产生胡言乱语.这是我得到的视频的快照(仅适用于.h264文件).

我的输入图像格式是YUV图像(来自相机预览的NV21).我不能让它成为任何可玩的格式.我尝试了所有COLOR_FormatYUV420格式和相同的乱码输出.我仍然无法找到(使用MediaCodec)来添加音频.
fad*_*den 11
我认为你有正确的总体思路.有些事情要注意:
COLOR_FormatYUV420SemiPlanar.有些人只接受平面.(Android 4.3引入了CTS测试,以确保AVC编解码器支持其中一种.)inputBuffers[].clear(),如果它仍然是-1,你将会爆炸).queueInputBuffer呼叫发送EOS .可以丢弃该帧中的数据.始终使用零长度缓冲区发送EOS.编解码器的输出通常非常"原始",例如AVC编解码器发出H.264基本流而不是"熟"的.mp4文件.许多玩家不会接受这种格式.如果您不能依赖于MediaMuxer您的存在,则需要找到另一种方法来烹饪数据(在stackoverflow上搜索想法).
毫无疑问,mediaserver进程会崩溃.
您可以在此处找到一些示例和4.3 CTS测试的链接.
更新:从Android 4.3开始,MediaCodec并Camera没有共同的ByteBuffer格式,所以至少你需要摆弄色度平面.但是,这种问题的表现方式却截然不同(如本问题的图像所示).
您添加的图像看起来像视频,但有大步和/或对齐问题.确保您的像素布局正确.在CTS EncodeDecodeTest中,该generateFrame()方法(第906行)显示了如何编码平面和半平面YUV420 MediaCodec.
避免格式问题的最简单方法是移动帧Surface(如CameraToMpegTest示例),但不幸的是,这在Android 4.1中是不可能的.
| 归档时间: |
|
| 查看次数: |
11912 次 |
| 最近记录: |