支持语音与视频即时通讯项目杂记(二)

news2024/11/25 16:25:50

目录

概念:

视频帧(Video Frame)是组成视频的基本单元。它可以被视为一幅静止的图像,它在一定的时间间隔内连续播放,从而形成了流畅的视频。

Changes to Qt Multimedia

New features in Qt 6

Removed features

Changed features

qt6中的正则表达式校验的应用

概念:

视频帧(Video Frame)是组成视频的基本单元。它可以被视为一幅静止的图像,它在一定的时间间隔内连续播放,从而形成了流畅的视频。

视频帧由像素组成,每个像素代表了图像中的一个点的颜色值。视频帧的大小通常以宽度和高度来描述,例如 1920x1080 表示宽度为 1920 像素,高度为 1080 像素。每个像素的颜色值可以通过不同的图像格式来表示,例如 RGB、YUV 等。

视频帧之间的时间间隔称为帧率(Frame Rate),用于衡量每秒播放的视频帧数。常见的帧率有 24fps、30fps、60fps 等。较高的帧率可以提供更流畅的视频播放效果。

理解帧的概念可以类比为一本动画书,每页都是一个静止画面,当您快速翻动这些画面时,就会产生连续的动画效果。同样地,视频帧也是以相似的方式运作,通过连续播放静止的视频帧,我们感知到了动态的视频内容。

在视频处理和编辑中,您可以对视频帧进行各种操作,如剪辑、特效处理、颜色校正等。通过对视频帧的处理,可以实现视频的编辑、修复和增强等功能。

总结起来,视频帧是组成视频的静止图像,通过连续播放这些图像,我们可以观看到流畅的动态视频内容。

QVideoFrame 是 Qt Multimedia 模块中的一个类,用于表示视频帧的数据。它提供了处理和操作视频帧的功能。

下面是 QVideoFrame 的一些常见用途和作用:

  1. 获取视频帧数据:通过 QVideoFrame,您可以获取视频帧的原始数据,包括像素数据、图像格式、图像大小等。这使得您可以进行视频处理、分析和编辑等操作。

  2. 格式转换:QVideoFrame 提供了方法将视频帧转换为不同的图像格式,以便与您的应用程序或其他模块兼容。您可以使用 QVideoFrame::map() 函数将帧数据映射到一个 QImage 或者 QPixmap 对象中,然后进行格式转换。

  3. 视频播放和显示:QVideoFrame 可以与其他 Qt 组件(如 QImageQLabelQGraphicsView 等)进行集成,实现视频的播放和显示。通过将视频帧数据与相应的图像组件结合使用,您可以在用户界面中实时显示视频。

  4. 视频输入输出:通过 QVideoFrame,您可以处理和传输视频帧数据。例如,您可以将视频帧保存为文件,或者从摄像头或其他视频源接收视频帧。

综上所述,QVideoFrame 类提供了对视频帧的访问和处理功能,使您能够灵活地处理视频数据以满足应用程序的需求。

在Qt项目中,.pri文件是一种特殊的文件类型,称为"包含文件"(Include File),主要用于将共享的构建设置和规则抽象成一个可复用的模块,方便在其他项目中重复使用。.pri文件可以包含编译器选项、头文件路径、库依赖关系以及其他自定义构建规则等信息。

要创建一个.pri文件,您可以按照以下步骤操作:

  1. 打开Qt Creator,并且打开您要将.pri文件添加到的项目。

  2. 在项目视图中,右键单击您想要创建.pri文件的文件夹,选择"新建文件"(New File)。

  3. 在弹出的对话框中,选择"其他"(Other)-> "Pro 文件"(Pro File),然后点击下一步。

  4. 输入文件名并选择保存位置,例如:"myproject.pri",然后点击下一步。

  5. 在下一个对话框中,确认文件属性并且选择添加需要的模块或者库,并且可以在此处定义全局变量、宏定义、编译器选项等设置。然后点击完成来创建文件。

  6. 在您的项目文件(例如.pro文件)中包含该.pri文件:在您的项目文件中加入如下语句:

    include(myproject.pri)
    

