android 使用MediaCodec 编解码总结_android学习笔记总结

2020-02-28 其他工作总结 下载本文

android 使用MediaCodec 编解码总结由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“android学习笔记总结”。

android 使用MediaCodec 编解码总结

本文将主要介绍在安卓中调用MediaCodec类实现视频文件的硬解码,以及如何将以byte[]类型存储的图像数据通过硬编码合成视频文件。1.MediaCodec类的编解码原理 参考链接:https://developer.Android.com/ 工作流是这样的: 以编码为例,首先要初始化硬件编码器,配置要编码的格式、视频文件的长宽、码率、帧率、关键帧间隔等等。这一步叫configure。之后开启编码器,当前编码器便是可用状态,随时准备接收数据。下一个过程便是编码的running过程,在此过程中,需要维护两个buffer队列,InputBuffer 和OutputBuffer,用户需要不断出队InputBuffer(即dequeueInputBuffer),往里边放入需要编码的图像数据之后再入队等待处理,然后硬件编码器开始异步处理,一旦处理结束,他会将数据放在OutputBuffer中,并且通知用户当前有输出数据可用了,那么用户就可以出队一个OutputBuffer,将其中的数据拿走,然后释放掉这个buffer。结束条件在于end-of-stream这个flag标志位的设定。在编码结束后,编码器调用stop函数停止编码,之后调用release函数将编码器完全释放掉,整体流程结束。

2.视频解码程序示例 代码来源于

Android: MediaCodec视频文件硬件解码以下所有代码可以在此处下载[java] view plain copy

print?

package com.example.guoheng_iri.helloworld;

import android.graphics.ImageFormat;

import android.graphics.Rect;

import android.graphics.YuvImage;

import android.media.Image;

import android.media.MediaCodec;

import android.media.MediaCodecInfo;

import android.media.MediaExtractor;

import android.media.MediaFormat;

import android.util.Log;

import java.io.File;import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.util.concurrent.LinkedBlockingQueue;

public cla VideoDecode {

private static final String TAG = “VideoToFrames”;

private static final boolean VERBOSE = true;

private static final long DEFAULT_TIMEOUT_US = 10000;

private static final int COLOR_FormatI420 = 1;

private static final int COLOR_FormatNV21 = 2;

public static final int FILE_TypeI420 = 1;

public static final int FILE_TypeNV21 = 2;

public static final int FILE_TypeJPEG = 3;

private final int decodeColorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;

private int outputImageFileType =-1;

private String OUTPUT_DIR;

public int ImageWidth=0;

public int ImageHeight=0;

MediaExtractor extractor = null;

MediaCodec decoder = null;

MediaFormat mediaFormat;

public void setSaveFrames(String dir, int fileType)throws IOException {

if(fileType!= FILE_TypeI420 && fileType!= FILE_TypeNV21 && fileType!= FILE_TypeJPEG){

throw new IllegalArgumentException(“only support FILE_TypeI420 ” + “and FILE_TypeNV21 ” + “and FILE_TypeJPEG”);

}

outputImageFileType = fileType;

File theDir = new File(dir);

if(!theDir.exists()){

theDir.mkdirs();

} else if(!theDir.isDirectory()){

throw new IOException(“Not a directory”);

}

OUTPUT_DIR = theDir.getAbsolutePath()+ “/”;

}

public void VideoDecodePrepare(String videoFilePath){

extractor = null;

decoder = null;

try {

File videoFile = new File(videoFilePath);

extractor = new MediaExtractor();

extractor.setDataSource(videoFile.toString());

int trackIndex = selectTrack(extractor);

if(trackIndex

throw new RuntimeException(“No video track found in ” + videoFilePath);

}

extractor.selectTrack(trackIndex);

mediaFormat = extractor.getTrackFormat(trackIndex);

String mime = 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, “set decode color format to type ” + decodeColorFormat);

} else {

Log.i(TAG, “unable to set decode color format, color format type ” + decodeColorFormat + “ not supported”);

}

decoder.configure(mediaFormat, null, null, 0);

decoder.start();

} catch(IOException ioe){

throw new RuntimeException(“failed init encoder”, ioe);

}

}

public void close(){

decoder.stop();

decoder.release();

if(extractor!= null){

extractor.release();

extractor = null;

}

}

public void excuate()

{

try {

decodeFramesToImage(decoder, extractor, mediaFormat);

}finally {

// release encoder, muxer, and input Surface

close();

}

}

private void showSupportedColorFormat(MediaCodecInfo.CodecCapabilities caps){

System.out.print(“supported color format: ”);

for(int c : caps.colorFormats){

System.out.print(c + “t”);

}

System.out.println();

}

private boolean isColorFormatSupported(int colorFormat, MediaCodecInfo.CodecCapabilities caps){

for(int c : caps.colorFormats){

if(c == colorFormat){

return true;

}

}

return false;

}

public void decodeFramesToImage(MediaCodec decoder, MediaExtractor extractor, MediaFormat mediaFormat){

MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();

boolean sawInputEOS = false;

boolean sawOutputEOS = false;

final int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);

