RK Camera hal 图像处理

soc:RK3568

system:Android12

今天发现外接的USBCamera用Camera 2API打开显示颠倒,如果在APP 里使用Camera1处理这块接口较少,调整起来比较麻烦

RK Camera hal位置:hardware/interfaces/camera

核心的文件在:

开机会启动:android.hardware.camera.provider@2.4-external-service服务

遍历/dev/videox ,通过V4l2获取摄像头驱动 长 宽 数据格式与帧率,判断当前的摄像头节点是否有效,有效就会告诉CameraServer注册为CameraId,主要代码如下

ExternalCameraDevice.cpp

std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormatsLocked(
    int fd, CroppingType cropType,
    const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
    const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
    const Size& minStreamSize,
    bool depthEnabled) {
    std::vector<SupportedV4L2Format> outFmts;
if (!mSubDevice){
    // VIDIOC_QUERYCAP get Capability
    struct v4l2_capability capability;
    
    int ret_query = ioctl(fd, VIDIOC_QUERYCAP, &capability);
    if (ret_query < 0) {
        ALOGE("%s v4l2 QUERYCAP %s failed: %s", __FUNCTION__, strerror(errno));
    }

    struct v4l2_fmtdesc fmtdesc{};
    fmtdesc.index = 0;
    if (capability.device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    else
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    int ret = 0;
    while (ret == 0) {
        //获取摄像头格式
        ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
        ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
                fmtdesc.pixelformat & 0xFF,
                (fmtdesc.pixelformat >> 8) & 0xFF,
                (fmtdesc.pixelformat >> 16) & 0xFF,
                (fmtdesc.pixelformat >> 24) & 0xFF);
        if (ret == 0 && !(fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
            auto it = std::find (
                    kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
            if (it != kSupportedFourCCs.end()) {
                // Found supported format
                v4l2_frmsizeenum frameSize {
                        .index = 0,
                        .pixel_format = fmtdesc.pixelformat};
                //获取摄像头SIZE
                for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
                        ++frameSize.index) {
                    if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
                        ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
                            fmtdesc.pixelformat & 0xFF,
                            (fmtdesc.pixelformat >> 8) & 0xFF,
                            (fmtdesc.pixelformat >> 16) & 0xFF,
                            (fmtdesc.pixelformat >> 24) & 0xFF,
                            frameSize.discrete.width, frameSize.discrete.height);
                        // Disregard h > w formats so all aspect ratio (h/w) <= 1.0
                        // This will simplify the crop/scaling logic down the road
                        if (frameSize.discrete.height > frameSize.discrete.width) {
                            continue;
                        }
                        // Discard all formats which is smaller than minStreamSize
                        if (frameSize.discrete.width < minStreamSize.width
                            || frameSize.discrete.height < minStreamSize.height) {
                            continue;
                        }
                        SupportedV4L2Format format {
                            .width = frameSize.discrete.width,
                            .height = frameSize.discrete.height,
                            .fourcc = fmtdesc.pixelformat
                        };
                        //获取对于的摄像头参数
                        if (format.fourcc == V4L2_PIX_FMT_Z16 && depthEnabled) {
                            updateFpsBounds(fd, cropType, depthFpsLimits, format, outFmts);
                        } else {
                            updateFpsBounds(fd, cropType, fpsLimits, format, outFmts);
                        }
                    }
                }
#ifdef HDMI_ENABLE
                if(strstr((const char*)capability.driver,"hdmi")){
                    ALOGE("driver.find :%s",capability.driver);
                    struct v4l2_dv_timings timings;

                    if(TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, &timings)) == 0)
                    {
                        char fmtDesc[5]{0};
                        sprintf(fmtDesc,"%c%c%c%c",
                        fmtdesc.pixelformat & 0xFF,
                        (fmtdesc.pixelformat >> 8) & 0xFF,
                        (fmtdesc.pixelformat >> 16) & 0xFF,
                        (fmtdesc.pixelformat >> 24) & 0xFF);
                        ALOGV("hdmi index:%d,ret:%d, format:%s", fmtdesc.index, ret,fmtDesc);
                        ALOGE("%s, hdmi I:%d, wxh:%dx%d", __func__,
                        timings.bt.interlaced, timings.bt.width, timings.bt.height);

                            ALOGV("add hdmi index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
                            fmtdesc.pixelformat & 0xFF,
                            (fmtdesc.pixelformat >> 8) & 0xFF,
                            (fmtdesc.pixelformat >> 16) & 0xFF,
                            (fmtdesc.pixelformat >> 24) & 0xFF);
                            SupportedV4L2Format formatGet {
                                .width = timings.bt.width,
                                .height = timings.bt.height,
                                .fourcc = fmtdesc.pixelformat
                            };
                            updateFpsBounds(fd, cropType, fpsLimits, formatGet, outFmts);

                            SupportedV4L2Format format_640x360 {
                                    .width = 640,
                                    .height = 360,
                                    .fourcc = fmtdesc.pixelformat
                            };
                            updateFpsBounds(fd, cropType, fpsLimits, format_640x360, outFmts);
                            SupportedV4L2Format format_1920x1080 {
                                    .width = 1920,
                                    .height = 1080,
                                    .fourcc = fmtdesc.pixelformat
                            };
                            updateFpsBounds(fd, cropType, fpsLimits, format_1920x1080, outFmts);

                    }
                }
#endif
            }
        }
        fmtdesc.index++;
    }
    trimSupportedFormats(cropType, &outFmts);

}