这样就可以在您的项目中使用.pri文件中定义的构建规则和设置了。需要注意的是,.pri文件中定义的变量或宏在引入该文件的项目中是全局可见的。因此,如果您有多个.pri文件,建议将它们放在独立文件夹中,以便管理和维护。

官网中说明:

Changes to Qt Multimedia

Qt 6 is a result of the conscious effort to make the framework more efficient and easy to use.

We try to maintain binary and source compatibility for all the public APIs in each release. But some changes were inevitable in an effort to make Qt a better framework.

The module has been refactored significantly and has changed classification, from essential to add-on. The Qt Multimedia module in Qt 6 replaces the Qt Multimedia module from Qt 5.x. Existing code that uses Qt Multimedia from Qt 5 can be ported with limited effort.

New features in Qt 6

There are a number of new features in Qt Multimedia:

  • QMediaCaptureSession class is the central object for media capture.
  • QMediaRecorder class is now a class limited to recording audio and video. It handles encoding of data produced in a capture session.
  • Using QMediaFormat and QMediaRecorder, setting up the desired encoding when recording has changed significantly.
  • You can now also monitor the audio recorded by a capture session.
  • Support for selection of audio, video and subtitle tracks when playing back media files has been added.
  • QAudioDecoder is now supported on all platforms.

Removed features

Removed featureNotes or suggested alternative
Playlist in QMediaPlayerQMediaPlayer does not do any playlist handling anymore in Qt 6.
QMediaPlayListThis class has been removed from the API. It does however still exist as part of the Media Player Example.
QAudioProbe and QVideoProbeThe audio and video probing API has been removed.
QAudioRecorderUse the QMediaCaptureSession or CaptureSession QML type.
Audio QML typeUse MediaPlayer QML type.
QMediaObject and QMediaBindableInterfaceThese classes have been removed in favor of a more direct API for setting up connections between objects using, for example, setVideoOutput and QMediaCaptureSession.
QCameraViewFinderSettingsThis class has been removed. Use QCameraFormat to define the resolution and frame rate the camera should be using.
QMediaContentThe class has been removed. Use QUrl for individual media files instead.
QSoundUse QSoundEffect instead.
QVideoFilterRunnableUse shader effects in QML instead or access the QVideoFrame's content in C++.
Public back-end APIThe back-end API of Qt Multimedia is private in Qt 6. This improves response time for supporting new multimedia use cases. Any classes that contain the words "Control" or "Abstract" in the class name in Qt 5 are now private in Qt 6.
Back-end pluginsQt Multimedia in Qt 6 does not use a plugin infrastructure for its back ends anymore. This means that users no longer need to ship those back ends with their application. Instead, the back end being used is determined at compile time based on the underlying operating system. Qt uses gstreamer on Linux, WMF on Windows, AVFoundation on macOS and iOS and the Android multimedia APIs on Android.

Changed features

A number of classes previously offered in Qt Multimedia have changed in ways that may affect previously written code. The following table highlights these changes.

Changed featureNotes
Handling of Camera resolutions and frame ratesHandling of these has been simplified and a new QCameraFormat class helps with selecting the correct resolution and frame rate for the camera.
Video output handling on the C++ side has changed significantly.QAbstractVideoSurface has been replaced by the QVideoSink class, and generic rendering support has been enhanced to cover all pixel formats supported by Qt Multimedia.
Metadata typesQMediaMetaData has changed significantly: mainly moving from string based to enum based keys, and reducing the set of supported keys to the ones that can be supported on most platforms.
QMediaFormatHandling of formats for encoded media and the settings for the media recorder have changed significantly. Qt 5 provides a string-based API, a separated file format, and audio and video codecs into three classes. However, Qt 6 unifies the formats in the QMediaFormat class. Additional settings are directly specified in QMediaRecorder. Setting up file formats and codecs is now implemented with enums and no longer uses strings. This puts some limitations on the set of codecs that can be used, but helps provide a consistent cross-platform API.
QCameraImageCapture renamed QImageCaptureNone
Audio inputs and outputsQMediaPlayer and QMediaCaptureSession (and the corresponding QML types MediaPlayer and CaptureSession) are not connected to any audio devices by default. Explicitly connect them to a QAudioInput/AudioInput or QAudioOutput/AudioOutput to capture or play back audio.
Capturing videoA capture session is by default not connected to a Camera. Connect it to a QCamera object (Camera item) to be able to capture video or still images.

