codec2play是android上codec2的一个demo程序,在frameworks/av/media/codec2/components/cmds
目录下可以找到原始代码,这里把hardware component
创建和software component
创建做一个对比,加深对codec2
的理解。
首先,Codec2Client::CreateFromService中通过hidl ServiceManager获取ServiceManager对象,然后通过listManifestByInterface接口,查询平台的component name,然后返回name合集,根据name创建创建Codec2Client对象client,SetPreferredCodec2ComponentStore将client设置到gPreferredComponentStore,后面创建component就从这个store里面创建。
// create decoder component
std::shared_ptr<Codec2Client> client = Codec2Client::CreateFromService("default");
SetPreferredCodec2ComponentStore(std::make_shared<Codec2ClientInterfaceWrapper>(client));
mComponent = Codec2Client::CreateComponentByName("c2.qti.avc.decoder", mClientListener, &client);
serviceManager中获取service的代码:
transResult = serviceManager->listManifestByInterface(
IComponentStore::descriptor,
[&defaultNames, &vendorNames, &otherNames](
hidl_vec<hidl_string> const& instanceNames) {
for (hidl_string const& instanceName : instanceNames) {
char const* name = instanceName.c_str();
if (strncmp(name, "default", 7) == 0) {
defaultNames.emplace_back(name);
} else if (strncmp(name, "vendor", 6) == 0) {
vendorNames.emplace_back(name);
} else {
otherNames.emplace_back(name);
}
}
});
Base1_0和Base1_1的定义实际上是V1_0和V1_1的IComponent别名:
typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
typedef Base1_0 Base;
hidl中的接口类的声明:
namespace android::hardware::media::c2::V1_0 {
struct IConfigurable;
struct IComponent;
struct IComponentInterface;
struct IComponentStore;
struct IInputSink;
struct IInputSurface;
struct IInputSurfaceConnection;
} // namespace android::hardware::media::c2::V1_0
namespace android::hardware::media::c2::V1_1 {
struct IComponent;
struct IComponentStore;
} // namespace android::hardware::media::c2::V1_1
通过Base1_0或者Base1_1的createComponent接口,创建component:
c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{
};
mBase1_0->createComponent(
name,
hidlListener,
ClientManager::getInstance(),
[&status, component, hidlListener](
Status s,
const sp<hardware::media::c2::V1_0::IComponent>& c) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
return;
}
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
}
);
其中lambda表达式可以理解为一个函数指针对应的函数体,要知道这个在哪调用,进入createComponent_1_1函数就可以看到,最后component创建后以后会作为参数c传递给lambda表达式,status的值作为参数s,在createComponent_1_1中通过
_hidl_cb
调用,lambda表达式实际上就是_hidl_cb
。[&status, component, hidlListener]( Status s, const sp<hardware::media::c2::V1_0::IComponent>& c) { status = static_cast<c2_status_t>(s); if (status != C2_OK) { return; } *component = std::make_shared<Codec2Client::Component>(c); hidlListener->component = *component; }
ComponentStore::createComponent_1_1函数,也就是hidl中的::android::hardware::media::c2::V1_1::utils::ComponentStore::createComponent_1_1
,真正创建component就是在这里创建的。
// from ::android::hardware::media::c2::V1_1::utils::ComponentStore
Return<void> ComponentStore::createComponent_1_1(
const hidl_string& name,
const sp<IComponentListener>& listener,
const sp<IClientManager>& pool,
createComponent_1_1_cb _hidl_cb) {
sp<Component> component;
std::shared_ptr<C2Component> c2component;
Status status = static_cast<Status>(
mStore->createComponent(name, &c2component));
if (status == Status::OK) {
onInterfaceLoaded(c2component->intf());
component = new Component(c2component, listener, this, pool);
if (!component) {
status = Status::CORRUPTED;
} else {
reportComponentBirth(component.get());
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
} else {
component->initListener(component);
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
}
}
}
}
// 这个调用就走到lambda表达式里面
_hidl_cb(status, component);
return Void();
}
codec2play中原始代码是直接获取platform component store,通过store直接创建component的,这个store里面只是注册了软解的codec component。
std::shared_ptr<C2ComponentStore> store = GetCodec2PlatformComponentStore();
std::shared_ptr<C2Component> component;
(void)store->createComponent("c2.android.avc.decoder", &component);
可以看到C2PlatformComponentStore加载的库都在这个列表里面:
C2PlatformComponentStore::C2PlatformComponentStore()
: mVisited(false),
mReflector(std::make_shared<C2ReflectorHelper>()),
mInterface(mReflector) {
auto emplace = [this](const char *libPath) {
mComponents.emplace(libPath, libPath);
};
emplace("libcodec2_soft_aacdec.so");
emplace("libcodec2_soft_aacenc.so");
emplace("libcodec2_soft_amrnbdec.so");
emplace("libcodec2_soft_amrnbenc.so");
emplace("libcodec2_soft_amrwbdec.so");
emplace("libcodec2_soft_amrwbenc.so");
emplace("libcodec2_soft_avcdec.so");
emplace("libcodec2_soft_avcenc.so");
emplace("libcodec2_soft_flacdec.so");
emplace("libcodec2_soft_flacenc.so");
emplace("libcodec2_soft_g711alawdec.so");
emplace("libcodec2_soft_g711mlawdec.so");
emplace("libcodec2_soft_gsmdec.so");
emplace("libcodec2_soft_h263dec.so");
emplace("libcodec2_soft_h263enc.so");
emplace("libcodec2_soft_hevcdec.so");
emplace("libcodec2_soft_hevcenc.so");
emplace("libcodec2_soft_mp3dec.so");
emplace("libcodec2_soft_mpeg2dec.so");
emplace("libcodec2_soft_mpeg4dec.so");
emplace("libcodec2_soft_mpeg4enc.so");
emplace("libcodec2_soft_opusdec.so");
emplace("libcodec2_soft_opusenc.so");
emplace("libcodec2_soft_rawdec.so");
emplace("libcodec2_soft_vorbisdec.so");
emplace("libcodec2_soft_vp8dec.so");
emplace("libcodec2_soft_vp8enc.so");
emplace("libcodec2_soft_vp9dec.so");
emplace("libcodec2_soft_vp9enc.so");
}
hardware/interfaces/media/c2/
├── 1.0
│ ├── Android.bp
│ ├── IComponent.hal
│ ├── IComponentInterface.hal
│ ├── IComponentListener.hal
│ ├── IComponentStore.hal
│ ├── IConfigurable.hal
│ ├── IInputSink.hal
│ ├── IInputSurfaceConnection.hal
│ ├── IInputSurface.hal
│ └── types.hal
└── 1.1
├── Android.bp
├── IComponent.hal
└── IComponentStore.hal
namespace android::hardware::media::c2::V1_0 {
struct IConfigurable;
struct IComponent;
struct IComponentInterface;
struct IComponentStore;
struct IInputSink;
struct IInputSurface;
struct IInputSurfaceConnection;
} // namespace android::hardware::media::c2::V1_0
namespace android::hardware::media::c2::V1_1 {
struct IComponent;
struct IComponentStore;
} // namespace android::hardware::media::c2::V1_1
类似的可以在drm里面看到:
- drm/libmediadrm/interface/mediadrm/ICrypto.h
namespace android { namespace hardware { class HidlMemory; namespace drm { namespace V1_0 { struct SharedBuffer; struct DestinationBuffe } // namespace V1_0 } // namespace drm } // namespace hardwar } // namespace android
namespace android
namespace hardware
namespace media
namespace c2
namespace V1_0
struct IConfigurable
struct IComponent
struct IComponentInterface
struct IComponentStore
struct IInputSink
struct IInputSurface
struct IInputSurfaceConnection
namespace android
namespace hardware
namespace media
namespace c2
namespace V1_1
struct IComponent
struct IComponentStore
namespace android
namespace hardware
namespace media
namespace bufferpool
namespace V2_0
struct IClientManager
namespace android
namespace hardware
namespace graphics
namespace bufferqueue
namespace V1_0
struct IGraphicBufferProducer
namespace android
namespace hardware
namespace graphics
namespace bufferqueue
namespace V2_0
struct IGraphicBufferProducer
namespace android
namespace hardware
namespace media
namespace omx
namespace V1_0
struct IGraphicBufferSource
Codec2Client是包含以下内部类的主类:
- Listener
- Configurable
- Interface
- Component
Codec2Client中的类、codec2.0接口,和HIDL之间的关系:
- Codec2Client <==> C2ComponentStore <==> IComponentStore
- Codec2Client::Listener <==> C2Component::Listener <==> IComponentListener
- Codec2Client::Configurable <==> [No equivalent] <==> IConfigurable
- Codec2Client::Interface <==> C2ComponentInterface <==> IComponentInterface
- Codec2Client::Component <==> C2Component <==> IComponent
入口点是Codec2Client::CreateFromService(),它创建一个Codec2Client对象,在Codec2Client中,可以通过调用createComponent()和createInterface()来创建接口和组件对象。createComponent()接受一个Listener对象,该对象必须由用户实现。
目前,createBlockPool()是唯一一个生成可配置对象。但是请注意,接口、组件和Codec2Client是可配置的所有子类。
Codec2Client::CreateFromService
getServiceIndex
Codec2Client::GetServiceNames
serviceManager = IServiceManager::getService
serviceManager->listManifestByInterface
Codec2Client::CreateFromService会通过Hidl ServiceManager::listManifestByInterface获取service名字,创建Codec2Client,然后SetPreferredCodec2ComponentStore之后,就可以访问vendor的store。
// set up preferred component store to access vendor store parameters
client = Codec2Client::CreateFromService("default");
if (client) {
ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
SetPreferredCodec2ComponentStore(
std::make_shared<Codec2ClientInterfaceWrapper>(client));
}
这部分是从CCodecBufferChannel::renderOutputBuffer代码中找出来的,用于理解hardwarecodec的渲染流程,首先从output中获得c2Buffer,然后创建android::IGraphicBufferProducer::QueueBufferInput
对象qbi,最后是mComponent->queueToOutputSurface把buffer
送给surface显示。
这部分的调用栈:
NuPlayer::Decoder::onRenderBuffer
MediaCodec::renderOutputBufferAndRelease
MediaCodec::onReleaseOutputBuffer
CCodecBufferChannel::renderOutputBuffer
CCodecBufferChannel::renderOutputBuffer中的主要代码:
// c2Buffer
std::shared_ptr<C2Buffer> c2Buffer;
bool released = false;
{
Mutexed<Output>::Locked output(mOutput);
if (output->buffers) {
released = output->buffers->releaseBuffer(buffer, &c2Buffer);
}
}
// get C2ConstGraphicBlock
std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
if (blocks.size() != 1u) {
ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
return UNKNOWN_ERROR;
}
const C2ConstGraphicBlock &block = blocks.front();
// TODO: revisit this after C2Fence implementation.
android::IGraphicBufferProducer::QueueBufferInput qbi(
timestampNs,
false, // droppable
dataSpace,
Rect(blocks.front().crop().left,
blocks.front().crop().top,
blocks.front().crop().right(),
blocks.front().crop().bottom()),
videoScalingMode,
transform,
Fence::NO_FENCE, 0);
// we don't have dirty regions
qbi.setSurfaceDamage(Region::INVALID_REGION);
android::IGraphicBufferProducer::QueueBufferOutput qbo;
status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
if (result != OK) {
ALOGI("[%s] queueBuffer failed: %d", mName, result);
return result;
}
int slot;
sp<Fence> fence;
std::shared_ptr<C2Buffer> output;
const sp<IGraphicBufferProducer> &igbp = mSurface->getIGraphicBufferProducer();
size_t size = work->worklets.front()->output.buffers.size();
if (size == 1u) {
output = work->worklets.front()->output.buffers[0];
} else {
fprintf(stderr, "got output buffers size: %zu.\n", size);
}
// 从work中拿到C2Buffer类型的output后进行渲染
if (output != nullptr) {
const C2ConstGraphicBlock block = output->data().graphicBlocks().front();
native_handle_t *grallocHandle = UnwrapNativeCodec2GrallocHandle(block.handle());
sp<GraphicBuffer> buffer(new GraphicBuffer(
grallocHandle,
GraphicBuffer::CLONE_HANDLE,
block.width(),
block.height(),
HAL_PIXEL_FORMAT_YV12,
1,
(uint64_t)GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
block.width()));
native_handle_delete(grallocHandle);
// 创建QueueBufferInput
status_t err = igbp->attachBuffer(&slot, buffer);
IGraphicBufferProducer::QueueBufferInput qbi(
(work->worklets.front()->output.ordinal.timestamp * 1000ll).peekll(),
false,
HAL_DATASPACE_UNKNOWN,
Rect(block.width(), block.height()),
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
0,
Fence::NO_FENCE,
0);
// 调用IGraphicBufferProducer::queueBuffer把inputbuffer给送给surface
IGraphicBufferProducer::QueueBufferOutput qbo;
err = igbp->queueBuffer(slot, qbi, &qbo);
fprintf(stderr, "%d igbp queue buffer.\n", gettid());
}
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法