android 使用MediaCodec 编解码总结

合集下载

mediacodec 用法

mediacodec 用法

mediacodec 用法MediaCodec是Android平台上的一个多媒体编解码器API,它允许开发人员对音频和视频进行高效的编解码操作。

在本文中,我们将会详细介绍MediaCodec的用法,从实例代码到关键概念,并逐步回答相关问题。

MediaCodec用法MediaCodec的主要用法可以分为以下几个步骤:创建编解码器、配置编解码器、启动编解码器、处理输入数据、获取编解码后的数据、停止编解码器和释放资源。

一、创建编解码器首先需要实例化一个MediaCodec对象,通过createDecoderByType或createEncoderByType方法,传入对应的媒体类型(mime type)来创建对应的解码器或编码器。

例如,创建一个H.264解码器的实例可以使用以下代码:javaMediaCodec codec = MediaCodec.createDecoderByType("video/avc");二、配置编解码器在创建编解码器之后,需要对其进行配置。

首先,我们需要通过MediaFormat 来指定输入和输出格式。

对于解码器而言,输入格式通常是一个媒体文件的编码格式;而输出格式通常是原始的音频或视频格式。

例如,对于H.264解码器,可以使用如下代码来配置编解码器:javaMediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height);codec.configure(format, null, null, 0);在配置编解码器后,我们还可以通过getInputBuffers和getOutputBuffers方法获取输入和输出缓冲区,并将其保存在一个缓冲区数组中,以供进一步处理。

三、启动编解码器在配置完成后,我们需要调用start方法来启动编解码器。

这将导致编解码器开始处理输入数据,并将编码后的数据写入输出缓冲区。

【Android】AndroidCamera实时数据采集及通过MediaCodec硬编码编。。。

【Android】AndroidCamera实时数据采集及通过MediaCodec硬编码编。。。

【Android】AndroidCamera实时数据采集及通过MediaCodec硬编码编。

吐槽: 其实常⽤流程都差不多,但是有时候还是会忘记某⼀步的详细⽤法,但是各位朋友请注意,官⽅已经不推荐Camera类的使⽤(现在是android.hardware.camera2),但⽆奈公司项⽬之前是使⽤Camera类实现的,并且Camera2貌似是基于API 21以上的,这Android 7的风声都放出来了,可是6.0现在出了3个多⽉了市场占有率也才貌似3%不到,什么时候才能有个标准化和统⼀规范,作为⼀名Android开发者实属不易啊,叹⽓~Android实现摄像头实时数据采集及通过硬编码编码数据的流程:/** 编码器获取数据,编码,编码后的数据的处理等⼤致流程如下:*//* 1.获取原始帧 */@OverrideonPreviewFrame( byte[] onPreviewData, Camera camera) {/* 在此可以对onPreviewData进⾏Rotate或者Scale* 也可以转换yuv的格式,例如yuv420P(YV12)或者yuv420SP(NV21/NV12)* 相关开源类库可以使⽤libyuv/ffmpeg等*/getRawFrame(onPreviewData)/* 然后将onPreviewData加⼊Camera回调*/addCallbackBuffer(onPreviewData);}private void getRawFrame( byte[] rawFrame ) { encodFrame(rawFrame); }/* 2.进⾏编码 */private byte[] encodFrame(byte[] inputData) { return encodedData; }/* 3.取得编码后的数据便可进⾏相应的操作,可以保存为本地⽂件,也可进⾏推流 */Operation ? Send(byte[] sendData) : Save(byte[] saveData)上述代码onPreviewFrame为Camera类的接⼝,使⽤Camera前需要进⾏SurfaceView及SurfaceHolder的初始化及相应interface的实现:// init the preview surfaceprivate void initview() {SurfaceView surfaceView = (SurfaceView) findViewById(R.id.record_surface);SurfaceHolder surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(this);surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {openCamera(holder); // 开启相机}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {releaseCamera(); // 在surfaceDestroyed的时候记得releaseCamera}private void openCamera(SurfaceHolder holder) {releaseCamera();try {camera = getCamera(Camera.CameraInfo.CAMERA_FACING_BACK); // 根据需求选择前/后置摄像头} catch (Exception e) {camera = null;if (AppContext.isDebugMode) {e.printStackTrace();}}if(mCamera != null){try {mCamera.setPreviewCallback(this);mCamera.setDisplayOrientation(90); // 此⽅法为官⽅提供的旋转显⽰部分的⽅法,并不会影响onPreviewFrame⽅法中的原始数据;if(parameters == null){parameters = mCamera.getParameters();}parameters.setPreviewFormat(ImageFormat.NV21); // 常⽤格式:NV21 / YV12parameters.setPreviewSize(width, height); // 还可以设置很多相机的参数,但是建议先遍历当前相机是否⽀持该配置,不然可能会导致出错;mCamera.setParameters(parameters);mCamera.setPreviewDisplay(holder);mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}}@TargetApi(9)private Camera getCamera(int cameraType) {Camera camera = null;try {camera = Camera.open(cameraType);} catch (Exception e) {e.printStackTrace();}return camera; // returns null if camera is unavailable}private synchronized void releaseCamera() {if (camera != null) {try {camera.setPreviewCallback(null);} catch (Exception e) {e.printStackTrace();}try {camera.stopPreview();} catch (Exception e) {e.printStackTrace();}try {camera.release();} catch (Exception e) {e.printStackTrace();}camera = null;}}MediaCodec硬编码实现部分:此处推荐参考SRS开源项⽬中的实现⽅法:// video device.private Camera camera;private MediaCodec vencoder;private MediaCodecInfo vmci;private MediaCodec.BufferInfo vebi;private byte[] vbuffer;// video camera settings.private Camera.Size vsize;private int vcolor;private int vbitrate_kbps = 300;private final static int VFPS = 20;private final static int VGOP = 5;private final static int VWIDTH = 640;private final static int VHEIGHT = 480;/* ⾸先需要初始化MediaCodec的配置 */private void initMediaCodec() {// choose the right vencoder, perfer qcom then google.vcolor = chooseVideoEncoder();// vencoder yuv to 264 es stream.// requires sdk level 16+, Android 4.1, 4.1.1, the JELLY_BEANtry {vencoder = MediaCodec.createByCodecName(vmci.getName());} catch (IOException e) {Log.e(TAG, "create vencoder failed.");e.printStackTrace();return;}vebi = new MediaCodec.BufferInfo();// setup the vencoder.// @see https:///reference/android/media/MediaCodec.htmlMediaFormat vformat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, vsize.width, vsize.height); vformat.setInteger(MediaFormat.KEY_COLOR_FORMAT, vcolor);vformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);vformat.setInteger(MediaFormat.KEY_BIT_RATE, 1000 * vbitrate_kbps);vformat.setInteger(MediaFormat.KEY_FRAME_RATE, VFPS);vformat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, VGOP);Log.i(TAG, String.format("vencoder %s, color=%d, bitrate=%d, fps=%d, gop=%d, size=%dx%d",vmci.getName(), vcolor, vbitrate_kbps, VFPS, VGOP, vsize.width, vsize.height));// the following error can be ignored:// 1. the storeMetaDataInBuffers error:// [OMX.qcom.video.encoder.avc] storeMetaDataInBuffers (output) failed w/ err -2147483648// @see /mediacodec/#q12vencoder.configure(vformat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);vencoder.start();}// for the vbuffer for YV12(android YUV), @see below://https:///reference/android/hardware/Camera.Parameters.html#setPreviewFormat(int)//https:///reference/android/graphics/ImageFormat.html#YV12private int getYuvBuffer(int width, int height) {// stride = ALIGN(width, 16)int stride = (int) Math.ceil(width / 16.0) * 16;// y_size = stride * heightint y_size = stride * height;// c_stride = ALIGN(stride/2, 16)int c_stride = (int) Math.ceil(width / 32.0) * 16;// c_size = c_stride * height/2int c_size = c_stride * height / 2;// size = y_size + c_size * 2return y_size + c_size * 2;}// choose the video encoder by name.private MediaCodecInfo chooseVideoEncoder(String name, MediaCodecInfo def) {int nbCodecs = MediaCodecList.getCodecCount();for (int i = 0; i < nbCodecs; i++) {MediaCodecInfo mci = MediaCodecList.getCodecInfoAt(i);if (!mci.isEncoder()) {continue;}String[] types = mci.getSupportedTypes();for (int j = 0; j < types.length; j++) {if (types[j].equalsIgnoreCase(VCODEC)) {//Log.i(TAG, String.format("vencoder %s types: %s", mci.getName(), types[j]));if (name == null) {return mci;}if (mci.getName().contains(name)) {return mci;}}}}return def;}// choose the right supported color format. @see below://https:///reference/android/media/MediaCodecInfo.html//https:///reference/android/media/MediaCodecInfo.CodecCapabilities.htmlprivate int chooseVideoEncoder() {// choose the encoder "video/avc":// 1. select one when type matched.// 2. perfer google avc.// 3. perfer qcom avc.vmci = chooseVideoEncoder(null, null);//vmci = chooseVideoEncoder("google", vmci);//vmci = chooseVideoEncoder("qcom", vmci);int matchedColorFormat = 0;MediaCodecInfo.CodecCapabilities cc = vmci.getCapabilitiesForType(VCODEC);for (int i = 0; i < cc.colorFormats.length; i++) {int cf = cc.colorFormats[i];Log.i(TAG, String.format("vencoder %s supports color fomart 0x%x(%d)", vmci.getName(), cf, cf));// choose YUV for h.264, prefer the bigger one.// corresponding to the color space transform in onPreviewFrameif ((cf >= cc.COLOR_FormatYUV420Planar && cf <= cc.COLOR_FormatYUV420SemiPlanar)) {if (cf > matchedColorFormat) {matchedColorFormat = cf;}}}for (int i = 0; i < cc.profileLevels.length; i++) {MediaCodecInfo.CodecProfileLevel pl = cc.profileLevels[i];Log.i(TAG, String.format("vencoder %s support profile %d, level %d", vmci.getName(), pl.profile, pl.level));}Log.i(TAG, String.format("vencoder %s choose color format 0x%x(%d)", vmci.getName(), matchedColorFormat, matchedColorFormat));return matchedColorFormat;} 上述代码为SRS的部分实现,仅作参考。

