首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何在GLSurfaceView上展示Android MediaCodec解码帧

在GLSurfaceView上展示Android MediaCodec解码帧,可以通过以下步骤实现:

  1. 创建一个GLSurfaceView对象,并设置Renderer。GLSurfaceView是Android提供的用于在OpenGL环境中绘制图形的视图组件,Renderer用于处理OpenGL绘制逻辑。
  2. 在Renderer的onSurfaceCreated方法中,初始化OpenGL环境,包括创建和编译着色器程序、创建纹理等。
  3. 在Renderer的onSurfaceChanged方法中,设置视口大小,确保OpenGL绘制的内容能够适应GLSurfaceView的大小。
  4. 在Renderer的onDrawFrame方法中,进行OpenGL绘制操作。首先,使用MediaCodec解码视频帧数据,得到解码后的图像数据。然后,将图像数据绑定到纹理上,并使用OpenGL绘制命令将纹理渲染到GLSurfaceView上。

以下是一种可能的实现方式:

代码语言:txt
复制
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.view.Surface;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class VideoRenderer implements GLSurfaceView.Renderer {
    private static final String MIME_TYPE = "video/avc";
    private static final int VIDEO_WIDTH = 1280;
    private static final int VIDEO_HEIGHT = 720;
    private static final int FRAME_RATE = 30;
    private static final int BIT_RATE = 2000000;

    private Context context;
    private GLSurfaceView glSurfaceView;
    private SurfaceTexture surfaceTexture;
    private Surface surface;
    private MediaCodec mediaCodec;

    public VideoRenderer(Context context, GLSurfaceView glSurfaceView) {
        this.context = context;
        this.glSurfaceView = glSurfaceView;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 初始化OpenGL环境
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);

        // 创建并配置MediaCodec
        try {
            MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT);
            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
            format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
            format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);

            mediaCodec = MediaCodec.createDecoderByType(MIME_TYPE);
            mediaCodec.configure(format, surface, null, 0);
            mediaCodec.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        // 使用MediaCodec解码视频帧数据
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int inputBufferIndex = mediaCodec.dequeueInputBuffer(0);
        if (inputBufferIndex >= 0) {
            // 获取输入缓冲区
            ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
            // 将视频帧数据填充到输入缓冲区
            // ...

            // 提交输入缓冲区
            mediaCodec.queueInputBuffer(inputBufferIndex, 0, inputSize, presentationTimeUs, 0);
        }

        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        while (outputBufferIndex >= 0) {
            // 获取输出缓冲区
            ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
            // 处理解码后的图像数据
            // ...

            // 渲染到GLSurfaceView上
            surfaceTexture.updateTexImage();
            // 绘制纹理
            // ...

            // 释放输出缓冲区
            mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        }
    }

    public void start() {
        glSurfaceView.setEGLContextClientVersion(2);
        glSurfaceView.setRenderer(this);
        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);

        surfaceTexture = new SurfaceTexture(0);
        surface = new Surface(surfaceTexture);
    }

    public void stop() {
        glSurfaceView.setRenderer(null);

        if (mediaCodec != null) {
            mediaCodec.stop();
            mediaCodec.release();
            mediaCodec = null;
        }

        if (surface != null) {
            surface.release();
            surface = null;
        }

        if (surfaceTexture != null) {
            surfaceTexture.release();
            surfaceTexture = null;
        }
    }
}

在使用时,可以在Activity中调用start()方法启动GLSurfaceView的渲染,调用stop()方法停止渲染。

代码语言:txt
复制
public class MainActivity extends AppCompatActivity {
    private GLSurfaceView glSurfaceView;
    private VideoRenderer videoRenderer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        glSurfaceView = findViewById(R.id.gl_surface_view);
        videoRenderer = new VideoRenderer(this, glSurfaceView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        videoRenderer.start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        videoRenderer.stop();
    }
}

这样,就可以在GLSurfaceView上展示Android MediaCodec解码的视频帧了。在实际应用中,可以根据具体需求进行适当的修改和优化。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

Android工程师的音视频开发学习指南

AudioRecord 是一个比较偏底层的 API,它可以获取到一 PCM 数据,之后可以对这些数据进行处理。...Android 中有 GLSurfaceView,这个类似于 SurfaceView,不过可以利用 Renderer 对其进行渲染。...硬编则是使用 Android 自身提供的 MediaCodec。 硬编码和软编码的区别是:软编码可以在运行时确定、修改;而硬编码是不能够改变的。...硬编则是采用 Android 自身提供的 MediaCodec,使用 MediaCodec 需要传入相应的数据,这些数据可以是 YUV 的图像信息,也可以是一个 Surface,一般推荐使用 Surface...在使用 Surface 的时候,通常不能直接访问原始视频数据,但是可以使用ImageReader 类来访问不可靠的解码后 (或原始) 的视频

