一般情況下Android的平臺(tái)都是硬解碼視頻的,尤其是在Arm平臺(tái)這種成熟的硬件平臺(tái)上面(硬解碼代碼由芯片廠商提供)。但是Android移植到 MIPS平臺(tái)時(shí)間還不長(zhǎng),還不成熟,還需要自己實(shí)現(xiàn)硬件解碼的工作。為了早日讓Android在MIPS平臺(tái)運(yùn)行起來(lái),我選擇了先用軟解碼播放視頻。
我的Android代碼是從Android on MIPS社區(qū)獲得的代碼。發(fā)現(xiàn)軟解碼視頻播放過(guò)程中會(huì)發(fā)生崩潰。經(jīng)過(guò)分析好像是內(nèi)存分配的問(wèn)題。
經(jīng)過(guò)研究OpenCore庫(kù)(Android框架是通過(guò)OpenCore來(lái)播放視頻的,網(wǎng)上有很多關(guān)于OpenCore的介紹,這里就不多說(shuō)了),并參考Android平臺(tái)——Surfaceflinger機(jī)制。發(fā)現(xiàn)問(wèn)題出在源文件:
frameworks/base/libs/surfaceflinger/LayerBuffer.cpp
的LayerBuffer::BufferSource::postBuffer方法中:
............
buffer = new LayerBuffer::Buffer(buffers, offset);
............
類(lèi)LayerBuffer::Buffer的構(gòu)造函數(shù)代碼如下:
LayerBuffer::Buffer::Buffer(const ISurface::BufferHeap& buffers, ssize_t offset) : mBufferHeap(buffers) { NativeBuffer& src(mNativeBuffer); src.img.handle = 0; gralloc_module_t const * module = LayerBuffer::getGrallocModule(); if (module && module->perform) { int err = module->perform(module, GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER, buffers.heap->heapID(), buffers.heap->getSize(), offset, buffers.heap->base(), &src.img.handle); if (err == NO_ERROR) { src.crop.l = 0; src.crop.t = 0; src.crop.r = buffers.w; src.crop.b = buffers.h; src.img.w = buffers.hor_stride ?: buffers.w; src.img.h = buffers.ver_stride ?: buffers.h; src.img.format = buffers.format; src.img.base = (void*)(intptr_t(buffers.heap->base()) + offset); } } }
LayerBuffer::getGrallocModule方法的調(diào)用到的Gralloc為:
hardware/libhardware/modules/gralloc/gralloc.cpp
因?yàn)榈臎](méi)有實(shí)現(xiàn)在自己的硬件只能用通用的Gralloc,經(jīng)過(guò)分析發(fā)現(xiàn)通用的Gralloc沒(méi)有實(shí)現(xiàn) module->perform函數(shù)指針,module->perform為NULL,所以不會(huì)對(duì)Buffer進(jìn)行必要的初始化(我覺(jué)得應(yīng)該 是一個(gè)疏忽,只是不知道是谷歌的疏忽,還是MIPS移植人員的疏忽,最起碼應(yīng)該能夠讓通用硬件能跑起來(lái))。參考其他的硬件實(shí)現(xiàn)一個(gè)perform函數(shù)指針 到通用Gralloc中。
在源文件:
hardware/libhardware/modules/gralloc/mapper.cpp
增加如下的函數(shù)定義:
int gralloc_perform(struct gralloc_module_t const* module, int operation, ... ) { int res = -EINVAL; va_list args; va_start(args, operation); switch (operation) { case GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER: { int fd = va_arg(args, int); size_t size = va_arg(args, size_t); size_t offset = va_arg(args, size_t); void* base = va_arg(args, void*); native_handle_t** handle = va_arg(args, native_handle_t**); private_handle_t* hnd = (private_handle_t*)native_handle_create( private_handle_t::sNumFds, private_handle_t::sNumInts); hnd->magic = private_handle_t::sMagic; hnd->fd = fd; hnd->flags = private_handle_t::PRIV_FLAGS_USES_PMEM; hnd->size = size; hnd->offset = offset; hnd->base = intptr_t(base) + offset; hnd->lockState = private_handle_t::LOCK_STATE_MAPPED; *handle = (native_handle_t *)hnd; res = 0; break; } } va_end(args); return res; }
然后在gralloc.cpp中增加,gralloc_perform的聲明:
extern int gralloc_perform(struct gralloc_module_t const* module, int operation, ... );
并修改HAL_MODULE_INFO_SYM的定義,增加perform字段的定義:
struct private_module_t HAL_MODULE_INFO_SYM = {
base: {
.......
perform: gralloc_perform,
},
......
};
重新編譯gralloc模塊,再次用Gallary應(yīng)用程序通過(guò)軟解碼播放視頻,就可以流暢的播放了,軟解碼的效率挺高的,沒(méi)有卡的感覺(jué)!贊一個(gè)。