mediacodec压缩参数

mediacodec压缩参数

mediacodec压缩参数
MediaCodec 是Android 中用于音视频编解码的框架,它可以与Camera、SurfaceView、SurfaceTexture 等其他框架配合使用,实现高效的视频录制或播放功能。

在使用MediaCodec 进行视频编码时,需要设置一些压缩参数,以控制编码的输出质量及性能。

在设置MediaCodec 的压缩参数时,需要设置以下3 个主要参数:
1.编码器类型:MediaCodec 支持多种编码器类型,如H.264、VP8、H.265 等。

不同的编码器类型会影响编码的效率和输出质量,需要根据实际需求进行选择。

2.视频分辨率和帧率:分辨率和帧率是影响视频质量的重要因素,需要根据实际需求进行选择。

一般来说,较高的视频分辨率和帧率会导致更好的视频质量,但同时也会增加编码的负担和输出文件大小。

3.视频比特率:比特率是指视频输出的数据量大小,以每秒的比特数(bps)表示。

增加比特率可以提高视频输出的质量,但同时也会增加编码时间和输出文件大小。

需要根据实际需求进行选择。

除了这些主要参数外,MediaCodec 还支持一些其他的压缩参数,如I 帧间隔、码率控制方式、颜色格式等。

这些参数同样也可以根据实际需求进行调整,以达到最优的编码效果。

总的来说,设置MediaCodec 的压缩参数需要综合考虑多个因素,如视频质量、编码效率、输出文件大小等等。

需要根据实际需求进行选择,并进行不断的试验和优化,以实现最佳的编码效果和性能表现。

Android开发中的视频播放和流媒体处理技术(七)

Android开发中的视频播放和流媒体处理技术(七)

Android开发中的视频播放和流媒体处理技术随着智能手机的普及和网络带宽的提升,视频成为了人们生活中不可或缺的一部分。

Android作为全球最大的移动操作系统之一,自然也成为了主要的视频播放平台之一。

在Android开发中,视频播放和流媒体处理技术起到了至关重要的作用。

本文将从视频播放原理、流媒体处理技术以及相关的开发框架等方面进行论述。

一、视频播放原理在Android的视频播放中,最核心的技术之一是视频解码。

视频解码是将压缩后的视频文件解析成可显示的图像的过程。

Android系统中使用的主要视频解码器是MediaCodec,它支持硬件加速解码,能够提供更高的解码性能和更低的功耗。

视频解码的过程可以简述为以下几个步骤:首先,Android系统会通过MediaPlayer或者ExoPlayer等媒体播放器将视频文件读取到内存中;然后,媒体播放器将视频数据传递给MediaCodec进行解码;解码后的视频数据会通过Surface类的实例绘制到屏幕上。

除了视频解码,视频播放还涉及到音频解码、视频渲染、播放控制等一系列技术。

音频解码使用的是AudioTrack类,它可以将压缩后的音频数据解码成原始音频数据。

视频渲染相关的技术主要使用的是SurfaceView类或TextureView类,它们可以以不同的方式将解码后的视频数据显示在屏幕上。

播放控制方面,Android提供了MediaPlayer类和ExoPlayer类等媒体播放器,开发者可以通过这些类实现视频播放的各种操作。

二、流媒体处理技术随着网络带宽的提升,流媒体成为了人们观看视频的主要方式。

在流媒体处理中,最常见的技术是流媒体传输协议和流媒体编码。

在Android开发中,最常用的流媒体传输协议是HTTP协议。

HTTP 协议可以通过流式传输的方式,将视频数据分段传输到客户端进行播放。

常见的HTTP流媒体协议有HLS和DASH等。

HLS(HTTP Live Streaming)是苹果公司推出的一种流媒体传输协议,它通过将视频文件切分成小的TS文件,并采用HTTP协议进行传输。

ndkmediacodec用法

ndkmediacodec用法

ndkmediacodec用法随着Android平台的发展,多媒体处理已经变得越来越重要。

对于开发人员来说,NDKMediaCodec库提供了一种在Android平台上进行多媒体处理的方式。

本文将详细介绍NDKMediaCodec库的用法,帮助您更好地理解和使用它。

NDKMediaCodec是一个用于Android平台的多媒体编解码库,它提供了对MediaCodec接口的封装,使得开发人员能够更方便地在Android平台上进行多媒体处理。

通过使用NDKMediaCodec库,开发人员可以轻松地实现视频和音频的编解码、播放和处理等功能。

二、准备工作在使用NDKMediaCodec库之前,您需要确保您的开发环境已经正确设置,并且已经包含了NDKMediaCodec库的相关依赖。

此外,您还需要了解Android NDK的相关知识,以便能够正确地使用NDKMediaCodec库。

三、基本用法在使用NDKMediaCodec库进行多媒体处理时,您需要按照以下步骤进行操作:1. 初始化MediaCodec:首先,您需要初始化MediaCodec,指定要处理的媒体格式和编解码器类型。

2. 设置输入数据:使用MediaCodec提供的API将媒体数据输入到编解码器中。

3. 开始编解码:调用MediaCodec的start()方法开始编解码过程。

4. 获取输出数据:在编解码完成后,您可以使用MediaCodec提供的API获取编解码器的输出数据。

5. 释放资源:在完成多媒体处理后,您需要释放MediaCodec及相关资源。

下面是一个简单的示例代码,演示了如何使用NDKMediaCodec库进行音频编解码:```c++// 初始化MediaCodecint ret = MediaCodec::createEncoder(mediaCodecType, &codec);if (ret != 0) {// 错误处理}// 设置输入数据std::vector<uint8_t> inputBuffer(1024);// 将音频数据填充到inputBuffer中codec->queueInputBuffer(0, 0, inputBuffer.size(), nullptr, 0);// 开始编解码codec->start();// 获取输出数据uint8_t outputBuffer[1024];ssize_t outputSize = codec->dequeueOutputBuffer(outputBuffer, sizeof(outputBuffer));if (outputSize >= 0) {// 处理输出数据}// 释放资源codec->stop();codec->release();```四、高级用法除了基本用法外,NDKMediaCodec库还提供了许多高级功能和选项,如编解码器配置、输入和输出缓冲区的设置等。

