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

【MediaFoundation】OpenCV VideoCapture 读取音频源码

OpenCV 读取音频代码实例

在windows7 以及OpenCV4 过后可以使用 CAP_MSMF 读取音频,但是OpenCV没有播放音频的API。代码示例如下。 本文解析OpenCVCAP_MSMF 进行文件、设备的 音频读取,学习MediaFoundation 的使用。

#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;int main(int argc, const char** argv)
{Mat videoFrame;Mat audioFrame;vector<vector<Mat>> audioData;VideoCapture cap;vector<int> params {    CAP_PROP_AUDIO_STREAM, 0,CAP_PROP_VIDEO_STREAM, -1,CAP_PROP_AUDIO_DATA_DEPTH, CV_32F   };//cap.open(file, CAP_MSMF, params);// 打开第一个音频输入设备cap.open(0, CAP_MSMF, params);if (!cap.isOpened()){cerr << "ERROR! Can't to open file: " + file << endl;return -1;}const int audioBaseIndex = (int)cap.get(CAP_PROP_AUDIO_BASE_INDEX);const int numberOfChannels = (int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS);cout << "CAP_PROP_AUDIO_DATA_DEPTH: " << depthToString((int)cap.get(CAP_PROP_AUDIO_DATA_DEPTH)) << endl;cout << "CAP_PROP_AUDIO_SAMPLES_PER_SECOND: " << cap.get(CAP_PROP_AUDIO_SAMPLES_PER_SECOND) << endl;cout << "CAP_PROP_AUDIO_TOTAL_CHANNELS: " << cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS) << endl;cout << "CAP_PROP_AUDIO_TOTAL_STREAMS: " << cap.get(CAP_PROP_AUDIO_TOTAL_STREAMS) << endl;int numberOfSamples = 0;int numberOfFrames = 0;audioData.resize(numberOfChannels);mfcap::AudioOutput audioOutput;audioOutput.Open((int)cap.get(CAP_PROP_AUDIO_TOTAL_CHANNELS),(int)cap.get(CAP_PROP_AUDIO_SAMPLES_PER_SECOND),16);for (;;){if (cap.grab()){//cap.retrieve(videoFrame);std::vector<const unsigned char*> planes;planes.resize(numberOfChannels);for (int nCh = 0; nCh < numberOfChannels; nCh++){cap.retrieve(audioFrame, audioBaseIndex+nCh);if (!audioFrame.empty()){audioData[nCh].push_back(audioFrame);//planes[nCh] = audioFrame.data + nCh * audioFrame.cols;}numberOfSamples+=audioFrame.cols;}} else { break; }}cout << "Number of audio samples: " << numberOfSamples << endl<< "Number of video frames: " << numberOfFrames << endl;return 0;
}

打开设备

bool CvCapture_MSMF::open(int index, const cv::VideoCaptureParameters* params)
{// 先重置环境close();if (index < 0)return false;if (params){// 开启硬件编解码加速,这里先省略,在后面的硬件加速上学习。configureHW(*params);/* configureStream 主要是配置是否捕获音频或视频流// 如果需要捕获音频流: audioStream = 0 否者 audioStream  = -1// 视频流同理,对应的变量为: videoStream*//* setAudioProperties // outputAudioFormat: 音频的位深, CV_16S 等// audioSamplesPerSecond 采样率// syncLastFrame: 是否需要音视频同步,OpenCV里面只支持视频文件的音视频同步*/if (!(configureStreams(*params) && setAudioProperties(*params)))return false;}// 仅支持打开音频流或者视频流,不能在一个对象里面打开或者都不打开。if (videoStream != -1 && audioStream != -1 || videoStream == -1 && audioStream == -1){CV_LOG_DEBUG(NULL, "Only one of the properties CAP_PROP_AUDIO_STREAM " << audioStream << " and " << CAP_PROP_VIDEO_STREAM << " must be different from -1");return false;}// DeviceList  主要检测当前系统中,视频或音频输入设备的个数,以及激活某一个设备。DeviceList devices;UINT32 count = 0;// 如果是读音频设备就枚举音频输入设备if (audioStream != -1)count = devices.read(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID);// 读视频设备同理。值得注意的是,opencv只支持读音频或视频设备// 如果都设置为0, 则默认读视频if (videoStream != -1)count = devices.read(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);if (count == 0 || static_cast<UINT32>(index) > count){CV_LOG_DEBUG(NULL, "Device " << index << " not found (total " << count << " devices)");return false;}/* getDefaultSourceConfig 这个主要设置硬件加速相关,这里可以先跳过*/_ComPtr<IMFAttributes> attr = getDefaultSourceConfig();/*SourceReaderCB 读取回调设置读取回调,当设置了读取的回调之后,MediaFoundation 读取Source 为异步模式这个Open函数是读设备的,还有其他重载函数用于读文件在OpenCV里面,读取设备使用异步模式,读取文件使用同步模式。*/_ComPtr<IMFSourceReaderCallback> cb = new SourceReaderCB();attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, cb.Get());// 激活目标设备_ComPtr<IMFMediaSource> src = devices.activateSource(index);if (!src.Get() || FAILED(MFCreateSourceReaderFromMediaSource(src.Get(), attr.Get(), &videoFileSource))){CV_LOG_DEBUG(NULL, "Failed to create source reader");return false;}isOpen = true;device_status = true;camid = index;readCallback = cb;duration = 0;// 选择合适的摄像头的流,比如宽高,fps.一般一个摄像头有很多个拉流的格式// 音频设备同理,比如有不同的采样率,位深等。if (configureOutput()){frameStep = captureVideoFormat.getFrameStep();}if (isOpen && !openFinalize_(params)){close();return false;}if (isOpen){if (audioStream != -1)if (!checkAudioProperties())return false;}return isOpen;
}

