Android codec2 视频框架 之应用

文章目录

应用流程

外部主动获取输入和输出buffer

解码的调用流程,以android原生的一个bin来说明

android 原生代码位置: frameworks/av/cmds/stagefright/codec.cpp

frameworks/av/cmds/stagefright/SimplePlayer.cpp

编译出来的是codec的bin,使用bin播放mp4, 可以使用如下的命令进行调试。

screenrecord /sdcard/test.mp4
codec -pSR /sdcard/test.mp4
  • prepare: 跟编码同样的流程

    createByType: 根据MIME创建解码器。

    configure:配置视频宽高、fromat信息到解码器。

    start:启动解码器进行解码。

    获取输入和输出的buffer 队列:先dequeue有效的输入buffer,然后将extract到的csd数据放入到这块buffer 中, 将这块buffer在queue到codec中(作用是 将解码所需要的额外的数据 给到解码器,类似于ffmpeg中的extradata)。

  • start: dequeue所有可用的input 和output buffer。然后解析封装读取数据 将数据拷贝到dequeue出来的input buffer 中, 拷贝完成后 queue到解码器, 同时从解码器中尽可能多的取输出的buffer, 对每个输出buffer 获取显示的时间戳。跟现有的时间比较,到显示时间的范围内则调用renderOutputBufferAndRelease将buffer 显示出去。

          state->mCodec = MediaCodec::CreateByType(
                  looper, mime.c_str(), false /* encoder */);
          CHECK(state->mCodec != NULL);
          err = state->mCodec->configure(
                  format, isVideo ? surface : NULL,
                  NULL /* crypto */,
                  0 /* flags */);
    
          CHECK_EQ((status_t)OK, codec->start());
          CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
          CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers))
    
           err = state->mCodec->queueInputBuffer(
                              index,
                              0 /* offset */,
                              buffer->size(),
                              timeUs,
                              bufferFlags);
    
外部设置回调

大部分应用都不会主动去获取解码输入和输出buffer。 类似NuPlayer是通过外部设置回调。MediaCodec内部有输出或者输入buffer的时候 回调到应用层。

NuPlayerDecoder.cpp
void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
    sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
    mCodec->setCallback(reply);
}
void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case kWhatCodecNotify:
        {
            switch (cbID) {
                case MediaCodec::CB_INPUT_AVAILABLE:
                {
                    int32_t index;
                    CHECK(msg->findInt32("index", &index));
                    handleAnInputBuffer(index);
                    break;
                }

                case MediaCodec::CB_OUTPUT_AVAILABLE:
                {
                    CHECK(msg->findInt32("index", &index));
                    CHECK(msg->findSize("offset", &offset));
   
                    handleAnOutputBuffer(index, offset, size, timeUs, flags);
                    break;
                }
}

内部流程

  • create 和configure

create:mediacodeclist中遍历所有的解码器 然后将所有match的解码器返回。 这个里面放的是component名字如c2.android.vorbis.decoder等等。 找到之后 就用这个名字来init mediacodec。

configure: 将format 和 surface 配置到解码器当中,。

  • format的configure

其中format可以存储很多信息 比如基本的图像宽高,解码器的类型等等。

configure将编解码的一些关键信息配置到编解码器 比如宽高、MIME、bitrate、frameRate 等等。

  • surface 的configure surface
  1. 在设置surface的流程中操作为nativeWindowConnect、设置一个surface的generaration,然后又重新connect、disconnect。
  2. 调用codec的setSurface, codec直接调用的channel 的setSurface。
  3. channel的setSurface不会调用mComponent->setOutputSurface, 因为初始化的时候对应的outputPoolId为0.
  • mediacodec 的start()
  1. 调用component 的start, 调用对应的SimpleC2Component的start(), 对应的每个解码器实现的onInit(),。

  2. mChannel->start, 调用channel的start
    这里有一个问题,如何决定要申请的buffer 是graphic 还是liner类型的。
    这在simpleC2interface中已经定义,会按照音视频的类型进行决定,视频 grahic,音频liner

     addParameter(
             DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE)
             .withConstValue(new C2StreamBufferTypeSetting::input(
                     0u, isEncoder ? rawBufferType : codedBufferType))
             .build());
    

2.1 在Channel的start 中会根据是编码输入的surface 还是解码输出的surface 配置申请buffer的个数, 以及调用Component->createBlockPool,创建graphic的pool。会返回pool的allocatorID 和outputPoolId

对应于在底层的实现是在C2AllocatedGraphic。 同时为生成的pools->outputPoolId生成poolIdsTuning并将这个Tuning 设置到componet中。

2.2 调用mComponent->setOutputSurface: 设置surface到解码模块,使得后续可以从对应的nativewindow中申请buffer。

相关推荐
安静读书2 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
佑华硬盘拷贝机2 小时前
音频档案批量拷贝:专业SD拷贝机解决方案
音视频
EasyNVR2 小时前
NVR管理平台EasyNVR多个NVR同时管理:全方位安防监控视频融合云平台方案
安全·音视频·监控·视频监控
长亭外的少年6 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿8 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
xcLeigh9 小时前
HTML5超酷响应式视频背景动画特效(六种风格,附源码)
前端·音视频·html5
1024小神9 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri
兰琛9 小时前
20241121 android中树结构列表(使用recyclerView实现)
android·gitee
Y多了个想法10 小时前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
韩曙亮11 小时前
【FFmpeg】FFmpeg 内存结构 ③ ( AVPacket 函数简介 | av_packet_ref 函数 | av_packet_clone 函数 )
ffmpeg·音视频·avpacket·av_packet_clone·av_packet_ref·ffmpeg内存结构