Android用MediaCodec实现视频硬解码

Android用MediaCodec实现视频硬解码

Android⽤MediaCodec实现视频硬解码本⽂向你讲述如何⽤android标准的API (MediaCodec)实现视频的硬件编解码。

例程将从摄像头采集视频开始,然后进⾏H264编码,再解码,然后显⽰。

1、从摄像头采集视频可以通过摄像头Preview的回调,来获取视频数据。

⾸先创建摄像头,并设置参数:[java]01. cam = Camera.open();02. cam.setPreviewDisplay(holder);03. Camera.Parameters parameters = cam.getParameters();04. parameters.setFlashMode("off"); // ⽆闪光灯05. parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);06. parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);07. parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);08. parameters.setPreviewFormat(ImageFormat.YV12);09. parameters.setPictureSize(camWidth, camHeight);10. parameters.setPreviewSize(camWidth, camHeight);11. //这两个属性如果这两个属性设置的和真实⼿机的不⼀样时,就会报错12. cam.setParameters(parameters);宽度和⾼度必须是摄像头⽀持的尺⼨,否则会报错。

要获得所有⽀持的尺⼨,可⽤getSupportedPreviewSizes,这⾥不再累述。

mediacodec编程

mediacodec编程

mediacodec编程【最新版】目录1.媒体编解码器概述2.MediaCodec 的作用和优势3.MediaCodec 编程的基本步骤4.MediaCodec 的应用示例5.MediaCodec 的未来发展趋势正文【媒体编解码器概述】媒体编解码器(Media Codec)是一种用于音频和视频编解码的软件组件,可以实现对音频和视频数据的压缩和解压缩。

在数字媒体领域,编解码器是非常重要的技术,因为它们可以使音频和视频数据在网络传输和存储过程中更加高效。

【MediaCodec 的作用和优势】MediaCodec 是 Android 系统中的一个重要组件,主要用于音频和视频的编解码。

相较于传统的编解码器,MediaCodec 具有以下优势:1.开源:MediaCodec 是开源的,这意味着开发者可以自由地对其进行修改和定制,以满足不同的需求。

2.硬件加速:MediaCodec 支持硬件加速,这使得编解码过程更加高效,从而降低了功耗和提升了性能。

3.灵活性:MediaCodec 支持多种编解码格式,这使得开发者可以根据需求选择合适的编解码格式。

【MediaCodec 编程的基本步骤】要使用 MediaCodec 进行编程,需要遵循以下基本步骤:1.创建 MediaCodec 实例:首先,需要创建一个 MediaCodec 实例,这可以通过调用 MediaCodec.create() 方法实现。

2.配置 MediaCodec:创建 MediaCodec 实例后,需要对其进行配置,包括设置编解码格式、输入输出缓冲区等。

3.准备输入数据:在开始编解码之前,需要准备输入数据。

对于视频编解码,需要准备一幅幅的图像数据;对于音频编解码,需要准备音频采样数据。

4.开始编解码:准备工作完成后,可以调用 MediaCodec.start() 方法开始编解码。

在编解码过程中,需要不断地输入数据,并在适当的时候输出解码后的数据。

Android音频采集——MediaRecord(编码后录影文件)、AudioRecord。。。

Android音频采集——MediaRecord(编码后录影文件)、AudioRecord。。。

Android⾳频采集——MediaRecord(编码后录影⽂件)、AudioRecord。

⾳频简介常见的⾳频编解码的类型:AAC OPUS MP3 AMR Ogg PCMAAC: ⾼级⾳频编码对应 .m4a(audio/m4a)或者.3pg(audio/3gpp)⽂件 HEAAC:⾼级AAC,使⽤的⽐较多。

OPUS:有损声⾳编码的格式,由互联⽹⼯程任务组(IETF)进来开发,适⽤于⽹络上的实时声⾳传输,如:语⾳通话MP3: 使⽤的最⼴泛的⾳频编解码器对应 .mp3(audio/mp3) 各种⾳乐⽹站⼀般⽤这种。

AMR:⾃适应多速率⾳频编解码器,⼀般⽤于语⾳呼叫程序。

Ogg:开发的⽆专利的⾳频编解码器,其质量可与商业的和⼿专利保护的MP3以及AAC编解码相媲美。

PCM :原始⾳频,在平台上由audio record直接录⽤下来的,未经过编码的。

视频直播,语⾳通话中⼀般使⽤AAC或者OPUS ,如果对声⾳要进⾏处理就需要使⽤PCM原始⾳频加⼯处理,然后再进⾏编码.Android⾳频采集(捕获)android平台上的⾳频采集⼀般就三种:1.利⽤android内置的应⽤程序 2.使⽤MediaRecorder进⾏⾳频捕获 3.使⽤AudioRecord进⾏⾳频捕获。

此3种⽅式的灵活性逐渐增⼤,相应的所需要做的⼯作也逐渐增多。

⼀、Android 内置的应⽤程序。

[java]1. Intent intent=new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);2. startActivityForResult(intent,0); //通过startActivityForResult获取⾳频录制的结果的路径这种⽅式灵活度最差,⼀般就是做着演⽰下,开发中基本不⽤这种⽅案。

⼆、使⽤MediaRecorder进⾏⾳频的捕获。

这个是录影视频和⾳频分别编码后保存成⼀个⽂件,单独⾳频也可以,不过是编码后的数据这种⽅案相较于调⽤系统内置的⽤⽤程序,灵活度要⾼很多,便于开发者在UI界⾯上布局,⽽且系统封装的很好,便于使⽤,唯⼀的缺点是使⽤它录下来的⾳频是经过编码的,没有办法的得到原始的⾳频。

Android最简单的视频播放器之MediaCodec硬件解码器封装(二)

Android最简单的视频播放器之MediaCodec硬件解码器封装(二)

Android最简单的视频播放器之MediaCodec硬件解码器封装(⼆)⼀、概述 MediaCodec是Android提供的硬件编解码器API,根据此api⽤户可以对媒体格式的⽂件执⾏编解码。