上面正常跑入,就可以通过dumpsys  media.camera | grep map 获取到支持的摄像头

rk3588_s:/ $ dumpsys media.camera | grep map
    Device 0 maps to "0"
    Device 1 maps to "1"
    Device 2 maps to "112"
    Device 3 maps to "201"

之后Camera 2 API 通过open 会调到CameraServer最终进到ExternalCameraDevice::open

1.openCamera

Return<void> ExternalCameraDevice::open(
        const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb) {
    Status status = Status::OK;
    sp<ExternalCameraDeviceSession> session = nullptr;

    if (callback == nullptr) {
        ALOGE("%s: cannot open camera %s. callback is null!",
                __FUNCTION__, mCameraId.c_str());
        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
        return Void();
    }
    //获取摄像头参数
    if (isInitFailed()) {
        ALOGE("%s: cannot open camera %s. camera init failed!",
                __FUNCTION__, mCameraId.c_str());
        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
        return Void();
    }

    mLock.lock();

    ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
    session = mSession.promote();
    if (session != nullptr && !session->isClosed()) {
        ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
        mLock.unlock();
        _hidl_cb(Status::CAMERA_IN_USE, nullptr);
        return Void();
    }
    //打开摄像头
    unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
#ifdef SUBDEVICE_ENABLE
    if(!mSubDevice){
        if (fd.get() < 0) {
            int numAttempt = 0;
            do {
                ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
                        __FUNCTION__, mDevicePath.c_str());
                usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
                fd.reset(::open(mDevicePath.c_str(), O_RDWR));
                numAttempt++;
            } while (fd.get() < 0 && numAttempt <= MAX_RETRY);

            if (fd.get() < 0) {
                ALOGE("%s: v4l2 device open %s failed: %s",
                        __FUNCTION__, mDevicePath.c_str(), strerror(errno));
                mLock.unlock();
                _hidl_cb(Status::INTERNAL_ERROR, nullptr);
                return Void();
            }
        }
    }
#else
    if (fd.get() < 0) {
        int numAttempt = 0;
        do {
            ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
                    __FUNCTION__, mDevicePath.c_str());
            usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
            fd.reset(::open(mDevicePath.c_str(), O_RDWR));
            numAttempt++;
        } while (fd.get() < 0 && numAttempt <= MAX_RETRY);

        if (fd.get() < 0) {
            ALOGE("%s: v4l2 device open %s failed: %s",
                    __FUNCTION__, mDevicePath.c_str(), strerror(errno));
            mLock.unlock();
            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
            return Void();
        }
    }
#endif
    //创建Session
    session = createSession(
            callback, mCfg, mSupportedFormats, mCroppingType,
            mCameraCharacteristics, mCameraId, std::move(fd));
    if (session == nullptr) {
        ALOGE("%s: camera device session allocation failed", __FUNCTION__);
        mLock.unlock();
        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
        return Void();
    }
    if (session->isInitFailed()) {
        ALOGE("%s: camera device session init failed", __FUNCTION__);
        session = nullptr;
        mLock.unlock();
        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
        return Void();
    }
    mSession = session;

    mLock.unlock();

    _hidl_cb(status, session->getInterface());
    return Void();
}