选择合适的设备流 configureOutput

bool CvCapture_MSMF::configureOutput()
{// 读取设备所有的流,当然也可以读第一个流if (FAILED(videoFileSource->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false))){CV_LOG_WARNING(NULL, "Failed to reset streams");return false;}bool tmp = true;// 配置视频流if (videoStream != -1)tmp = (!device_status)? configureVideoOutput(MediaType(), outputVideoFormat) : configureVideoOutput(MediaType::createDefault_Video(), outputVideoFormat);// 配置音频流if (audioStream != -1)tmp &= (!device_status)? configureAudioOutput(MediaType()) : configureAudioOutput(MediaType::createDefault_Audio());return tmp;
}

配置音频流 configureAudioOutput

bool CvCapture_MSMF::configureAudioOutput(MediaType newType)
{/*FormatStorage  存储设备的流信息,以及挑选最合适的流*/FormatStorage formats;formats.read(videoFileSource.Get());std::pair<FormatStorage::MediaID, MediaType> bestMatch;formats.countNumberOfAudioStreams(numberOfAudioStreams);if (device_status)bestMatch = formats.findBestAudioFormat(newType);elsebestMatch = formats.findAudioFormatByStream(audioStream);if (bestMatch.second.isEmpty(true)){CV_LOG_DEBUG(NULL, "Can not find audio stream with requested parameters");isOpen = false;return false;}dwAudioStreamIndex = bestMatch.first.stream;dwStreamIndices.push_back(dwAudioStreamIndex);MediaType newFormat = bestMatch.second;newFormat.majorType = MFMediaType_Audio;newFormat.nSamplesPerSec = (audioSamplesPerSecond == 0) ? 44100 : audioSamplesPerSecond;switch (outputAudioFormat){case CV_8S:newFormat.subType = MFAudioFormat_PCM;newFormat.bit_per_sample = 8;break;case CV_16S:newFormat.subType = MFAudioFormat_PCM;newFormat.bit_per_sample = 16;break;case CV_32S:newFormat.subType = MFAudioFormat_PCM;newFormat.bit_per_sample = 32;case CV_32F:newFormat.subType = MFAudioFormat_Float;newFormat.bit_per_sample = 32;break;default:break;}// 初始化流return initStream(dwAudioStreamIndex, newFormat);
}

初始化流 initStream

bool CvCapture_MSMF::initStream(DWORD streamID, const MediaType mt)
{CV_LOG_DEBUG(NULL, "Init stream " << streamID << " with MediaType " << mt);_ComPtr<IMFMediaType> mediaTypesOut;if (mt.majorType == MFMediaType_Audio){captureAudioFormat = mt;mediaTypesOut = mt.createMediaType_Audio();}if (mt.majorType == MFMediaType_Video){captureVideoFormat = mt;mediaTypesOut = mt.createMediaType_Video();}if (FAILED(videoFileSource->SetStreamSelection(streamID, true))){CV_LOG_WARNING(NULL, "Failed to select stream " << streamID);return false;}HRESULT hr = videoFileSource->SetCurrentMediaType(streamID, NULL, mediaTypesOut.Get());if (hr == MF_E_TOPO_CODEC_NOT_FOUND){CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(codec not found)");return false;}else if (hr == MF_E_INVALIDMEDIATYPE){CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(unsupported media type)");return false;}else if (FAILED(hr)){CV_LOG_WARNING(NULL, "Failed to set mediaType (stream " << streamID << ", " << mt << "(HRESULT " << hr << ")");return false;}return true;
}