其单独没法⼯作还需要配合上⼀节介绍的 案例:本例最主要的是三个类,分别是BaseDecoder.java 、AudioDecoder、VideoDecoder.java即⾳视频解码类实例⼆、代码实例 1.BaseDecoder.java:硬件解码器基类import android.media.MediaCodec;import android.media.MediaFormat;import android.util.Log;import com.yw.thesimpllestplayer.extractor.IExtractor;import java.io.File;import java.nio.ByteBuffer;/*** @ProjectName: TheSimpllestplayer* @Package: com.yw.thesimpllestplayer.mediaplayer.decoder* @ClassName: BaseDecoder* @Description: 硬件解码器基类* @Author: wei.yang* @CreateDate: 2021/11/6 10:32* @UpdateUser: 更新者:wei.yang* @UpdateDate: 2021/11/6 10:32* @UpdateRemark: 更新说明:* @Version: 1.0*/public abstract class BaseDecoder implements IDecoder {private String filePath = null;public BaseDecoder(String filePath) {this.filePath = filePath;}private static final String TAG = "BaseDecoder";//-------------线程相关------------------------/*** 解码器是否在运⾏*/private boolean mIsRunning = true;/*** 线程等待锁*/private Object mLock = new Object();/*** 是否可以进⼊解码*/private boolean mReadyForDecode = false;//---------------状态相关-----------------------/*** ⾳视频解码器(硬件解码器)*/private MediaCodec mCodec = null;/*** ⾳视频数据读取器*/private IExtractor mExtractor = null;/*** 解码输⼊缓存区*/private ByteBuffer[] mInputBuffers = null;/*** 解码输出缓存区private ByteBuffer[] mOutputBuffers = null;/*** 解码数据信息*/private MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo(); /*** 初始化解码状态*/private DecodeState mState = DecodeState.STOP;/*** 解码状态回调*/protected IDecoderStateListener mStateListener;/*** 流数据是否结束*/private boolean mIsEOS = false;/*** 视频宽度*/private int mVideoWidth = 0;/*** 视频⾼度*/private int mVideoHeight = 0;/*** 视频时长*/private long mDuration = 0;/*** 视频结束时间*/private long mEndPos = 0;/*** 开始解码时间,⽤于⾳视频同步*/private long mStartTimeForSync = -1L;/*** 是否需要⾳视频渲染同步*/private boolean mSyncRender = true;@Overridepublic void pause() {mState = DecodeState.PAUSE;}@Overridepublic void goOn() {mState = DecodeState.DECODING;notifyDecode();}@Overridepublic long seekTo(long pos) {return0;}@Overridepublic long seekAndPlay(long pos) {return0;}@Overridepublic void stop() {mState = DecodeState.STOP;mIsRunning = false;notifyDecode();}@Overridepublic boolean isDecoding() {return mState == DecodeState.DECODING;}@Overridepublic boolean isSeeking() {return mState == DecodeState.SEEKING;}@Overridereturn mState == DecodeState.STOP;}@Overridepublic int getWidth() {return mVideoWidth;}@Overridepublic int getHeight() {return mVideoHeight;}@Overridepublic long getDuration() {return mDuration;}@Overridepublic long getCurTimeStamp() {return mBufferInfo.presentationTimeUs / 1000;}@Overridepublic int getRotationAngle() {return0;}@Overridepublic MediaFormat getMediaFormat() {return mExtractor.getFormat();}@Overridepublic int getTrack() {return0;}@Overridepublic String getFilePath() {return filePath;}@Overridepublic IDecoder withoutSync() {mSyncRender = false;return this;}@Overridepublic void setSizeListener(IDecoderProgress iDecoderProgress) {}@Overridepublic void setStateListener(IDecoderStateListener iDecoderStateListener) { this.mStateListener = iDecoderStateListener;}@Overridepublic void run() {//解码开始时改变解码状态if (mState == DecodeState.STOP) {mState = DecodeState.START;}if (mStateListener != null) {mStateListener.decoderPrepare(this);}//初始化并启动解码器,如果解码失败则暂停线程if (!init()) return;//开始解码Log.e(TAG, "开始解码");try {while (mIsRunning) {//循环解码渲染if (mState != DecodeState.START &&mState != DecodeState.DECODING &&mState != DecodeState.SEEKING) {Log.i(TAG, "进⼊等待:" + mState);//解码进⼊等待waitDecode();// ---------【同步时间矫正】-------------//当前系统时间减去bufferinfo中的时间=等待解码流失的时间mStartTimeForSync = System.currentTimeMillis() - getCurTimeStamp(); }//停⽌解码,就直接退出循环了if (!mIsRunning ||mState == DecodeState.STOP) {mIsRunning = false;break;}//更新开始解码时间if (mStartTimeForSync == -1L) {mStartTimeForSync = System.currentTimeMillis();}//如果数据没有解码完毕,将数据推⼊解码器解码if (!mIsEOS) {//【解码步骤:2. 见数据压⼊解码器输⼊缓冲】mIsEOS = pushBufferToDecoder();}//将解码后的数据从缓冲区中拉取出来int outputBufferIndex = pullBufferFromDecoder();if (outputBufferIndex >= 0) {// ---------【⾳视频同步】-------------if (mSyncRender && mState == DecodeState.DECODING) {sleepRender();}//渲染if (mSyncRender) {render(mOutputBuffers[outputBufferIndex], mBufferInfo);}//将解码数据传出去Frame frame = new Frame();frame.buffer = mOutputBuffers[outputBufferIndex];frame.setBufferInfo(mBufferInfo);if (mStateListener != null) {mStateListener.decodeOneFrame(this, frame);}//释放输出缓冲mCodec.releaseOutputBuffer(outputBufferIndex, true);if (mState == DecodeState.START) {mState = DecodeState.PAUSE;}}//判断是否解码完成if (mBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) { Log.e(TAG, "解码结束");mState = DecodeState.FINISH;if (mStateListener != null) {mStateListener.decoderFinish(this);}}}} catch (Exception e) {e.printStackTrace();} finally {finishDecode();release();}}/*** 初始化解码器,如果初始化失败则停⽌解码** @return*/private boolean init() {//如果⽂件路径不存在或者⽂件路径指定的⽂件为空if (filePath == null || !new File(filePath).exists()) {Log.e(TAG, "⽂件路径异常");if (mStateListener != null) {mStateListener.decoderError(this, "⽂件路径为空");}return false;}if (!check()) return false;//初始化数据提取器mExtractor = initExtractor(filePath);if (mExtractor == null || mExtractor.getFormat() == null) {Log.e(TAG, "⽆法解析⽂件");if (mStateListener != null) {mStateListener.decoderError(this, "⽆法解析⽂件");return false;}//初始化参数if (!initParams()) return false;//初始化渲染器if (!initRender()) return false;//初始化解码器if (!initCodec()) return false;return true;}/*** 初始化媒体时长及初始化媒体参数** @return*/private boolean initParams() {try {MediaFormat format = mExtractor.getFormat();mDuration = format.getLong(MediaFormat.KEY_DURATION) / 1000;if (mEndPos == 0L) mEndPos = mDuration;initSpecParams(format);} catch (Exception e) {e.printStackTrace();Log.e(TAG, "提取媒体⽂件时长或者初始化媒体参数失败:" + e.getMessage());if (mStateListener != null) {mStateListener.decoderError(this, "提取媒体⽂件时长或者初始化媒体参数失败"); }return false;}return true;}private boolean initCodec() {try {//获取媒体类型String mimeType = mExtractor.getFormat().getString(MediaFormat.KEY_MIME);//创建解码器mCodec = MediaCodec.createDecoderByType(mimeType);//配置解码器if (!configCodec(mCodec, mExtractor.getFormat())) {//解码线程进⼊等待waitDecode();}//开始解码mCodec.start();//从缓冲区中去取输⼊缓冲mInputBuffers = mCodec.getInputBuffers();//从缓冲区中取出输出缓冲mOutputBuffers = mCodec.getOutputBuffers();} catch (Exception e) {e.printStackTrace();return false;}return true;}/*** 解码线程进⼊等待*/private void waitDecode() {try {if (mState == DecodeState.PAUSE) {if (mStateListener != null) {mStateListener.decoderPause(this);}}synchronized (mLock) {mLock.wait();}} catch (Exception e) {e.printStackTrace();}}/*** 通知解码线程继续运⾏*/protected void notifyDecode() {synchronized (mLock) {mLock.notifyAll();if (mState == DecodeState.DECODING) {if (mStateListener != null) {mStateListener.decoderRunning(this);}}}/*** 向缓冲区中压缩解码前的数据** @return*/private boolean pushBufferToDecoder() {//从缓冲区中获取⼀个bufferindexint inputBufferIndex = mCodec.dequeueInputBuffer(1000);boolean isEndOfStream = false;if (inputBufferIndex >= 0) {//根据inputBufferIndex获取inputBufferByteBuffer inputBuffer = mInputBuffers[inputBufferIndex];//使⽤数据提取器Extractor读取⼀帧数据int sampleSize = mExtractor.readBuffer(inputBuffer);if (sampleSize < 0) {//如果数据帧兑取失败则说明读完了mCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isEndOfStream = true;} else {//将读取到的数据送⼊缓冲区(压⼊)mCodec.queueInputBuffer(inputBufferIndex, 0, sampleSize, mExtractor.getCurrentTimestamp(), 0);}}return isEndOfStream;}/*** 从缓冲区中取出解码后的数据** @return*/private int pullBufferFromDecoder() {//从缓冲区中取出outputbufferindexint outputBufferIndex = mCodec.dequeueOutputBuffer(mBufferInfo, 1000);switch (outputBufferIndex) {case _OUTPUT_FORMAT_CHANGED:break;case _TRY_AGAIN_LATER:break;case _OUTPUT_BUFFERS_CHANGED:mOutputBuffers = mCodec.getOutputBuffers();break;default:return outputBufferIndex;}return -1;}/*** ⾳视频同步*/private void sleepRender() {try {long passTime = System.currentTimeMillis() - mStartTimeForSync;long currTime = getCurTimeStamp();if (currTime > passTime) {Thread.sleep(currTime - passTime);}} catch (Exception e) {e.printStackTrace();}}/*** 释放解码器*/private void release() {try {Log.i(TAG, "解码停⽌,释放解码器");mState = DecodeState.STOP;mIsEOS = false;mExtractor.stop();mCodec.stop();mCodec.release();if (mStateListener != null) {mStateListener.decoderDestroy(this);} catch (Exception e) {e.printStackTrace();}}/*** 检查⼦类参数** @return*/public abstract boolean check();/*** 初始化数据提取器** @param filePath 媒体⽂件路径* @return 数据提取器*/public abstract IExtractor initExtractor(String filePath);/*** 初始化⼦类⾃⼰持有的媒体参数** @param format*/public abstract void initSpecParams(MediaFormat format);/*** 配置解码器** @param codec 硬件解码器* @param format 媒体格式参数* @return*/public abstract boolean configCodec(MediaCodec codec, MediaFormat format);/*** 初始化渲染器** @return*/public abstract boolean initRender();/*** 执⾏渲染操作** @param outputBuffer 输出的渲染数据* @param bufferInfo 解码出来的数据*/public abstract void render(ByteBuffer outputBuffer, MediaCodec.BufferInfo bufferInfo); /*** 结束解码*/public abstract void finishDecode();} 2.AudioDecoder.java:⾳频解码器import android.media.MediaCodec;import android.media.MediaFormat;import com.yw.thesimpllestplayer.audioplayer.AudioPlayer;import com.yw.thesimpllestplayer.extractor.AudioExtractor;import com.yw.thesimpllestplayer.extractor.IExtractor;import java.nio.ByteBuffer;/*** @ProjectName: TheSimpllestplayer* @Package: com.yw.thesimpllestplayer.mediaplayer.decoder* @ClassName: AudioDecoder* @Description: ⾳频解码器* @Author: wei.yang* @CreateDate: 2021/11/6 13:55* @UpdateUser: 更新者:wei.yang* @UpdateDate: 2021/11/6 13:55* @UpdateRemark: 更新说明:* @Version: 1.0*/private AudioPlayer audioPlayer;public AudioDecoder(String filePath) {super(filePath);}@Overridepublic boolean check() {return true;}@Overridepublic IExtractor initExtractor(String filePath) {return new AudioExtractor(filePath);}@Overridepublic void initSpecParams(MediaFormat format) {if (audioPlayer == null) {audioPlayer = new AudioPlayer(format);}}@Overridepublic boolean configCodec(MediaCodec codec, MediaFormat format) {codec.configure(format, null, null, 0);return true;}@Overridepublic boolean initRender() {audioPlayer.initPlayer();return true;}@Overridepublic void render(ByteBuffer outputBuffer, MediaCodec.BufferInfo bufferInfo) { audioPlayer.play(outputBuffer, bufferInfo);}@Overridepublic void finishDecode() {audioPlayer.stop();audioPlayer.release();}} 2.VideoDecoder.java:视频解码器import android.media.MediaCodec;import android.media.MediaFormat;import android.util.Log;import android.view.Surface;import com.yw.thesimpllestplayer.extractor.IExtractor;import com.yw.thesimpllestplayer.extractor.VideoExtractor;import java.nio.ByteBuffer;/*** @ProjectName: TheSimpllestplayer* @Package: com.yw.thesimpllestplayer.mediaplayer.decoder* @ClassName: VideoDecoder* @Description: 视频解码器* @Author: wei.yang* @CreateDate: 2021/11/6 13:49* @UpdateUser: 更新者:wei.yang* @UpdateDate: 2021/11/6 13:49* @UpdateRemark: 更新说明:* @Version: 1.0*/public class VideoDecoder extends BaseDecoder {private static final String TAG = "VideoDecoder";private Surface surface;public VideoDecoder(String filePath, Surface surface) {super(filePath);this.surface = surface;@Overridepublic boolean check() {if (surface == null) {Log.e(TAG, "Surface不能为空");if (mStateListener != null) {mStateListener.decoderError(this, "显⽰器为空");}return false;}return true;}@Overridepublic IExtractor initExtractor(String filePath) {return new VideoExtractor(filePath);}@Overridepublic void initSpecParams(MediaFormat format) {}@Overridepublic boolean configCodec(MediaCodec codec, MediaFormat format) {if (surface != null) {codec.configure(format, surface, null, 0);notifyDecode();} else {if (mStateListener != null) {mStateListener.decoderError(this, "配置解码器失败,因为Surface为空"); }Log.e(TAG, "配置解码器失败,因为Surface为空");return false;}return true;}@Overridepublic boolean initRender() {return true;}@Overridepublic void render(ByteBuffer outputBuffer, MediaCodec.BufferInfo bufferInfo) { }@Overridepublic void finishDecode() {}}。

mediacodec ndk编程

mediacodec ndk编程

【mediacodec ndk编程】在Android应用开发中,利用NDK(Native Development Kit)进行底层编程,能够更好地发挥硬件性能,提高应用的性能和用户体验。

而在音视瓶处理方面,使用mediacodec编程可以实现高效的音视瓶编解码,提高应用在音视瓶处理方面的性能。

1. mediacodec编程的基本概念mediacodec是Android提供的用于音视瓶编解码的API,通过mediacodec可以实现对音视瓶数据的编码和解码操作。

在Android 中,mediacodec主要分为软件编解码和硬件编解码两种方式,可以根据实际需求选择合适的编解码方式。

2. mediacodec编程的优势相比于软件编解码,硬件编解码能够充分利用设备的硬件加速能力,提高编解码的效率和性能。

在高清视瓶播放和实时视瓶通信等场景下,使用硬件编解码能够更好地满足用户的需求,提供流畅的音视瓶体验。

3. mediacodec编程的应用场景在移动直播、视瓶通话、视瓶播放器等应用中,mediacodec编程都有着重要的应用价值。

通过对音视瓶数据的编解码操作,可以实现高清、流畅的视瓶播放和实时的视瓶通话,为用户提供更好的视听体验。

4. mediacodec编程的技术实现在Android应用开发中,可以利用NDK进行mediacodec编程。

通过JNI(Java Native Interface)将C/C++代码集成到Java代码中,实现对mediacodec的调用和控制。

借助NDK,开发者可以充分发挥硬件的性能优势,提高音视瓶编解码的效率和质量。

5. mediacodec编程的挑战和解决方案在进行mediacodec编程时,开发者需要充分了解设备的硬件能力和支持的编解码格式,同时需要处理好编解码器的状态管理和数据流的传输。

不同设备和Android版本对mediacodec的支持也存在差异,需要进行充分的测试和适配工作。

android 使用MediaCodec 编解码总结

android 使用MediaCodec 编解码总结

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

1.MediaCodec类的编解码原理参考链接:https:///reference/android/media/M ediaCodec.html工作流是这样的:以编码为例,首先要初始化硬件编码器,配置要编码的格式、视频文件的长宽、码率、帧率、关键帧间隔等等。

这一步叫configure。

之后开启编码器,当前编码器便是可用状态,随时准备接收数据。

下一个过程便是编码的running过程,在此过程中,需要维护两个buffer队列,InputBuffer 和OutputBuffer,用户需要不断出队InputBuffer (即dequeueInputBuffer),往里边放入需要编码的图像数据之后再入队等待处理,然后硬件编码器开始异步处理,一旦处理结束,他会将数据放在OutputBuffer中,并且通知用户当前有输出数据可用了,那么用户就可以出队一个OutputBuffer,将其中的数据拿走,然后释放掉这个buffer。

结束条件在于end-of-stream这个flag标志位的设定。

在编码结束后,编码器调用stop函数停止编码,之后调用release 函数将编码器完全释放掉,整体流程结束。

2. 视频解码程序示例代码来源于Android: MediaCodec视频文件硬件解码以下所有代码可以在此处下载[java] view plain copyprint?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 class 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_FormatYUV4 20Flexible;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 &amp;&amp; fileType != FILE_TypeNV21 &amp;&amp; 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 &lt; 0) {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().getC apabilitiesForType(mime));if(isColorFormatSupported(decodeColorFormat, decoder.getCodecInfo().getCapabilitiesForType(mime))) {mediaFormat.setInteger(MediaFormat.KEY_COLOR_FOR MAT, 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 Surfaceclose();}}private voidshowSupportedColorFormat(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 = newMediaCodec.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 &gt;= 0) {ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);int sampleSize =extractor.readSampleData(inputBuffer, 0); //将一部分视频数据读取到inputbuffer中,大小为sampleSizeif (sampleSize &lt; 0) {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 &gt;= 0) {if ((info.flags &amp;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);compressToJpeg(fileName, image);break;}}image.close();decoder.releaseOutputBuffer(outputBufferId, true);}}}}private static int selectTrack(MediaExtractor extractor) {int numTracks = extractor.getTrackCount();for (int i = 0; i &lt; numTracks; 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 booleanisImageFormatSupported(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&amp;&amp; colorFormat != COLOR_FormatNV21) {throw new IllegalArgumentException("only support COLOR_FormatI420 " + "andCOLOR_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&amp;&amp; colorFormat != COLOR_FormatNV21) {throw new IllegalArgumentException("only support COLOR_FormatI420 " + "andCOLOR_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 = newbyte[planes[0].getRowStride()];int channelOffset = 0;int outputStride = 1;for (int i = 0; i &lt; planes.length; 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 用法

