android 使用MediaCodec 编解码总结

转载地址:https://blog.csdn.net/stn_lcd/article/details/53694120

 

http://blog.csdn.net/gh_home/article/details/52143102

 

导言

 

本文将主要介绍在安卓中调用MediaCodec类实现视频文件的硬解码,以及如何将以byte[]类型存储的图像数据通过硬编码合成视频文件。

 

 

1.MediaCodec类的编解码原理

参考链接:https://developer.Android.com/reference/android/media/MediaCodec.html

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

 

                             

 

2. 视频解码程序示例

代码来源于

Android: MediaCodec视频文件硬件解码

 

 

以下所有代码可以在此处下载

 

[java] view plain copy 

  1. package com.example.guoheng_iri.helloworld;  
  2.   
  3. import android.graphics.ImageFormat;  
  4. import android.graphics.Rect;  
  5. import android.graphics.YuvImage;  
  6. import android.media.Image;  
  7. import android.media.MediaCodec;  
  8. import android.media.MediaCodecInfo;  
  9. import android.media.MediaExtractor;  
  10. import android.media.MediaFormat;  
  11. import android.util.Log;  
  12.   
  13. import java.io.File;  
  14. import java.io.FileOutputStream;  
  15. import java.io.IOException;  
  16. import java.nio.ByteBuffer;  
  17. import java.util.concurrent.LinkedBlockingQueue;  
  18.   
  19.   
  20. public class VideoDecode {  
  21.     private static final String TAG = "VideoToFrames";  
  22.     private static final boolean VERBOSE = true;  
  23.     private static final long DEFAULT_TIMEOUT_US = 10000;  
  24.   
  25.     private static final int COLOR_FormatI420 = 1;  
  26.     private static final int COLOR_FormatNV21 = 2;  
  27.   
  28.     public static final int FILE_TypeI420 = 1;  
  29.     public static final int FILE_TypeNV21 = 2;  
  30.     public static final int FILE_TypeJPEG = 3;  
  31.   
  32.     private final int decodeColorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;  
  33.   
  34.     private int outputImageFileType = -1;  
  35.     private String OUTPUT_DIR;  
  36.   
  37.   
  38.   
  39.     public int ImageWidth=0;  
  40.     public int ImageHeight=0;  
  41.   
  42.     MediaExtractor extractor = null;  
  43.     MediaCodec decoder = null;  
  44.     MediaFormat mediaFormat;  
  45.   
  46.   
  47.     public void setSaveFrames(String dir, int fileType) throws IOException {  
  48.         if (fileType != FILE_TypeI420 && fileType != FILE_TypeNV21 && fileType != FILE_TypeJPEG) {  
  49.             throw new IllegalArgumentException("only support FILE_TypeI420 " + "and FILE_TypeNV21 " + "and FILE_TypeJPEG");  
  50.         }  
  51.         outputImageFileType = fileType;  
  52.         File theDir = new File(dir);  
  53.         if (!theDir.exists()) {  
  54.             theDir.mkdirs();  
  55.         } else if (!theDir.isDirectory()) {  
  56.             throw new IOException("Not a directory");  
  57.         }  
  58.         OUTPUT_DIR = theDir.getAbsolutePath() + "/";  
  59.     }  
  60.   
  61.     public void VideoDecodePrepare(String videoFilePath) {  
  62.         extractor = null;  
  63.         decoder = null;  
  64.         try {  
  65.             File videoFile = new File(videoFilePath);  
  66.             extractor = new MediaExtractor();  
  67.             extractor.setDataSource(videoFile.toString());  
  68.             int trackIndex = selectTrack(extractor);  
  69.             if (trackIndex < 0) {  
  70.                 throw new RuntimeException("No video track found in " + videoFilePath);  
  71.             }  
  72.             extractor.selectTrack(trackIndex);  
  73.             mediaFormat = extractor.getTrackFormat(trackIndex);  
  74.             String mime = mediaFormat.getString(MediaFormat.KEY_MIME);  
  75.             decoder = MediaCodec.createDecoderByType(mime);  
  76.             showSupportedColorFormat(decoder.getCodecInfo().getCapabilitiesForType(mime));  
  77.             if (isColorFormatSupported(decodeColorFormat, decoder.getCodecInfo().getCapabilitiesForType(mime))) {  
  78.                 mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, decodeColorFormat);  
  79.                 Log.i(TAG, "set decode color format to type " + decodeColorFormat);  
  80.             } else {  
  81.                 Log.i(TAG, "unable to set decode color format, color format type " + decodeColorFormat + " not supported");  
  82.             }  
  83.   
  84.             decoder.configure(mediaFormat, nullnull, 0);  
  85.             decoder.start();  
  86.   
  87.         } catch (IOException ioe) {  
  88.             throw new RuntimeException("failed init encoder", ioe);  
  89.         }  
  90.     }  
  91.   
  92.     public void close() {  
  93.   
  94.         decoder.stop();  
  95.         decoder.release();  
  96.   
  97.         if (extractor != null) {  
  98.   
  99.             extractor.release();  
  100.             extractor = null;  
  101.         }  
  102.     }  
  103.   
  104.   
  105.     public void excuate()  
  106.     {  
  107.         try {  
  108.   
  109.             decodeFramesToImage(decoder, extractor, mediaFormat);  
  110.   
  111.         }finally {  
  112.             // release encoder, muxer, and input Surface  
  113.             close();  
  114.         }  
  115.   
  116.     }  
  117.   
  118.     private void showSupportedColorFormat(MediaCodecInfo.CodecCapabilities caps) {  
  119.         System.out.print("supported color format: ");  
  120.         for (int c : caps.colorFormats) {  
  121.             System.out.print(c + "\t");  
  122.         }  
  123.         System.out.println();  
  124.     }  
  125.   
  126.     private boolean isColorFormatSupported(int colorFormat, MediaCodecInfo.CodecCapabilities caps) {  
  127.         for (int c : caps.colorFormats) {  
  128.             if (c == colorFormat) {  
  129.                 return true;  
  130.             }  
  131.         }  
  132.         return false;  
  133.     }  
  134.   
  135.     public void decodeFramesToImage(MediaCodec decoder, MediaExtractor extractor, MediaFormat mediaFormat) {  
  136.         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();  
  137.         boolean sawInputEOS = false;  
  138.         boolean sawOutputEOS = false;  
  139.   
  140.         final int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);  
  141.         final int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);  
  142.   
  143.         ImageWidth=width;  
  144.         ImageHeight=height;  
  145.   
  146.         int outputFrameCount = 0;  
  147.         while (!sawOutputEOS) {  
  148.             if (!sawInputEOS) {  
  149.                 int inputBufferId = decoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);  
  150.                 if (inputBufferId >= 0) {  
  151.                     ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);  
  152.                     int sampleSize = extractor.readSampleData(inputBuffer, 0); //将一部分视频数据读取到inputbuffer中,大小为sampleSize  
  153.                     if (sampleSize < 0) {  
  154.                         decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  155.                         sawInputEOS = true;  
  156.                     } else {  
  157.                         long presentationTimeUs = extractor.getSampleTime();  
  158.                         decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);  
  159.                         extractor.advance();  //移动到视频文件的下一个地址  
  160.                     }  
  161.                 }  
  162.             }  
  163.             int outputBufferId = decoder.dequeueOutputBuffer(info, DEFAULT_TIMEOUT_US);  
  164.             if (outputBufferId >= 0) {  
  165.                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {  
  166.                     sawOutputEOS = true;  
  167.                 }  
  168.                 boolean doRender = (info.size != 0);  
  169.                 if (doRender) {  
  170.                     outputFrameCount++;  
  171.                     Image image = decoder.getOutputImage(outputBufferId);  
  172.                     System.out.println("image format: " + image.getFormat());  
  173.                     if (outputImageFileType != -1) {  
  174.                         String fileName;  
  175.                         switch (outputImageFileType) {  
  176.                              case FILE_TypeI420:  
  177.                                 fileName = OUTPUT_DIR + String.format("frame_%05d_I420_%dx%d.yuv", outputFrameCount, width, height);  
  178.                                 dumpFile(fileName, getDataFromImage(image, COLOR_FormatI420));  
  179.                                 break;  
  180.                             case FILE_TypeNV21:  
  181.                                 fileName = OUTPUT_DIR + String.format("frame_%05d_NV21_%dx%d.yuv", outputFrameCount, width, height);  
  182.                                 dumpFile(fileName, getDataFromImage(image, COLOR_FormatNV21));  
  183.                                 break;  
  184.                             case FILE_TypeJPEG:  
  185.                                 fileName = OUTPUT_DIR + String.format("frame_%05d.jpg", outputFrameCount);  
  186.                                 compressToJpeg(fileName, image);  
  187.                                 break;  
  188.                         }  
  189.                     }  
  190.                     image.close();  
  191.                     decoder.releaseOutputBuffer(outputBufferId, true);  
  192.                 }  
  193.             }  
  194.         }  
  195.     }  
  196.   
  197.     private static int selectTrack(MediaExtractor extractor) {  
  198.         int numTracks = extractor.getTrackCount();  
  199.         for (int i = 0; i < numTracks; i++) {  
  200.             MediaFormat format = extractor.getTrackFormat(i);  
  201.             String mime = format.getString(MediaFormat.KEY_MIME);  
  202.             if (mime.startsWith("video/")) {  
  203.                 if (VERBOSE) {  
  204.                     Log.d(TAG, "Extractor selected track " + i + " (" + mime + "): " + format);  
  205.                 }  
  206.                 return i;  
  207.             }  
  208.         }  
  209.         return -1;  
  210.     }  
  211.   
  212.     private static boolean isImageFormatSupported(Image image) {  
  213.         int format = image.getFormat();  
  214.         switch (format) {  
  215.             case ImageFormat.YUV_420_888:  
  216.             case ImageFormat.NV21:  
  217.             case ImageFormat.YV12:  
  218.                 return true;  
  219.         }  
  220.         return false;  
  221.     }  
  222.   
  223.     public static byte[] getGrayFromData(Image image, int colorFormat) {  
  224.         if (colorFormat != COLOR_FormatI420 && colorFormat != COLOR_FormatNV21) {  
  225.             throw new IllegalArgumentException("only support COLOR_FormatI420 " + "and COLOR_FormatNV21");  
  226.         }  
  227.         if (!isImageFormatSupported(image)) {  
  228.             throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());  
  229.         }  
  230.   
  231.         Image.Plane[] planes = image.getPlanes();  
  232.   
  233.         int i = 0;  
  234.   
  235.         ByteBuffer buffer = planes[i].getBuffer();  
  236.   
  237.         byte[] data = new byte[buffer.remaining()];  
  238.         buffer.get(data, 0, data.length);  
  239.   
  240.   
  241.         if (VERBOSE) Log.v(TAG, "Finished reading data from plane " + i);  
  242.   
  243.         return data;  
  244.     }  
  245.   
  246.     public static byte[] getDataFromImage(Image image, int colorFormat) {  
  247.         if (colorFormat != COLOR_FormatI420 && colorFormat != COLOR_FormatNV21) {  
  248.             throw new IllegalArgumentException("only support COLOR_FormatI420 " + "and COLOR_FormatNV21");  
  249.         }  
  250.         if (!isImageFormatSupported(image)) {  
  251.             throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());  
  252.         }  
  253.         Rect crop = image.getCropRect();  
  254.         int format = image.getFormat();  
  255.         int width = crop.width();  
  256.         int height = crop.height();  
  257.         Image.Plane[] planes = image.getPlanes();  
  258.         byte[] data = new byte[width * height * ImageFormat.getBitsPerPixel(format) / 8];  
  259.         byte[] rowData = new byte[planes[0].getRowStride()];  
  260.   
  261.         int channelOffset = 0;  
  262.         int outputStride = 1;  
  263.         for (int i = 0; i < planes.length; i++) {  
  264.             switch (i) {  
  265.                 case 0:  
  266.                     channelOffset = 0;  
  267.                     outputStride = 1;  
  268.                     break;  
  269.                 case 1:  
  270.                     if (colorFormat == COLOR_FormatI420) {  
  271.                         channelOffset = width * height;  
  272.                         outputStride = 1;  
  273.                     } else if (colorFormat == COLOR_FormatNV21) {  
  274.                         channelOffset = width * height ;  
  275.                         outputStride = 2;  
  276.                     }  
  277.                     break;  
  278.                 case 2:  
  279.                     if (colorFormat == COLOR_FormatI420) {  
  280.                         channelOffset = (int) (width * height * 1.25);  
  281.                         outputStride = 1;  
  282.                     } else if (colorFormat == COLOR_FormatNV21) {  
  283.                         channelOffset = width * height + 1;  
  284.                         outputStride = 2;  
  285.                     }  
  286.                     break;  
  287.             }  
  288.             ByteBuffer buffer = planes[i].getBuffer();  
  289.             int rowStride = planes[i].getRowStride();  
  290.             int pixelStride = planes[i].getPixelStride();  
  291.             if (VERBOSE) {  
  292.                 Log.v(TAG, "pixelStride " + pixelStride);  
  293.                 Log.v(TAG, "rowStride " + rowStride);  
  294.                 Log.v(TAG, "width " + width);  
  295.                 Log.v(TAG, "height " + height);  
  296.                 Log.v(TAG, "buffer size " + buffer.remaining());  
  297.             }  
  298.             int shift = (i == 0) ? 0 : 1;  
  299.             int w = width >> shift;  
  300.             int h = height >> shift;  
  301.             buffer.position(rowStride * (crop.top >> shift) + pixelStride * (crop.left >> shift));  
  302.             for (int row = 0; row < h; row++) {  
  303.                 int length;  
  304.                 if (pixelStride == 1 && outputStride == 1) {  
  305.                     length = w;  
  306.                     buffer.get(data, channelOffset, length);  
  307.                     channelOffset += length;  
  308.                 } else {  
  309.                     length = (w - 1) * pixelStride + 1;  
  310.                     buffer.get(rowData, 0, length);  
  311.                     for (int col = 0; col < w; col++) {  
  312.                         data[channelOffset] = rowData[col * pixelStride];  
  313.                         channelOffset += outputStride;  
  314.                     }  
  315.                 }  
  316.                 if (row < h - 1) {  
  317.                     buffer.position(buffer.position() + rowStride - length);  
  318.                 }  
  319.             }  
  320.             if (VERBOSE) Log.v(TAG, "Finished reading data from plane " + i);  
  321.         }  
  322.         return data;  
  323.     }  
  324.   
  325.   
  326.     private static void dumpFile(String fileName, byte[] data) {  
  327.         FileOutputStream outStream;  
  328.         try {  
  329.             outStream = new FileOutputStream(fileName);  
  330.         } catch (IOException ioe) {  
  331.             throw new RuntimeException("Unable to create output file " + fileName, ioe);  
  332.         }  
  333.         try {  
  334.             outStream.write(data);  
  335.             outStream.close();  
  336.         } catch (IOException ioe) {  
  337.             throw new RuntimeException("failed writing data to file " + fileName, ioe);  
  338.         }  
  339.     }  
  340.   
  341.     private void compressToJpeg(String fileName, Image image) {  
  342.         FileOutputStream outStream;  
  343.         try {  
  344.             outStream = new FileOutputStream(fileName);  
  345.         } catch (IOException ioe) {  
  346.             throw new RuntimeException("Unable to create output file " + fileName, ioe);  
  347.         }  
  348.         Rect rect = image.getCropRect();  
  349.         YuvImage yuvImage = new YuvImage(getDataFromImage(image, COLOR_FormatNV21), ImageFormat.NV21, rect.width(), rect.height(), null);  
  350.         yuvImage.compressToJpeg(rect, 100, outStream);  
  351.     }  
  352. }  
  353.   
  354.   
  355. /*************************************** 
  356.  //here is video decode example 
  357.  VideoDecode videodecoder=new VideoDecode();     
  358.  try{ 
  359.  videodecoder.setSaveFrames(outputdir,2);   //这里用于设置输出YUV的位置和YUV的格式 
  360.  videodecoder.VideoDecodePrepare(videodir);  //这里要输入待解码视频文件的地址 
  361.  videodecoder.excuate(); 
  362.  
  363.  }catch(IOException el){ 
  364.  
  365.  } 
  366.  
  367.  *************************************/  

 

 