qt6中的正则表达式校验的应用

项目中,涉及IP地址校验等需求,qt6 正则表达式和qt5有一定差异,见下面的代码

#ifndef CLINEEDIT_H
#define CLINEEDIT_H

#include <QLineEdit>
#include <QEvent>

class QLabel;

class QIPLineEdit : public QLineEdit
{
	Q_OBJECT

public:
	QIPLineEdit(QWidget *parent = 0);
	~QIPLineEdit();

	void setText(const QString &strIP);
	QString text() const;
protected:
	bool eventFilter(QObject *obj, QEvent *ev);

	int getIndex(QLineEdit *pEdit);
	bool isTextValid(const QString &strIP);
private:
	QLineEdit *m_lineEidt[4];
};

/
class QMacLineEdit : public QLineEdit
{
    Q_OBJECT

public:
    QMacLineEdit(QWidget *parent = 0);
    ~QMacLineEdit();

    void setText(const QString &strMac);
    QString text() const;
protected:
//    void paintEvent(QPaintEvent *event);
    bool eventFilter(QObject *obj, QEvent *ev);

    int getIndex(QLineEdit *pEdit);
    bool isTextValid(const QString &strIP);
private:
    QLineEdit *m_lineEidt[6];
};

class QIconLineEdit : public QLineEdit {
    Q_OBJECT
public:
    QIconLineEdit(QWidget *parent = 0);
    ~QIconLineEdit();

    void SetIcon(const QPixmap &pixmap);
private:
    QLabel *labelPixmap;
};

#endif // QIPLINEEDIT_H
#include "clineedit.h"
#include "ipvalidator.h"
#include <QLabel>
#include <QRegularExpressionValidator>
#include <QRegularExpression>
#include <QValidator>
#include <QPainter>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QMessageBox>
#include <QDebug>
#include <QRegularExpression>
#include <QValidator>





QIPLineEdit::QIPLineEdit(QWidget *parent)
    : QLineEdit(parent)
{
     QRegularExpression rx("(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})");
    //QRegExp rx("(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})");
    QHBoxLayout *pHBox = new QHBoxLayout(this);
    pHBox->setSpacing(2);
    pHBox->setContentsMargins(2, 2, 2, 2);
    QLabel *labelDot[3];
    for (int i = 0; i < 4; i++)
    {
        m_lineEidt[i] = new QLineEdit(this);
        m_lineEidt[i]->setProperty("ip", true);
        m_lineEidt[i]->setFrame(false);
        m_lineEidt[i]->setMaxLength(3);
        m_lineEidt[i]->setAlignment(Qt::AlignCenter);
        m_lineEidt[i]->installEventFilter(this);
        //m_lineEidt[i]->setValidator(new QRegExpValidator(rx, this));
        m_lineEidt[i]->setValidator(new IPValidator(this));

        m_lineEidt[i]->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
        pHBox->addWidget(m_lineEidt[i]);
        if (i < 3) {
            labelDot[i] = new QLabel(this);
            labelDot[i]->setText(".");
            labelDot[i]->setFixedWidth(2);
            pHBox->addWidget(labelDot[i]);
        }
    }
    this->setReadOnly(true);
    m_lineEidt[0]->setFocus();
    m_lineEidt[0]->selectAll();
}

QIPLineEdit::~QIPLineEdit()
{
}

// 获取当前输入框索引
int QIPLineEdit::getIndex(QLineEdit *pEdit)
{
    int index = -1;
    for (int i = 0; i < 4; i++)
    {
        if (pEdit == m_lineEidt[i])
            index = i;
    }
    return index;
}