android mediacodec 用法

android mediacodec 用法Android Mediacodec 是Android 提供的一个用于音视频编解码的API,它可以让开发者在自己的应用程序中直接使用硬件加速的编解码器来进行音视频处理。

本文将以"Android Mediacodec 用法"为主题,详细介绍Mediacodec的使用方法。

一、什么是Android MediacodecAndroid Mediacodec 是Android 系统提供的一个多媒体编解码库,它可以让开发者使用硬件加速的编解码器来处理音频和视频数据。

相比于传统的软件编解码方式,Mediacodec 在性能上有很大的提升,能够更好地满足应用程序对音视频处理的需求。

二、Mediacodec 的基本使用步骤在开始使用Mediacodec 之前,首先需要了解一下Mediacodec 的基本使用步骤。

下面是Mediacodec 的基本使用步骤:1. 创建Mediacodec 对象:使用Mediacodec 的静态方法`createDecoderByType` 或`createEncoderByType` 来创建一个Mediacodec 对象。

需要传入一个String 类型的参数,表示要使用的编解码器的类型,例如"video/avc" 表示使用H.264 编解码器。

2. 配置Mediacodec:在创建Mediacodec 对象之后,需要通过调用`configure` 方法来配置Mediacodec。

需要传入一个MediaFormat 对象,该对象需要指定各种参数,例如输入数据的格式、输出数据的格式、编码码率等等。