1.2K40

基于 ffmpeg 的跨平台播放器实现

这里顺便提下,随着 Android、iOS 平台的普及,ffmpeg 版本的也逐步支持了 Android、iOS 的硬件解码器,f fmpeg 在很早之前就支持了 libstagefright,最新的...也存在很严重的兼容性问题,我在 Android4.4 的机型就遇到无法解码的问题。...MediaCodecMediaCodec 是 Google 在 Android4.1(API16)以后新提供的硬件编解码 API,其工作原理如图所示: 以解码为例,先从 Codec 获取 inputBuffer...,SurfaceView,TextureView或者是GLSurfaceView。...如果是使用了 MediaCodec 进行解码,那么视频渲染将变得异常简单,只需在 MediaCodec 配置时(MediaCodec.configure)指定图像渲染的 Surface,然后再解码完每一图像的时候调用

6.7K11

干货 | 移动端使用OpenGL转场特效的音视频合成应用

2.1.1 Mediacodec MediaCodec是从API16后引入的处理音视频编解码的类,它可以直接访问Android底层的多媒体编解码器,通常与MediaExtractor,MediaSync...这里要分两种情况来讨论: 1)利用MediaCodec进行解码的时候,输入input是待解码的buffer数据,输出output是解码好的buffer数据。...OpenGL绘制的内容一般都是呈现在GLSurfaceView中的(GLSurfaceView的surface),如果我们需要将内容编码成视频,需要将绘制的内容渲染到MediaCodec提供的Surface...AVAssetWriterInput可以设置视频的主要参数输出码率,帧率,最大间隔,编码方式,输出分辨率以及填充模式等。也可以设置音频的主要参数采样率,声道,编码方式,输出码率等。...然后分别介绍了Android和iOS这两个移动平台音视频编解码API,利用这些平台自带的API,我们可以将OpenGL渲染的画面编码成音视频文件。

40011

iOSAndroid 音视频开发专题

下面是本次专题介绍: Android 专题计划: 音视频相关概念入门 音视频编解码理论知识 音视频码流分析工具介绍 Android MediaCodec 介绍 OpenGL ES 介绍 Android...GLSurfaceView/Surface/SurfaceTexture 介绍 Android 音视频分离器/解码器架构设计 Android 音视频分离器/解码器初步实现 Android 音视频播放器架构设计...Android 使用 OpenGL ES 渲染视频实现视频(无音频) Android AudioTrack 介绍 Android 使用 AudioTrack 实现音频播放器 Android 整合音视频播放器...,实现音视频同步器 Android 音视频播放器实现快速预览精准 seek Android 音视频播放器总结 iOS 专题计划: GPUImage 介绍 iOS AVFoundation 介绍 iOS...AVAssetReaderOutput 分离音视频数据 iOS 音视频分离器架构设计 iOS 音视频分离器实现 iOS 音视频播放器架构设计 iOS 使用 OpenGL ES + GPUImage 渲染视频

78610

使用 AudioTrack 播放音频轨道

在上篇文章 OpenGL ES 实现播放视频 中我们已经知道如何使用 GLSurfaceView解码后的视频渲染到屏幕,但是,我们的播放器还不具备音频播放的功能,在本篇文章中我们将使用 AudioTrack...03 AudioTrack API 介绍 在 Android 中,如果你想要播放一个音频文件,我们一般优先选用 MediaPlayer,使用 MediaPlayer 时你不需要关心文件的具体格式,也不需要对文件进行解码...streamType 流类型 * @link AudioManager#STREAM_VOICE_CALL, 语音通话 * @link AudioManager#STREAM_SYSTEM, 系统声音 低电量...04 MediaCodec 解码并播放音频轨道 如果我们要播放一个音频轨道,需要将音轨解码后才可以播放,之前我们一直在说如何解码视频,如果你看过 AVPlayer Demo ,你一定对如何创建视频轨道解码器很熟悉了...// 从 MediaCodec 吐出解码后的音频信息 private boolean drainOutputBuffer(MediaCodec mediaCodec) { if

2.1K31

Camera开发需要关注哪些点

