status_t allocateAtomBuffer(AtomBuffer &aBuff, const AtomBuffer &formatDescriptor, Callbacks *aCallbacks) { LOG1("%s with these properties: (%dx%d)s:%d fourcc %s", __FUNCTION__, formatDescriptor.width, formatDescriptor.height, formatDescriptor.bpl, v4l2Fmt2Str(formatDescriptor.fourcc)); status_t status = OK; aBuff.dataPtr = NULL; aCallbacks->allocateMemory(&aBuff, formatDescriptor.size); if (aBuff.buff == NULL) { LOGE("Failed to allocate AtomBuffer"); return NO_MEMORY; } aBuff.width = formatDescriptor.width; aBuff.height = formatDescriptor.height; aBuff.bpl = formatDescriptor.bpl; aBuff.fourcc = formatDescriptor.fourcc; aBuff.size = formatDescriptor.size; aBuff.dataPtr = aBuff.buff->data; aBuff.shared = false; LOG1("@%s allocated heap buffer with pointer %p", __FUNCTION__, aBuff.dataPtr); return status; }
void ImageScaler::downScaleImage(void *src, void *dest, int dest_w, int dest_h, int dest_bpl, int src_w, int src_h, int src_bpl, int fourcc, int src_skip_lines_top, // number of lines that are skipped from src image start pointer int src_skip_lines_bottom) // number of lines that are skipped after reading src_h (should be set always to reach full image height) { unsigned char *m_dest = (unsigned char *)dest; const unsigned char * m_src = (const unsigned char *)src; LOG1("%s: dest_w:%d, dest_h:%d, src_w:%d, src_h:%d, fourcc:%s 0x%x", __func__, dest_w, dest_h, src_w, src_h, v4l2Fmt2Str(fourcc), fourcc); switch (fourcc) { case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV12: { if (dest_w == src_w && dest_h == src_h) { // trim only ImageScaler::trimNv12Image(m_dest, m_src, dest_w, dest_h, dest_bpl, src_w, src_h, src_bpl, src_skip_lines_top, src_skip_lines_bottom); } else { // downscale & crop ImageScaler::downScaleAndCropNv12Image(m_dest, m_src, dest_w, dest_h, dest_bpl, src_w, src_h, src_bpl, src_skip_lines_top, src_skip_lines_bottom); } break; } case V4L2_PIX_FMT_YUYV: // downscale ImageScaler::downScaleYUY2Image(m_dest, m_src, dest_w, dest_h, src_w, src_h); break; default: { ALOGE("no downscale support for fourcc = %s 0x%x", v4l2Fmt2Str(fourcc), fourcc); break; } } }
/** * Update the current device node configuration (low-level) * * This called is allowed in the following states: * - OPEN * - CONFIGURED * - PREPARED * * This methods allows more detailed control of the format than the previous one * It updates the internal configuration used to check for discrepancies between * configuration and buffer pool properties * * \param aFormat:[IN] reference to the new v4l2_format . * * \return NO_ERROR if everything went well * INVALID_OPERATION if device is not in correct state (open) * UNKNOW_ERROR if we get an error from the v4l2 ioctl's */ status_t V4L2VideoNode::setFormat(struct v4l2_format &aFormat) { LOG1("@%s device = %s", __FUNCTION__, mName.string()); int ret(0); if ((mState != DEVICE_OPEN) && (mState != DEVICE_CONFIGURED) && (mState != DEVICE_PREPARED) ){ ALOGE("%s invalid device state %d",__FUNCTION__, mState); return INVALID_OPERATION; } LOG1("VIDIOC_S_FMT: width: %d, height: %d, bpl: %d, fourcc: %s, field: %d", aFormat.fmt.pix.width, aFormat.fmt.pix.height, aFormat.fmt.pix.bytesperline, v4l2Fmt2Str(aFormat.fmt.pix.pixelformat), aFormat.fmt.pix.field); ret = ioctl(mFd, VIDIOC_S_FMT, &aFormat); if (ret < 0) { ALOGE("VIDIOC_S_FMT failed: %s", strerror(errno)); return UNKNOWN_ERROR; } // Update current configuration with the new one mFormatDescriptor.fourcc = aFormat.fmt.pix.pixelformat; mFormatDescriptor.width = aFormat.fmt.pix.width; mFormatDescriptor.height = aFormat.fmt.pix.height; mFormatDescriptor.bpl = aFormat.fmt.pix.bytesperline; // TODO: we should respect fmt.pix.sizeimage ensure its always // page aligned with our types of allocations mFormatDescriptor.size = frameSize(mFormatDescriptor.fourcc, bytesToPixels(mFormatDescriptor.fourcc, mFormatDescriptor.bpl), mFormatDescriptor.height); LOG1("bpl: %d from ISP", mFormatDescriptor.bpl); mState = DEVICE_CONFIGURED; mSetBufferPool.clear(); mSetBufferPool.setCapacity(MAX_V4L2_BUFFERS); return NO_ERROR; }
/** * Update the current device node configuration (low-level) * * This called is allowed in the following states: * - OPEN * - CONFIGURED * - PREPARED * * This methods allows more detailed control of the format than the previous one * It updates the internal configuration used to check for discrepancies between * configuration and buffer pool properties * * \param aFormat:[IN] reference to the new v4l2_format . * * \return NO_ERROR if everything went well * INVALID_OPERATION if device is not in correct state (open) * UNKNOW_ERROR if we get an error from the v4l2 ioctl's */ status_t V4L2VideoNode::setFormat(struct v4l2_format &aFormat) { LOG1("@%s device = %s", __FUNCTION__, mName.string()); int ret(0); if ((mState != DEVICE_OPEN) && (mState != DEVICE_CONFIGURED) && (mState != DEVICE_PREPARED) ){ LOGE("%s invalid device state %d",__FUNCTION__, mState); return INVALID_OPERATION; } LOG1("VIDIOC_S_FMT: width: %d, height: %d, bpl: %d, fourcc: %s, field: %d", aFormat.fmt.pix.width, aFormat.fmt.pix.height, aFormat.fmt.pix.bytesperline, v4l2Fmt2Str(aFormat.fmt.pix.pixelformat), aFormat.fmt.pix.field); ret = pioctl(mFd, VIDIOC_S_FMT, &aFormat); if (ret < 0) { LOGE("VIDIOC_S_FMT failed: %s", strerror(errno)); return UNKNOWN_ERROR; } // Update current configuration with the new one mConfig.originalFormat = mConfig.format = aFormat.fmt.pix.pixelformat; mConfig.width = aFormat.fmt.pix.width; mConfig.height = aFormat.fmt.pix.height; mConfig.stride = bytesToPixels(mConfig.format,aFormat.fmt.pix.bytesperline); mConfig.size = frameSize(mConfig.format, mConfig.stride, mConfig.height); if (mConfig.stride != mConfig.width) LOG1("stride: %d from ISP width: %d", mConfig.stride,mConfig.width); mState = DEVICE_CONFIGURED; mSetBufferPool.clear(); return NO_ERROR; }
/** * RD Helper methods to dump a YUV file stored in an AtomBuffer to a file * This function can be used during investigations anywhere in the HAL * codebase * */ int CameraDump::dumpAtom2File(const AtomBuffer *b, const char *name) { int bytes = 0; ALOGE("Dumping %s resolution (%dx%d) format %s",name,b->width, b->height,v4l2Fmt2Str(b->fourcc)); FILE *fd = fopen(name, "wb+"); if(fd == NULL) { ALOGE("%s could not open dump file ",__FUNCTION__); return -1; } bytes = fwrite(b->dataPtr, 1, b->size, fd); if (bytes != b->size) { ALOGE("ERROR DUMPING %s written %d size %d",name, bytes, b->size); } fclose(fd); return 0; }
/** * setBufferPool * updates the set buffer pool with externally allocated memory * * The device has to be at least in CONFIGURED state but once configured * it the buffer pool can be reset in PREPARED state. * * This pool will become active after calling start() * \param pool: array of void* where the memory is available * \param poolSize: amount of buffers in the pool * \param formatDescriptor: description of the properties of the buffers * it should match the configuration passed during setFormat * \param cached: boolean to detect whether the buffers are cached or not * A cached buffer in this context means that the buffer * memory may be accessed through some system caches, and * the V4L2 driver must do cache invalidation in case * the image data source is not updating system caches * in hardware. * When false (not cached), V4L2 driver can assume no cache * invalidation/flushes are needed for this buffer. */ status_t V4L2VideoNode::setBufferPool(void **pool, int poolSize, AtomBuffer *formatDescriptor, bool cached) { LOG1("@%s: device = %s", __FUNCTION__, mName.string()); struct v4l2_buffer_info vinfo; CLEAR(vinfo); uint32_t cacheflags = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | V4L2_BUF_FLAG_NO_CACHE_CLEAN; if ((mState != DEVICE_CONFIGURED) && (mState != DEVICE_PREPARED)) { ALOGE("%s:Invalid operation, device %s not configured (state = %d)", __FUNCTION__, mName.string(), mState); return INVALID_OPERATION; } if (pool == NULL || formatDescriptor == NULL) { ALOGE("Invalid parameters, pool %p frameInfo %p",pool, formatDescriptor); return BAD_TYPE; } /** * check that the configuration of these buffers matches what we have already * told the driver. */ if ((formatDescriptor->width != mFormatDescriptor.width) || (formatDescriptor->height != mFormatDescriptor.height) || (formatDescriptor->bpl != mFormatDescriptor.bpl) || (formatDescriptor->fourcc != mFormatDescriptor.fourcc) ) { ALOGE("Pool configuration does not match device configuration: (%dx%d) s:%d f:%s Pool is: (%dx%d) s:%d f:%s ", mFormatDescriptor.width, mFormatDescriptor.height, mFormatDescriptor.bpl, v4l2Fmt2Str(mFormatDescriptor.fourcc), formatDescriptor->width, formatDescriptor->height, formatDescriptor->bpl, v4l2Fmt2Str(formatDescriptor->fourcc)); return BAD_VALUE; } mSetBufferPool.clear(); mSetBufferPool.setCapacity(MAX_V4L2_BUFFERS); for (int i = 0; i < poolSize; i++) { vinfo.data = pool[i]; vinfo.width = formatDescriptor->width; vinfo.height = formatDescriptor->height; vinfo.format = formatDescriptor->fourcc; vinfo.length = formatDescriptor->size; if (cached) vinfo.cache_flags = 0; else vinfo.cache_flags = cacheflags; mSetBufferPool.push(vinfo); } mState = DEVICE_PREPARED; return NO_ERROR; }