捕获音频帧 Garb()

捕获帧的回调 SourceReaderCB

OpenCV捕获设备数据,采用异步模式,需要自定义一个捕获帧的回调

// 需要继承 IMFSourceReaderCallback
class SourceReaderCB : public IMFSourceReaderCallback
{
public:
// 最大的缓冲帧数量static const size_t MSMF_READER_MAX_QUEUE_SIZE = 3;SourceReaderCB() :m_nRefCount(0), m_hEvent(CreateEvent(NULL, FALSE, FALSE, NULL)), m_bEOS(FALSE), m_hrStatus(S_OK), m_reader(NULL), m_dwStreamIndex(0){}// COM 接口必须的,感觉就是照着格式写// IUnknown methodsSTDMETHODIMP QueryInterface(REFIID iid, void** ppv) CV_OVERRIDE{
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4838)
#endifstatic const QITAB qit[] ={QITABENT(SourceReaderCB, IMFSourceReaderCallback),{ 0 },};
#ifdef _MSC_VER
#pragma warning(pop)
#endifreturn QISearch(this, qit, iid, ppv);}STDMETHODIMP_(ULONG) AddRef() CV_OVERRIDE{return InterlockedIncrement(&m_nRefCount);}STDMETHODIMP_(ULONG) Release() CV_OVERRIDE{ULONG uCount = InterlockedDecrement(&m_nRefCount);if (uCount == 0){delete this;}return uCount;}// 在 调用wait()的时候 被调用STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) CV_OVERRIDE{HRESULT hr = 0;cv::AutoLock lock(m_mutex);if (SUCCEEDED(hrStatus)){if (pSample){CV_LOG_DEBUG(NULL, "videoio(MSMF): got frame at " << llTimestamp);// 如果缓冲的帧的数量大于最大的数量,需要弹出前面的帧if (m_capturedFrames.size() >= MSMF_READER_MAX_QUEUE_SIZE){
#if 0CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed). Timestamp=" << m_capturedFrames.front().timestamp);m_capturedFrames.pop();
#else// this branch reduces latency if we drop frames due to slow processing.// avoid fetching of already outdated frames from the queue's front.CV_LOG_DEBUG(NULL, "videoio(MSMF): drop previous frames (not processed): " << m_capturedFrames.size());std::queue<CapturedFrameInfo>().swap(m_capturedFrames);  // similar to missing m_capturedFrames.clean();
#endif}m_capturedFrames.emplace(CapturedFrameInfo{ llTimestamp, _ComPtr<IMFSample>(pSample), hrStatus });}}else{CV_LOG_WARNING(NULL, "videoio(MSMF): OnReadSample() is called with error status: " << hrStatus);}if (MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags){// Reached the end of the stream.m_bEOS = true;}m_hrStatus = hrStatus;if (FAILED(hr = m_reader->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL))){CV_LOG_WARNING(NULL, "videoio(MSMF): async ReadSample() call is failed with error status: " << hr);m_bEOS = true;}if (pSample || m_bEOS){SetEvent(m_hEvent);}return S_OK;}STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) CV_OVERRIDE{return S_OK;}STDMETHODIMP OnFlush(DWORD) CV_OVERRIDE{return S_OK;}HRESULT Wait(DWORD dwMilliseconds, _ComPtr<IMFSample>& mediaSample, LONGLONG& sampleTimestamp, BOOL& pbEOS){pbEOS = FALSE;for (;;){{cv::AutoLock lock(m_mutex);pbEOS = m_bEOS && m_capturedFrames.empty();if (pbEOS)return m_hrStatus;if (!m_capturedFrames.empty()){CV_Assert(!m_capturedFrames.empty());CapturedFrameInfo frameInfo = m_capturedFrames.front(); m_capturedFrames.pop();CV_LOG_DEBUG(NULL, "videoio(MSMF): handle frame at " << frameInfo.timestamp);mediaSample = frameInfo.sample;CV_Assert(mediaSample);sampleTimestamp = frameInfo.timestamp;ResetEvent(m_hEvent);  // event is auto-reset, but we need this forced reset due time gap between wait() and mutex hold.return frameInfo.hrStatus;}}CV_LOG_DEBUG(NULL, "videoio(MSMF): waiting for frame... ");DWORD dwResult = WaitForSingleObject(m_hEvent, dwMilliseconds);if (dwResult == WAIT_TIMEOUT){return E_PENDING;}else if (dwResult != WAIT_OBJECT_0){return HRESULT_FROM_WIN32(GetLastError());}}}private:// Destructor is private. Caller should call Release.virtual ~SourceReaderCB(){CV_LOG_INFO(NULL, "terminating async callback");}public:long                m_nRefCount;        // Reference count.cv::Mutex           m_mutex;HANDLE              m_hEvent;BOOL                m_bEOS;HRESULT             m_hrStatus;IMFSourceReader *m_reader;DWORD m_dwStreamIndex;struct CapturedFrameInfo {LONGLONG timestamp;_ComPtr<IMFSample> sample;HRESULT hrStatus;};std::queue<CapturedFrameInfo> m_capturedFrames;
};