学习音视频的同学应该很熟悉这种模式,视频解码放入队列,然后另外一个线程分别从这个队列中取出,我想之所以这样设置也是为了异步处理。...实现一个相机应用,需要结合OpenGL实现渲染绘制,OpenGL通过矩阵运算可以将相机以特定的比例映射到渲染画布,使用OpenGL处理的好处还有后期兼容滤镜、特效等画面处理非常方便。...编码使用MediaCodec硬编码和x264/x265软编码来处理视频。...Camera调整画布 开发相机应用中最基本的需要调整画布,实现9/16、3/4、1/1比例,如下图:我们知道标准的相机Size比例只有9/16、3/4,基本没有1/1的比例的,所以Camera出的比例想要设置成...1/1的,一般会采用OpenGL渲染,将相机投影到渲染画布

68710

LiTr:适用于Android的轻量级视频音频转码器

介绍 在Android可以使用软件或硬件编码器进行转码。...成员通常选择共享可以在其设备播放的视频,这意味着它们可以被解码。而且由于大多数Android设备都以H.264压缩方式录制视频,因此我们可以使用该编解码器对视频进行编码。...适用于Android的轻量级硬件加速视频/音频转码器,或简称LiTr。 媒体编解码器(MediaCodec) 为了访问编码器硬件,LiTr使用AndroidMediaCodec API。...创建编解码器实例后,必须为其配置一组参数,例如分辨率,比特率,速率等。如果不支持所需的参数(例如,如果我们尝试解码4K视频,则配置可能会失败)在不支持4K分辨率的硬件)。...解码器使用并解码已编码的源。例如,视频解码器将采用H.264编码的视频并将其解码为像素,而音频解码器会将压缩的AAC音频解码为未压缩的PCM

2.4K20

视频播放优化浅析

带着这些问题,本文尝试从播放器的原理开始着手,梳理一下在Android客户端上的播放架构的演进,以及在播放体验的核心指标的优化,针对不同场景所作出的各种优化。 本文目录结构: ?...感兴趣的可以参考系列文章:https://zhuanlan.zhihu.com/p/44684432 首渲染 对于Android端来说,通常是渲染在SurafaceView或TextureView,...在渲染前也可以对视频做后处理,超分、添加黑白滤镜等操作。...详细二则的差别,可参考下列文章 Android 5.0(Lollipop)中的SurfaceTexture,TextureView, SurfaceView和GLSurfaceView 四、冷启动场景下的首优化...对于这两个问题,我们可以在播放器性能和封面隐藏的策略做出优化: 在未起播下个视频前,就启动下个视频的解码流程,然后提前渲染首,当用户画到下个视频时已经是首,就看不到封面了; 如果没有命中预缓存,那么在隐藏封面时

4.2K20

LiTr:适用于Android的轻量级视频音频转码器

介绍 在Android可以使用软件或硬件编码器进行转码。...成员通常选择共享可以在其设备播放的视频,这意味着它们可以被解码。而且由于大多数Android设备都以H.264压缩方式录制视频,因此我们可以使用该编解码器对视频进行编码。...创建编解码器实例后,必须为其配置一组参数,例如分辨率,比特率,速率等。如果不支持所需的参数(例如,如果我们尝试解码4K视频,则配置可能会失败)在不支持4K分辨率的硬件)。...使用MediaCodec进行转码 要进行代码转换,我们将需要两个MediaCodec实例:一个作为解码器运行,另一个作为编码器运行。解码器使用并解码已编码的源。...例如,视频解码器将采用H.264编码的视频并将其解码为像素,而音频解码器会将压缩的AAC音频解码为未压缩的PCM。然后,编码器使用已解码,以生成所需目标格式的编码

3.3K20

Android工程师的音视频教程之一文弄懂MediaCodec

Android工程师的音视频开发学习指南 音视频开发基础知识(2)——最通俗易懂的视频编解码理论知识 简介 MediaCodecAndroid提供的用于对音视频进行编解码的类,是Android...主要API介绍 简介: 1.MediaCodec创建: createDecoderByType/createEncoderByType:根据特定MIME类型("video/avc")创建codec。...在一些设备,offset是相对裁剪矩形的左上角像素,而在大多数设备,offset是相对整个的左上角像素。 size:buffer中的数据量(以字节为单位)。...BUFFER_FLAG_PARTIAL_FRAME:buffer只包含的一部分,解码器应该对数据进行批处理,直到在解码之前出现没有该标志的buffer为止。...使用实践 通过MediaCodec进行编解码,播放视频和音频,具体示例见项目: MediaCodecDemo 参考文章: developer.android/reference//MediaCodec

1.4K10

Android 音视频开发打怪升级:OpenGL渲染视频画面篇】四、深入了解OpenGL之EGL