// 事件过滤器,判断按键输入
bool QIPLineEdit::eventFilter(QObject *obj, QEvent *ev)
{
    if (children().contains(obj) && QEvent::KeyPress == ev->type())
    {
        QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(ev);
        QLineEdit *pCurrentEdit = qobject_cast<QLineEdit *>(obj);
        switch (keyEvent->key())
        {
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
        {
            QString strText = pCurrentEdit->text();
            if (pCurrentEdit->selectedText().length())
            {
                pCurrentEdit->text().replace(pCurrentEdit->selectedText(), QChar(keyEvent->key()));
            }
            else if (strText.length() <=3 &&
                     strText.toInt() * 10 > 255)
            {
                int index = getIndex(pCurrentEdit);
                if (index != -1 && index != 3)
                {
                    m_lineEidt[index + 1]->setFocus();
                    m_lineEidt[index + 1]->selectAll();
                }
            }
            else if (strText.length() == 2 && strText.toInt() * 10 < 255)
            {
                if (Qt::Key_0 == keyEvent->key() && strText.toInt())
                {
                    pCurrentEdit->setText(strText.insert(pCurrentEdit->cursorPosition(),
                                                         QChar(Qt::Key_0)));
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
            break;
        case Qt::Key_Backspace:
        {
            QString strText = pCurrentEdit->text();
            if (strText.isEmpty())
            {
                int index = getIndex(pCurrentEdit);
                if (index != -1 && index != 0)
                {
                    m_lineEidt[index - 1]->setFocus();
                    int length = m_lineEidt[index - 1]->text().length();
                    m_lineEidt[index - 1]->setCursorPosition(length ? length : 0);
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
        case Qt::Key_Left:
        {
            if (!pCurrentEdit->cursorPosition())
            {
                int index = getIndex(pCurrentEdit);
                if (index != -1 && index != 0)
                {
                    m_lineEidt[index - 1]->setFocus();
                    int length = m_lineEidt[index - 1]->text().length();
                    m_lineEidt[index - 1]->setCursorPosition(length ? length : 0);
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
        case Qt::Key_Right:
        {
            if (pCurrentEdit->cursorPosition() == pCurrentEdit->text().length())
            {
                int index = getIndex(pCurrentEdit);
                if (index != -1 && index != 3)
                {
                    m_lineEidt[index + 1]->setFocus();
                    m_lineEidt[index + 1]->setCursorPosition(0);
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
            // 小键盘的“.”号
        case Qt::Key_Period:
        {
            int index = getIndex(pCurrentEdit);
            if (index != -1 && index != 3)
            {
                m_lineEidt[index + 1]->setFocus();
                m_lineEidt[index + 1]->setCursorPosition(0);
            }
            return QLineEdit::eventFilter(obj, ev);
        }
            break;
        default:
            break;
        }
    }
    return false;
}

// 设置信息
void QIPLineEdit::setText(const QString &strIP)
{
    // 是否是IP地址
    if (!isTextValid(strIP))
    {
        QMessageBox::warning(this, "Attention",
                             "Your IP Address is Invalid!",
                             QMessageBox::StandardButton::Ok);
        return;
    }
    else
    {
        int i = 0;
        QStringList ipList = strIP.split(".");

        foreach (QString ip ,ipList)
        {
            m_lineEidt[i]->setText(ip);
            i++;
        }
    }
}

// 判断IP地址
bool QIPLineEdit::isTextValid(const QString &strIP)
{
    //QRegExp rx2("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b");
    QRegularExpression rx2("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b");
    QRegularExpressionMatch match = rx2.match(strIP);
    if (!match.hasMatch()) {
        return false;
    }
    //    if (!rx2.exactMatch(strIP))
//        return false;
    return true;
}


// 获取IP地址
QString QIPLineEdit::text() const
{
    QString strIP;
    for (int i = 0; i < 4; i++) {
        strIP.append(m_lineEidt[i]->text());
        if (3 != i) {
            strIP.append(".");
        }
    }

    return strIP;
}

QMacLineEdit::QMacLineEdit(QWidget *parent)
    : QLineEdit(parent)
{
    //QRegExp rx("([0-9A-Fa-f]{2})");
    QRegularExpression rx("([0-9A-Fa-f]{2})");

    QHBoxLayout *pHBox = new QHBoxLayout(this);
    pHBox->setSpacing(2);
    pHBox->setContentsMargins(2, 2, 2, 2);
    QLabel *labelDot[5];
    for (int i = 0; i < 6; i++)
    {
        m_lineEidt[i] = new QLineEdit(this);
        m_lineEidt[i]->setFrame(false);
        m_lineEidt[i]->setMaxLength(2);
        m_lineEidt[i]->setAlignment(Qt::AlignCenter);
        m_lineEidt[i]->installEventFilter(this);
        //m_lineEidt[i]->setValidator(new QRegExpValidator(rx, this));
        //m_lineEidt[i]->setValidator(new QValidator (0,100,this));
        QRegularExpressionValidator* validator = new QRegularExpressionValidator(QRegularExpression("(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})"), this);
        m_lineEidt[i]->setValidator(validator);
        m_lineEidt[i]->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
        pHBox->addWidget(m_lineEidt[i]);
        if (i < 5) {
            labelDot[i] = new QLabel(this);
            labelDot[i]->setText("-");
            labelDot[i]->setFixedWidth(2);
            pHBox->addWidget(labelDot[i]);
        }
    }
    this->setReadOnly(true);
    m_lineEidt[0]->setFocus();
    m_lineEidt[0]->selectAll();
}

QMacLineEdit::~QMacLineEdit()
{
}

int QMacLineEdit::getIndex(QLineEdit *pEdit)
{
    int index = -1;
    for (int i = 0; i < 6; i++)
    {
        if (pEdit == m_lineEidt[i])
            index = i;
    }
    return index;
}

//
bool QMacLineEdit::eventFilter(QObject *obj, QEvent *ev)
{
    if (children().contains(obj) && QEvent::KeyPress == ev->type())
    {
        QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(ev);
        QLineEdit *pCurrentEdit = qobject_cast<QLineEdit *>(obj);

        switch (keyEvent->key())
        {
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
        case Qt::Key_A:
        case Qt::Key_B:
        case Qt::Key_C:
        case Qt::Key_D:
        case Qt::Key_E:
        case Qt::Key_F:
        {
            QString strText = pCurrentEdit->text();
            if (pCurrentEdit->selectedText().length())
            {
                pCurrentEdit->text().replace(pCurrentEdit->selectedText(),
                                             QChar(keyEvent->key()).toUpper());
            }
            else if (strText.length() == 2) {
                int index = getIndex(pCurrentEdit);
                if (0 <= index  && index < 5)
                {
                    m_lineEidt[index + 1]->setFocus();
                    m_lineEidt[index + 1]->selectAll();
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
            break;
        case Qt::Key_Backspace:
        {
            QString strText = pCurrentEdit->text();
            if (strText.isEmpty())
            {
                int index = getIndex(pCurrentEdit);
                if (index != -1 && index != 0)
                {
                    m_lineEidt[index - 1]->setFocus();
                    int length = m_lineEidt[index - 1]->text().length();
                    m_lineEidt[index - 1]->setCursorPosition(length ? length : 0);
                }
            }
            return QLineEdit::eventFilter(obj, ev);
        }
        case Qt::Key_Period:
        {
            int index = getIndex(pCurrentEdit);
            QString strText = pCurrentEdit->text();
            if (strText.length() == 1) {
                pCurrentEdit->setText(strText.insert(0, QChar(Qt::Key_0)));
            }
            else if (strText.length() == 0) {
                pCurrentEdit->setText("00");
            }

            if (index != -1 && index < 5)
            {
                m_lineEidt[index + 1]->setFocus();
                m_lineEidt[index + 1]->setCursorPosition(0);
            }
            return QLineEdit::eventFilter(obj, ev);
        }
            break;
        default:
            break;
        }
    }
    return false;
}

//
void QMacLineEdit::setText(const QString &strMac)
{
    if (!isTextValid(strMac))
    {
        QMessageBox::warning(this, "Attention",
                             "Your MAC Address is Invalid!",
                             QMessageBox::StandardButton::Ok);
        return;
    }
    else
    {
        int i = 0;
        QStringList macList = strMac.split("-");

        foreach (QString mac ,macList)
        {
            m_lineEidt[i]->setText(mac);
            i++;
        }
    }
}

bool QMacLineEdit::isTextValid(const QString &strIP)
{
  //qt6的写法
    QRegularExpression rx2("([0-9A-Za-z]{2})([0-9A-Za-z:-]{3}){5}");
    QRegularExpressionMatch match = rx2.match(strIP);
    return match.hasMatch();
  //qt5的写法
  //QRegExp rx2("([0-9A-Za-z]{2})([0-9A-Za-z:-]{3}){5}");
  //    if (!rx2.exactMatch(strIP))
  //        return false;
  // return true;
}

QString QMacLineEdit::text() const
{
    QString strMac;
    for (int i = 0; i < 5; i++) {
        strMac.append(m_lineEidt[i]->text());
        if (3 != i) {
            strMac.append("-");
        }
    }
    return strMac;
}

QIconLineEdit::QIconLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
    labelPixmap = new QLabel(this);
    labelPixmap->setMinimumSize(16, 16);
    labelPixmap->setVisible(false);

}

QIconLineEdit::~QIconLineEdit()
{

}

void QIconLineEdit::SetIcon(const QPixmap &pixmap)
{
    if (pixmap.isNull()) return;

    labelPixmap->setPixmap(pixmap);
    labelPixmap->setVisible(true);
    labelPixmap->setGeometry(5,(this->height() - pixmap.height()) / 2, 16, 16);
    this->setTextMargins(25, 1, 1, 1);
}



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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【具身智能模型2】RT-1: Robotics Transformer for Real-World Control at Scale

论文标题&#xff1a;RT-1: Robotics Transformer for Real-World Control at Scale 论文作者&#xff1a;Anthony Brohan, Noah Brown, Justice Carbajal, Yevgen Chebotar, Joseph Dabis, Chelsea Finn, Keerthana Gopalakrishnan, Karol Hausman, Alex Herzog, Jasmine Hsu,…

如何处理前端打包体积过大的问题?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

如何使用前端桌面应用程序框架(Electron等)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

STM32实现USB转TTL串口工具

STM32实现USB转TTL串口工具 具有USB接口和UART接口的STM32芯片&#xff0c;如STM32F1, STM32F4等等&#xff0c;都可以实现USB转TTL串口工具的制作。目前具有USB接口的最小资源的芯片是STM32F103C6T6。这里介绍USB转UART的代码设计。 STM32例化的USB VCOM&#xff0c;数据通讯…

(1)(1.1) Bluetooth

文章目录 前言 1 连接到自动驾驶仪 2 连接Mission Planner快速入门 3 与Mission Planner的详细连接 4 从安卓地面站连接 5 如何更改波特率、设备名称和设备密码 6 故障排除 7 产品规格 前言 蓝牙数据链路&#xff08;如 HC-06 模块&#xff09;(HC-06 module)可用于将…

Node.JS---npm相关

文章目录 前言一、package.json配置项version&#xff1a;1.0.0devDependenciesdependenciespeerDependenciesoptionalDependencies 二、npm命令1、npm config listxmzs使用2、npm installpackage-lock.json作用 3、npm run4、 查看全局安装的可执行文件 npm生命周期npxnpx简介…

对象属性的读写两种方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 对象属性的读写 两种方法 选择题 下列代码执行输出的结果是? class C(object): name hello c1 C() print("【执行】c1C()") print("【显示】print(c1.name)") print(c…

伽马函数:将阶乘函数扩展到正整数之外

一、说明 &#xff0c;是对阶乘这种运算的实数域拓展。属于高级的数学模型&#xff0c;在高级概率模型用于定义分布函数。本文将介绍这个函数的基础概念和属性。 二、gamma函数定义 众所周知&#xff0c;阶乘这个运算本来是用于简化形如 n(n−1)(n−2)…321 的乘积的&#xff0…

OCR文字识别软件对于硬件的哪方面需求较高?

这个还得看OCR软件是远程识别还是本地识别&#xff0c;前者对电脑配置要求相对较低&#xff0c;因为OCR识别是在远程服务器上进行的&#xff0c;本地只是负责优化图片和保存识别结果&#xff0c;如金鸣表格文字识别和眼精星表格文字识别这类的软件就是基于远程的OCR识别方案&am…

MySQL性能优化指南:深入分析重做日志刷新到磁盘的机制

文章目录 &#x1f31f; MySQL重做日志性能优化指南&#x1f34a; 重做日志对数据库性能的影响&#x1f34a; 重做日志刷入磁盘的机制&#x1f34a; 实战使用&#x1f389; 1. 确认MySQL的redo log配置&#x1f389; 2. 强制刷新重做日志&#x1f389; 3. 检查重做日志是否已经…

【GIS前言技术】到底什么是实景三维?

文章目录 什么是实景三维&#xff1f;实景三维是怎么制作的&#xff1f;实景三维有哪些应用&#xff1f; 什么是实景三维&#xff1f; 实景三维是客观真实反映现实世界的三维模型&#xff0c;具有单体化、实体化、结构化、语义化的特点&#xff0c;通过融合模型三维、倾斜三维…

中文编程工具构件的应用:会员管理系统软件登录界面所用的构件编程实例

中文编程工具构件的应用&#xff1a;会员管理系统软件登录界面所用的构件编程实例 该实际应用的软件登录界面中的 用户名使用了 组合框构件&#xff0c;其内容可以读取动态赋值&#xff0c;密码框使用了 行编辑 构件&#xff0c;该构件可以预先设置密码字符。 该中文编程工具免…

【汇编】寄存器(学习笔记)

一、CPU工作原理 1、CPU概述 CPU由运算器、控制器、寄存器等器件组成&#xff0c;这些器件靠内部总线相连。 内部总线&#xff1a;CPU内部 <–> 各个器件 外部总线&#xff1a;CPU <–> 主板上其它器件 2、通用寄存器 8086CPU所有的寄存器都是16位的&#xff0c…

老胡的周刊(第112期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 LocalAI[2] &#x1f916; 免费、开源的 Ope…

iOS自动化测试方案(三):WDA+iOS自动化测试解决方案

文章目录 一、背景二、环境准备三、总结四、扩展4.1、WDA Client4.2、先使用WDA实现自动化4.3、代码示例&#xff1a;4.4、脱离macOS测试iOS App自动化&#xff0c;两个解决方案&#xff1a;4.5、第二种解决办法&#xff1a;pip install -U weditor4.6、下载安装Appium-Inspect…

2023 年 42 周 - 学习 倦怠期回顾

2023 年 42 周 - 学习 & 倦怠期回顾 本周属于反思怪的时间&#xff0c;1/4 的内容涉及到反思自己&#xff0c;剩下超过 2/3 的内容是对于学习方法加强的笔记 顺便重新复习了一下上周的笔记&#xff0c;然后发现&#xff0c;其实周算错了……截图的日历直接用周日算成一周…

【tg】 7 GroupInstanceCustomImpl

group GroupInstanceCustomImpl 核心GroupInstanceCustomInternal G:\CDN\P2P-DEV\tdesktop-offical\Telegram\ThirdParty\tgcalls\tgcalls\group\GroupInstanceCustomImpl.h 最核心是是GroupInstanceCustomInternal: private:std::shared_ptr<Threads> _threads;std::u…

python学习笔记:引用、浅拷贝和深拷贝(底层原理)

前言 在python中“一切皆对象”&#xff0c;包括整数&#xff08;int&#xff09;&#xff0c;小数&#xff08;float&#xff09;等 引用 Python解释器维护了一个内部的数据结构&#xff0c;称为命名空间或符号表&#xff0c;它将变量名与对象的内存地址关联起来。当您创建一…

【ArcGIS模型构建器】02:shp批量转kml/kmz

文章目录 一、加载实验数据二、设计模型构建器三、保存模型构建器 一、加载实验数据 打开ArcMap&#xff0c;加载专栏配套实验数据data02.rar中的&#xff0c;位于乡镇根目录文件夹内的15个乡镇矢量数据。 接下来跟我一步步实现用模型构建器批量转为kml。 二、设计模型构建器…

如何创建前端绘图和图表?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…