Android 使用MediaCodec将一系列图像保存为视频
我正在尝试使用Android 使用MediaCodec将一系列图像保存为视频,android,video,android-mediacodec,Android,Video,Android Mediacodec,我正在尝试使用MediaCodec将一系列图像(保存为文件中的字节数组)保存到视频文件中。我已经在SurfaceView上测试了这些图像(连续播放),我可以很好地看到它们。我看过许多使用MediaCodec的例子,以下是我的理解(如果我错了,请纠正我): 从MediaCodec对象获取InputBuffers->用帧的 图像数据->将输入缓冲区排队->获取编码输出缓冲区-> 将其写入文件->增加演示时间并重复 然而,我已经对此进行了大量测试,最终得到了两个案例中的一个: 我尝试模拟的所有示例项
MediaCodec
将一系列图像(保存为文件中的字节数组)保存到视频文件中。我已经在SurfaceView上测试了这些图像(连续播放),我可以很好地看到它们。我看过许多使用MediaCodec
的例子,以下是我的理解(如果我错了,请纠正我):
从MediaCodec对象获取InputBuffers->用帧的
图像数据->将输入缓冲区排队->获取编码输出缓冲区->
将其写入文件->增加演示时间并重复
然而,我已经对此进行了大量测试,最终得到了两个案例中的一个:
- 我尝试模拟的所有示例项目都在第二次调用
queueInputBuffer
时导致媒体服务器死亡
- 最后我尝试调用
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;
}
mediacodecodec=MediaCodec.createEncoderByType(MIMETYPE);
MediaFormat MediaFormat=null;
if(摄像机档案文件hasProfile(摄像机档案文件质量_720P)){
mediaFormat=mediaFormat.createVideoFormat(MIMETYPE,1280720);
}否则{
mediaFormat=mediaFormat.createVideoFormat(MIMETYPE,720480);
}
mediaFormat.setInteger(mediaFormat.KEY\u比特率,700000);
mediaFormat.setInteger(mediaFormat.KEY\u FRAME\u RATE,10);
mediaFormat.setInteger(mediaFormat.KEY\u COLOR\u FORMAT,MediaCodecInfo.CodecCapabilities.COLOR\u formatyuv420semipular);
mediaFormat.setInteger(mediaFormat.KEY\u I\u FRAME\u INTERVAL,5);
codec.configure(mediaFormat,null,null,MediaCodec.configure\u FLAG\u ENCODE);
codec.start();
ByteBuffer[]inputBuffers=codec.getInputBuffers();
ByteBuffer[]outputBuffers=codec.getOutputBuffers();
布尔值sawInputEOS=false;
int-inputBufferIndex=-1,outputBufferIndex=-1;
BufferInfo=null;
//循环从文件中读取YUV字节数组
inputBufferIndex=codec.dequeueInputBuffer(WAITTIME);
如果(字节读取=0){
如果(!sawInputEOS){
int samplesiz=dat.length;
inputBuffers[inputBufferIndex].put(dat);
queueInputBuffer(inputBufferIndex,0,samplesiz,presentationTime,0);
presentationTime+=100;
info=新的BufferInfo();
outputBufferIndex=codec.dequeueOutputBuffer(信息,等待时间);
Log.i(“BATA”、“outputBufferIndex=“+outputBufferIndex”);
如果(outputBufferIndex>=0){
字节[]数组=新字节[info.size];
outputBuffers[outputBufferIndex].get(数组);
if(数组!=null){
试一试{
写(数组);
}捕获(IOE异常){
e、 printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex,false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
如果(锯入)断裂;
}
}否则{
codec.queueInputBuffer(inputBufferIndex,0,0,presentationTime,MediaCodec.BUFFER\u标志\u结束\u流);
info=新的BufferInfo();
outputBufferIndex=codec.dequeueOutputBuffer(信息,等待时间);
如果(outputBufferIndex>=0){
字节[]数组=新字节[info.size];
outputBuffers[outputBufferIndex].get(数组);
if(数组!=null){
试一试{
写(数组);
}捕获(IOE异常){
e、 printStackTrace();
}
}
codec.releaseOutputBuffer(outputBufferIndex,false);
inputBuffers[inputBufferIndex].clear();
outputBuffers[outputBufferIndex].clear();
打破
}
}
}
}
codec.flush();
试一试{
fstream2.close();
dos.flush();
dos.close();
}捕获(IOE异常){
e、 printStackTrace();
}
codec.stop();
codec.release();
编解码器=空;
返回true;
}
我的问题是,如何使用MediaCodec从图像流中获取工作视频。我做错了什么
另一个问题(如果我不是太贪心的话),我想在这个视频中添加一个音频曲目,它也可以用MediaCodec完成,还是必须使用FFmpeg
注意:我知道Android 4.3中的MediaMux
,但是,这不是我的选择,因为我的应用程序必须在Android 4.1+上运行
更新
多亏了fadden的回答,我能够在媒体服务器不死掉的情况下访问EOS(上面的代码是经过修改的)。然而,我得到的文件却在胡言乱语。这是我得到的视频快照(仅作为.h264文件使用)
我的输入图像格式是YUV图像(相机预览中的NV21)。我不能让它成为任何可播放的格式。我尝试了所有的颜色格式Yuv420格式和相同的胡言乱语输出。我仍然无法找到(使用MediaCodec)添加音频的方法。我认为您的总体思路是正确的。需要注意的一些事项:
- 并非所有设备都支持
COLOR\u FormatYUV420