EGLConfig EGL配置,rgba位数 EGLSurface 渲染缓存,一块内存空间,所有要渲染到屏幕的图像数据,都要先缓存在EGLSurface。...Android 指定的标志EGL_RECORDABLE_ANDROID 告诉EGL它创建的surface必须和视频编解码器兼容。...实际GLSurfaceView#Renderer的三个回调方法,都是在GLThread中进行调用的。...2,Android视频硬编码必须要使用EGL 如果你需要使用到Android Mediacodec的编码能力,那么EGL就是必不可少的东西,在后续的关于视频编码的文章中,你将会看到如何使用EGL来实现编码...3, FFmpeg编解码都需要用到EGL相关的知识 在JNI层,Android并没有实现一个类似GLSurfaceView的工具,来帮我们隐藏EGL相关的内容。

2.2K20

android视频系列:视频解码篇--android视频播放的实现

那么播放器播放,就需要先解压缩成图像,再放到屏幕。所以,播放器的两个核心功能,一个是解码,一个是显示。 我们来看看,Android为我们提供了哪些对象,可以让我们做视频的播放。...Android播放视频 下面我们介绍3种在Android播放视频的方法。 1. 使用VideoView播放视频 ?...在解码方面,它支持常用的解码控制操作,start(), pause(), resume(), seek(), seekTo()等。...至此,opengl拿到了解码的图像数据后,就可以自如的做任何图像相关的处理,渲染到屏幕。 总结 以上在Android实现的三种播放视频方法,从简单到复杂,可以根据自己功能的需要,灵活进行选择。...如果要对每一图像做处理,可以使用MediaPlayer和GLSurfaceView。 ---- 作者简介:taoxiong(熊涛),天天P图Android工程师

3.9K131

音视频全链路技能分析之音视频消费侧技能树

有人会说,只是将视频播放出来,这个容易,Android不是有自带的MediaPlayer,iOS也有VideoToolBox,就以Android端为例吧,MediaPlayer性能是差点,但是用还是没问题的...又有同学开始吐槽了,AndroidMediaCodec,我要知道这么多干什么?是的,MediaCodec很牛皮,轮子已有的情况下你了解这些你走得更快,轮子没有的情况下你就可以造轮子。...当然我们要相信MediaCodec在进步,在发展。 4.音视频同步 从上面的流程分析来看,我们分离出音频流和视频流,就要分别起线程去解码音频和解码视频。...利用 Android 提供的 AudioRecord 采集音频,利用 AudioTrack 播放音频,利用 MediaCodec 来编解码,这些 API 均是 Android 提供的 Java 层 API...6.TextureView Or SurfaceView 渲染视频画面,我们可以用Android原生提供的TextureView或者SurfaceView,也可以使用OpenGL ES配合GLSurfaceView

1.5K30

如何使用MediaCodec解码音视频

中如何使用OpenGL播放视频 Android平台下解码音视频可以采用软件解码ffmpeg,或使用硬件解码MediaCodec来实现软件解码:利用CPU进行解码处理,这种方式会加大CPU负担并增加功耗...,它的优点则是具有更强的适配性;硬件解码:调用GPU的专门解码音视频的模块来处理,减少CPU运算,降低功耗.由于Android机型碎片化比较严重,硬件解码的实现又依赖于具体的厂商,所以硬件解码的适配性并不是那么友好一般而言...,在Android设备支持硬解的情况下优先使用Android设备的硬件解码,减少CPU占用,降低功耗;在硬解不支持的情况下选择使用软解码,至少让音视频能正常播放....MediaCodec简介 android.media.MediaCodec是从API16开始由Android提供的供开发者能更加灵活的处理音视频的编解码组件,与MediaPlayer/MediaRecorder...,我们需要根据视频的时间戳来做同步,否则视频将很快的进行渲染播放 private fun sync(info: MediaCodec.BufferInfo, startMs: Long) {

2.3K20

Android端的短视频开发,我们该如何快速实现移动端短视频功能?

MediaCodecAndroid提供的编解码类,MediaMuxer则是复用类(生成视频文件)。...帧数:每秒显示多少个画面,fps 关键间隔:在H.264编码中,编码后输出的压缩图像数据有多种,可以简单的分为关键和非关键。关键能够进行独立解码,看成是一个图像经过压缩的产物。...而非关键包含了与其他的“差异”信息,也可以称呼为“参考”,它的解码需要参考关键才能够解码出一个图像。非关键拥有更高的压缩率。...五、MediaCodec+MediaMuxer的使用 MediaMuxer和MediaCodec这两个类,它们的参考文http://developer.android.com/reference/android..., null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mAudioEncoder.start(); 第2部分进入主循环,app在Surface直接绘图,

2K20
领券