3. 视频编码示例

这部分代码是将一个自动生成的Byte[] frameData 传入到视频编码器生成视频文件,后续用户可以传入自己的frameData即可

[java] view plain copy 

  1. package com.example.guoheng_iri.helloworld;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.nio.ByteBuffer;  
  7. import java.util.Arrays;  
  8. import java.util.LinkedList;  
  9. import java.util.Queue;  
  10.   
  11. import android.media.MediaCodec;  
  12. import android.media.MediaCodecInfo;  
  13. import android.media.MediaFormat;  
  14. import android.media.MediaMuxer;  
  15. import android.os.Environment;  
  16. import android.util.Log;  
  17.   
  18. import junit.framework.Assert;  
  19.   
  20.   
  21. public class VideoEncode {  
  22.   
  23.     private static final int TEST_Y = 120;                  // YUV values for colored rect  
  24.     private static final int TEST_U = 160;  
  25.     private static final int TEST_V = 200;  
  26.   
  27.     public int mWidth=1920;  
  28.     public int mHeight=1080;  
  29.   
  30.     private static final int BIT_RATE = 1920*1080*30;            // 2Mbps  
  31.     private static final int FRAME_RATE = 30;               // 30fps  
  32.     private static final int IFRAME_INTERVAL = 10;          // 10 seconds between I-frames  
  33.     private static final int WIDTH = 1920;  
  34.     private static final int HEIGHT = 1080;  
  35.   
  36.     public static final int NUMFRAMES=300;  
  37.   
  38.     private static final String TAG = "EncodeDecodeTest";  
  39.     private static final boolean VERBOSE = true;           // lots of logging  
  40.     private static final String MIME_TYPE = "video/avc";    // H.264 Advanced Video Coding  
  41.   
  42.   
  43.     private MediaCodec.BufferInfo mBufferInfo;  
  44.   
  45.     public MediaCodec mediaCodec;  
  46.   
  47.     public MediaMuxer mMuxer;  
  48.     public int mTrackIndex;  
  49.     public boolean mMuxerStarted;  
  50.   
  51.     private static final int encoderColorFormat=MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar;  
  52.   
  53.     public void VideoEncodePrepare()   //这里需要传进来一个编码时的mediaformat,后续做  
  54.     {  
  55.         String outputPath = new File(Environment.getExternalStorageDirectory(),  
  56.                 "mytest." + WIDTH + "x" + HEIGHT + ".mp4").toString();  
  57.   
  58.   
  59.         mBufferInfo = new MediaCodec.BufferInfo();  
  60.   
  61.         MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);  
  62.   
  63.         // Set some properties.  Failing to specify some of these can cause the MediaCodec  
  64.         // configure() call to throw an unhelpful exception.  
  65.         format.setInteger(MediaFormat.KEY_COLOR_FORMAT, encoderColorFormat);  
  66.         format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);  
  67.         format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);  
  68.         format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);  
  69.   
  70.   
  71.         mediaCodec = null;  
  72.   
  73.         try {  
  74.             mediaCodec = MediaCodec.createEncoderByType(MIME_TYPE);  
  75.             mediaCodec.configure(format, nullnull, MediaCodec.CONFIGURE_FLAG_ENCODE);  
  76.             mediaCodec.start();  
  77.   
  78.             mMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);  
  79.   
  80.         }catch (IOException ioe) {  
  81.             throw new RuntimeException("failed init encoder", ioe);  
  82.         }  
  83.   
  84.         mTrackIndex = -1;  
  85.         mMuxerStarted = false;  
  86.   
  87.     }  
  88.   
  89.     public void close()  {  
  90.   
  91.         mediaCodec.stop();  
  92.         mediaCodec.release();  
  93.   
  94.         if (mMuxer != null) {  
  95.             mMuxer.stop();  
  96.             mMuxer.release();  
  97.             mMuxer = null;  
  98.         }  
  99.   
  100.   
  101.   
  102.     }  
  103.   
  104.     public void offerEncoder(byte[] input, int frameIdx) {  
  105.         try {  
  106.             ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();  
  107.             //outputBuffers = mediaCodec.getOutputBuffers();  
  108.   
  109.             int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);  
  110.   
  111.   
  112.             if (inputBufferIndex >= 0) {  
  113.   
  114.                 if (frameIdx==NUMFRAMES)  
  115.                 {  
  116.                     mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, System.nanoTime()/1000,  
  117.                             MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  118.                     if (VERBOSE) Log.d(TAG, "sent input EOS (with zero-length frame)");  
  119.                 }  
  120.                 else  
  121.                 {  
  122.                     ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];  
  123.                     Assert.assertTrue(inputBuffer.capacity() >= input.length); //断言,帧数据容器超过缓冲区会抛出 AssertionFailedError  
  124.                     inputBuffer.clear();  
  125.                     inputBuffer.put(input);  
  126.                     mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);  
  127.                 }  
  128.             }else {  
  129.                 Log.i("AvcEncoder",  "input buffer "+ frameIdx + " not read");  
  130.             }  
  131.   
  132.         } catch (Throwable t) {  
  133.             t.printStackTrace();  
  134.         }  
  135.   
  136.     }  
  137.   
  138.   
  139.   
  140.   
  141.     private void generateFrame(int frameIndex, int colorFormat, byte[] frameData) {  
  142.         final int HALF_WIDTH = mWidth / 2;  
  143.         boolean semiPlanar = isSemiPlanarYUV(colorFormat);  
  144.         // Set to zero.  In YUV this is a dull green.  
  145.         Arrays.fill(frameData, (byte) 0);  
  146.         int startX, startY, countX, countY;  
  147.         frameIndex %= 8;  
  148.         //frameIndex = (frameIndex / 8) % 8;    // use this instead for debug -- easier to see  
  149.         if (frameIndex < 4) {  
  150.             startX = frameIndex * (mWidth / 4);  
  151.             startY = 0;  
  152.         } else {  
  153.             startX = (7 - frameIndex) * (mWidth / 4);  
  154.             startY = mHeight / 2;  
  155.         }  
  156.         for (int y = startY + (mHeight/2) - 1; y >= startY; --y) {  
  157.             for (int x = startX + (mWidth/4) - 1; x >= startX; --x) {  
  158.                 if (semiPlanar) {  
  159.                     // full-size Y, followed by UV pairs at half resolution  
  160.                     // e.g. Nexus 4 OMX.qcom.video.encoder.avc COLOR_FormatYUV420SemiPlanar  
  161.                     // e.g. Galaxy Nexus OMX.TI.DUCATI1.VIDEO.H264E  
  162.                     //        OMX_TI_COLOR_FormatYUV420PackedSemiPlanar  
  163.                     frameData[y * mWidth + x] = (byte) TEST_Y;  
  164.                     if ((x & 0x01) == 0 && (y & 0x01) == 0) {  
  165.                         frameData[mWidth*mHeight + y * HALF_WIDTH + x] = (byte) TEST_U;  
  166.                         frameData[mWidth*mHeight + y * HALF_WIDTH + x + 1] = (byte) TEST_V;  
  167.                     }  
  168.                 } else {  
  169.                     // full-size Y, followed by quarter-size U and quarter-size V  
  170.                     // e.g. Nexus 10 OMX.Exynos.AVC.Encoder COLOR_FormatYUV420Planar  
  171.                     // e.g. Nexus 7 OMX.Nvidia.h264.encoder COLOR_FormatYUV420Planar  
  172.                     frameData[y * mWidth + x] = (byte) TEST_Y;  
  173.                     if ((x & 0x01) == 0 && (y & 0x01) == 0) {  
  174.                         frameData[mWidth*mHeight + (y/2) * HALF_WIDTH + (x/2)] = (byte) TEST_U;  
  175.                         frameData[mWidth*mHeight + HALF_WIDTH * (mHeight / 2) +  
  176.                                 (y/2) * HALF_WIDTH + (x/2)] = (byte) TEST_V;  
  177.                     }  
  178.                 }  
  179.             }  
  180.         }  
  181.     }  
  182.   
  183.   
  184.     private static boolean isSemiPlanarYUV(int colorFormat) {  
  185.         switch (colorFormat) {  
  186.             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:  
  187.             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:  
  188.                 return false;  
  189.             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:  
  190.             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:  
  191.             case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:  
  192.                 return true;  
  193.             default:  
  194.                 throw new RuntimeException("unknown format " + colorFormat);  
  195.         }  
  196.     }  
  197.   
  198.   
  199.     public void excuate()  
  200.     {  
  201.         try {  
  202.             VideoEncodePrepare();  
  203.             doEncodeVideoFromBuffer(mediaCodec,encoderColorFormat);  
  204.   
  205.         }finally {  
  206.             // release encoder, muxer, and input Surface  
  207.             close();  
  208.         }  
  209.   
  210.     }  
  211.   
  212.   
  213.     public byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {  
  214.         byte[] i420bytes = new byte[yv12bytes.length];  
  215.         for (int i = 0; i < width*height; i++)  
  216.             i420bytes[i] = yv12bytes[i];  
  217.         for (int i = width*height; i < width*height + (width/2*height/2); i++)  
  218.             i420bytes[i] = yv12bytes[i + (width/2*height/2)];  
  219.         for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)  
  220.             i420bytes[i] = yv12bytes[i - (width/2*height/2)];  
  221.         return i420bytes;  
  222.     }  
  223.   
  224.     void swapYV12toNV21(byte[] yv12bytes, byte[] nv12bytes, int width,int height) {  
  225.   
  226.         int nLenY = width * height;  
  227.   
  228.         int nLenU = nLenY / 4;  
  229.   
  230.         System.arraycopy(yv12bytes, 0, nv12bytes, 0, width * height);  
  231.   
  232.         for (int i = 0; i < nLenU; i++) {  
  233.   
  234.             nv12bytes[nLenY + 2 * i + 1] = yv12bytes[nLenY + i];  
  235.   
  236.             nv12bytes[nLenY + 2 * i] = yv12bytes[nLenY + nLenU + i];  
  237.   
  238.         }  
  239.   
  240.     }  
  241.   
  242.     private void doEncodeVideoFromBuffer(MediaCodec encoder, int encoderColorFormat) {  
  243.         final int TIMEOUT_USEC = 10000;  
  244.         ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();  
  245.         ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();  
  246.   
  247.         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();  
  248.   
  249.         int generateIndex = 0;  
  250.         int checkIndex = 0;  
  251.         int badFrames = 0;  
  252.   
  253.   
  254.         // The size of a frame of video data, in the formats we handle, is stride*sliceHeight  
  255.         // for Y, and (stride/2)*(sliceHeight/2) for each of the Cb and Cr channels.  Application  
  256.         // of algebra and assuming that stride==width and sliceHeight==height yields:  
  257.         byte[] frameData = new byte[mWidth * mHeight * 3 / 2];  
  258.         byte[] frameDataYV12 = new byte[mWidth * mHeight * 3 / 2];  
  259.         // Just out of curiosity.  
  260.         long rawSize = 0;  
  261.         long encodedSize = 0;  
  262.         // Save a copy to disk.  Useful for debugging the test.  Note this is a raw elementary  
  263.         // stream, not a .mp4 file, so not all players will know what to do with it.  
  264.   
  265.   
  266.   
  267.         // Loop until the output side is done.  
  268.         boolean inputDone = false;  
  269.         boolean encoderDone = false;  
  270.         boolean outputDone = false;  
  271.   
  272.         while (!outputDone) {  
  273.   
  274.             // If we're not done submitting frames, generate a new one and submit it.  By  
  275.             // doing this on every loop we're working to ensure that the encoder always has  
  276.             // work to do.  
  277.             //  
  278.             // We don't really want a timeout here, but sometimes there's a delay opening  
  279.             // the encoder device, so a short timeout can keep us from spinning hard.  
  280.             if (!inputDone) {  
  281.                 int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);  
  282.   
  283.                 if (inputBufIndex >= 0) {  
  284.                     long ptsUsec = computePresentationTime(generateIndex);  
  285.                     if (generateIndex == NUMFRAMES) {  
  286.                         // Send an empty frame with the end-of-stream flag set.  If we set EOS  
  287.                         // on a frame with data, that frame data will be ignored, and the  
  288.                         // output will be short one frame.  
  289.                         encoder.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,  
  290.                                 MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  291.                         inputDone = true;  
  292.                         if (VERBOSE) Log.d(TAG, "sent input EOS (with zero-length frame)");  
  293.   
  294.   
  295.                     } else {  
  296.                         generateFrame(generateIndex, encoderColorFormat, frameData);  
  297.                           
  298.                         ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];  
  299.                         // the buffer should be sized to hold one full frame  
  300.   
  301.                         inputBuf.clear();  
  302.                         inputBuf.put(frameData);  
  303.                         encoder.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);  
  304.                         if (VERBOSE) Log.d(TAG, "submitted frame " + generateIndex + " to enc");  
  305.                     }  
  306.                     generateIndex++;  
  307.                 } else {  
  308.                     // either all in use, or we timed out during initial setup  
  309.                     if (VERBOSE) Log.d(TAG, "input buffer not available");  
  310.                 }  
  311.             }  
  312.             // Check for output from the encoder.  If there's no output yet, we either need to  
  313.             // provide more input, or we need to wait for the encoder to work its magic.  We  
  314.             // can't actually tell which is the case, so if we can't get an output buffer right  
  315.             // away we loop around and see if it wants more input.  
  316.             //  
  317.             // Once we get EOS from the encoder, we don't need to do this anymore.  
  318.             if (!encoderDone) {  
  319.                 int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);  
  320.                 if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {  
  321.                     // no output available yet  
  322.                     if (VERBOSE) Log.d(TAG, "no output from encoder available");  
  323.                 } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {  
  324.                     // not expected for an encoder  
  325.                     encoderOutputBuffers = encoder.getOutputBuffers();  
  326.                     if (VERBOSE) Log.d(TAG, "encoder output buffers changed");  
  327.                 } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {  
  328.                     // not expected for an encoder  
  329.                     MediaFormat newFormat = encoder.getOutputFormat();  
  330.                     if (VERBOSE) Log.d(TAG, "encoder output format changed: " + newFormat);  
  331.   
  332.                     if (mMuxerStarted) {  
  333.                         throw new RuntimeException("format changed twice");  
  334.                     }  
  335.   
  336.                     Log.d(TAG, "encoder output format changed: " + newFormat);  
  337.   
  338.                     // now that we have the Magic Goodies, start the muxer  
  339.                     mTrackIndex = mMuxer.addTrack(newFormat);  
  340.                     mMuxer.start();  
  341.                     mMuxerStarted = true;  
  342.   
  343.                 } else if (encoderStatus < 0) {  
  344.                     Log.d(TAG,"unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);  
  345.                 } else { // encoderStatus >= 0  
  346.                     ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];  
  347.                     if (encodedData == null) {  
  348.                         Log.d(TAG,"encoderOutputBuffer " + encoderStatus + " was null");  
  349.                     }  
  350.   
  351.                     if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {  
  352.                         // Codec config info.  Only expected on first packet.  One way to  
  353.                         // handle this is to manually stuff the data into the MediaFormat  
  354.                         // and pass that to configure().  We do that here to exercise the API.  
  355.   
  356.                         MediaFormat format =  
  357.                                 MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);  
  358.                         format.setByteBuffer("csd-0", encodedData);  
  359.   
  360.                         info.size = 0;  
  361.   
  362.                     } else {  
  363.                         // Get a decoder input buffer, blocking until it's available.  
  364.   
  365.                         encoderDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;  
  366.   
  367.                         if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)  
  368.                             outputDone = true;  
  369.                         if (VERBOSE) Log.d(TAG, "passed " + info.size + " bytes to decoder"  
  370.                                 + (encoderDone ? " (EOS)" : ""));  
  371.                     }  
  372.   
  373.   
  374.                     // It's usually necessary to adjust the ByteBuffer values to match BufferInfo.  
  375.   
  376.                     if (info.size != 0) {  
  377.                         encodedData.position(info.offset);  
  378.                         encodedData.limit(info.offset + info.size);  
  379.                         mMuxer.writeSampleData(mTrackIndex, encodedData, info);  
  380.   
  381.                         encodedSize += info.size;  
  382.   
  383.                     }  
  384.   
  385.                     encoder.releaseOutputBuffer(encoderStatus, false);  
  386.                 }  
  387.             }  
  388.   
  389.   
  390.         }  
  391.         if (VERBOSE) Log.d(TAG, "decoded " + checkIndex + " frames at "  
  392.                 + mWidth + "x" + mHeight + ": raw=" + rawSize + ", enc=" + encodedSize);  
  393.   
  394.   
  395.         if (checkIndex != NUMFRAMES) {  
  396.             Log.d(TAG,"expected " + 120 + " frames, only decoded " + checkIndex);  
  397.         }  
  398.         if (badFrames != 0) {  
  399.             Log.d(TAG,"Found " + badFrames + " bad frames");  
  400.         }  
  401.     }  
  402.   
  403.     public static long computePresentationTime(int frameIndex) {  
  404.         return 132 + frameIndex * 1000000 / FRAME_RATE;  
  405.     }  