Camera framework 调用ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req)通过enqueueV4l2Frame 获取到每一帧数据,


void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp<V4L2Frame>& frame) {
    ATRACE_CALL();
    frame->unmap();
    ATRACE_BEGIN("VIDIOC_QBUF");
    v4l2_buffer buffer{};
    if (mCapability.device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
        buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    else
        buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buffer.memory = V4L2_MEMORY_MMAP;
    if (V4L2_TYPE_IS_MULTIPLANAR(buffer.type)) {
        buffer.m.planes = planes;
        buffer.length = PLANES_NUM;
    }

    buffer.index = frame->mBufferIndex;
#ifdef SUBDEVICE_ENABLE
    if(!isSubDevice()){
        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
            ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__,
                    frame->mBufferIndex, strerror(errno));
            return;
        }
    }
#else
    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
        ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__,
                frame->mBufferIndex, strerror(errno));
        return;
    }
#endif
    ATRACE_END();

    {
        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
        mNumDequeuedV4l2Buffers--;
    }
    mV4L2BufferReturned.notify_one();
}

Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
    ATRACE_CALL();
    // Return V4L2 buffer to V4L2 buffer queue
    sp<V3_4::implementation::V4L2Frame> v4l2Frame =
            static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
    enqueueV4l2Frame(v4l2Frame);

    // NotifyShutter
    notifyShutter(req->frameNumber, req->shutterTs);

    // Fill output buffers
    hidl_vec<CaptureResult> results;
    results.resize(1);
    CaptureResult& result = results[0];
    result.frameNumber = req->frameNumber;
    result.partialResult = 1;
    result.inputBuffer.streamId = -1;
    result.outputBuffers.resize(req->buffers.size());
    for (size_t i = 0; i < req->buffers.size(); i++) {
        result.outputBuffers[i].streamId = req->buffers[i].streamId;
        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
        if (req->buffers[i].fenceTimeout) {
            result.outputBuffers[i].status = BufferStatus::ERROR;
            if (req->buffers[i].acquireFence >= 0) {
                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
                handle->data[0] = req->buffers[i].acquireFence;
                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
            }
            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
        } else {
            result.outputBuffers[i].status = BufferStatus::OK;
            // TODO: refactor
            if (req->buffers[i].acquireFence >= 0) {
                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
                handle->data[0] = req->buffers[i].acquireFence;
                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
            }
        }
    }

    // Fill capture result metadata
    fillCaptureResult(req->setting, req->shutterTs);
    const camera_metadata_t *rawResult = req->setting.getAndLock();
    V3_2::implementation::convertToHidl(rawResult, &result.result);
    req->setting.unlock(rawResult);

    // update inflight records
    {
        std::lock_guard<std::mutex> lk(mInflightFramesLock);
        mInflightFrames.erase(req->frameNumber);
    }

    // Callback into framework
    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
    freeReleaseFences(results);
    return Status::OK;
}

接下来主要是initialize,通过开启一些OutputThread ,图像处理线程FormatConvertThread


bool ExternalCameraDeviceSession::initialize() {
#ifdef SUBDEVICE_ENABLE
    if(!isSubDevice()){
        if (mV4l2Fd.get() < 0) {
            ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
            return true;
        }
    }
#else
    if (mV4l2Fd.get() < 0) {
        ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
        return true;
    }
#endif
    struct v4l2_capability capability;
#ifdef SUBDEVICE_ENABLE
    int ret = -1;
    if(!isSubDevice()){
        ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability);
    }
#else
    int ret = ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability);
