Qt/C++音視頻開發59-使用mdk-sdk組件/原qtav作者力作/性能兇殘/超級跨平臺

一、前言

最近一個月一直在研究mdk-sdk音視頻組件,這個組件是原qtav作者的最新力作,提供了各種各樣的示例demo,不僅限于支持C++,其他各種比如java/flutter/web/android等全部支持,性能上也是杠杠的,目前大概是在V0.23版本,大部分軟件發布基本上都是在1.0版本才是比較穩定的,不過目前用下來,感覺還是挺不錯的,跨平臺,什么windows/linux/macos/ios/android/web等全部支持,底層還支持各種渲染框架。其實mdk底層就是封裝的ffmpeg,也可以說核心就是ffmpeg,得益于作者在ffmpeg的使用方面應該是到了如火純情的境界,主要是三大塊,一塊是音視頻同步、一塊是硬解碼、一塊是渲染到不同的平臺。這三大快在音視頻領域都是重點也是難點,要想做的穩定做得好性能又好,是很難的。沒個十年八年的功力是不行的。

由于mdk-sdk作者也是搞qt開發很多年,所以對qt+mdk的使用提供了非常友好完善的示例。
第一步:下載示例源碼 git clone git@github.com:wang-bin/mdk-examples.git
第二步:下載庫文件 https://sourceforge.net/projects/mdk-sdk/files/nightly/
第三步:將mdk-sdk目錄放到mdk-examples目錄下。
第四步:打開projects.pro編譯就行,如果本機沒有vulkan環境,可以注釋vkwindow、qmlrhi 、qmlrhi0項目。

在經歷眾多音視頻組件的各種高強度對比測試驗證下,mdk的優點非常多,這里就不多說,缺點就是線程有點多,一個播放基本上就占了30個線程,10個就是300,可能是通過犧牲一部分內存來提升性能,好比谷歌瀏覽器也是占內存大戶,但是性能強悍,目前幾乎是一統瀏覽器江湖。各種播放組件中,對于4K、8K、16K視頻文件的解碼,開啟硬解碼模式下,mpv是全宇宙CPU占用最低的,其次就是mdk,vlc的表現最拉垮。可能mpv直接走的屏幕繪制,直接是顯卡中的數據繪制的,沒有經過內存拷貝。

二、效果圖

在這里插入圖片描述

三、體驗地址

  1. 國內站點:https://gitee.com/feiyangqingyun
  2. 國際站點:https://github.com/feiyangqingyun
  3. 個人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 體驗地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取碼:01jf 文件名:bin_video_demo。

四、功能特點

4.1. 基礎功能

  1. 支持各種音頻視頻文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。
  2. 支持本地攝像頭設備和本地桌面采集,支持多設備和多屏幕。
  3. 支持各種視頻流格式,比如rtp、rtsp、rtmp、http、udp等。
  4. 本地音視頻文件和網絡音視頻文件,自動識別文件長度、播放進度、音量大小、靜音狀態等。
  5. 文件可以指定播放位置、調節音量大小、設置靜音狀態等。
  6. 支持倍速播放文件,可選0.5倍、1.0倍、2.5倍、5.0倍等速度,相當于慢放和快放。
  7. 支持開始播放、停止播放、暫停播放、繼續播放。
  8. 支持抓拍截圖,可指定文件路徑,可選抓拍完成是否自動顯示預覽。
  9. 支持錄像存儲,手動開始錄像、停止錄像,部分內核支持暫停錄像后繼續錄像,跳過不需要錄像的部分。
  10. 支持無感知切換循環播放、自動重連等機制。
  11. 提供播放成功、播放完成、收到解碼圖片、收到抓拍圖片、視頻尺寸變化、錄像狀態變化等信號。
  12. 多線程處理,一個解碼一個線程,不卡主界面。

