您的当前位置:首页正文

Android 平台编解码——软解、硬解对比

2024-11-13 来源:个人技术集锦

文章目录

前言

一、概念解释 

1. 概念:

2. 优缺点对比:

3. 播放器示例:

二、Android 硬解组件

1. MediaPlayer

2. MediaCodec

3. MediaCodec 的函数调用流程

        总结


前言

提示:本文只做相关概念总体上的介绍和解释,不做深入讨论


一、概念解释 

1. 概念:

硬解,即硬件解码:硬件解码是图形芯片厂商提出的用 GPU 资源解码视频流的方案;

软解,即软件解码:相对于硬件解码,传统的软件解码是用 CPU 承担解码工作。

2. 优缺点对比:

对比优点缺点
硬解

效率高、

功耗低、

热功耗低

a)缺乏有力的支持(包括滤镜、字幕)、局限性较大、设置较为复杂;

b)需要硬件有硬件解码模块、相关的驱动配合、合适的播放软件以及对播放软件的正确设置,缺一不可。否则无法开启硬件解码功能。

软解具备普遍适应性主要靠算法解码,很耗费CPU性能、耗电。

3. 播放器示例:

3.1 硬解播放器

  •  最简单的播放器组件 —— VideoView

VideoView 基于 MediaPlayer 实现,其基本等价于 MediaPalyer + Surface 的组合。通常原生的 Android 系统,其 MediaPlayer 本身对于视频编解码协议支持比较有限。而 MediaPlayer 内部实现主要通过 MediaExtractor + MediaCodec 的组合实现。

  • Google 的 ExoPlayer

ExoPlayer 基于 MediaCodec 实现。而 MediaCodec 则具备很高的拓展性,支持的协议较多,可以根据流媒体的协议和设备硬件本身来自定义硬件解码。

3.2 软解播放器

  • FFmpeg 播放器框架:FFmpeg

FFmpeg 是一个全平台的,非常强大的软解播放器框架。正是因为 MediaPlayer 支持的媒体格式有限。为了能够播放更多的媒体,许多开发人员使用了 FFmpeg 软件解码器来开发播放器。

对应在 Android 平台的移植,可以参考优秀的博客教程:雷霄骅(leixiaohua1020)的专栏

  • Bilibili 播放器:ijkplayer

是Bilibili 公司 基于 FFmpeg 的开发的一款开源的的播放器。


二、Android 硬解组件

通过上面的介绍可知,无论是 MediaPlayer 还是 MediaCodec,都属于 Android 的硬解(Hardware Codec)。下面简单介绍一下相关的示例。

1. MediaPlayer

Android 自 API level 1 以来都包含的播放器是 MediaPlayer。开发者能够简单、方便的上手使用它播放音频和视频。播放器如果只是播放音频,可以直接使用 MediaPlayer,如果播放视频,通常使用 MediaPlayer + Surface的组合( 当然,也可以直接使用 VideoView )。

Android平台,实现一个最简单的,使用 VideoView (内部实现基本等价于 MediaPalyer + Surface 的组合)开发的播放器,代码示例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private VideoView videoView;
    private Button btn_start;
    private Button btn_pause;
    private Button btn_stop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }
    
    private void bindViews() {
        videoView = (VideoView) findViewById(R.id.videoView);
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_pause = (Button) findViewById(R.id.btn_pause);
        btn_stop = (Button) findViewById(R.id.btn_stop);

        btn_start.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
        
        // 方式一:根据设备上的视频文件路径播放
        if (Environment.getExternalStorageState().
                    equals(Environment.MEDIA_MOUNTED)) {
            videoView.setVideoPath(Environment.
                    getExternalStorageDirectory() + "/lesson.mp4");
        }

        // 方式二:读取放在 app 安装文件的 raw 目录的视频文件
        //videoView.setVideoURI(Uri.parse(
        //        "android.resource://com.jay.videoviewdemo/" + R.raw.lesson));

        videoView.setMediaController(new MediaController(this));
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start:
                videoView.start();
                break;
            case R.id.btn_pause:
                videoView.pause();
                break;
            case R.id.btn_stop:
                videoView.stopPlayback();
                break;
        }
    }
}

2. MediaCodec

在 Android 的 Jelly Bean 版本,发布了 Android.media.MediaCodec API。该 API 使用与 OpenMAX(媒体行业中的著名标准)相同的原理和架构设计,有效地从纯粹的高级媒体播放器转换到低级编码器/解码器。

由于 MediaCodec 是使用 Java API 编写的,因此它允许接口访问底层系统编解码器,无论是硬件编解码器,还是结合音频编解码器,都是高度优化的软件编解码器。使用MediaCodec能获得合理性能优化并节省电量。

3. MediaCodec 的函数调用流程

调用流程设计的非常简单,参照下图。

配置完成后,开发人员使用 dequeueInputBuffer 获取硬件缓冲区ID。

将解码原始缓冲区复制到输入队列后,使用 queueInputBuffer 使硬件编解码器执行解码功能。

开发人员使用 dequeueOutputBuffer 获取解码缓冲区,然后使用 releaseOutputBuffer 释放硬件缓冲区,输出渲染到屏幕。   

 有关详细代码,请参阅 Android 源码

https://cs.android.com/android/platform/superproject/main

cts/tests/tests/media/decoder/src/android/media/decoder/cts/DecoderTest.java

此示例代码使用 MediaExtractor 作为媒体格式解析器。

开发人员需要使用 MediaFormat.createVideoFormat 来创建视频格式(如果使用 MediaExtractor,则使用 getTrackFormat 来获取格式)。

一些解码器(例如:H.264)需要额外的配置信息。可以使用 MediaFormat 或者 刷新帧 添加此信息。例如: H.264刷新帧是IDR帧,在该帧的报头中包括附加配置信息。创建 H.264视频格式示例代码:

videoformat = MediaFormat.createVideoFormat(“video/avc”, width,height);

videoformat.setByteBuffer("csd-0", extra configure data);


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

Top