相关文章:

【MediaFoundation】OpenCV VideoCapture 读取音频源码

OpenCV 读取音频代码实例 在windows7 以及OpenCV4 过后可以使用 CAP_MSMF 读取音频&#xff0c;但是OpenCV没有播放音频的API。代码示例如下。 本文解析OpenCVCAP_MSMF 进行文件、设备的 音频读取&#xff0c;学习MediaFoundation 的使用。 #include <opencv2/core.hpp>…...

2024秋招,百度测试开发工程师一面

前言 大家好&#xff0c;今天我来回顾一下秋招中的一场很重要技术面试 一面面试官深挖我的项目经历&#xff0c;并提出了很多的实际场景&#xff0c;我现在回顾依然有很多新的认识 过程 自我介绍实习工作中&#xff0c;做得最好的地方是什么&#xff1f; 我先介绍了一下实习…...

Git 使用与问题记录 二(公司快速上手版)

写在前面 记录自己学习的内容&#xff0c;方便后面忘记的时候查看。给像我一样的新手提供一点参考 正文 上一章已经安装好了Git&#xff0c;如何使用呢。我这里会分享两种办法&#xff0c;第一种是在VS2022中克隆代码&#xff0c;修改和提交&#xff1b;第二种是用命令提交。…...

【C语言小游戏】贪吃蛇

文章目录 1.引言2.运行图2.涉及知识3 Windows API3.1 控制台3.2 控制台屏幕坐标3.3 操作句柄3.4 控制台屏幕光标3.5 监视按键 4. 设计说明5. 完整代码 1.引言 使⽤C语⾔在Windows环境的控制台中模拟实现经典⼩游戏贪吃蛇 实现基本的功能&#xff1a; 贪吃蛇地图绘制蛇吃⻝物的…...

价值7500的在线授权网站源码支持IP+域名+双向授权全开源

PHP授权验证更新系统完整版&#xff0c;一键更新系统&#xff0c;一键卡密生成自助授权功能&#xff0c;域名ip双重验证功能等等 修复盗版检测&#xff0c;确保实时查看盗版 修复在线加密系统&#xff0c;一键加密 授权系统几乎所有的程序都能整合使用,包括您的app和计算机程序…...

haiku实现门控多头注意力模块

在多头注意力机制中&#xff0c;通常输入的数据包括查询&#xff08;Q&#xff09;、键&#xff08;K&#xff09;和值&#xff08;V&#xff09;。这些数据的维度以及权重矩阵的维度在多头注意力机制中扮演关键角色。下面对数据及权重的维度进行解释&#xff1a; 输入数据&…...

【React 常用的 TS 类型】持续更新

1&#xff09;定义样式的 TS 类型 【 React.CSSProperties 】 一般定义样式时需要的类型限制&#xff0c;如下&#xff1a; const customStyle: React.CSSProperties {color: blue,fontSize: 16px,margin: 10px,}; 2&#xff09;定义 Input Ref 属性时的 TS 类型限制 【 R…...

打破传统边界,VR技术与六西格玛设计理念的创新融合!

在科技飞速发展的今天&#xff0c;虚拟现实&#xff08;VR&#xff09;技术以其独特的沉浸式体验&#xff0c;正在改变我们的生活和工作方式。然而&#xff0c;要让VR真正成为主流&#xff0c;我们必须解决一些关键问题&#xff0c;其中最重要的就是用户体验。六西格玛设计&…...

[uniapp] uni-ui+vue3.2小程序评论列表组件 回复评论 点赞和删除