3. 启动Mediacodec:在配置Mediacodec 完成之后,调用`start` 方法来启动Mediacodec。

4. 处理输入数据:使用Mediacodec 的`dequeueInputBuffer` 方法获取一个可以用于填充输入数据的ByteBuffer 对象,并将音视频数据填充到ByteBuffer 中。

mediacodec使用方法

mediacodec使用方法

mediacodec使用方法MediaCodec是Android平台上用于实时的音视频编解码的API。

通过使用MediaCodec,开发者可以高效地对音视频数据进行编解码操作,实现音视频的录制、播放、编解码等功能。

一、MediaCodec简介MediaCodec是Android提供的一个多媒体编解码器,它允许开发者对音频和视频进行编解码操作,是实现音视频处理的重要组件之一。

MediaCodec提供了硬件加速的选项,可以提高音视频编解码的性能,减少CPU的负载。

同时,它也支持软件编解码,适用于不支持硬件加速的平台。

二、MediaCodec的基本概念1. 编码器(Encoder):将原始的音视频数据压缩成特定格式的编码器,如将PCM音频编码为AAC格式。

2. 解码器(Decoder):将已经编码的音视频数据解压缩还原为原始的数据格式,如将AAC音频解码为PCM格式。

3. 媒体格式(MediaFormat):用于描述音视频数据的格式,包括媒体类型(音频或视频)、采样率、位宽、编码器名称等。

4. 输入缓冲区(Input Buffer):用于存储待编码的音视频数据,在编码之前需要将数据填充到输入缓冲区。

5. 输出缓冲区(Output Buffer):用于存储编码后或解码后的音视频数据,在编解码完成后可以从输出缓冲区获取数据。

三、使用MediaCodec进行音视频编码以下是使用MediaCodec进行音视频编码的步骤:1. 创建一个MediaCodec实例:调用MediaCodec.createEncoderByType()方法或MediaCodec.createDecoderByType()方法创建一个编码器或解码器实例。

传入媒体类型参数,如"audio/mp4a-latm"表示AAC音频编码器。

2. 配置编码器或解码器:配置媒体格式(MediaFormat),包括音频采样率、位宽、声道数等信息。

Android使用MediaCodec将摄像头采集的视频编码为h264

Android使用MediaCodec将摄像头采集的视频编码为h264