final int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);

ImageWidth=width;

ImageHeight=height;

int outputFrameCount = 0;

while(!sawOutputEOS){

if(!sawInputEOS){

int inputBufferId = decoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);

if(inputBufferId >= 0){

ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);

int sampleSize = extractor.readSampleData(inputBuffer, 0);//将一部分视频数据读取到inputbuffer中,大小为sampleSize

if(sampleSize

decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);

sawInputEOS = true;

} else {

long presentationTimeUs = extractor.getSampleTime();

decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);

extractor.advance();//移动到视频文件的下一个地址

}

}

}

int outputBufferId = decoder.dequeueOutputBuffer(info, DEFAULT_TIMEOUT_US);

if(outputBufferId >= 0){

if((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM)!= 0){

sawOutputEOS = true;

}

boolean doRender =(info.size!= 0);

if(doRender){

outputFrameCount++;

Image image = decoder.getOutputImage(outputBufferId);

System.out.println(“image format: ” + image.getFormat());

if(outputImageFileType!=-1){

String fileName;

switch(outputImageFileType){

case FILE_TypeI420:

fileName = OUTPUT_DIR + String.format(“frame_%05d_I420_%dx%d.yuv”, outputFrameCount, width, height);

dumpFile(fileName, getDataFromImage(image, COLOR_FormatI420));

break;

case FILE_TypeNV21:

fileName = OUTPUT_DIR + String.format(“frame_%05d_NV21_%dx%d.yuv”, outputFrameCount, width, height);

dumpFile(fileName, getDataFromImage(image, COLOR_FormatNV21));

break;

case FILE_TypeJPEG:

fileName = OUTPUT_DIR + String.format(“frame_%05d.jpg”, outputFrameCount);

compreToJpeg(fileName, image);

break;

}

}

image.close();

decoder.releaseOutputBuffer(outputBufferId, true);

}

}

}

}

private static int selectTrack(MediaExtractor extractor){

int numTracks = extractor.getTrackCount();

for(int i = 0;i

MediaFormat format = extractor.getTrackFormat(i);

String mime = format.getString(MediaFormat.KEY_MIME);

if(mime.startsWith(“video/”)){

if(VERBOSE){

Log.d(TAG, “Extractor selected track ” + i + “(” + mime + “): ” + format);

}

return i;

}

}

return-1;

}

private static boolean isImageFormatSupported(Image image){

int format = image.getFormat();

switch(format){

case ImageFormat.YUV_420_888:

case ImageFormat.NV21:

case ImageFormat.YV12:

return true;

}

return false;

}

public static byte[] getGrayFromData(Image image, int colorFormat){

if(colorFormat!= COLOR_FormatI420 && colorFormat!= COLOR_FormatNV21){

throw new IllegalArgumentException(“only support COLOR_FormatI420 ” + “and COLOR_FormatNV21”);

}

if(!isImageFormatSupported(image)){

throw new RuntimeException(“can't convert Image to byte array, format ” + image.getFormat());

}

Image.Plane[] planes = image.getPlanes();

int i = 0;

ByteBuffer buffer = planes[i].getBuffer();

byte[] data = new byte[buffer.remaining()];

buffer.get(data, 0, data.length);

if(VERBOSE)Log.v(TAG, “Finished reading data from plane ” + i);

return data;

}

public static byte[] getDataFromImage(Image image, int colorFormat){

if(colorFormat!= COLOR_FormatI420 && colorFormat!= COLOR_FormatNV21){

throw new IllegalArgumentException(“only support COLOR_FormatI420 ” + “and COLOR_FormatNV21”);

}

if(!isImageFormatSupported(image)){

throw new RuntimeException(“can't convert Image to byte array, format ” + image.getFormat());

}

Rect crop = image.getCropRect();

int format = image.getFormat();

int width = crop.width();

int height = crop.height();

Image.Plane[] planes = image.getPlanes();

byte[] data = new byte[width * height * ImageFormat.getBitsPerPixel(format)/ 8];

byte[] rowData = new byte[planes[0].getRowStride()];

int channelOffset = 0;

int outputStride = 1;

for(int i = 0;i

switch(i){

case 0:

channelOffset = 0;

outputStride = 1;

break;

case 1:

if(colorFormat == COLOR_FormatI420){

channelOffset = width * height;

outputStride = 1;

} else if(colorFormat == COLOR_FormatNV21){

channelOffset = width * height;

outputStride = 2;

}

break;

case 2:

if(colorFormat == COLOR_FormatI420){

channelOffset =(int)(width * height * 1.25);

outputStride = 1;

} else if(colorFormat =

《android 使用MediaCodec 编解码总结.docx》
将本文的Word文档下载,方便收藏和打印
推荐度:
android 使用MediaCodec 编解码总结
点击下载文档
相关专题 android学习笔记总结 编解码 Android MediaCodec android学习笔记总结 编解码 Android MediaCodec
[其他工作总结]相关推荐
    [其他工作总结]热门文章
      下载全文