先看效果 下载地址 uni-app官方插件市场: cc-comment组件 环境 基于vue3.2和uni-ui开发; 依赖版本参考如下: "dependencies": {"dcloudio/uni-mp-weixin": "3.0.0-3090820231124001","dcloudio/uni-ui": "^1.4.28","…...

TongLINKQ(3):TongLINKQ常用命令

启动&#xff1a; tlq 暂停&#xff1a; tlq -cabort -y -w1 查看lic信息&#xff1a; tlqstat –lic 查看队列消息&#xff1a; tlqstat -qcu qcu名 -c 查看发送连接状态&#xff1a; tlqstat -snd qcu名 -1 -ct 1 查看指定的Qcu连接状态&#xff1a; tlqsta…...

抽水马桶出水慢解决记录

今天分享一些修马桶的小心得&#xff08;雾&#xff09; 家里的马桶出水很好&#xff0c;但是水却不怎么被冲下去&#xff08;出水很慢&#xff09;&#xff0c;这会导致内容物滞留&#xff0c;造成很不好的使用体验。 出于成本考虑&#xff0c;首先选择自己维修。 首先直接…...

img标签的奇怪问题

本来只是为实现一个轮播图&#xff0c;img的url地址是从后端接口获取的&#xff0c;但不巧的是url地址的图片都过期了。 因为懒得重新到网上找图&#xff0c;就想直接用一下本地的图片&#xff0c;简单的想法遇到一堆问题。 问题一&#xff1a; 因为是springboot项目&#xf…...

深入探究Hibernate:优雅、强大的Java持久化框架

目录 1、前言 2、Hibernate简介 2.1 什么是Hibernate 2.2 为什么选择Hibernate 3、Hibernate核心概念 3.1 实体类和映射文件 3.2 数据库表和持久化类的映射 3.3 主键生成策略 3.4 持久化操作 3.5 查询语言(HQL和Criteria) 3.6 事务管理 4、Hibernate配置与连接 4…...

JavaScript高级特性详解

摘要&#xff1a;本文将深入探讨JavaScript中的一些高级特性&#xff0c;包括闭包、原型链、高阶函数和异步编程。我们将通过详细的注释和实例来帮助读者理解这些概念&#xff0c;并通过总结部分强调其在实际开发中的应用。 一、闭包 闭包是JavaScript中一个非常重要的概念&a…...

网站建设网络设计营销类网站eyouCMS模板(PC+WAP)

模板介绍&#xff1a; 本模板自带eyoucms内核&#xff0c;无需再下载eyou系统&#xff0c;原创设计、手工书写DIVCSS&#xff0c;完美兼容IE7、Firefox、Chrome、360浏览器等&#xff1b;主流浏览器&#xff1b;结构容易优化&#xff1b;多终端均可正常预览。...

迅为RK3568开发板Android11/12/Linux编译驱动到内核

在平时的驱动开发中&#xff0c;经常需要在内核中配置某种功能&#xff0c;为了方便大家开发和学习&#xff0c;本小 节讲解如何在内核中添加驱动。具体的讲解原理讲解请参考本手册的驱动教程。 Android11 源码如果想要修改内核&#xff0c;可以运行以下命令进行修改: cd ke…...

SaaS 应用深度解析:Marketo

随着数字营销的不断发展&#xff0c;企业需要强大而智能的工具来管理营销活动、吸引潜在客户、并实现销售目标。在众多营销自动化工具中&#xff0c;Marketo 是一款备受推崇的 SaaS 应用&#xff0c;为企业提供全面的营销解决方案。本文将深入了解 Marketo&#xff0c;探讨其功…...

闲聊篇-求职的点点滴滴~~

引言 求职之旅是一段充满挑战与机遇的旅程。它不仅仅是寻找工作的过程&#xff0c;更是一个自我探索和成长的过程。在这篇文章中&#xff0c;我们将探讨求职的各个方面&#xff0c;从准备简历到面试&#xff0c;再到最终拿到心仪的offer。 1. 简历&#xff1a;你的敲门砖 精…...

微软最新研究成果:使用GPT-4合成数据来训练AI模型,实现SOTA!

文本嵌入是各项NLP任务的基础&#xff0c;用于将自然语言转换为向量表示。现有的大部分方法通常采用复杂的多阶段训练流程&#xff0c;先在大规模数据上训练&#xff0c;再在小规模标注数据上微调。此过程依赖于手动收集数据制作正负样本对&#xff0c;缺乏任务的多样性和语言多…...

爬虫案例—抓取小米商店应用

爬虫案例—抓取小米商店应用 代码如下&#xff1a; # 抓取第一页的内容 import requests from lxml import etree url ‘https://app.mi.com/catTopList/0?page1’ headers { ‘User-Agent’: ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (K…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

掌握 HTTP 请求:理解 cURL GET 语法

cURL 是一个强大的命令行工具&#xff0c;用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中&#xff0c;cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...