4.2. 特色功能

  1. 同時支持多種解碼內核,包括qmedia內核(Qt4/Qt5/Qt6)、ffmpeg內核(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5/ffmpeg6)、vlc內核(vlc2/vlc3)、mpv內核(mpv1/mp2)、mdk內核、海康sdk、easyplayer內核等。
  2. 非常完善的多重基類設計,新增一種解碼內核只需要實現極少的代碼量,就可以應用整套機制,極易拓展。
  3. 同時支持多種畫面顯示策略,自動調整(原始分辨率小于顯示控件尺寸則按照原始分辨率大小顯示,否則等比縮放)、等比縮放(永遠等比縮放)、拉伸填充(永遠拉伸填充)。所有內核和所有視頻顯示模式下都支持三種畫面顯示策略。
  4. 同時支持多種視頻顯示模式,句柄模式(傳入控件句柄交給對方繪制控制)、繪制模式(回調拿到數據后轉成QImage用QPainter繪制)、GPU模式(回調拿到數據后轉成yuv用QOpenglWidget繪制)。
  5. 支持多種硬件加速類型,ffmpeg可選dxva2、d3d11va等,vlc可選any、dxva2、d3d11va,mpv可選auto、dxva2、d3d11va,mdk可選dxva2、d3d11va、cuda、mft等。不同的系統環境有不同的類型選擇,比如linux系統有vaapi、vdpau,macos系統有videotoolbox。
  6. 解碼線程和顯示窗體分離,可指定任意解碼內核掛載到任意顯示窗體,動態切換。
  7. 支持共享解碼線程,默認開啟并且自動處理,當識別到相同的視頻地址,共享一個解碼線程,在網絡視頻環境中可以大大節約網絡流量以及對方設備的推流壓力。國內頂尖視頻廠商均采用此策略。這樣只要拉一路視頻流就可以共享到幾十個幾百個通道展示。
  8. 自動識別視頻旋轉角度并繪制,比如手機上拍攝的視頻一般是旋轉了90度的,播放的時候要自動旋轉處理,不然默認是倒著的。
  9. 自動識別視頻流播放過程中分辨率的變化,在視頻控件上自動調整尺寸。比如攝像機可以在使用過程中動態配置分辨率,當分辨率改動后對應視頻控件也要做出同步反應。
  10. 音視頻文件無感知自動切換循環播放,不會出現切換期間黑屏等肉眼可見的切換痕跡。
  11. 視頻控件同時支持任意解碼內核、任意畫面顯示策略、任意視頻顯示模式。
  12. 視頻控件懸浮條同時支持句柄、繪制、GPU三種模式,非絕對坐標移來移去。
  13. 本地攝像頭設備支持指定設備名稱、分辨率、幀率進行播放。
  14. 本地桌面采集支持設定采集區域、偏移值、指定桌面索引、幀率、多個桌面同時采集等。
  15. 錄像文件同時支持打開的視頻文件、本地攝像頭、本地桌面、網絡視頻流等。
  16. 瞬間響應打開和關閉,無論是打開不存在的視頻或者網絡流,探測設備是否存在,讀取中的超時等待,收到關閉指令立即中斷之前的操作并響應。
  17. 支持打開各種圖片文件,支持本地音視頻文件拖曳播放。
  18. 視頻流通信方式可選tcp/udp,有些設備可能只提供了某一種協議通信比如tcp,需要指定該種協議方式打開。
  19. 可設置連接超時時間(視頻流探測用的超時時間)、讀取超時時間(采集過程中的超時時間)。
  20. 支持逐幀播放,提供上一幀/下一幀函數接口,可以逐幀查閱采集到的圖像。
  21. 音頻文件自動提取專輯信息比如標題、藝術家、專輯、專輯封面,自動顯示專輯封面。
  22. 視頻響應極低延遲0.2s左右,極速響應打開視頻流0.5s左右,專門做了優化處理。
  23. 支持H264/H265編碼(現在越來越多的監控攝像頭是H265視頻流格式)生成視頻文件,內部自動識別切換編碼格式。
  24. 支持用戶信息中包含特殊字符(比如用戶信息中包含+#@等字符)的視頻流播放,內置解析轉義處理。
  25. 支持濾鏡,各種水印及圖形效果,支持多個水印和圖像,可以將OSD標簽信息和各種圖形信息寫入到MP4文件。
  26. 支持視頻流中的各種音頻格式,AAC、PCM、G.726、G.711A、G.711Mu、G.711ulaw、G.711alaw、MP2L2等都支持,推薦選擇AAC兼容性跨平臺性最好。
  27. 內核ffmpeg采用純qt+ffmpeg解碼,非sdl等第三方繪制播放依賴,gpu繪制采用qopenglwidget,音頻播放采用qaudiooutput。
  28. 內核ffmpeg和內核mdk支持安卓,其中mdk支持安卓硬解碼,性能非常兇殘。
  29. 可以切換音視頻軌道,也就是節目通道,可能ts文件帶了多個音視頻節目流,可以分別設置要播放哪一個,可以播放前設置好和播放過程中動態設置。
  30. 可以設置視頻旋轉角度,可以播放前設置好和播放過程中動態設置。
  31. 視頻控件懸浮條自帶開始和停止錄像切換、聲音靜音切換、抓拍截圖、關閉視頻等功能。
  32. 音頻組件支持聲音波形值數據解析,可以根據該值繪制波形曲線和柱狀聲音條,默認提供了聲音振幅信號。
  33. 標簽和圖形信息支持三種繪制方式,繪制到遮罩層、繪制到圖片、源頭繪制(對應信息可以存儲到文件)。
  34. 通過傳入一個url地址,該地址可以帶上通信協議、分辨率、幀率等信息,無需其他設置。
  35. 保存視頻到文件支持三種策略,自動處理、僅限文件、全部轉碼,轉碼策略支持自動識別、轉264、轉265,編碼保存支持指定分辨率縮放或者等比例縮放。比如對保存文件體積有要求可以指定縮放后再存儲。
  36. 支持加密保存文件和解密播放文件,可以指定秘鑰文本。
  37. 支持電子放大,在懸浮條切換到電子放大模式,在畫面上選擇需要放大的區域,選取完畢后自動放大,再次切換放大模式可以復位。
  38. 各組件中極其詳細的打印信息提示,尤其是報錯信息提示,封裝的統一打印格式。針對現場復雜的設備環境測試極其方便有用,相當于精確定位到具體哪個通道哪個步驟出錯。
  39. 同時提供了簡單示例、視頻播放器、多畫面視頻監控、監控回放、逐幀播放、多屏渲染等單獨窗體示例,專門演示對應功能如何使用。
  40. 代碼框架和結構優化到最優,性能強悍,持續迭代更新升級。
  41. 源碼支持Qt4、Qt5、Qt6,兼容所有版本。

4.3. 視頻控件

  1. 可動態添加任意多個osd標簽信息,標簽信息包括名字、是否可見、字號大小、文本文字、文本顏色、背景顏色、標簽圖片、標簽坐標、標簽格式(文本、日期、時間、日期時間、圖片)、標簽位置(左上角、左下角、右上角、右下角、居中、自定義坐標)。
  2. 可動態添加任意多個圖形信息,這個非常有用,比如人工智能算法解析后的圖形區域信息直接發給視頻控件即可。圖形信息支持任意形狀,直接繪制在原始圖片上,采用絕對坐標。
  3. 圖形信息包括名字、邊框大小、邊框顏色、背景顏色、矩形區域、路徑集合、點坐標集合等。
  4. 每個圖形信息都可指定三種區域中的一種或者多種,指定了的都會繪制。
  5. 內置懸浮條控件,懸浮條位置支持頂部、底部、左側、右側。
  6. 懸浮條控件參數包括邊距、間距、背景透明度、背景顏色、文本顏色、按下顏色、位置、按鈕圖標代碼集合、按鈕名稱標識集合、按鈕提示信息集合。
  7. 懸浮條控件一排工具按鈕可自定義,通過結構體參數設置,圖標可選圖形字體還是自定義圖片。
  8. 懸浮條按鈕內部實現了錄像切換、抓拍截圖、靜音切換、關閉視頻等功能,也可以自行在源碼中增加自己對應的功能。
  9. 懸浮條按鈕對應實現了功能的按鈕,有對應圖標切換處理,比如錄像按鈕按下后會切換到正在錄像中的圖標,聲音按鈕切換后變成靜音圖標,再次切換還原。
  10. 懸浮條按鈕單擊后都用名稱唯一標識作為信號發出,可以自行關聯響應處理。
  11. 懸浮條空白區域可以顯示提示信息,默認顯示當前視頻分辨率大小,可以增加幀率、碼流大小等信息。
  12. 視頻控件參數包括邊框大小、邊框顏色、焦點顏色、背景顏色(默認透明)、文字顏色(默認全局文字顏色)、填充顏色(視頻外的空白處填充黑色)、背景文字、背景圖片(如果設置了圖片優先取圖片)、是否拷貝圖片、縮放顯示模式(自動調整、等比縮放、拉伸填充)、視頻顯示模式(句柄、繪制、GPU)、啟用懸浮條、懸浮條尺寸(橫向為高度、縱向為寬度)、懸浮條位置(頂部、底部、左側、右側)。

五、相關代碼

#include "mdkplayer.h"
#include "videohelper.h"MdkPlayer::MdkPlayer(QObject *parent) : QObject(parent)
{//實例化播放對象player = new mdk::Player;//默認等比例填充player->setAspectRatio(mdk::KeepAspectRatio);//設置緩沖大小//player->setBufferRange(0, 5000, true);//渲染回調觸發界面更新player->setRenderCallback([this](void *vo) {QObject *render = (QObject *)vo;if (render && render->isWidgetType()) {QMetaObject::invokeMethod(render, "update");}});//播放狀態變化player->onStateChanged([this](mdk::State state) {emit stateChanged(state);});//媒體狀態變化player->onMediaStatus([this](mdk::MediaStatus oldValue, mdk::MediaStatus newValue) {emit mediaStatusChanged(newValue);return true;});//各種事件觸發player->onEvent([this](const mdk::MediaEvent & e) {emit eventChanged(e);return false;});render = NULL;
}MdkPlayer::~MdkPlayer()
{//沒有設置過渲染窗體釋放的時候會崩潰if (render) {delete player;}
}void MdkPlayer::setMedia(const QString &url)
{player->setMedia(url.toUtf8().constData());//設置媒體后立即獲取媒體信息/手冊說要按照下面這樣寫VideoType type = VideoHelper::getVideoType(url);if (type == VideoType_FileLocal || type == VideoType_FileWeb) {player->waitFor(mdk::State::Stopped);player->prepare(0, [this](int64_t, bool *) {QMetaObject::invokeMethod(parent(), "readMediaInfo");return true;});}//不做音視頻同步if (type == VideoType_Rtsp) {player->onSync([] {return DBL_MAX;});}
}void MdkPlayer::setFilter(const QString &filter)
{player->setProperty("video.avfilter", filter.toStdString());
}void MdkPlayer::setDecoders(const QStringList &names)
{std::vector<std::string> decoders;foreach (QString name, names) {decoders.push_back(name.toStdString());}player->setDecoders(mdk::MediaType::Video, decoders);
}void MdkPlayer::setProperty(const std::string &key, const std::string &value)
{player->setProperty(key, value);
}void MdkPlayer::play()
{player->set(mdk::State::Playing);
}void MdkPlayer::stop()
{player->set(mdk::State::Stopped);
}void MdkPlayer::pause()
{player->set(mdk::State::Paused);
}void MdkPlayer::next()
{player->set(mdk::State::Playing);
}mdk::State MdkPlayer::state()
{return player->state();
}void MdkPlayer::setLoop(int count)
{player->setLoop(count);
}void MdkPlayer::rotate(int degree, QObject *render)
{player->rotate(degree, render);
}void MdkPlayer::setAspect(float value, QObject *render)
{player->setAspectRatio(value, render);
}void MdkPlayer::setBackgroundColor(float r, float g, float b, float a, QObject *render)
{player->setBackgroundColor(r, g, b, a, render);
}QSize MdkPlayer::getSize(int stream)
{QSize size;std::vector<mdk::VideoStreamInfo> video = player->mediaInfo().video;if (video.size() > stream) {mdk::VideoCodecParameters para = video.at(stream).codec;size = QSize(para.width, para.height);}return size;
}qint64 MdkPlayer::duration()
{return player->mediaInfo().duration;
}qint64 MdkPlayer::position()
{return player->position();
}void MdkPlayer::seek(qint64 position)
{player->seek(position);
}void MdkPlayer::seek(bool backward, int frame)
{mdk::SeekFlag flags = (mdk::SeekFlag::FromNow | mdk::SeekFlag::Frame);if (backward) {player->seek(-frame, flags);} else {player->seek(frame, flags);}
}float MdkPlayer::playbackRate()
{return player->playbackRate();
}void MdkPlayer::setPlaybackRate(float value)
{player->setPlaybackRate(value);
}float MdkPlayer::volume()
{return player->volume();
}void MdkPlayer::setVolume(float value)
{player->setVolume(value);
}bool MdkPlayer::isMute()
{return player->isMute();
}void MdkPlayer::setMute(bool value)
{player->setMute(value);
}void MdkPlayer::snapshot(int rotate, QObject *render)
{mdk::Player::SnapshotRequest sr{};player->snapshot(&sr, [this, rotate](mdk::Player::SnapshotRequest * sr2, double) {QImage image = QImage(sr2->data, sr2->width, sr2->height, Format_RGB);//如果有旋轉角度先要旋轉VideoHelper::rotateImage(rotate, image);emit imageCaptured(image.copy());return std::string();}, render);
}void MdkPlayer::record(const QString &fileName, const QString &format)
{player->record(fileName.toUtf8().constData(), format.toUtf8().constData());
}void MdkPlayer::readMetaData()
{//標題/藝術家/專輯/專輯封面QString title, artist, album;mdk::MediaInfo mediaInfo = player->mediaInfo();std::unordered_map<std::string, std::string> metadata = mediaInfo.metadata;for (auto i = metadata.begin(); i != metadata.end(); i++) {QString key = QString::fromStdString(i->first);QString value = QString::fromStdString(i->second);if (key == "title") {title = value;} else if (key == "artist") {artist = value;} else if (key == "album") {album = value;}}QString format = mediaInfo.format;emit receiveMetaData(format, title, artist, album);
}void MdkPlayer::readAudioInfo(int index)
{std::vector<mdk::AudioStreamInfo> audios = player->mediaInfo().audio;if (index >= 0 && audios.size() > index) {mdk::AudioStreamInfo audio = audios.at(index);mdk::AudioCodecParameters para = audio.codec;emit receiveAudioInfo(audio.index, para.sample_rate, para.channels, para.profile, para.bit_rate, para.codec);}
}void MdkPlayer::readVideoInfo(int index)
{std::vector<mdk::VideoStreamInfo> videos = player->mediaInfo().video;if (index >= 0 && videos.size() > index) {mdk::VideoStreamInfo video = videos.at(index);mdk::VideoCodecParameters para = video.codec;//取出封面QImage image;if (video.image_size > 0) {image = QImage::fromData(video.image_data, video.image_size);}emit receiveVideoInfo(video.index, para.width, para.height, para.frame_rate, video.rotation, para.codec, image);}
}void MdkPlayer::readTrackInfo(QList<int> &audioTracks, QList<int> &videoTracks)
{mdk::MediaInfo mediaInfo = player->mediaInfo();audioTracks.clear();std::vector<mdk::AudioStreamInfo> audioTrackInfo = mediaInfo.audio;foreach (mdk::AudioStreamInfo info, audioTrackInfo) {audioTracks << info.index;}videoTracks.clear();std::vector<mdk::VideoStreamInfo> videoTrackInfo = mediaInfo.video;foreach (mdk::VideoStreamInfo info, videoTrackInfo) {videoTracks << info.index;}//可能獲取到的索引是 音頻(3, 4, 5) / 視頻(0, 1, 2)//底層設置節目流按照 0/1/2 這樣排列/所以需要強制矯正int count = videoTracks.count();audioTracks.clear();videoTracks.clear();for (int i = 0; i < count; ++i) {audioTracks << i;videoTracks << i;}
}void MdkPlayer::setAudioTrack(int track)
{std::set<int> tracks;tracks.insert(track);player->setActiveTracks(mdk::MediaType::Audio, tracks);
}void MdkPlayer::setVideoTrack(int track)
{std::set<int> tracks;tracks.insert(track);player->setActiveTracks(mdk::MediaType::Video, tracks);
}void MdkPlayer::renderVideo(QObject *render)
{player->renderVideo(render);
}void MdkPlayer::setVideoSurfaceSize(int width, int height, QObject *render)
{this->render = render;player->setVideoSurfaceSize(width, height, render);connect(render, SIGNAL(destroyed(QObject *)), this, SLOT(clear(QObject *)), Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection));
}void MdkPlayer::clear(QObject *render)
{player->setVideoSurfaceSize(-1, -1, render);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/215537.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/215537.shtml
英文地址,請注明出處:http://en.pswp.cn/news/215537.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

cadence中如何在更新原理圖封裝

cadence中如何在更新原理圖封裝 一、更改原理圖封裝 當原理圖畫好后&#xff0c;如果我們發現某個封裝錯了&#xff0c;需要改動&#xff0c;需要找到你最初畫Library中器件封裝文件打開&#xff0c;進行修改&#xff0c;修改好后保存。 二、更新封裝 保存好后&#xff0c;…

C/C++ 有效的字母異位詞

題目&#xff1a; 給定兩個字符串s和t&#xff0c;編寫一個函數來判斷t是否是s的字母異位詞。 注&#xff1a;若s和t中每個字符出現的次數都相同&#xff0c;則稱s和t互為字母異位詞。 示例 1: 輸入: s "anagram", t "nagaram" 輸出: true …

2024年廣西職業院校技能大賽中職組《網絡安全》賽項樣題

2024年廣西職業院校技能大賽 中職組《網絡安全》賽項樣題 目錄 任務一 登錄安全加固 任務二 數據庫加固&#xff08;Data&#xff09; 任務三 Web安全加固(Web) 任務四 流量完整性保護&#xff08;Web,Data&#xff09; 任務五 事件監控 任務一 應急響應 任務二 …

295. 數據流的中位數

二分法實現 295. 數據流的中位數 295. 數據流的中位數 本題的第一個難點&#xff0c;要自己構造一個類&#xff08;因為個人構造類的題目做的較少&#xff09; 屬性&#xff1a; 數組的長度int 數組的數據結構 List保證原數組是一個有序數組&#xff0c;我使用了二分查找插入新…

【IDEA】反向撤銷操作快捷鍵 ctrl+shift+z 和搜狗熱鍵沖突的解決辦法

當我們執行某些操作時與搜狗熱鍵沖突&#xff0c;直接取消搜狗的快捷鍵即可&#xff01;&#xff01;&#xff01;以下以 ctrlshiftz 為例。 在輸入懸浮框右鍵找到更多設置 按鍵里面找到系統功能快捷鍵設置 取消掉沖突的熱鍵即可

?gzip --- 對 gzip 格式的支持?

源代碼&#xff1a; Lib/gzip.py 此模塊提供的簡單接口幫助用戶壓縮和解壓縮文件&#xff0c;功能類似于 GNU 應用程序 gzip 和 gunzip。 數據壓縮由 zlib 模塊提供。 gzip 模塊提供 GzipFile 類和 open()、compress()、decompress() 幾個便利的函數。GzipFile 類可以讀寫 gz…

Codeforces Round 911 (Div. 2)

Codeforces Round 911 (Div. 2) A 有大于3的區間就可以無限取水&#xff0c;答案為2&#xff0c;其他的按照個數 #include <bits/stdc.h>using namespace std;void solve() {int n, k 0;cin >> n;string s, t "...";cin >> s;auto it search…

ARM day6

2.串口發送指令控制硬件工作 結果&#xff1a; uart.h #ifndef __UART_H__ #define __UART_H__ #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_uart.h"void myuart4_init(); void myputchar(char i); cha…

element-ui基本使用

基本使用&#xff1a;npm i element-uimain.js&#xff1a;/*** 該文件是整個項目的入口文件*/ import Vue from vue; import App from ./App.vue; import ElementUI from element-ui; // 引入Element全部樣式 import element-ui/lib/theme-chalk/index.css;// 關閉vue的生產提…

C++ this指針

通常情況下&#xff0c;類的成員函數都只涉及一個對象&#xff0c;即調用它的對象。但有時候方法可能涉及到兩個對象&#xff0c;在這種情況就需要使用到C的this指針。 class Stock { private: ... double total_val; ... public: double total() const {return total_val;} }…

【Linux】進程周邊002之進程狀態

&#x1f440;樊梓慕&#xff1a;個人主頁 &#x1f3a5;個人專欄&#xff1a;《C語言》《數據結構》《藍橋杯試題》《LeetCode刷題筆記》《實訓項目》《C》《Linux》 &#x1f31d;每一個不曾起舞的日子&#xff0c;都是對生命的辜負 目錄 前言 1.什么是狀態&#xff1f; …

ChatGLM 手記

ChatGLM-6B&#xff1a;GitHub - THUDM/ChatGLM-6B: ChatGLM-6B: An Open Bilingual Dialogue Language Model | 開源雙語對話語言模型 ChatGLM3&#xff1a; GitHub - THUDM/ChatGLM3: ChatGLM3 series: Open Bilingual Chat LLMs | 開源雙語對話語言模型 chatglm.cpp&…

利用開源工具Chartmuseum,搭建私有helm chart倉庫

1、ChartMuseum是什么? ChartMuseum 是一個用 Go 語言寫的開源的 Helm Chart Repository 服務器,有多種 API 來完成對 Helm Chart Repository、Chart 以及 Server 的操作。所有可用的 API 以及使用方法可查看GitHub Repo。 2、ChartMuseum的安裝 ChartMuseum安裝可參考官網…

Python中的魔力編程:掌握面向對象之道

Python中的面向對象編程 背景&#xff1a; ? 最近在看一些代碼的時候&#xff0c;對類中的一些內置方法不是很懂&#xff0c;因此出一篇文章來細說一下&#xff0c;希望大家看完后對Python中類有一個清楚的認識。 基礎鋪墊&#xff1a; ? 面向對象的三個特點&#xff1a;…

C語言中的成員訪問:普通變量與指針變量的區別與使用

C語言中的成員訪問 在C語言中&#xff0c;我們可以通過變量來訪問它們的成員。根據變量的類型&#xff0c;我們使用不同的成員訪問符&#xff1a;.和->。本文將詳細介紹這兩個成員訪問符的使用。 目錄 普通變量的成員訪問指針變量的成員訪問示例代碼總結 普通變量的成員…

深入探索 Spring Boot:簡化開發,加速部署的全方位利器

目錄 導言 1. 自動配置&#xff08;Auto-Configuration&#xff09; 2. 起步依賴&#xff08;Starter Dependencies&#xff09; 3. 嵌入式 Web 服務器 4. Actuator 5. 外部化配置 6. 簡化的安全性配置 7. Spring Boot CLI 8. Spring Boot DevTools 導言 在當今軟件開…

java基礎之抽象的概念(全網最詳細)

一.抽象的概念 如下圖所示&#xff1a; 如上圖所示&#xff0c;一個父類為圖形&#xff0c;計算圖形的面積方法&#xff0c;那么就會有疑問&#xff0c;計算哪個圖形的面積呢&#xff1f;所以這個計算圖形的面積方法就稱為抽象方法&#xff1b; 二.抽象方法和抽象類的格式 …

3、Kafka 線上集群部署方案怎么做?

文章目錄 1、操作系統的選擇1.1、I/O 模型的使用1.2、數據網絡傳輸效率1.3、社區支持度 2、磁盤的選擇3、磁盤容量的規劃3.1、舉例思考本問題&#xff1a;3.2、計算一下&#xff1a;3.3、規劃磁盤容量時你需要考慮下面這幾個元素&#xff1a; 4、帶寬規劃4.1、計算 總結 1、操作…

電商淘寶爬蟲API與淘寶官方開放平臺API的區別以及如何選擇適合自己的API接口

隨著數字化時代的到來&#xff0c;數據已經成為企業競爭力的重要因素。為了獲取數據&#xff0c;企業或個人常常需要使用API接口。常見的API接口包括爬蟲API和官方開放平臺API。本文將詳細介紹這兩種API接口的區別以及如何選擇適合自己的API接口。 一、爬蟲API與官方開放平臺A…

如何使用GaussDB創建外表(FOREIGN TABLE)

目錄 一、前言 二、創建外表的特點 二、GaussDB創建外表訪問外部數據庫表&#xff08;示例&#xff09; 1、創建外表 2、FAQ&#xff1a;CREATE USER MAPPING錯誤 三、GaussDB創建外表映射數據文件&#xff08;示例&#xff09; 1、創建數據文件 2、創建外表 3、FAQ&a…