3. 读入一个视频,在硬件解码后将其硬件编码回去的示例

[java] view plain copy 

  1. package com.example.guoheng_iri.helloworld;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.nio.ByteBuffer;  
  7. import java.util.Arrays;  
  8.   
  9. import android.media.MediaCodec;  
  10. import android.media.MediaCodecInfo;  
  11. import android.media.MediaFormat;  
  12. import android.media.MediaMuxer;  
  13. import android.os.Environment;  
  14. import android.util.Log;  
  15.   
  16. import junit.framework.Assert;  
  17.   
  18. import android.graphics.ImageFormat;  
  19. import android.graphics.Rect;  
  20. import android.graphics.YuvImage;  
  21. import android.media.Image;  
  22. import android.media.MediaExtractor;  
  23. import android.util.Log;  
  24.   
  25. import java.util.LinkedList;  
  26. import java.util.Queue;  
  27. import java.util.concurrent.LinkedBlockingQueue;  
  28.   
  29.   
  30. /** 
  31.  * Created by guoheng-iri on 2016/8/1. 
  32.  */  
  33. public class VideoEncodeDecode {  
  34.   
  35.     public int mWidth=-1;  
  36.     public int mHeight=-1;  
  37.   
  38.     private static final int BUFFER_SIZE = 30;  
  39.   
  40.     private static final String MIME_TYPE = "video/avc";    // H.264 Advanced Video Coding  
  41.   
  42.     private static final int DEFAULT_TIMEOUT_US=20000;  
  43.   
  44.   
  45.     public static int NUMFRAMES=590;  
  46.   
  47.     private static final String TAG = "EncodeDecodeTest";  
  48.     private static final boolean VERBOSE = true;           // lots of logging  
  49.   
  50.   
  51.     Queue<byte[]> ImageQueue;  
  52.   
  53.   
  54.     VideoEncode myencoder;  
  55.     VideoDecode mydecoder;  
  56.   
  57.   
  58.   
  59.     void VideoCodecPrepare(String videoInputFilePath)  
  60.     {  
  61.         mydecoder=new VideoDecode();  
  62.         myencoder=new VideoEncode();  
  63.         mydecoder.VideoDecodePrepare(videoInputFilePath);  
  64.         myencoder.VideoEncodePrepare();  
  65.   
  66.         ImageQueue= new LinkedList<byte[]>();  
  67.   
  68.     }  
  69.   
  70.     void MyProcessing()  
  71.     {  
  72.         //do process  
  73.     }  
  74.   
  75.     void VideoEncodeDecodeLoop()  
  76.     {  
  77.         //here is decode flag  
  78.         boolean sawInputEOS = false;  
  79.         boolean sawOutputEOS = false;  
  80.   
  81.         boolean IsImageBufferFull=false;  
  82.   
  83.   
  84.         MediaCodec.BufferInfo encodeinfo = new MediaCodec.BufferInfo();  
  85.         MediaCodec.BufferInfo decodeinfo = new MediaCodec.BufferInfo();  
  86.         mWidth = mydecoder.mediaFormat.getInteger(MediaFormat.KEY_WIDTH);  
  87.         mHeight = mydecoder.mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);  
  88.   
  89.         byte[] frameData = new byte[mWidth * mHeight * 3 / 2];  
  90.         byte[] frameDataYV12 = new byte[mWidth * mHeight * 3 / 2];  
  91.         ByteBuffer[] encoderInputBuffers = myencoder.mediaCodec.getInputBuffers();  
  92.         ByteBuffer[] encoderOutputBuffers = myencoder.mediaCodec.getOutputBuffers();  
  93.   
  94.   
  95.         int generateIndex = 0;  
  96.   
  97.         boolean encodeinputDone = false;  
  98.         boolean encoderDone = false;  
  99.   
  100.   
  101.   
  102.         while((!encoderDone) && (!sawOutputEOS))  
  103.         {  
  104.   
  105.             while (!sawOutputEOS && (!IsImageBufferFull)) {  
  106.                 if (!sawInputEOS) {  
  107.                     int inputBufferId = mydecoder.decoder.dequeueInputBuffer(DEFAULT_TIMEOUT_US);  
  108.                     if (inputBufferId >= 0) {  
  109.                         ByteBuffer inputBuffer = mydecoder.decoder.getInputBuffer(inputBufferId);  
  110.                         int sampleSize = mydecoder.extractor.readSampleData(inputBuffer, 0); //将一部分视频数据读取到inputbuffer中,大小为sampleSize  
  111.                         if (sampleSize < 0) {  
  112.                             mydecoder.decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  113.                             sawInputEOS = true;  
  114.                         } else {  
  115.                             long presentationTimeUs = mydecoder.extractor.getSampleTime();  
  116.                             mydecoder.decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);  
  117.                             mydecoder.extractor.advance();  //移动到视频文件的下一个地址  
  118.                         }  
  119.                     }  
  120.                 }  
  121.                 int outputBufferId = mydecoder.decoder.dequeueOutputBuffer(decodeinfo, DEFAULT_TIMEOUT_US);  
  122.                 if (outputBufferId >= 0) {  
  123.                     if ((decodeinfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {  
  124.                         sawOutputEOS = true;  
  125.                     }  
  126.                     boolean doRender = (decodeinfo.size != 0);  
  127.                     if (doRender) {  
  128.                         //NUMFRAMES++;  
  129.                         Image image = mydecoder.decoder.getOutputImage(outputBufferId);  
  130.   
  131.                         byte[] imagedata=mydecoder.getDataFromImage(image, mydecoder.FILE_TypeNV21);  
  132.                         ImageQueue.offer(imagedata);  
  133.                         if (ImageQueue.size()==BUFFER_SIZE)  
  134.                         {  
  135.                             IsImageBufferFull = true;  
  136.                         }  
  137.   
  138.   
  139.                         image.close();  
  140.                         mydecoder.decoder.releaseOutputBuffer(outputBufferId, true);  
  141.                     }  
  142.                 }  
  143.             }  
  144.   
  145.   
  146.             //MyProcessing();  
  147.   
  148.   
  149.             while ((!encoderDone) && IsImageBufferFull) {  
  150.   
  151.                 if (!encodeinputDone) {  
  152.                     int inputBufIndex = myencoder.mediaCodec.dequeueInputBuffer(DEFAULT_TIMEOUT_US);  
  153.   
  154.                     if (inputBufIndex >= 0) {  
  155.                         long ptsUsec = myencoder.computePresentationTime(generateIndex);  
  156.                         if (generateIndex == NUMFRAMES) {  
  157.   
  158.                             myencoder.mediaCodec.queueInputBuffer(inputBufIndex, 0, 0, ptsUsec,  
  159.                                     MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  160.                             encodeinputDone = true;  
  161.                             if (VERBOSE) Log.d(TAG, "sent input EOS (with zero-length frame)");  
  162.   
  163.   
  164.                         } else {  
  165.                               
  166.   
  167.                             frameData=ImageQueue.poll();  
  168.                          
  169.                             ByteBuffer inputBuf = encoderInputBuffers[inputBufIndex];  
  170.                             // the buffer should be sized to hold one full frame  
  171.   
  172.                             inputBuf.clear();  
  173.                             inputBuf.put(frameData);  
  174.                             myencoder.mediaCodec.queueInputBuffer(inputBufIndex, 0, frameData.length, ptsUsec, 0);  
  175.   
  176.                             if (ImageQueue.size()==0)  
  177.                             {  
  178.                                 IsImageBufferFull=false;  
  179.                             }  
  180.   
  181.                             if (VERBOSE) Log.d(TAG, "submitted frame " + generateIndex + " to enc");  
  182.                         }  
  183.                         generateIndex++;  
  184.                     } else {  
  185.                         // either all in use, or we timed out during initial setup  
  186.                         if (VERBOSE) Log.d(TAG, "input buffer not available");  
  187.                     }  
  188.                 }  
  189.                 // Check for output from the encoder.  If there's no output yet, we either need to  
  190.                 // provide more input, or we need to wait for the encoder to work its magic.  We  
  191.                 // can't actually tell which is the case, so if we can't get an output buffer right  
  192.                 // away we loop around and see if it wants more input.  
  193.                 //  
  194.                 // Once we get EOS from the encoder, we don't need to do this anymore.  
  195.                 if (!encoderDone) {  
  196.                     int encoderStatus = myencoder.mediaCodec.dequeueOutputBuffer(encodeinfo, DEFAULT_TIMEOUT_US);  
  197.                     if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {  
  198.                         // no output available yet  
  199.                         if (VERBOSE) Log.d(TAG, "no output from encoder available");  
  200.                     } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {  
  201.                         // not expected for an encoder  
  202.                         encoderOutputBuffers = myencoder.mediaCodec.getOutputBuffers();  
  203.                         if (VERBOSE) Log.d(TAG, "encoder output buffers changed");  
  204.                     } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {  
  205.                         // not expected for an encoder  
  206.                         MediaFormat newFormat = myencoder.mediaCodec.getOutputFormat();  
  207.                         if (VERBOSE) Log.d(TAG, "encoder output format changed: " + newFormat);  
  208.   
  209.                         if (myencoder.mMuxerStarted) {  
  210.                             throw new RuntimeException("format changed twice");  
  211.                         }  
  212.   
  213.                         Log.d(TAG, "encoder output format changed: " + newFormat);  
  214.   
  215.                         // now that we have the Magic Goodies, start the muxer  
  216.                         myencoder.mTrackIndex = myencoder.mMuxer.addTrack(newFormat);  
  217.                         myencoder.mMuxer.start();  
  218.                         myencoder.mMuxerStarted = true;  
  219.   
  220.                     } else if (encoderStatus < 0) {  
  221.                         Log.d(TAG,"unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);  
  222.                     } else { // encoderStatus >= 0  
  223.                         ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];  
  224.                         if (encodedData == null) {  
  225.                             Log.d(TAG,"encoderOutputBuffer " + encoderStatus + " was null");  
  226.                         }  
  227.   
  228.                         if ((encodeinfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {  
  229.   
  230.                             MediaFormat format =  
  231.                                     MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);  
  232.                             format.setByteBuffer("csd-0", encodedData);  
  233.   
  234.                             encodeinfo.size = 0;  
  235.   
  236.                         } else {  
  237.                             // Get a decoder input buffer, blocking until it's available  
  238.   
  239.                             if ((encodeinfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0)  
  240.                                 encoderDone = true;  
  241.                             if (VERBOSE) Log.d(TAG, "passed " + encodeinfo.size + " bytes to decoder"  
  242.                                     + (encoderDone ? " (EOS)" : ""));  
  243.                         }  
  244.   
  245.   
  246.                         // It's usually necessary to adjust the ByteBuffer values to match BufferInfo.  
  247.                         if (encodeinfo.size != 0) {  
  248.                             encodedData.position(encodeinfo.offset);  
  249.                             encodedData.limit(encodeinfo.offset + encodeinfo.size);  
  250.                             myencoder.mMuxer.writeSampleData(myencoder.mTrackIndex, encodedData, encodeinfo);  
  251.   
  252.                         }  
  253.                         myencoder.mediaCodec.releaseOutputBuffer(encoderStatus, false);  
  254.                     }  
  255.                 }  
  256.   
  257.   
  258.             }  
  259.   
  260.   
  261.         }  
  262.     }  
  263.   
  264.   
  265.     public void close()  
  266.     {  
  267.         myencoder.close();  
  268.         mydecoder.close();  
  269.     }  
  270.   
  271. }  

useful links:

http://bigflake.com/mediacodec/

你可能感兴趣的:(frameworks)