#endif
    std::string make, model;
    if (ret < 0) {
        ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
        mExifMake = "Generic UVC webcam";
        mExifModel = "Generic UVC webcam";
    } else {
        // capability.card is UTF-8 encoded
        char card[32];
        int j = 0;
        for (int i = 0; i < 32; i++) {
            if (capability.card[i] < 128) {
                card[j++] = capability.card[i];
            }
            if (capability.card[i] == '\0') {
                break;
            }
        }
        if (j == 0 || card[j - 1] != '\0') {
            mExifMake = "Generic UVC webcam";
            mExifModel = "Generic UVC webcam";
        } else {
            mExifMake = card;
            mExifModel = card;
        }
    }

    initOutputThread();
    if (mOutputThread == nullptr) {
        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
        return true;
    }
    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
    mFormatConvertThread->createJpegDecoder();

    status_t status = initDefaultRequests();
    if (status != OK) {
        ALOGE("%s: init default requests failed!", __FUNCTION__);
        return true;
    }

    mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
            kMetadataMsgQueueSize, false /* non blocking */);
    if (!mRequestMetadataQueue->isValid()) {
        ALOGE("%s: invalid request fmq", __FUNCTION__);
        return true;
    }
    mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
            kMetadataMsgQueueSize, false /* non blocking */);
    if (!mResultMetadataQueue->isValid()) {
        ALOGE("%s: invalid result fmq", __FUNCTION__);
        return true;
    }

    // TODO: check is PRIORITY_DISPLAY enough?
    mOutputThread->run("ExtCamOut", PRIORITY_DISPLAY);
    mFormatConvertThread->run("ExtFmtCvt", PRIORITY_DISPLAY);

#ifdef HDMI_ENABLE
#ifdef HDMI_SUBVIDEO_ENABLE
    sp<rockchip::hardware::hdmi::V1_0::IHdmi> client = rockchip::hardware::hdmi::V1_0::IHdmi::getService();
    if(client.get()!= nullptr){
        ::android::hardware::hidl_string deviceId;
        client->getHdmiDeviceId( [&](const ::android::hardware::hidl_string &id){
                deviceId = id.c_str();
        });
        ALOGE("getHdmiDeviceId:%s",deviceId.c_str());
        if(strstr(deviceId.c_str(), mCameraId.c_str())){
                ALOGE("HDMI attach SubVideo %s",mCameraId.c_str());
            if(strlen(ExternalCameraDevice::kSubDevName)>0){
                sprintf(main_ctx.dev_name,"%s",ExternalCameraDevice::kSubDevName);
                ALOGE("main_ctx.dev_name:%s",main_ctx.dev_name);
            }
            mSubVideoThread = new SubVideoThread(0);
            mSubVideoThread->run("SubVideo", PRIORITY_DISPLAY);
        }
     }
#endif
#endif

    return false;
}

每一帧都会在bool ExternalCameraDeviceSession::OutputThread::threadLoop() 里做格式转换和裁剪

//通过RGA处理每一帧图像,图像显示有问题可以在里面改

bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
    std::shared_ptr<HalRequest> req;
    auto parent = mParent.promote();
    if (parent == nullptr) {
       ALOGE("%s: session has been disconnected!", __FUNCTION__);
       return false;
    }
    ...
                } else if (req->frameIn->mFourcc == V4L2_PIX_FMT_NV12){

                    int handle_fd = -1, ret;

                    const native_handle_t* tmp_hand = (const native_handle_t*)(*(halBuf.bufPtr));
                    ret = ExCamGralloc4::get_share_fd(tmp_hand, &handle_fd);

                    if (handle_fd == -1) {
                        LOGE("convert tmp_hand to dst_fd error");
                        return -EINVAL;
                    }
                    ALOGV("%s(%d): halBuf handle_fd(%d)", __FUNCTION__, __LINE__, handle_fd);
                    ALOGV("%s(%d) halbuf_wxh(%dx%d) frameNumber(%d)", __FUNCTION__, __LINE__,
                        halBuf.width, halBuf.height, req->frameNumber);
                    unsigned long vir_addr =  reinterpret_cast<unsigned long>(req->inData);
                    //通过RGA处理每一帧图像,图像显示有问题可以在里面改
                    camera2::RgaCropScale::rga_scale_crop(
                        tempFrameWidth, tempFrameHeight, vir_addr,
                        HAL_PIXEL_FORMAT_YCrCb_NV12,handle_fd,
                        halBuf.width, halBuf.height, 100, false, false,
                        (halBuf.format == PixelFormat::YCRCB_420_SP), is16Align,
                        true);
                } else if (req->frameIn->mFourcc == V4L2_PIX_FMT_NV16){
    ...
}