Android使⽤MediaCodec将摄像头采集的视频编码为h264本⽂实例为⼤家分享了Android使⽤MediaCodec将摄像头采集的视频编码为h264,供⼤家参考,具体内容如下MainActivity.javaimport android.app.Activity;import android.graphics.ImageFormat;import android.hardware.Camera;import android.hardware.Camera.Parameters;import android.hardware.Camera.PreviewCallback;import android.os.Bundle;import android.view.SurfaceHolder;import android.view.SurfaceView;import java.io.IOException;import java.util.concurrent.ArrayBlockingQueue;public class MainActivity extends Activity implements SurfaceHolder.Callback,PreviewCallback{private SurfaceView surfaceview;private SurfaceHolder surfaceHolder;private Camera camera;private Parameters parameters;int width = 1280;int height = 720;int framerate = 30;int biterate = 8500*1000;private static int yuvqueuesize = 10;//待解码视频缓冲队列,静态成员!public static ArrayBlockingQueue<byte[]> YUVQueue = new ArrayBlockingQueue<byte[]>(yuvqueuesize);private AvcEncoder avcCodec;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_main);surfaceview = (SurfaceView)findViewById(R.id.surfaceview);surfaceHolder = surfaceview.getHolder();surfaceHolder.addCallback(this);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {camera = getBackCamera();startcamera(camera);//创建AvEncoder对象avcCodec = new AvcEncoder(width,height,framerate,biterate);//启动编码线程avcCodec.StartEncoderThread();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {if (null != camera) {camera.setPreviewCallback(null);camera.stopPreview();camera.release();camera = null;avcCodec.StopThread();}}@Overridepublic void onPreviewFrame(byte[] data, android.hardware.Camera camera) {//将当前帧图像保存在队列中putYUVData(data,data.length);}public void putYUVData(byte[] buffer, int length) {if (YUVQueue.size() >= 10) {YUVQueue.poll();}YUVQueue.add(buffer);}private void startcamera(Camera mCamera){if(mCamera != null){try {mCamera.setPreviewCallback(this);mCamera.setDisplayOrientation(90);if(parameters == null){parameters = mCamera.getParameters();}//获取默认的camera配置parameters = mCamera.getParameters();//设置预览格式parameters.setPreviewFormat(ImageFormat.NV21);//设置预览图像分辨率parameters.setPreviewSize(width, height);//配置camera参数mCamera.setParameters(parameters);//将完全初始化的SurfaceHolder传⼊到setPreviewDisplay(SurfaceHolder)中//没有surface的话,相机不会开启preview预览mCamera.setPreviewDisplay(surfaceHolder);//调⽤startPreview()⽤以更新preview的surface,必须要在拍照之前start Preview mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}}private Camera getBackCamera() {Camera c = null;try {//获取Camera的实例c = Camera.open(0);} catch (Exception e) {e.printStackTrace();}//获取Camera的实例失败时返回nullreturn c;}}2.AvcEncoder.javaimport android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaFormat;import android.os.Environment;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import static android.media.MediaCodec.BUFFER_FLAG_CODEC_CONFIG;import static android.media.MediaCodec.BUFFER_FLAG_KEY_FRAME;public class AvcEncoder{private final static String TAG = "MeidaCodec";private int TIMEOUT_USEC = 12000;private MediaCodec mediaCodec;int m_width;int m_height;int m_framerate;public byte[] configbyte;public AvcEncoder(int width, int height, int framerate, int bitrate) {m_width = width;m_height = height;m_framerate = framerate;MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width*height*5);mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);try {mediaCodec = MediaCodec.createEncoderByType("video/avc");} catch (IOException e) {e.printStackTrace();}//配置编码器参数mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);//启动编码器mediaCodec.start();//创建保存编码后数据的⽂件createfile();}private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h264";private BufferedOutputStream outputStream;private void createfile(){File file = new File(path);if(file.exists()){file.delete();}try {outputStream = new BufferedOutputStream(new FileOutputStream(file));} catch (Exception e){e.printStackTrace();}}private void StopEncoder() {try {mediaCodec.stop();mediaCodec.release();} catch (Exception e){e.printStackTrace();}}public boolean isRuning = false;public void StopThread(){isRuning = false;try {StopEncoder();outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}int count = 0;public void StartEncoderThread(){Thread EncoderThread = new Thread(new Runnable() {@Overridepublic void run() {isRuning = true;byte[] input = null;long pts = 0;long generateIndex = 0;while (isRuning) {//访问MainActivity⽤来缓冲待解码数据的队列if (MainActivity.YUVQueue.size() >0){//从缓冲队列中取出⼀帧input = MainActivity.YUVQueue.poll();byte[] yuv420sp = new byte[m_width*m_height*3/2];//把待编码的视频帧转换为YUV420格式NV21ToNV12(input,yuv420sp,m_width,m_height);input = yuv420sp;}if (input != null) {try {long startMs = System.currentTimeMillis();//编码器输⼊缓冲区ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();//编码器输出缓冲区ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);if (inputBufferIndex >= 0) {pts = computePresentationTime(generateIndex);ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];inputBuffer.clear();//把转换后的YUV420格式的视频帧放到编码器输⼊缓冲区中inputBuffer.put(input);mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, pts, 0);generateIndex += 1;}MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);while (outputBufferIndex >= 0) {//Log.i("AvcEncoder", "Get H264 Buffer Success! flag = "+bufferInfo.flags+",pts = "+bufferInfo.presentationTimeUs+""); ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];byte[] outData = new byte[bufferInfo.size];outputBuffer.get(outData);if(bufferInfo.flags == BUFFER_FLAG_CODEC_CONFIG){configbyte = new byte[bufferInfo.size];configbyte = outData;}else if(bufferInfo.flags == BUFFER_FLAG_KEY_FRAME){byte[] keyframe = new byte[bufferInfo.size + configbyte.length];System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length);//把编码后的视频帧从编码器输出缓冲区中拷贝出来System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length);outputStream.write(keyframe, 0, keyframe.length);}else{//写到⽂件中outputStream.write(outData, 0, outData.length);}mediaCodec.releaseOutputBuffer(outputBufferIndex, false);outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);}} catch (Throwable t) {t.printStackTrace();}} else {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}});EncoderThread.start();}private void NV21ToNV12(byte[] nv21,byte[] nv12,int width,int height){if(nv21 == null || nv12 == null)return;int framesize = width*height;int i = 0,j = 0;System.arraycopy(nv21, 0, nv12, 0, framesize);for(i = 0; i < framesize; i++){nv12[i] = nv21[i];}for (j = 0; j < framesize/2; j+=2){nv12[framesize + j-1] = nv21[j+framesize];}for (j = 0; j < framesize/2; j+=2){nv12[framesize + j] = nv21[j+framesize-1];}}/*** Generates the presentation time for frame N, in microseconds.*/private long computePresentationTime(long frameIndex) {return 132 + frameIndex * 1000000 / m_framerate;}}3.activity_main.xml<RelativeLayout xmlns:android="/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><SurfaceViewandroid:id="@+id/surfaceview"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout>4.添加权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.INTERNET" />以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

mediacodec底层原理

mediacodec底层原理

mediacodec底层原理
MediaCodec是Android平台提供的一个多媒体编解码器,它可以用于音频和视频的编解码操作。

它的底层原理涉及到多个方面,包括硬件加速、编解码流程、缓冲区管理等。

首先,MediaCodec可以利用硬件加速来提高编解码性能。

Android平台上的部分设备支持硬件加速的编解码操作,这意味着MediaCodec可以利用设备上的专用硬件来执行编解码任务,从而提高性能并降低功耗。

这通常通过底层的硬件抽象层(HAL)来实现,使得MediaCodec可以与设备上的硬件编解码器进行交互。

其次,MediaCodec的编解码流程包括了数据输入、数据处理和数据输出三个主要阶段。

在数据输入阶段,应用程序将原始的音频或视频数据传递给MediaCodec进行编码或解码处理;在数据处理阶段,MediaCodec利用编解码器进行数据处理,包括压缩(编码)或解压缩(解码)操作;最后,在数据输出阶段,MediaCodec将处理后的数据输出到指定的目标,比如Surface或者ByteBuffer。

此外,MediaCodec还涉及到缓冲区的管理。

在编解码过程中,数据通常需要在不同的阶段进行缓冲,MediaCodec负责管理这些缓
冲区的分配、填充和释放。

这涉及到对数据的处理顺序和时序的管理,以确保数据能够按照正确的顺序进行处理和输出。

总的来说,MediaCodec的底层原理涉及到硬件加速、编解码流程和缓冲区管理等多个方面,它通过与设备上的硬件编解码器进行交互,实现了高效的音视频编解码功能。

希望这个回答能够全面解答你的问题。

AndroidMediaCodec硬编码H264文件(四),安卓kotlin

AndroidMediaCodec硬编码H264文件(四),安卓kotlin

AndroidMediaCodec硬编码H264文件(四),安卓kotlinMediaCodec 处理完了之后,再从输出队列中出队得到一个可用的缓冲区,这个缓冲里面的数据就是编码或者解码后的数据了,把这些数据进行相应的处理之后,还需要释放这个缓冲区,让它回到队列中去,可供下一次使用。

MediaCodec 生命周期另外,MediaCodec 也存在相应的?生命周期,如下图所示:当创建了 MediaCodec 之后,是处于未初始化的?Uninitialized?状态,调用configure 方法之后就处于?Configured?状态,调用了start 方法之后,就处于?Executing?状态。

在?Executing?状态下开始处理数据,它又有三个子状态,分别是:•Flushed•Running•End of Stream当一调用start 方法之后,就进入了?Flushed?状态,从输入缓冲区队列中取出一个缓冲区就进入了?Running?状态,当入队的缓冲区带有?EOS?标志时,就会切换到?End of Stream?状态,MediaCodec 不再接受入队的缓冲区,但是仍然会对已入队的且没有进行编解码操作的缓冲区进行操作、输出,直到输出的缓冲区带有?EOS?标志,表示编解码操作完成了。

在?Executing?状态下可以调用flush 方法,使MediaCodec 切换到?Flushed?状态。

在?Executing?状态下可以调用 stop 方法,使 MediaCodec 切换到?Uninitialized?状态,然后再次调用configure 方法进入?Configured?状态。

另外,当调用reset 方法也会进入到?Uninitialized?状态。

当不再需要 MediaCodec 时,调用 release 方法将它释放掉,进入?Released?状态。

当 MediaCodec 工作发生异常时,会进入到?Error?状态,此时还是可以通过 reset 方法恢复过来,进入?Uninitialized?状态。

Android音视频开发(六):MediaCodecAPI详解

Android音视频开发(六):MediaCodecAPI详解

Android⾳视频开发(六):MediaCodecAPI详解在学习了Android ⾳视频的基本的相关知识,并整理了相关的API之后,我们应该对基本的⾳视频有⼀定的轮廓了。

下⾯开始接触⼀个Android⾳视频中相当重要的⼀个API: MediaCodec。

通过这个API,我们能够做很多Android⾳视频⽅⾯的⼯作,下⾯是我们学习这个API的时候,主要的⽅向:学习 MediaCodec API,完成⾳频 AAC 硬编、硬解学习 MediaCodec API,完成视频 H.264 的硬编、硬解⼀、MediaCodec 介绍 MediaCodec类可以⽤于使⽤⼀些基本的多媒体编解码器(⾳视频编解码组件),它是Android基本的多媒体⽀持基础架构的⼀部分通常和 , , , , , , , and ⼀起使⽤。

⼀个编解码器可以处理输⼊的数据来产⽣输出的数据,编解码器使⽤⼀组输⼊和输出缓冲器来异步处理数据。

你可以创建⼀个空的输⼊缓冲区,填充数据后发送到编解码器进⾏处理。

编解码器使⽤输⼊的数据进⾏转换,然后输出到⼀个空的输出缓冲区。

最后你获取到输出缓冲区的数据,消耗掉⾥⾯的数据,释放回编解码器。

如果后续还有数据需要继续处理,编解码器就会重复这些操作。

输出流程如下:编解码器⽀持的数据类型: 编解码器能处理的数据类型为:压缩数据、原始⾳频数据和原始视频数据。

你可以通过ByteBuffers能够处理这三种数据,但是需要你提供⼀个Surface,⽤于对原始的视频数据进⾏展⽰,这样也能提⾼编解码的性能。

Surface使⽤的是本地的视频缓冲区,这个缓冲区不映射或拷贝到ByteBuffers。

这样的机制让编解码器的效率更⾼。

通常在使⽤Surface的时候,⽆法访问原始的视频数据,但是你可以使⽤ImageReader访问解码后的原始视频帧。

在使⽤ByteBuffer的模式下,您可以使⽤Image类和getInput/OutputImage(int)访问原始视频帧。

androidmediacodec编码h264怎样调节gop

androidmediacodec编码h264怎样调节gop

androidmediacodec编码h264怎样调节gopandroid mediacodec编码h264 怎样调节gop简单地说。

软解码是用软件方式进行解码,需要占用CPU资源,速度相当较慢。

硬解码直接用硬件方式解决,不占用CPU资源,速度相对较快。

mov编码h264跟mp4编码h264的区别?mov和mp4是两种不同的封装格式,里面的h.264都是一样的H264编码 H264编码器哪个牌子好单位用的是视盈,几年来一直很稳定。

推荐你联系视盈黄国耀。

一三七,一一一四,六六九一。

MediaCodec编码可以获取到H264帧类型吗?仅转换可以使用命令,把任一mp4转换成tsffmpeg -i input.mp4 -c copy -bsf h264_mp4toannexb output.ts 很高兴为您解答!有不明白的可以追问!如果您认可我的回答。

如何实时h264编码及aac编码1. 简单介绍首先是捕获,这里采用了DirectShow的方式,对它进行了一定程度的封装,包括音视频。

好处是直接使用native api,你可以做想做的任何修改,坏处是,不能跨平台,采集音视频这种应用,linux平台也是需要滴呀。

有跨平台的做法,对视频,可以使用OpenCV,对音频,可以使用OpenAL或PortAudio等,这样就行了。

编码可以选择的余地比较大,对视频来讲,有H264, MPEG-4, WebM/VP8, Theora等,音频有Speex, AAC, Ogg/Vorbis等,它们都有相应的开源项目方案,我采用的是x264进行H264编码,libfaac 进行aac编码,之后是否更改编码方案,等具体项目需求再说了。

这里提一下WebM,Google牵头的项目,完全开放和自由,使用VP8和Vorbis编码,webm(mkv)封装,有多家巨头支持,目的是想要取代当前的H264视频编码,号称比后者更加优秀,我没有测试过实际效果。

amediacodec解码后的数据保存成yuv文件

amediacodec解码后的数据保存成yuv文件

在Android开发中,我们可以使用MediaCodec来解码媒体文件,然后将解码后的数据保存为YUV文件。

以下是一个基本的步骤和代码示例:1.首先,我们需要获取解码的输入和输出格式。

通常,解码的输入格式是MediaExtractor从媒体文件中提取出来的,而输出格式是我们自己设置的。

2.使用MediaCodec的dequeueInputBuffer和dequeueOutputBuffer方法来获取输入和输出缓冲区,并处理解码。

3.保存解码后的数据为YUV文件。

这是一个简单的示例代码:java复制代码import android.graphics.ImageFormat;import android.media.MediaCodec;import android.media.MediaExtractor;import android.media.MediaFormat;import android.util.Log;import java.io.File;import java.io.IOException;import java.nio.ByteBuffer;public class DecodeVideo {private static final String TAG = "DecodeVideo";private MediaCodec codec;private MediaExtractor extractor;private int inputBufferIndex;private ByteBuffer[] inputBuffers;private ByteBuffer[] outputBuffers;private byte[] yuvBytes;private File file;private int videoFrameSize = 0;public DecodeVideo(String videoPath) {file = new File(videoPath);extractor = new MediaExtractor(videoPath);int videoTrackIndex = extractor.getTrackCount();MediaFormat videoFormat = extractor.getTrackFormat(videoTrackIndex);String mime = videoFormat.getString(MediaFormat.KEY_MIME);if (!mime.startsWith("video/")) {throw new IllegalArgumentException("Unsupported mime type: " + mime);}videoFrameSize = videoFormat.getInteger(MediaFormat.KEY_FRAME_SIZE);int colorFormat = videoFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);if (colorFormat != MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) { throw new IllegalArgumentException("Unsupported color format: " + colorFormat); }int inputSize = videoFormat.getInteger(MediaFormat.KEY_INPUT_SIZE);if (inputSize != videoFrameSize * videoFrameSize * 2) { // 如果是NV12格式,那么inputSize = frameSize^2 * 2,frameSize为帧的高度或宽度,这里假设宽高一样。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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

1.MediaCodec类的编解码原理参考链接:https:///reference/android/media/M ediaCodec.html工作流是这样的:以编码为例,首先要初始化硬件编码器,配置要编码的格式、视频文件的长宽、码率、帧率、关键帧间隔等等。

这一步叫configure。

之后开启编码器,当前编码器便是可用状态,随时准备接收数据。

下一个过程便是编码的running过程,在此过程中,需要维护两个buffer队列,InputBuffer 和OutputBuffer,用户需要不断出队InputBuffer (即dequeueInputBuffer),往里边放入需要编码的图像数据之后再入队等待处理,然后硬件编码器开始异步处理,一旦处理结束,他会将数据放在OutputBuffer中,并且通知用户当前有输出数据可用了,那么用户就可以出队一个OutputBuffer,将其中的数据拿走,然后释放掉这个buffer。

结束条件在于end-of-stream这个flag标志位的设定。

在编码结束后,编码器调用stop函数停止编码,之后调用release 函数将编码器完全释放掉,整体流程结束。

2. 视频解码程序示例代码来源于Android: MediaCodec视频文件硬件解码以下所有代码可以在此处下载[java] view plain copyprint?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 class 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_FormatYUV4 20Flexible;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 &amp;&amp; fileType != FILE_TypeNV21 &amp;&amp; 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 &lt; 0) {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().getC apabilitiesForType(mime));if(isColorFormatSupported(decodeColorFormat, decoder.getCodecInfo().getCapabilitiesForType(mime))) {mediaFormat.setInteger(MediaFormat.KEY_COLOR_FOR MAT, 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 Surfaceclose();}}private voidshowSupportedColorFormat(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 = newMediaCodec.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 &gt;= 0) {ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);int sampleSize =extractor.readSampleData(inputBuffer, 0); //将一部分视频数据读取到inputbuffer中,大小为sampleSizeif (sampleSize &lt; 0) {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 &gt;= 0) {if ((info.flags &amp;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);compressToJpeg(fileName, image);break;}}image.close();decoder.releaseOutputBuffer(outputBufferId, true);}}}}private static int selectTrack(MediaExtractor extractor) {int numTracks = extractor.getTrackCount();for (int i = 0; i &lt; numTracks; 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 booleanisImageFormatSupported(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&amp;&amp; colorFormat != COLOR_FormatNV21) {throw new IllegalArgumentException("only support COLOR_FormatI420 " + "andCOLOR_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&amp;&amp; colorFormat != COLOR_FormatNV21) {throw new IllegalArgumentException("only support COLOR_FormatI420 " + "andCOLOR_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 = newbyte[planes[0].getRowStride()];int channelOffset = 0;int outputStride = 1;for (int i = 0; i &lt; planes.length; 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 =。

相关文档
最新文档