当前位置: 首页 > news >正文

qt下ffmpeg录制mp4经验分享,支持音视频(h264、h265,AAC,G711 aLaw, G711muLaw)

前言

    MP4,是最常见的国际通用格式,在常见的播放软件中都可以使用和播放,磁盘空间占地小,画质一般清晰,它本身是支持h264、AAC的编码格式,对于其他编码的话,需要进行额外处理。本文提供了ffmpeg录制mp4的封装代码,经测试视频上它支持h264、h265编码,音频支持了AAC、G711的aLaw、muLaw编码。对于以上编码的支持,部分是需要修改ffmpeg的源码,本文也有提供已编译好的ffmpeg以及说明源码上需要修改的地方。

一、时间戳处理

    在mp4录制中,有碰到一个问题,即在录制实时流后,用播放器进行播放,播放时间没有从0秒开始。windows自带的media play播放时,一开始都是静止的画面,从第n秒后,才开始正式播放,用VLC可以直接跳到n秒进行播放。这个问题的原因是时间戳没有处理好,需要记录下首帧,指定首帧时间戳为0,然后后续视频帧的时间戳等于当前帧的时间戳减去首帧时间戳。代码如下:
在这里插入图片描述

二、添加h264、h265、AAC解码头信息

    解码头信息是保存在解码器上下文(AVCodecContext)的extradata中,这些信息包含h264的SPS、PPS头信息,AAC的adts头信息,h265的VPS、SPS、PPS,我们需要使用比特流过滤器(AVBitStreamFilter)来为每一种格式添加相应的头部信息,这样才能在解码器中正常进行解码。以下为添加解码头信息的相关代码:
    初始化时视频:
在这里插入图片描述
    循环读帧中,视频:
在这里插入图片描述
    初始化时音频:
在这里插入图片描述
    循环读帧中,音频:
在这里插入图片描述

三、ffmpeg支持g711 aLaw muLaw

在ffmpeg源码movenc.c文件中,找到mov_write_audio_tag函数,修改以下:
在这里插入图片描述
和在该文件中增加以下:
在这里插入图片描述
muLaw修改类似,它的MKTAG为 ‘u’,‘l’, ‘a’,‘w’。

四、代码分享

mp4recorder.h