int RgaCropScale::rga_scale_crop(
		int src_width, int src_height,
		unsigned long src_fd, int src_format,unsigned long dst_fd,
		int dst_width, int dst_height,
		int zoom_val, bool mirror, bool isNeedCrop,
		bool isDstNV21, bool is16Align, bool isYuyvFormat)
{
    int ret = 0;
    rga_info_t src,dst;
    int zoom_cropW,zoom_cropH;
    int ratio = 0;
    ...
    //我的是图像需要镜像 可以在这里改
    if (mirror)
        src.rotation = HAL_TRANSFORM_ROT_90; //HAL_TRANSFORM_ROT_
    else 
        src.rotation = HAL_TRANSFORM_ROT_180;
    ...
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/370885.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows 搭建nginx http服务

下载 下面链接直接点击下载&#xff0c;下载的就是包含rtmp服务器相关功能的&#xff0c;只不过需要配置下 Index of /download/ (ecsds.eu) nginx 1.7.11.3 Gryphon.zip直接点击额下面的连接即可下载 http://nginx-win.ecsds.eu/download/nginx%201.7.11.3%20Gryphon.zip …

Go语言Gin框架安全加固:全面解析SQL注入、XSS与CSRF的解决方案

前言 在使用 Gin 框架处理前端请求数据时&#xff0c;必须关注安全性问题&#xff0c;以防范常见的攻击。本文将探讨 Gin 框架中常见的安全问题&#xff0c;并提供相应的处理方法&#xff0c;以确保应用程序的稳健性和安全性。 处理前端请求数据时&#xff0c;确保应用程序的…

GaussDB新体验,新零售选品升级注入新思路【华为云GaussDB:与数据库同行的日子】

选品思维&#xff1a;低频VS高频 一个的商超&#xff0c;假设有50个左右的品类&#xff0c;每个品类下有2到10个不等的商品。然而如此庞大的商品&#xff0c;并非所有都是高频消费品。 结合自身日常的消费习惯&#xff0c;对于高频和低频的区分并不难。一般大型家电、高端礼盒…

802.11n 802.11ac (WiFi 4/5 )的核心要点

802.11n 802.11ac &#xff08;WiFi 4/5 &#xff09;是什么&#xff1f; WiFi 4&#xff1a; Ieee 802.11n Enhancements for High Throughput &#xff08;HT&#xff09; WiFi 5&#xff1a; Ieee 802.11ac Enhancements for Very High Throughput &#xff08;VHT&#x…

前缀和 acwing

思路&#xff1a;两个数组&#xff0c;一个数组用来保存数据&#xff0c;一个数组来求对应项的和 前缀和S[r]-s[r-1] 空出来下标0 从1开始 方便表示&#xff0c;防止越界 c代码实现: #include<iostream> using namespace std; const int N1000000; int a[N],s[N]; …

Linux底层基础知识

一.汇编&#xff0c;C语言&#xff0c;C&#xff0c;JAVA之间的关系 汇编&#xff0c;C语言&#xff0c;C可以通过不同的编译器&#xff0c;编译成机器码。而java只能由Java虚拟机识别。Java虚拟机可以看成一个操作系统&#xff0c;Java虚拟机是由汇编&#xff0c;C&#xff0c…

【刷题题解】最长回文子序列

给你一个字符串 s &#xff0c;找出其中最长的回文子序列&#xff0c;并返回该序列的长度。 子序列定义为&#xff1a;不改变剩余字符顺序的情况下&#xff0c;删除某些字符或者不删除任何字符形成的一个序列 这道题&#xff0c;一眼动态规划&#xff0c;但是即使动起来也规划…

总结了一下中继引擎(can中继器,TCP总机器)开发实际经验

多路数据进行中继的研究 1.数据中继的概念 数据中继是一种数据传输技术&#xff0c;用于在两个通信设备之间提供数字信号的传输。它利用数字信道传输数据信号&#xff0c;可以提供永久性和半永久性连接的数字数据传输信道。 数据中继的主要作用是提高通信质量和可靠性&#xf…

问题:金属电化学反应的实质是氧化还原反应,被腐蚀金属发生还原反应( ) #知识分享#知识分享#媒体

问题&#xff1a;金属电化学反应的实质是氧化还原反应&#xff0c;被腐蚀金属发生还原反应(  ) A、正确 B、错误 参考答案如图所示

解析Python中HTTP代理的常见问题

在Python编程中&#xff0c;HTTP代理是一个经常被提及的概念&#xff0c;尤其在处理网络请求和爬虫时。但与此同时&#xff0c;使用HTTP代理也经常会遇到一些令人头疼的问题。接下来&#xff0c;就让我们一起解析一下Python中使用HTTP代理时常见的那些问题。 1. 代理服务器无响…

如何在本地部署chatGLM3

文章目录 1. 参考2. ChatGLM3 介绍3. 本地运行3.1 硬件配置3.2 下载ChatGLM3代码3.3 下载需要加载的模型3.4 运行大模型3.4.1 ChatGLM3目录介绍3.4.2 安装依赖3.4.2 综合demo演示3.4.3 启动对话模式工具模式代码解释器 4. 总结 前面一章节有讲到 基于MacBook Pro M1芯片运行ch…

Debian系统显示中文

开发板上的debian默认不显示中文。 安装字体 sudo apt install fonts-wqy-zenhei 安装locals sudo apt install locales &#xff08;无必要&#xff09;设置/etc/locale.gen、设置/etc/locale.conf 运行dpkg-reconfigure locales dpkg-reconfigure locales 可以选择UT…

基于动作合成视频、线免费使用不需要注册,支持多种视频任务:图像生成视频、文本生成视频、视频修改、视频风格化、用Transformer构建世界模型

基于动作合成视频、线免费使用不需要注册&#xff0c;支持多种视频任务&#xff1a;图像生成视频、文本生成视频、视频修改、视频风格化、用Transformer构建世界模型。 WorldDreamer无缝逐帧AI模型: 基于Transformer生成高质量电影级别视频的通用世界模型"。从20亿数据中…

【linux】git和gdb调试工具

在linux下提交代码同步到gitee 1.创建一个新的仓库&#xff08;演示步骤&#xff09; 2.init 这两个步骤用于识别提交代码的身份&#xff0c;一个你的名字&#xff0c;一个你的邮箱 开启本地仓库 克隆本地仓库成功 我们将这个仓库拷到了111目录底下. 我们发现少了一个.gitig…

Fink CDC数据同步(五)Kafka数据同步Hive

6、Kafka同步到Hive 6.1 建映射表 通过flink sql client 建Kafka topic的映射表 CREATE TABLE kafka_user_topic(id int,name string,birth string,gender string ) WITH (connector kafka,topic flink-cdc-user,properties.bootstrap.servers 192.168.0.4:6668…

微信小程序使用ucharts折线图,有负数显示0刻度线

当数据有负数和正数的时候默认不会显示0刻度线&#xff0c;不方便看出正负对比 实现思路&#xff1a;显示的刻度线是根据数据的最大值和最小值自动分配到刻度线上面&#xff0c;把最大值和最小值设置为一样&#xff0c;然后平均分配给五个刻度线中间的刻度线就会为0就实现了显…

uniapp /微信小程序 使用map组件实现手绘地图方案

获取地图范围 点图拾取坐标-地图开放平台|腾讯位置服务 获取需要手绘地图左下角和右上角GPS坐标 以北京故宫为例&#xff1a; 截取需要手绘地图进行手绘地图制作 ​​​​​​​​​​​​​​ 素材处理 由于地图素材文件比较大&#xff0c;小程序又限制包大小<2M,无…

13.从桥接模式细品人生的几座桥

“物理学不存在了&#xff0c;今后也不会存在。”——《三体》 在《三体》中&#xff0c;有这样一个桥段&#xff0c;顶级的物理学家杨冬在三体文明超级计算机“智子”的干扰和误导下&#xff0c;得出了物理实验的结果在实验之前就会被某种力量确定的结论&#xff0c;导致自己…

PyTorch 2.2 中文官方教程(九)

在生产环境中部署 PyTorch 模型 通过 Flask 在 Python 中部署 PyTorch 的 REST API 原文&#xff1a;pytorch.org/tutorials/intermediate/flask_rest_api_tutorial.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 注意 点击这里下载完整的示例代码 作者&#…

Windows鼠标右键菜单闪一下就没了?说不定是这个搞的鬼!

前言 这几天接到有些小伙伴反馈&#xff1a;Windows的右键菜单闪一下就没了。 本来是要按鼠标右键进行界面刷新或者新建文件夹等操作的&#xff0c;结果闪一下就没有了&#xff0c;感觉这个系统就好像中了病毒了一样。 相信很多小伙伴应该也遇到过同样的情况&#xff0c;但具…
最新文章