| /** |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/mman.h> |
| #include <stdio.h> |
| #include <dirent.h> |
| #include <dlfcn.h> |
| #include <signal.h> |
| #include <SoftOMXPlugin.h> |
| #include <SoftOMXComponent.h> |
| #include "ihevc_typedefs.h" |
| #include "iv.h" |
| #include "ivd.h" |
| #include "SoftHEVC.h" |
| #include "ihevc_buf_mgr.h" |
| #define LIBNAME "/system/lib/libstagefright_soft_hevcdec.so" |
| #define LIBNAME_VNDK "/system/lib/vndk-28/libstagefright_soft_hevcdec.so" |
| #define MAX_ENTRIES (1024) |
| |
| #define DISABLE_MEM_ACCESS(mem, size)\ |
| mprotect((char *) mem, size, PROT_NONE); |
| |
| #define ENABLE_MEM_ACCESS(mem, size)\ |
| mprotect((char *) mem, size, PROT_READ | PROT_WRITE); |
| |
| typedef struct _map_struct_t { |
| void *start_ptr; |
| void *mem_ptr; |
| int num_pages; |
| size_t mem_size; |
| } map_struct_t; |
| |
| static void* (*real_memalign)(size_t, size_t) = NULL; |
| static void (*real_free)(void *) = NULL; |
| static int s_memutils_initialized = 0; |
| static int s_mem_map_index = 0; |
| static int s_free_write_index = 0; |
| static int s_free_read_index = 0; |
| static int s_free_list_size = 0; |
| static struct sigaction new_sa, old_sa; |
| map_struct_t s_mem_map[MAX_ENTRIES]; |
| map_struct_t s_free_list[MAX_ENTRIES]; |
| |
| void exit_handler(void) { |
| size_t page_size = getpagesize(); |
| for (int i = 0; i < s_mem_map_index; i++) { |
| if (NULL != s_mem_map[i].start_ptr) { |
| ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr, |
| (s_mem_map[i].num_pages * page_size)); |
| } |
| } |
| for (int i = 0; i < MAX_ENTRIES; i++) { |
| if (NULL != s_free_list[i].start_ptr) { |
| ENABLE_MEM_ACCESS(s_free_list[i].start_ptr, |
| (s_free_list[i].num_pages * page_size)); |
| real_free(s_free_list[i].start_ptr); |
| memset(&s_free_list[i], 0, sizeof(map_struct_t)); |
| } |
| } |
| } |
| |
| void sigsegv_handler(int signum, siginfo_t *info, void* context) { |
| exit_handler(); |
| (*old_sa.sa_sigaction)(signum, info, context); |
| } |
| |
| void sighandler_init(void) { |
| sigemptyset(&new_sa.sa_mask); |
| new_sa.sa_flags = SA_SIGINFO; |
| new_sa.sa_sigaction = sigsegv_handler; |
| sigaction(SIGSEGV, &new_sa, &old_sa); |
| } |
| |
| void memutils_init(void) { |
| real_memalign = (void *(*)(size_t, size_t))dlsym(RTLD_NEXT, "memalign"); |
| if (NULL == real_memalign) { |
| return; |
| } |
| real_free = (void (*)(void *))dlsym(RTLD_NEXT, "free"); |
| if (NULL == real_free) { |
| return; |
| } |
| memset(&s_mem_map, 0, MAX_ENTRIES * sizeof(map_struct_t)); |
| sighandler_init(); |
| atexit(exit_handler); |
| s_memutils_initialized = 1; |
| } |
| |
| void *memalign(size_t alignment, size_t size) { |
| if (s_memutils_initialized == 0) { |
| memutils_init(); |
| } |
| |
| if (size == sizeof(buf_mgr_t)) { |
| return NULL; |
| } |
| |
| char* start_ptr; |
| char* mem_ptr; |
| size_t total_size; |
| size_t aligned_size = size; |
| size_t new_alignment = sizeof(size_t); |
| size_t no_of_pages; |
| size_t page_size = getpagesize(); |
| |
| if (s_mem_map_index == MAX_ENTRIES) { |
| return real_memalign(alignment, size); |
| } |
| |
| if (alignment > page_size) { |
| return real_memalign(alignment, size); |
| } |
| |
| if ((0 == page_size) || (0 == alignment) || (0 == size) |
| || (0 == new_alignment)) { |
| return real_memalign(alignment, size); |
| } |
| |
| if (0 != (size % new_alignment)) { |
| aligned_size = size + (new_alignment - (size % new_alignment)); |
| } |
| |
| if (0 != (aligned_size % page_size)) { |
| no_of_pages = (aligned_size / page_size) + 2; |
| } else { |
| no_of_pages = (aligned_size / page_size) + 1; |
| } |
| |
| total_size = (no_of_pages * page_size); |
| start_ptr = (char *) real_memalign(page_size, total_size); |
| mem_ptr = (char *) start_ptr + ((no_of_pages - 1) * page_size) |
| - aligned_size; |
| DISABLE_MEM_ACCESS((start_ptr + ((no_of_pages - 1) * page_size)), page_size); |
| s_mem_map[s_mem_map_index].start_ptr = start_ptr; |
| s_mem_map[s_mem_map_index].mem_ptr = mem_ptr; |
| s_mem_map[s_mem_map_index].num_pages = no_of_pages; |
| s_mem_map[s_mem_map_index].mem_size = size; |
| s_mem_map_index++; |
| return mem_ptr; |
| } |
| |
| void free(void *ptr) { |
| if (s_memutils_initialized == 0) { |
| memutils_init(); |
| } |
| if (ptr != NULL) { |
| int i = 0; |
| size_t page_size = getpagesize(); |
| for (i = 0; i < s_mem_map_index; i++) { |
| if (ptr == s_mem_map[i].mem_ptr) { |
| s_free_list[s_free_write_index].start_ptr = s_mem_map[i] |
| .start_ptr; |
| s_free_list[s_free_write_index].mem_ptr = s_mem_map[i].mem_ptr; |
| s_free_list[s_free_write_index].num_pages = s_mem_map[i] |
| .num_pages; |
| s_free_list[s_free_write_index].mem_size = |
| s_mem_map[i].mem_size; |
| s_free_write_index++; |
| s_free_list_size += s_mem_map[i].mem_size; |
| DISABLE_MEM_ACCESS(s_mem_map[i].start_ptr, |
| (s_mem_map[i].num_pages * page_size)); |
| memset(&s_mem_map[i], 0, sizeof(map_struct_t)); |
| while (s_free_list_size > MAX_WINDOW_SIZE) { |
| ENABLE_MEM_ACCESS( |
| s_free_list[s_free_read_index].start_ptr, |
| (s_free_list[s_free_read_index].num_pages |
| * page_size)); |
| real_free(s_free_list[s_free_read_index].start_ptr); |
| s_free_list_size -= s_free_list[s_free_read_index].mem_size; |
| memset(&s_free_list[s_free_read_index], 0, |
| sizeof(map_struct_t)); |
| s_free_read_index++; |
| if ((s_free_read_index == MAX_ENTRIES) |
| || (s_free_read_index >= s_free_write_index)) { |
| break; |
| } |
| } |
| return; |
| } |
| } |
| } |
| real_free(ptr); |
| return; |
| } |
| |
| using namespace android; |
| |
| typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)( |
| const char *, const OMX_CALLBACKTYPE *, OMX_PTR, OMX_COMPONENTTYPE **); |
| |
| int main(void) { |
| void *libHandle = dlopen(LIBNAME, RTLD_NOW | RTLD_LOCAL); |
| if (libHandle == NULL) { |
| return EXIT_FAILURE; |
| } |
| |
| CreateSoftOMXComponentFunc createSoftOMXComponent = |
| (CreateSoftOMXComponentFunc) dlsym( |
| libHandle, |
| "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE" |
| "PvPP17OMX_COMPONENTTYPE"); |
| |
| if (createSoftOMXComponent == NULL) { |
| dlclose(libHandle); |
| return EXIT_FAILURE; |
| } |
| |
| OMX_COMPONENTTYPE *component = NULL; |
| SoftHEVC* codec = (SoftHEVC*) (*createSoftOMXComponent)( |
| "OMX.google.hevc.decoder", NULL, NULL, &component); |
| |
| dlclose(libHandle); |
| return EXIT_SUCCESS; |
| } |