bool v4l2codecOperationInit(V4l2CodecOps *opFuncs) { if (!opFuncs) return false; int isVersionMatch = 0; IS_V4L2CODEC_OPS_VERSION_MATCH(opFuncs->mVersion, isVersionMatch); if (!isVersionMatch) { ERROR("V4l2CodecOps interface version doesn't match\n"); return false; } ASSERT(opFuncs->mSize == sizeof(V4l2CodecOps)); memset(opFuncs->mVendorString, 0, V4L2CODEC_VENDOR_STRING_SIZE); strncpy(opFuncs->mVendorString, "yami", V4L2CODEC_VENDOR_STRING_SIZE-1); #define V4L2_DLSYM_OR_RETURN_ON_ERROR(name) opFuncs->m##name##Func = YamiV4L2_##name V4L2_DLSYM_OR_RETURN_ON_ERROR(Open); V4L2_DLSYM_OR_RETURN_ON_ERROR(Close); V4L2_DLSYM_OR_RETURN_ON_ERROR(Ioctl); V4L2_DLSYM_OR_RETURN_ON_ERROR(Poll); V4L2_DLSYM_OR_RETURN_ON_ERROR(SetDevicePollInterrupt); V4L2_DLSYM_OR_RETURN_ON_ERROR(ClearDevicePollInterrupt); V4L2_DLSYM_OR_RETURN_ON_ERROR(Mmap); V4L2_DLSYM_OR_RETURN_ON_ERROR(Munmap); V4L2_DLSYM_OR_RETURN_ON_ERROR(SetParameter); #ifndef ANDROID V4L2_DLSYM_OR_RETURN_ON_ERROR(UseEglImage); #endif #undef V4L2_DLSYM_OR_RETURN_ON_ERROR return true; }
bool init() { const char* libName = "libyami_v4l2.so"; m_handle = dlopen(libName, RTLD_NOW | RTLD_GLOBAL); if (!m_handle) { ERROR("dlopen failed for %s", libName); return false; } V4l2codecOperationInitFunc initFunc = NULL; initFunc = (V4l2codecOperationInitFunc)dlsym(RTLD_DEFAULT, "v4l2codecOperationInit"); if (!initFunc) { ERROR("fail to dlsym v4l2codecOperationInit\n"); return false; } INIT_V4L2CODEC_OPS_SIZE_VERSION(&m_ops); if (!initFunc(&m_ops)) { ERROR("fail to init v4l2 device operation func pointers\n"); return false; } int isVersionMatch = 0; IS_V4L2CODEC_OPS_VERSION_MATCH(m_ops.mVersion, isVersionMatch); if (!isVersionMatch) { ERROR("V4l2CodecOps interface version doesn't match\n"); return false; } if (m_ops.mSize != sizeof(V4l2CodecOps)) { ERROR("V4l2CodecOps interface data structure size doesn't match\n"); return false; } return true; }
static bool loadV4l2CodecDevice(const char* libName ) { memset(&s_v4l2CodecOps, 0, sizeof(s_v4l2CodecOps)); s_v4l2Fd = 0; #ifndef ANDROID if (!dlopen(libName, RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)) { #else if (!dlopen(libName, RTLD_NOW | RTLD_GLOBAL)) { #endif ERROR("Failed to load %s\n", libName); return false; } V4l2codecOperationInitFunc initFunc = NULL; initFunc = (V4l2codecOperationInitFunc)dlsym(RTLD_DEFAULT, "v4l2codecOperationInit"); if (!initFunc) { ERROR("fail to dlsym v4l2codecOperationInit\n"); return false; } INIT_V4L2CODEC_OPS_SIZE_VERSION(&s_v4l2CodecOps); if (!initFunc(&s_v4l2CodecOps)) { ERROR("fail to init v4l2 device operation func pointers\n"); return false; } int isVersionMatch = 0; IS_V4L2CODEC_OPS_VERSION_MATCH(s_v4l2CodecOps.mVersion, isVersionMatch); if (!isVersionMatch) { ERROR("V4l2CodecOps interface version doesn't match\n"); return false; } if(s_v4l2CodecOps.mSize != sizeof(V4l2CodecOps)) { ERROR("V4l2CodecOps interface data structure size doesn't match\n"); return false; } return true; } #define SIMULATE_V4L2_OP(OP) s_v4l2CodecOps.m##OP##Func #else #define SIMULATE_V4L2_OP(OP) YamiV4L2_##OP #endif struct RawFrameData { uint32_t width; uint32_t height; uint32_t pitch[3]; uint32_t offset[3]; uint32_t fourcc; //NV12 uint8_t *data; }; const uint32_t k_maxInputBufferSize = 1024*1024; const int k_inputPlaneCount = 1; const int k_maxOutputPlaneCount = 3; int outputPlaneCount = 2; int videoWidth = 0; int videoHeight = 0; uint32_t inputQueueCapacity = 0; uint32_t outputQueueCapacity = 0; uint32_t k_extraOutputFrameCount = 2; static std::vector<uint8_t*> inputFrames; static std::vector<struct RawFrameData> rawOutputFrames; #if !__ENABLE_V4L2_GLX__ static VideoDataMemoryType memoryType = VIDEO_DATA_MEMORY_TYPE_DRM_NAME; static const char* typeStrDrmName = "drm-name"; static const char* typeStrDmaBuf = "dma-buf"; static const char* typeStrRawData = "raw-data"; // static const char* typeStrAndroidNativeBuffer = "android-native-buffer"; static const char* memoryTypeStr = typeStrDrmName; #define IS_DRM_NAME() (!strcmp(memoryTypeStr, typeStrDrmName)) #define IS_DMA_BUF() (!strcmp(memoryTypeStr, typeStrDmaBuf)) #define IS_RAW_DATA() (!strcmp(memoryTypeStr, typeStrRawData)) // #define IS_ANDROID_NATIVE_BUFFER() (!strcmp(memoryTypeStr, typeStrAndroidNativeBuffer)) #endif static FILE* outfp = NULL; #ifndef ANDROID static Display * x11Display = NULL; static Window x11Window = 0; #endif #ifdef ANDROID #elif __ENABLE_V4L2_GLX__ static GLXContextType *glxContext; std::vector <Pixmap> pixmaps; std::vector <GLXPixmap> glxPixmaps; #else static EGLContextType *eglContext = NULL; static std::vector<EGLImageKHR> eglImages; #endif #ifndef ANDROID static std::vector<GLuint> textureIds; #endif static bool isReadEOS=false; static int32_t stagingBufferInDevice = 0; static uint32_t renderFrameCount = 0; bool feedOneInputFrame(DecodeInput * input, int fd, int index = -1 /* if index is not -1, simple enque it*/) { VideoDecodeBuffer inputBuffer; struct v4l2_buffer buf; struct v4l2_plane planes[k_inputPlaneCount]; int ioctlRet = -1; memset(&buf, 0, sizeof(buf)); memset(&planes, 0, sizeof(planes)); buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; // it indicates input buffer(raw frame) type buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = planes; buf.length = k_inputPlaneCount; if (index == -1) { ioctlRet = SIMULATE_V4L2_OP(Ioctl)(fd, VIDIOC_DQBUF, &buf); if (ioctlRet == -1) return true; stagingBufferInDevice --; } else { buf.index = index; } if (isReadEOS) return false; if (!input->getNextDecodeUnit(inputBuffer)) { // send empty buffer for EOS buf.m.planes[0].bytesused = 0; isReadEOS = true; } else { ASSERT(inputBuffer.size <= k_maxInputBufferSize); memcpy(inputFrames[buf.index], inputBuffer.data, inputBuffer.size); buf.m.planes[0].bytesused = inputBuffer.size; buf.m.planes[0].m.mem_offset = 0; buf.flags = inputBuffer.flag; } ioctlRet = SIMULATE_V4L2_OP(Ioctl)(fd, VIDIOC_QBUF, &buf); ASSERT(ioctlRet != -1); stagingBufferInDevice ++; return true; }