android 使用MediaCodec 编解码总结.docx
- 文档编号:25988242
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:13
- 大小:17.56KB
android 使用MediaCodec 编解码总结.docx
《android 使用MediaCodec 编解码总结.docx》由会员分享,可在线阅读,更多相关《android 使用MediaCodec 编解码总结.docx(13页珍藏版)》请在冰豆网上搜索。
android使用MediaCodec编解码总结
android使用MediaCodec编解码总结
本文将主要介绍在安卓中调用MediaCodec类实现视频文件的硬解码,以及如何将以byte[]类型存储的图像数据通过硬编码合成视频文件。
1.MediaCodec类的编解码原理
参考链接:
https:
//developer.A
工作流是这样的:
以编码为例,首先要初始化硬件编码器,配置要编码的格式、视频文件的长宽、码率、帧率、关键帧间隔等等。
这一步叫configure。
之后开启编码器,当前编码器便是可用状态,随时准备接收数据。
下一个过程便是编码的running过程,在此过程中,需要维护两个buffer队列,InputBuffer和OutputBuffer,用户需要不断出队InputBuffer(即dequeueInputBuffer),往里边放入需要编码的图像数据之后再入队等待处理,然后硬件编码器开始异步处理,一旦处理结束,他会将数据放在OutputBuffer中,并且通知用户当前有输出数据可用了,那么用户就可以出队一个OutputBuffer,将其中的数据拿走,然后释放掉这个buffer。
结束条件在于end-of-stream这个flag标志位的设定。
在编码结束后,编码器调用stop函数停止编码,之后调用release函数将编码器完全释放掉,整体流程结束。
2.视频解码程序示例
代码来源于
Android:
MediaCodec视频文件硬件解码以下所有代码可以在此处下载[java]viewplaincopy
print?
packagecom.example.guoheng_iri.helloworld;
importandroid.graphics.ImageFormat;
importandroid.graphics.Rect;
importandroid.graphics.YuvImage;
importandroid.media.Image;
importandroid.media.MediaCodec;
importandroid.media.MediaCodecInfo;
importandroid.media.MediaExtractor;
importandroid.media.MediaFormat;
importandroid.util.Log;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.nio.ByteBuffer;
importjava.util.concurrent.LinkedBlockingQueue;
publicclassVideoDecode{
privatestaticfinalStringTAG="VideoToFrames";
privatestaticfinalbooleanVERBOSE=true;
privatestaticfinallongDEFAULT_TIMEOUT_US=10000;
privatestaticfinalintCOLOR_FormatI420=1;
privatestaticfinalintCOLOR_FormatNV21=2;
publicstaticfinalintFILE_TypeI420=1;
publicstaticfinalintFILE_TypeNV21=2;
publicstaticfinalintFILE_TypeJPEG=3;
privatefinalintdecodeColorFormat=MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
privateintoutputImageFileType=-1;
privateStringOUTPUT_DIR;
publicintImageWidth=0;
publicintImageHeight=0;
MediaExtractorextractor=null;
MediaCodecdecoder=null;
MediaFormatmediaFormat;
publicvoidsetSaveFrames(Stringdir,intfileType)throwsIOException{
if(fileType!
=FILE_TypeI420&&fileType!
=FILE_TypeNV21&&fileType!
=FILE_TypeJPEG){
thrownewIllegalArgumentException("onlysupportFILE_TypeI420"+"andFILE_TypeNV21"+"andFILE_TypeJPEG");
}
outputImageFileType=fileType;
FiletheDir=newFile(dir);
if(!
theDir.exists()){
theDir.mkdirs();
}elseif(!
theDir.isDirectory()){
thrownewIOException("Notadirectory");
}
OUTPUT_DIR=theDir.getAbsolutePath()+"/";
}
publicvoidVideoDecodePrepare(StringvideoFilePath){
extractor=null;
decoder=null;
try{
FilevideoFile=newFile(videoFilePath);
extractor=newMediaExtractor();
extractor.setDataSource(videoFile.toString());
inttrackIndex=selectTrack(extractor);
if(trackIndex<0){
thrownewRuntimeException("Novideotrackfoundin"+videoFilePath);
}
extractor.selectTrack(trackIndex);
mediaFormat=extractor.getTrackFormat(trackIndex);
Stringmime=mediaFormat.getString(MediaFormat.KEY_MIME);
decoder=MediaCodec.createDecoderByType(mime);
showSupportedColorFormat(decoder.getCodecInfo().getCapabilitiesForType(mime));
if(isColorFormatSupported(decodeColorFormat,decoder.getCodecInfo().getCapabilitiesForType(mime))){
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,decodeColorFormat);
Log.i(TAG,"setdecodecolorformattotype"+decodeColorFormat);
}else{
Log.i(TAG,"unabletosetdecodecolorformat,colorformattype"+decodeColorFormat+"notsupported");
}
decoder.configure(mediaFormat,null,null,0);
decoder.start();
}catch(IOExceptionioe){
thrownewRuntimeException("failedinitencoder",ioe);
}
}
publicvoidclose(){
decoder.stop();
decoder.release();
if(extractor!
=null){
extractor.release();
extractor=null;
}
}
publicvoidexcuate()
{
try{
decodeFramesToImage(decoder,extractor,mediaFormat);
}finally{
//releaseencoder,muxer,andinputSurface
close();
}
}
privatevoidshowSupportedColorFormat(MediaCodecInfo.CodecCapabilitiescaps){
System.out.print("supportedcolorformat:
");
for(intc:
caps.colorFormats){
System.out.print(c+"\t");
}
System.out.println();
}
privatebooleanisColorFormatSupported(intcolorFormat,MediaCodecInfo.CodecCapabilitiescaps){
for(intc:
caps.colorFormats){
if(c==colorFormat){
returntrue;
}
}
returnfalse;
}
publicvoiddecodeFramesToImage(MediaCodecdecoder,MediaExtractorextractor,MediaFormatmediaFormat){
MediaCodec.BufferInfoinfo=newMediaCodec.BufferInfo();
booleansawInputEOS=false;
booleansawOutputEOS=false;
finalintwidth=mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
finalintheight=mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
ImageWidth=width;
ImageHeight=height;
intoutputFrameCount=0;
while(!
sawOutputEOS){
if(!
sawInputEOS){
intinputBufferId=decoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);
if(inputBufferId>=0){
ByteBufferinputBuffer=decoder.getInputBuffer(inputBufferId);
intsampleSize=extractor.readSampleData(inputBuffer,0);//将一部分视频数据读取到inputbuffer中,大小为sampleSize
if(sampleSize<0){
decoder.queueInputBuffer(inputBufferId,0,0,0L,MediaCodec.BUFFER_FLAG_END_OF_STREAM);
sawInputEOS=true;
}else{
longpresentationTimeUs=extractor.getSampleTime();
decoder.queueInputBuffer(inputBufferId,0,sampleSize,presentationTimeUs,0);
extractor.advance();//移动到视频文件的下一个地址
}
}
}
intoutputBufferId=decoder.dequeueOutputBuffer(info,DEFAULT_TIMEOUT_US);
if(outputBufferId>=0){
if((info.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!
=0){
sawOutputEOS=true;
}
booleandoRender=(info.size!
=0);
if(doRender){
outputFrameCount++;
Imageimage=decoder.getOutputImage(outputBufferId);
System.out.println("imageformat:
"+image.getFormat());
if(outputImageFileType!
=-1){
StringfileName;
switch(outputImageFileType){
caseFILE_TypeI420:
fileName=OUTPUT_DIR+String.format("frame_%05d_I420_%dx%d.yuv",outputFrameCount,width,height);
dumpFile(fileName,getDataFromImage(image,COLOR_FormatI420));
break;
caseFILE_TypeNV21:
fileName=OUTPUT_DIR+String.format("frame_%05d_NV21_%dx%d.yuv",outputFrameCount,width,height);
dumpFile(fileName,getDataFromImage(image,COLOR_FormatNV21));
break;
caseFILE_TypeJPEG:
fileName=OUTPUT_DIR+String.format("frame_%05d.jpg",outputFrameCount);
compressToJpeg(fileName,image);
break;
}
}
image.close();
decoder.releaseOutputBuffer(outputBufferId,true);
}
}
}
}
privatestaticintselectTrack(MediaExtractorextractor){
intnumTracks=extractor.getTrackCount();
for(inti=0;i<numTracks;i++){
MediaFormatformat=extractor.getTrackFormat(i);
Stringmime=format.getString(MediaFormat.KEY_MIME);
if(mime.startsWith("video/")){
if(VERBOSE){
Log.d(TAG,"Extractorselectedtrack"+i+"("+mime+"):
"+format);
}
returni;
}
}
return-1;
}
privatestaticbooleanisImageFormatSupported(Imageimage){
intformat=image.getFormat();
switch(format){
caseImageFormat.YUV_420_888:
caseImageFormat.NV21:
caseImageFormat.YV12:
returntrue;
}
returnfalse;
}
publicstaticbyte[]getGrayFromData(Imageimage,intcolorFormat){
if(colorFormat!
=COLOR_FormatI420&&colorFormat!
=COLOR_FormatNV21){
thrownewIllegalArgumentException("onlysupportCOLOR_FormatI420"+"andCOLOR_FormatNV21");
}
if(!
isImageFormatSupported(image)){
thrownewRuntimeException("can'tconvertImagetobytearray,format"+image.getFormat());
}
Image.Plane[]planes=image.getPlanes();
inti=0;
ByteBufferbuffer=planes[i].getBuffer();
byte[]data=newbyte[buffer.remaining()];
buffer.get(data,0,data.length);
if(VERBOSE)Log.v(TAG,"Finishedreadingdatafromplane"+i);
returndata;
}
publicstaticbyte[]getDataFromImage(Imageimage,intcolorFormat){
if(colorFormat!
=COLOR_FormatI420&&colorFormat!
=COLOR_FormatNV21){
thrownewIllegalArgumentException("onlysupportCOLOR_FormatI420"+"andCOLOR_FormatNV21");
}
if(!
isImageFormatSupported(image)){
thrownewRuntimeException("can'tconvertImagetobytearray,format"+image.getFormat());
}
Rectcrop=image.getCropRect();
intformat=image.getFormat();
intwidth=crop.width();
intheight=crop.height();
Image.Plane[]planes=image.getPlanes();
byte[]data=newbyte[width*height*ImageFormat.getBitsPerPixel(format)/8];
byte[]rowData=newbyte[planes[0].getRowStride()];
intchannelOffset=0;
intoutputStride=1;
for(inti=0;i<planes.length;i++){
switch(i){
case0:
channelOffset=0;
outputStride=1;
break;
case1:
if(colorFormat==COLOR_FormatI420){
channelOffset=width*height;
outputStride=1;
}elseif(colorFormat==COLOR_FormatNV21){
channelOffset=width*height;
outputStride=2;
}
break;
case2:
if(colorFormat==COLOR_FormatI420){
channelOffset=(int)(width*height*1.25);
outputStride=1;
}elseif(colorFormat=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- android 使用MediaCodec 编解码总结 使用 MediaCodec 解码 总结