#ifndef MP4RECORDER_H
#define MP4RECORDER_Hextern "C"
{#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libavfilter/avfilter.h"#include "libswscale/swscale.h"#include "libavutil/frame.h"#include "libavutil/imgutils.h"#include "libavcodec/bsf.h"
}#include <QObject>
#include <QMutex>class mp4Recorder : public QObject
{Q_OBJECT
public:explicit mp4Recorder(QObject *parent = nullptr);virtual ~mp4Recorder();bool Init(AVFormatContext *pIfmtCtx, int nCodecType, int nAudioCodecType, QString& sFile);bool DeInit();bool isInit() {return m_bInit;}bool saveOneFrame(AVPacket& pkt, int nCodecType, int nAudioCodecType);private:uint64_t         m_nCounts;bool             m_bFirstGoP;bool             m_bInit;QString          m_sRecordFile;AVFormatContext *m_pIfmtCtx;AVFormatContext *m_pOfmtCtx; // output stream format. copy from instream format.const AVOutputFormat  *m_pOfmt; // save file format.QMutex           m_lock;int64_t          m_nVideoTimeStamp;int              m_nVideoDuration;int              m_nVideoIndex = -1;int              m_nAudioIndex = -1;int				 m_nSpsPpsSize = 0;AVBSFContext    *m_pBsfc = nullptr;AVBSFContext    *m_pBsfcAAC = nullptr;AVPacket        *m_pktFilter = nullptr;AVPacket        *m_pktFilterAudio = nullptr;int64_t         m_nFirstVideoPts = 0;int64_t         m_nFirstAudioPts = 0;bool            m_bTransCode = false;// stream map.int  *m_pStreamMapping;int   m_nMappingSize;};#endif // MP4RECORDER_H

mp4recorder.cpp

#include "mp4recorder.h"
#include "commondef.h"
#include "cteasyaacencoder.h"#define TRANSCODE 0mp4Recorder::mp4Recorder(QObject *parent) : QObject(parent)
{QMutexLocker guard(&m_lock);m_sRecordFile.clear();m_pIfmtCtx = nullptr;m_pOfmtCtx = nullptr;m_pOfmt = nullptr;m_pStreamMapping = nullptr;m_nMappingSize = 0;m_nCounts = 0;m_bFirstGoP = false;m_bInit = false;
}mp4Recorder::~mp4Recorder()
{DeInit();
}bool mp4Recorder::Init(AVFormatContext *pIfmtCtx, int nCodecType, int nAudioCodecType, QString &sFile)
{QMutexLocker guard(&m_lock);if(!pIfmtCtx || sFile.isEmpty()){MY_DEBUG << "sFile.isEmpty().";return false;}m_sRecordFile = sFile;m_pIfmtCtx = pIfmtCtx;QByteArray ba = m_sRecordFile.toLatin1();const char* pOutFile = ba.data();qDebug() << "pOutFile:" << pOutFile;unsigned i = 0;int ret = 0;int stream_index = 0;// 1. create output contextavformat_alloc_output_context2(&m_pOfmtCtx, nullptr, nullptr, pOutFile);if (!m_pOfmtCtx){MY_DEBUG << "Could not create output context.";ret = AVERROR_UNKNOWN;goto end;}// 2. get memory.m_nMappingSize = pIfmtCtx->nb_streams;m_pStreamMapping = (int*)av_mallocz_array(m_nMappingSize, sizeof(*m_pStreamMapping));if (!m_pStreamMapping){MY_DEBUG << "av_mallocz_array fail.";ret = AVERROR(ENOMEM);goto end;}// 3. copy steam information.m_pOfmt = m_pOfmtCtx->oformat;for (i = 0; i < pIfmtCtx->nb_streams; i++){AVStream *pOutStream;AVStream *pInStream = pIfmtCtx->streams[i];AVCodecParameters *pInCodecpar = pInStream->codecpar;if (pInCodecpar->codec_type != AVMEDIA_TYPE_AUDIO &&pInCodecpar->codec_type != AVMEDIA_TYPE_VIDEO &&pInCodecpar->codec_type != AVMEDIA_TYPE_SUBTITLE){m_pStreamMapping[i] = -1;continue;}if(pInCodecpar->codec_type == AVMEDIA_TYPE_VIDEO){m_nVideoIndex = i;//1.找到相应解码器的过滤器if(nCodecType == AV_CODEC_ID_HEVC){const AVBitStreamFilter *bsf = av_bsf_get_by_name("hevc_mp4toannexb");if (!bsf){MY_DEBUG << "av_bsf_get_by_name() video failed";return false;}//2.过滤器分配内存av_bsf_alloc(bsf, &m_pBsfc);}else{const AVBitStreamFilter *bsf = av_bsf_get_by_name("h264_mp4toannexb");if (!bsf){MY_DEBUG << "av_bsf_get_by_name() video failed";return false;}//2.过滤器分配内存av_bsf_alloc(bsf, &m_pBsfc);}//3.添加解码器属性avcodec_parameters_copy(m_pBsfc->par_in, pInCodecpar);//4. 初始化过滤器上下文av_bsf_init(m_pBsfc);}else if(pInCodecpar->codec_type == AVMEDIA_TYPE_AUDIO){m_nAudioIndex = i;#if TRANSCODEif(nAudioCodecType == AV_CODEC_ID_PCM_ALAW || nAudioCodecType == AV_CODEC_ID_PCM_MULAW){MY_DEBUG << "ctEasyAACEncoder Init";if(nAudioCodecType == AV_CODEC_ID_PCM_ALAW)ctEasyAACEncoder::getInstance().Init(Law_ALaw);elsectEasyAACEncoder::getInstance().Init(Law_ULaw);m_bTransCode = true;}elsem_bTransCode = false;#endifif(m_bTransCode || nAudioCodecType == AV_CODEC_ID_AAC){//1. 找到相应解码器的过滤器const AVBitStreamFilter *bsf = av_bsf_get_by_name("aac_adtstoasc");if (!bsf){MY_DEBUG << "av_bsf_get_by_name() audio failed";return false;}//2.过滤器分配内存av_bsf_alloc(bsf, &m_pBsfcAAC);//3.添加解码器属性avcodec_parameters_copy(m_pBsfcAAC->par_in, pInCodecpar);//4. 初始化过滤器上下文av_bsf_init(m_pBsfcAAC);}#if TRANSCODEif(m_bTransCode)m_pBsfcAAC->par_in->codec_id = AV_CODEC_ID_AAC;
#endif}// fill the stream index.m_pStreamMapping[i] = stream_index++;// copy the new codec prameters.pOutStream = avformat_new_stream(m_pOfmtCtx, nullptr);if (!pOutStream){MY_DEBUG << "Failed allocating output stream";ret = AVERROR_UNKNOWN;goto end;}ret = avcodec_parameters_copy(pOutStream->codecpar, pInCodecpar);if (ret < 0){MY_DEBUG << "Failed to copy codec parameters";goto end;}
#if TRANSCODEif(m_bTransCode && pInCodecpar->codec_type == AVMEDIA_TYPE_AUDIO)pOutStream->codecpar->codec_id = AV_CODEC_ID_AAC;
#endif//pOutStream->codecpar->bit_rate = 2000000;//pOutStream->codecpar->codec_tag = 0;}// 4. create MP4 header.if (!(m_pOfmt->flags & AVFMT_NOFILE)) // network stream{ret = avio_open(&m_pOfmtCtx->pb, pOutFile, AVIO_FLAG_WRITE);if (ret < 0){MY_DEBUG << "Could not open output file " << m_sRecordFile;goto end;}}// 5. write file header.ret = avformat_write_header(m_pOfmtCtx, nullptr);if (ret < 0){MY_DEBUG << "Error occurred when opening output file ret:" << ret;goto end;}m_pktFilter = new AVPacket;av_init_packet(m_pktFilter);m_pktFilter->data = NULL;m_pktFilter->size = 0;m_pktFilterAudio = new AVPacket;av_init_packet(m_pktFilterAudio);m_pktFilterAudio->data = NULL;m_pktFilterAudio->size = 0;m_nFirstVideoPts = 0;m_nFirstAudioPts = 0;m_bFirstGoP = false;m_bInit = true;m_nCounts = 0;return true;end:DeInit();if (ret < 0 && ret != AVERROR_EOF){MY_DEBUG << "Error occurred.";}return false;
}bool mp4Recorder::DeInit()
{// 1. save tail.if(m_bInit && m_pOfmtCtx){av_write_trailer(m_pOfmtCtx);}m_bInit = false;// 2. close outputif (m_pOfmtCtx && !(m_pOfmt->flags & AVFMT_NOFILE)){avio_closep(&m_pOfmtCtx->pb);}// 3. free contex.if(m_pOfmtCtx){avformat_free_context(m_pOfmtCtx);m_pOfmtCtx = nullptr;}av_freep(&m_pStreamMapping);if(m_pBsfc){av_bsf_free(&m_pBsfc);m_pBsfc = nullptr;}if(m_pBsfcAAC){av_bsf_free(&m_pBsfcAAC);m_pBsfcAAC = nullptr;}#if TRANSCODEif(m_bTransCode){ctEasyAACEncoder::getInstance().DeInit();m_bTransCode = false;}
#endifreturn true;
}bool mp4Recorder::saveOneFrame(AVPacket &pkt, int nCodecType, int nAudioCodecType)
{int ret = 0;if(!m_bInit){return false;}AVStream *pInStream, *pOutStream;if(nCodecType == AV_CODEC_ID_H264){if(m_bFirstGoP == false){if(pkt.flags != AV_PKT_FLAG_KEY){av_packet_unref(&pkt);return false; // first frame must be Iframe.}else{m_bFirstGoP = true;}}}pInStream  = m_pIfmtCtx->streams[pkt.stream_index];if (pkt.stream_index >= m_nMappingSize ||m_pStreamMapping[pkt.stream_index] < 0){av_packet_unref(&pkt);return true;}pkt.stream_index = m_pStreamMapping[pkt.stream_index];pOutStream = m_pOfmtCtx->streams[pkt.stream_index];if(pInStream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&pInStream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO){av_packet_unref(&pkt);return false;}if(pInStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){av_bsf_send_packet(m_pBsfc, &pkt);av_bsf_receive_packet(m_pBsfc, m_pktFilter);m_pktFilter->pts = av_rescale_q_rnd(m_pktFilter->pts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilter->dts = av_rescale_q_rnd(m_pktFilter->dts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilter->duration = av_rescale_q_rnd(m_pktFilter->duration, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilter->stream_index = pOutStream->index;//时间戳处理if(m_nFirstVideoPts == 0){m_nFirstVideoPts = m_pktFilter->pts;m_pktFilter->pts = 0;m_pktFilter->dts = 0;}else{m_pktFilter->pts = m_pktFilter->pts - m_nFirstVideoPts;m_pktFilter->dts = m_pktFilter->dts - m_nFirstVideoPts;}//av_packet_rescale_ts(&pkt, pInStream->time_base, pOutStream->time_base);m_pktFilter->pos = -1;m_pktFilter->flags |= AV_PKT_FLAG_KEY;ret = av_interleaved_write_frame(m_pOfmtCtx, m_pktFilter);av_packet_unref(&pkt);if (ret < 0){qDebug() << "Video Error muxing packet";}}else{
#if TRANSCODEif(m_bTransCode){AVPacket* pAACPkt = av_packet_clone(&pkt);if(ctEasyAACEncoder::getInstance().G711ToAAC(pkt.data, pkt.size, pAACPkt->data, pAACPkt->size) == false){av_packet_unref(&pkt);return false;}av_bsf_send_packet(m_pBsfcAAC, pAACPkt);av_bsf_receive_packet(m_pBsfcAAC, m_pktFilterAudio);}else
#endifif(m_bTransCode || nAudioCodecType == AV_CODEC_ID_AAC){av_bsf_send_packet(m_pBsfcAAC, &pkt);av_bsf_receive_packet(m_pBsfcAAC, m_pktFilterAudio);m_pktFilterAudio->pts = av_rescale_q_rnd(m_pktFilterAudio->pts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilterAudio->dts = av_rescale_q_rnd(m_pktFilterAudio->dts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilterAudio->duration = av_rescale_q_rnd(m_pktFilterAudio->duration, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);m_pktFilterAudio->stream_index = pOutStream->index;//用差值作时间戳if(m_nFirstAudioPts == 0){m_nFirstAudioPts = m_pktFilterAudio->pts;m_pktFilterAudio->pts = 0;m_pktFilterAudio->dts = 0;}else{m_pktFilterAudio->pts = m_pktFilterAudio->pts - m_nFirstAudioPts;m_pktFilterAudio->dts = m_pktFilterAudio->dts - m_nFirstAudioPts;}m_pktFilterAudio->pos = -1;m_pktFilterAudio->flags |= AV_PKT_FLAG_KEY;ret = av_interleaved_write_frame(m_pOfmtCtx, m_pktFilterAudio);}else{pkt.pts = av_rescale_q_rnd(pkt.pts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);pkt.dts = av_rescale_q_rnd(pkt.dts, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);pkt.duration = av_rescale_q_rnd(pkt.duration, pInStream->time_base, pOutStream->time_base, AV_ROUND_NEAR_INF);pkt.stream_index = pOutStream->index;//用差值作时间戳if(m_nFirstAudioPts == 0){m_nFirstAudioPts = pkt.pts;pkt.pts = 0;pkt.dts = 0;}else{pkt.pts = pkt.pts - m_nFirstAudioPts;pkt.dts = pkt.dts - m_nFirstAudioPts;}pkt.pos = -1;pkt.flags |= AV_PKT_FLAG_KEY;ret = av_interleaved_write_frame(m_pOfmtCtx, &pkt);}av_packet_unref(&pkt);if (ret < 0){qDebug() << "Audio Error muxing packet";}}return (ret == 0);
}

四、ffmpeg库下载

链接地址:https://download.csdn.net/download/linyibin_123/87542123

相关文章:

qt下ffmpeg录制mp4经验分享,支持音视频(h264、h265,AAC,G711 aLaw, G711muLaw)

前言 MP4&#xff0c;是最常见的国际通用格式&#xff0c;在常见的播放软件中都可以使用和播放&#xff0c;磁盘空间占地小&#xff0c;画质一般清晰&#xff0c;它本身是支持h264、AAC的编码格式&#xff0c;对于其他编码的话&#xff0c;需要进行额外处理。本文提供了ffmpeg录…...

C#读取Excel解析入门-1仅围绕三个主要的为阵地,进行重点解析,就是最理性的应对上法所在

业务中也是同样的功能点实现。只是多扩展了很多代码&#xff0c;构成了项目的其他部分&#xff0c;枝干所在。但是有用的枝干&#xff0c;仅仅不超过三个主要的&#xff01;所以您仅仅围绕三个主要的为阵地&#xff0c;进行重点解析&#xff0c;就是最理性的应对上法所在了 str…...

一起Talk Android吧(第五百一十八回:在Android中使用MQTT通信五)

文章目录 知识回顾问题描述解决过程经验分享各位看官们大家好,这一回中咱们说的例子是" 在Android中使用MQTT通信五",本章回内容与前后章节内容无关联。闲话休提,言归正转,让我们一起Talk Android吧! 知识回顾 我们在前面章回中介绍了如何使用MQTT通信,包含它…...

100种思维模型之混沌与秩序思维模型-027

人类崇尚秩序与连续性&#xff0c;我们习惯于我们的日常世界&#xff0c;它以线性方式运作&#xff0c;没有不连续或突跳。 为此&#xff0c;我们学会了期望各种过程以连续方式运行&#xff0c;我们的内心为了让我们更有安全感&#xff0c;把很多事物的结果归于秩序&#xff0c…...

Java开发 - Redis初体验

前言 es我们已经在前文中有所了解&#xff0c;和es有相似功能的是Redis&#xff0c;他们都不是纯粹的数据库。两者使用场景也是存在一定的差异的&#xff0c;本文目的并不重点说明他们之间的差异&#xff0c;但会简要说明&#xff0c;重点还是在对Redis的了解和学习上。学完本…...

Python - 使用 pymysql 操作 MySQL 详解

目录创建连接 pymsql.connect() 方法的可传参数连接对象 conn pymsql.connect() 方法游标对象 cursor() 方法使用示例创建数据库表插入数据操作数据查询操作数据更新操作数据删除操作SQL中使用变量封装使用简单使用&#xff1a; import pymysqldb pymysql.connect(host,user…...

机器学习-卷积神经网络CNN中的单通道和多通道图片差异

背景 最近在使用CNN的场景中&#xff0c;既有单通道的图片输入需求&#xff0c;也有多通道的图片输入需求&#xff0c;因此又整理回顾了一下单通道或者多通道卷积的差别&#xff0c;这里记录一下探索过程。 结论 直接给出结论&#xff0c;单通道图片和多通道图片在经历了第一…...

考研复试——计算机组成原理

文章目录计算机组成原理1. 计算机系统由哪两部分组成&#xff1f;计算机系统性能取决于什么&#xff1f;2. 冯诺依曼机的主要特点&#xff1f;3. 主存储器由什么组成&#xff0c;各部分有什么作用&#xff1f;4. 什么是存储单元、存储字、存储字长、存储体&#xff1f;5. 计算机…...

硬件设计 之摄像头分类(IR摄像头、mono摄像头、RGB摄像头、RGB-D摄像头、鱼眼摄像头)

总结一下在机器人上常用的几种摄像头&#xff0c;最近在组装机器人时&#xff0c;傻傻分不清摄像头的种类。由于本人知识有限&#xff0c;以下资料都是在网上搜索而来&#xff0c;按照摄像头的分类整理一下&#xff0c;供大家参考&#xff1a; 1.IR摄像头&#xff1a; IRinfr…...

PTA:C课程设计(2)

山东大学&#xff08;威海&#xff09;2022级大一下C习题集&#xff08;2&#xff09;2-5-1 字符定位函数&#xff08;程序填空题&#xff09;2-5-2 判断回文&#xff08;程序填空题&#xff09;2-6-1 数字金字塔(函数)2-6-2 使用函数求最大公约数(函数)2-6-3 使用函数求余弦函…...

第四章:面向对象编程

第四章&#xff1a;面向对象编程 4.1&#xff1a;面向过程与面向对象 面向过程(POP)与面向对象(OOP) 二者都是一种思想&#xff0c;面向对象是相对于面向过程而言的。面向过程&#xff0c;强调的是功能行为&#xff0c;以函数为最小单位&#xff0c;考虑怎么做。面向对象&…...

Linux 安装npm yarn pnpm 命令

下载安装包 node 下载地址解压压缩包 tar -Jxf node-v19.7.0-linux-x64.tar.xz -C /root/app echo "export PATH$PATH:/app/node-v16.9.0-linux-x64" >> /etc/profile source /etc/profile ln -sf /app/node-v16.9.0-linux-x64/bin/npm /usr/local/bin/ ln -…...

linux SPI驱动代码追踪

一、Linux SPI 框架概述 linux系统下的spi驱动程序从逻辑上可以分为3个部分: SPI Core&#xff1a;SPI Core 是 Linux 内核用来维护和管理 spi 的核心部分&#xff0c;SPI Core 提供操作接口&#xff0c;允许一个 spi master&#xff0c;spi driver 和 spi device 在 SPI Cor…...

Ls-dyna材料的相关学习笔记

Elastic Linear elastic materials -Isotropic:各向同性材料 -orthotropic 正交各向异性的 -anistropic 各向异性的...

Arrays方法(copyOfRange,fill)

Arrays方法 1、Arrays.copyOfRange Arrays.copyOfRange的使用方法 功能&#xff1a; 将数组拷贝至另外一个数组 参数&#xff1a; original&#xff1a;第一个参数为要拷贝的数组对象 from&#xff1a;第二个参数为拷贝的开始位置&#xff08;包含&#xff09; to&#xff1a;…...

AcWing - 蓝桥杯集训每日一题(DAY 1——DAY 5)

文章目录一、AcWing 3956. 截断数组&#xff08;中等&#xff09;1. 实现思路2. 实现代码二、AcWing 3729. 改变数组元素&#xff08;中等&#xff09;1. 实现思路2. 实现代码三、AcWing 1460. 我在哪&#xff1f;&#xff08;简单&#xff09;1. 实现思路2. 实现代码四、AcWin…...

RHCSA-文件的其他命令(3.7)

目录 文件的其他命令&#xff1a; 文本内容统计wc 移动和复制&#xff08;cp&#xff09; 移动 查找文件的路径 压缩和解压缩 .tar&#xff08;归档命令&#xff09; shell-命令解释器 linux中的特殊字符 查看系统上的别名&#xff1a;alias 历史命令&#xff08;his…...

多线程update导致的mysql死锁问题处理方法

最近想起之前处理过的一个mysql 死锁问题&#xff0c;是在高并发下update批量更新导致的&#xff0c;这里探讨一下发生的原因&#xff0c;以及解决办法&#xff1b; 发生死锁的sql语句如下&#xff0c;其中where条件后的字段是有复合索引的。 update t_push_message_device_h…...

SpringBoot 如何保证接口安全?

为什么要保证接口安全对于互联网来说&#xff0c;只要你系统的接口暴露在外网&#xff0c;就避免不了接口安全问题。 如果你的接口在外网裸奔&#xff0c;只要让黑客知道接口的地址和参数就可以调用&#xff0c;那简直就是灾难。举个例子&#xff1a;你的网站用户注册的时候&am…...

英伟达驱动爆雷?CPU占用率过高怎么办?

又有一新驱动导致CPU占用率过高&#xff1f; 上周英伟达发布531.18显卡驱动&#xff0c;为大家带来了视频超分辨率技术&#xff0c;并为新发布的热门游戏《原子之心》提供支持。 但在安装新驱动后没过不久就有玩家反映&#xff0c;在游戏结束后会出现CPU占用率突然飙升到10%以…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试&#xff0c;通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小&#xff0c;增大可提高计算复杂度duration: 测试持续时间&#xff08;秒&…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...