【音視頻】AAC-ADTS分析

AAC-ADTS 格式分析

AAC?頻格式:Advanced Audio Coding(?級?頻解碼),是?種由MPEG-4標準定義的有損?頻壓縮格式,由Fraunhofer發展,Dolby, Sony和AT&T是主
要的貢獻者。

  • ADIF:Audio Data Interchange Format ?頻數據交換格式。這種格式的特征是可以確定的找到這個?頻數據的開始,不需進?在?頻數據流中間開始
    的解碼,即它的解碼必須在明確定義的開始處進?。故這種格式常?在磁盤?件中。

  • ADTS的全稱是Audio Data Transport Stream。是AAC?頻的傳輸流格式。AAC?頻格式在MPEG-2(ISO-13318-7 2003)中有定義。AAC后來
    ?被采?到MPEG-4標準中。這種格式的特征是它是?個有同步字的?特流,解碼可以在這個流中任何位置開始。它的特征類似于mp3數據流格式。

簡單說,ADTS可以在任意幀解碼,也就是說它每?幀都有頭信息。ADIF只有?個統?的頭,所以必須得到所有的數據后解碼且這兩種的header的格式也是不同的,?前?般編碼后的和抽取出的都是ADTS格式的?頻流。兩者具體的組織結構如下所示:

  • AAC的ADIF格式?下圖:

在這里插入圖片描述

  • AAC的ADTS的?般格式?下圖:

在這里插入圖片描述

  • 有的時候當你編碼AAC裸流的時候,會遇到寫出來的AAC?件并不能在PC和?機上播放,很?的可能就是AAC?件的每?幀?缺少了ADTS頭信息?件的包裝拼接。
  • 只需要加?頭?件ADTS即可。?個AAC原始數據塊?度是可變的,對原始幀加上ADTS頭進?ADTS的封裝,就形成了ADTS幀。
  • AAC?頻?件的每?幀由ADTS Header和AAC Audio Data組成。結構體如下:

在這里插入圖片描述

每?幀的ADTS的頭?件都包含了?頻的采樣率,聲道,幀?度等信息,這樣解碼器才能解析讀取。?般情況下ADTS的頭信息都是7個字節,分為2部分:

  1. adts_fixed_header();
  2. adts_variable_header()

其?為固定頭信息,緊接著是可變頭信息。固定頭信息中的數據每?幀都相同,?可變頭信息則在幀與幀之間可變。

固定頭信息

在這里插入圖片描述

  • syncword :同步頭 總是0xFFF, all bits must be 1,代表著?個ADTS幀的開始
  • ID:MPEG標識符,0標識MPEG-4,1標識MPEG-2
  • Layer:always: ‘00’
  • protection_absent:表示是否誤碼校驗。Warning, set to 1 if there is noCRC and 0 if there is CRC
  • profile:表示使?哪個級別的AAC,如01 Low Complexity(LC)— AACLC。有些芯?只?持AAC LC 。

sampling_frequency_index:表示使?的采樣率下標,通過這個下標在SamplingFrequencies[]數組中查找得知采樣率的值。

在這里插入圖片描述

在MPEG-2 AAC中定義了3種:

在這里插入圖片描述

  • profile的值等于 Audio Object Type的值減1
  • profile = MPEG-4 Audio Object Type - 1

在這里插入圖片描述

  • channel_configuration: 表示聲道數,?如2表示?體聲雙聲道

在這里插入圖片描述

聲道數的定義如下

  • 0: Defined in AOT Specifc Config
  • 1: 1 channel: front-center
  • 2: 2 channels: front-left, front-right
  • 3: 3 channels: front-center, front-left, front-right
  • 4: 4 channels: front-center, front-left, front-right, back-center
  • 5: 5 channels: front-center, front-left, front-right, back-left, back-right
  • 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
  • 7: 8 channels: front-center, front-left, front-right, side-left, side-right,back-left, back-right, LFE-channel
  • 8-15: Reserved

接下來看下adts_variable_header();

可變頭信息
在這里插入圖片描述

  • frame_length : ?個ADTS幀的?度包括ADTS頭和AAC原始流.

  • frame length, this value must include 7 or 9 bytes of header length:aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame)

  • protection_absent=0時, header length=9bytes

  • protection_absent=1時, header length=7bytes

  • adts_buffer_fullness:0x7FF 說明是碼率可變的碼流。

  • number_of_raw_data_blocks_in_frame:表示ADTS幀中有number_of_raw_data_blocks_in_frame + 1個AAC原始幀。

  • 所以說number_of_raw_data_blocks_in_frame == 0 表示說ADTS幀中有?個AAC數據塊。

下?是ADTS的AAC?件部分:

  • ?字節開始算

在這里插入圖片描述

第?幀的幀頭7個字節為:0xFF 0xF1 0x4C 0x40 0x20 0xFF 0xFC

實現流程

準備文件,準備音頻格式在MPEG-2支持的3種AAC格式的mp4flv,這里不使用ts是因為它的aac流自帶ADTS頭部信息。

這三種都支持

  • Main Profile
  • LC
  • SSR

在這里插入圖片描述

將文件放入build路徑下,通過main參數傳遞進來

在這里插入圖片描述

創建一個輸出文件,以二進制寫的方式打開,用于寫入轉換后的ADTS文件

	char *in_filename = NULL;char *aac_filename = NULL;FILE *aac_fd = NULL;av_log_set_level(AV_LOG_DEBUG);if(argc < 3){av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n");return -1;}in_filename = argv[1];      // 輸入文件aac_filename = argv[2];     // 輸出文件if(in_filename == NULL || aac_filename == NULL){av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");return -1;}aac_fd = fopen(aac_filename, "wb");if (!aac_fd){av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", aac_filename);return -1;}

文件解封裝

將文件解封裝,無論是mp4還是flv,找出對應的音頻流,讀取音頻流數據

AVFormatContext *ifmt_ctx = NULL;// 打開輸入文件if((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// 獲取解碼器信息if((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// dump媒體信息av_dump_format(ifmt_ctx, 0, in_filename, 0);// 初始化packetav_init_packet(&pkt);// 查找audio對應的steam indexaudio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(audio_index < 0){av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",av_get_media_type_string(AVMEDIA_TYPE_AUDIO),in_filename);return AVERROR(EINVAL);}

我們查看一下當前的AAC類型的profile,因為我們只支持三種:

 printf("audio profile:%d, FF_PROFILE_AAC_LOW:%d\n",ifmt_ctx->streams[audio_index]->codecpar->profile,FF_PROFILE_AAC_LOW);

如果音頻格式對應支持的AAC,那么我們就可以進行循環讀取音頻包數據

  • 讀取音頻包數據,獲得對應的profilesample_rate以及channel
  • 傳入包的數據大小
  • ADTS一般是7字節,因此用一個7字節的char數組接收(一個char占1字節)
  • 寫入頭部后,將頭部信息寫入文件
  • 寫入數據包信息
  • 釋放數據包內存
 if(pkt.stream_index == audio_index){char adts_header_buf[7] = {0};adts_header(adts_header_buf, pkt.size,ifmt_ctx->streams[audio_index]->codecpar->profile,ifmt_ctx->streams[audio_index]->codecpar->sample_rate,ifmt_ctx->streams[audio_index]->codecpar->channels);fwrite(adts_header_buf, 1, 7, aac_fd);  // 寫adts header , ts流不適用,ts流分離出來的packet帶了adts headerlen = fwrite( pkt.data, 1, pkt.size, aac_fd);   // 寫adts dataif(len != pkt.size){av_log(NULL, AV_LOG_DEBUG, "warning、, length of writed data isn't equal pkt.size(%d, %d)\n",len,pkt.size);}}av_packet_unref(&pkt);

ADTS格式詳解

準備采樣率表
  • 這個是固定的,與協議對應
const int sampling_frequencies[] = {96000,  // 0x088200,  // 0x164000,  // 0x248000,  // 0x344100,  // 0x432000,  // 0x524000,  // 0x622050,  // 0x716000,  // 0x812000,  // 0x911025,  // 0xa8000   // 0xb// 0xc d e f是保留的
};
  • 我們這里直接使用48000采樣率即可
int sampling_frequency_index = 3; // 默認使用48000hz
寫入固定頭信息
  • 同步頭(12bit),始終為0xfff
p_adts_header[0] = 0xff;         //syncword:0xfff                          高8bits
p_adts_header[1] = 0xf0;         //syncword:0xfff                          低4bits
  • 版本號(1bit),如果使用的是MPEG-2為0,MPEG-4為1
p_adts_header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bit
  • layer(2bit),永遠是0
p_adts_header[1] |= (0 << 1);    //Layer:0
  • 校驗位(protection_absent),0表示有校驗,1表示無校驗(1bit)
p_adts_header[1] |= 1;           //protection absent:1                     1bit
  • profile(2bit),ffmpeg參考的是MPEG-2,因此這里使用它的枚舉值即可
p_adts_header[2] = (profile)<<6;            //profile:profile               2bits
  • 采樣率索引,需要轉為16進制(2bit)
p_adts_header[2] |= (sampling_frequency_index & 0x0f)<< 2; //sampling frequency index:sampling_frequency_index  4bits
  • private_bit,固定為0(1bit)
p_adts_header[2] |= (0 << 1);             //private bit:0                   1bit
  • 聲道布局,需要轉換為16進制(3bit)
p_adts_header[2] |= (channels & 0x04)>>2; //channel configuration:channels  高1bit
p_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bits
  • original_copy,固定為0(1bit)
p_adts_header[3] |= (0 << 5);               //original:0                1bit
  • home,固定為0(1bit)
p_adts_header[3] |= (0 << 4);               //home:0                    1bit
寫入可變頭
  • copyright_identification_bit,固定為0(1bit
p_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bit
  • copyright_identify_start,固定為0(1bit
p_adts_header[3] |= (0 << 2);               //copyright id start:0      1bit
  • aac_frame_lengthaac數據幀的長度(13bit),通過下面的方式獲取:
  1. 如果protection_absent校驗位為1,那么aac_frame_length = 7 + sizeof(aac_frame)
  2. 如果protection_absent校驗位為0,那么aac_frame_length = 9 + sizeof(aac_frame)

前面設置了校驗位為1,因此:

int adtsLen = data_length + 7;
p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bits
p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中間8bits
p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bits
  • adts_buffer_fullness11bit),設置為0x7ff表示為可變碼流
p_adts_header[5] |= 0x1f;        //buffer fullness:0x7ff 高5bits
p_adts_header[6] = 0xfc;         //buffer fullness:0x7ff 低6bits
  • number_of_raw_data_blocks_in_frame2bit),意義如下:
  1. 表示ADTS幀中有number_of_raw_data_blocks_in_frame+ 1個AAC原始幀。
  2. 因此我們設置number_of_raw_data_blocks_in_frame = 0 表示說ADTS幀中有?個AAC數據塊。
p_adts_header[6] |= 0 << 2;         //buffer fullness:0x7ff 低6bits

寫入的函數如下所示:

#define ADTS_HEADER_LEN  7;const int sampling_frequencies[] = {96000,  // 0x088200,  // 0x164000,  // 0x248000,  // 0x344100,  // 0x432000,  // 0x524000,  // 0x622050,  // 0x716000,  // 0x812000,  // 0x911025,  // 0xa8000   // 0xb// 0xc d e f是保留的
};int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{int sampling_frequency_index = 3; // 默認使用48000hzint adtsLen = data_length + ADTS_HEADER_LEN;int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);int i = 0;for(i = 0; i < frequencies_size; i++){if(sampling_frequencies[i] == samplerate){sampling_frequency_index = i;break;}}if(i >= frequencies_size){printf("unsupport samplerate:%d\n", samplerate);return -1;}p_adts_header[0] = 0xff;         //syncword:0xfff                          高8bitsp_adts_header[1] = 0xf0;         //syncword:0xfff                          低4bitsp_adts_header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bitp_adts_header[1] |= (0 << 1);    //Layer:0                                 2bitsp_adts_header[1] |= 1;           //protection absent:1                     1bitp_adts_header[2] = (profile)<<6;            //profile:profile               2bitsp_adts_header[2] |= (sampling_frequency_index & 0x0f)<< 2; //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] |= (0 << 1);             //private bit:0                   1bitp_adts_header[2] |= (channels & 0x04)>>2; //channel configuration:channels  高1bitp_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bitsp_adts_header[3] |= (0 << 5);               //original:0                1bitp_adts_header[3] |= (0 << 4);               //home:0                    1bitp_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bitp_adts_header[3] |= (0 << 2);               //copyright id start:0      1bitp_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bitsp_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中間8bitsp_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bitsp_adts_header[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bitsp_adts_header[6] = 0xfc;      //11111100 共八位       //buffer fullness:0x7ff 低6bits// p_adts_header[6] |= 0 << 2;     // number_of_raw_data_blocks_in_frame://    表示ADTS幀中有number_of_raw_data_blocks_in_frame + 1個AAC原始幀。return 0;
}

釋放內存

最后還是要釋放內存,關閉文件

 // 關閉輸入文件
if(ifmt_ctx)
{avformat_close_input(&ifmt_ctx);
}
if(aac_fd)
{fclose(aac_fd);
}
HE-AAC需要調整
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>#define ADTS_HEADER_LEN  7;const int sampling_frequencies[] = {96000,  // 0x088200,  // 0x164000,  // 0x248000,  // 0x344100,  // 0x432000,  // 0x524000,  // 0x622050,  // 0x716000,  // 0x812000,  // 0x911025,  // 0xa8000   // 0xb// 0xc d e f是保留的
};int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels) {int sampling_frequency_index = 3;int adtsLen = data_length + 7; // 修正宏定義問題// 查找采樣率索引for (int i = 0; i < sizeof(sampling_frequencies)/sizeof(int); i++) {if (sampling_frequencies[i] == samplerate) {sampling_frequency_index = i;break;}}// 設置ADTS頭各字段p_adts_header[0] = 0xFF;p_adts_header[1] = 0xF0;p_adts_header[1] |= 0x01; // protection_absent// Profile設置為傳入值(需外部處理HE-AAC情況)p_adts_header[2] = (profile & 0x03) << 6;p_adts_header[2] |= (sampling_frequency_index & 0x0F) << 2;p_adts_header[2] |= (channels >> 3) & 0x01; // 通道高1位p_adts_header[3] = (channels & 0x07) << 5; // 通道低3位p_adts_header[3] |= (adtsLen >> 11) & 0x03;p_adts_header[4] = (adtsLen >> 3) & 0xFF;p_adts_header[5] = (adtsLen & 0x07) << 5;p_adts_header[5] |= 0x1F;p_adts_header[6] = 0xFC;return 0;
}
int main(int argc, char *argv[])
{int ret = -1;char errors[1024];char *in_filename = NULL;char *aac_filename = NULL;FILE *aac_fd = NULL;int audio_index = -1;int len = 0;AVFormatContext *ifmt_ctx = NULL;AVPacket pkt;// 設置打印級別av_log_set_level(AV_LOG_DEBUG);if(argc < 3){av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n");return -1;}in_filename = argv[1];      // 輸入文件aac_filename = argv[2];     // 輸出文件if(in_filename == NULL || aac_filename == NULL){av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");return -1;}aac_fd = fopen(aac_filename, "wb");if (!aac_fd){av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", aac_filename);return -1;}// 打開輸入文件if((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// 獲取解碼器信息if((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// dump媒體信息av_dump_format(ifmt_ctx, 0, in_filename, 0);// 初始化packetav_init_packet(&pkt);// 查找audio對應的steam indexaudio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(audio_index < 0){av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",av_get_media_type_string(AVMEDIA_TYPE_AUDIO),in_filename);return AVERROR(EINVAL);}// 打印AAC級別printf("audio profile:%d, FF_PROFILE_AAC_LOW:%d\n",ifmt_ctx->streams[audio_index]->codecpar->profile,FF_PROFILE_AAC_LOW);if(ifmt_ctx->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC){printf("the media file no contain AAC stream, it's codec_id is %d\n",ifmt_ctx->streams[audio_index]->codecpar->codec_id);goto failed;}// 讀取媒體文件,并把aac數據幀寫入到本地文件while(av_read_frame(ifmt_ctx, &pkt) >=0 ){if(pkt.stream_index == audio_index){char adts_header_buf[7] = {0};adts_header(adts_header_buf, pkt.size,1,ifmt_ctx->streams[audio_index]->codecpar->sample_rate /2 ,ifmt_ctx->streams[audio_index]->codecpar->channels);fwrite(adts_header_buf, 1, 7, aac_fd);  // 寫adts header , ts流不適用,ts流分離出來的packet帶了adts headerlen = fwrite( pkt.data, 1, pkt.size, aac_fd);   // 寫adts dataif(len != pkt.size){av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",len,pkt.size);}}av_packet_unref(&pkt);}failed:// 關閉輸入文件if(ifmt_ctx){avformat_close_input(&ifmt_ctx);}if(aac_fd){fclose(aac_fd);}return 0;
}

profile字段錯誤
HE-AAC(AAC LC + SBR)的Profile值在ADTS頭中應設為1(對應AAC LC的Object Type減1),而非直接使用HE-AAC的Profile值(FF_PROFILE_AAC_HE為5)。直接使用導致高位溢出,字段無效。

采樣率索引未調整
HE-AAC使用SBR技術時,實際采樣率為ADTS頭中采樣率的兩倍。例如,48kHz音頻在ADTS頭中應使用24kHz的索引(索引6),但代碼未進行此調整。

更多資料:https://github.com/0voice

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

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

相關文章

機器學習 Day12 集成學習簡單介紹

1.集成學習概述 1.1. 什么是集成學習 集成學習是一種通過組合多個模型來提高預測性能的機器學習方法。它類似于&#xff1a; 超級個體 vs 弱者聯盟 單個復雜模型(如9次多項式函數)可能能力過強但容易過擬合 組合多個簡單模型(如一堆1次函數)可以增強能力而不易過擬合 集成…

通過爬蟲方式實現頭條號發布視頻(2025年4月)

1、將真實的cookie貼到代碼目錄中toutiaohao_cookie.txt文件里,修改python代碼里的user_agent和video_path, cover_path等變量的值,最后運行python腳本即可; 2、運行之前根據import提示安裝一些常見依賴,比如requests等; 3、2025年4月份最新版; 代碼如下: import js…

Linux ssh免密登陸設置

使用 ssh-copy-id 命令來設置 SSH 免密登錄&#xff0c;并確保所有相關文件和目錄權限正確設置&#xff0c;可以按照以下步驟進行&#xff1a; 步驟 1&#xff1a;在源服務器&#xff08;198.120.1.109&#xff09;生成 SSH 密鑰對 如果還沒有生成 SSH 密鑰對&#xff0c;首先…

《讓機器人讀懂你的心:情感分析技術融合奧秘》

機器人早已不再局限于執行簡單機械的任務&#xff0c;人們期望它們能像人類伙伴一樣&#xff0c;理解我們的喜怒哀樂&#xff0c;實現更自然、溫暖的互動。情感分析技術&#xff0c;正是賦予機器人這種“理解人類情緒”能力的關鍵鑰匙&#xff0c;它的融入將徹底革新機器人與人…

Linux筆記---進程間通信:匿名管道

1. 管道通信 1.1 管道的概念與分類 管道&#xff08;Pipe&#xff09; 是進程間通信&#xff08;IPC&#xff09;的一種基礎機制&#xff0c;主要用于在具有親緣關系的進程&#xff08;如父子進程、兄弟進程&#xff09;之間傳遞數據&#xff0c;其核心特性是通過內核緩沖區實…

Ollama API 應用指南

1. 基礎信息 默認地址: http://localhost:11434/api數據格式: application/json支持方法: POST&#xff08;主要&#xff09;、GET&#xff08;部分接口&#xff09; 2. 模型管理 API (1) 列出本地模型 端點: GET /api/tags功能: 獲取已下載的模型列表。示例:curl http://lo…

【OSCP-vulnhub】Raven-2

目錄 端口掃描 本地/etc/hosts文件解析 目錄掃描&#xff1a; 第一個flag 利用msf下載exp flag2 flag3 Mysql登錄 查看mysql的運行權限 MySql提權&#xff1a;UDF 查看數據庫寫入條件 查看插件目錄 查看是否可以遠程登錄 gcc編譯.o文件 創建so文件 創建臨時監聽…

Podman Desktop:現代輕量容器管理利器(Podman與Docker)

前言 什么是 Podman Desktop&#xff1f; Podman Desktop 是基于 Podman CLI 的圖形化開源容器管理工具&#xff0c;運行在 Windows&#xff08;或 macOS&#xff09;上&#xff0c;默認集成 Fedora Linux&#xff08;WSL 2 環境&#xff09;。它提供與 Docker 類似的使用體驗…

極狐GitLab 權限和角色如何設置?

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 權限和角色 (BASIC ALL) 將用戶添加到項目或群組時&#xff0c;您可以為他們分配角色。該角色決定他們在極狐GitLab 中可以執…

解鎖現代生活健康密碼,開啟養生新方式

在科技飛速發展的當下&#xff0c;我們享受著便捷生活&#xff0c;卻也面臨諸多健康隱患。想要維持良好狀態&#xff0c;不妨從這些細節入手&#xff0c;解鎖科學養生之道。? 腸道是人體重要的消化器官&#xff0c;也是最大的免疫器官&#xff0c;養護腸道至關重要。日常可多…

Kafka 主題設計與數據接入機制

一、前言&#xff1a;萬物皆流&#xff0c;Kafka 是入口 在構建實時數倉時&#xff0c;Kafka 既是 數據流動的起點&#xff0c;也是后續流處理系統&#xff08;如 Flink&#xff09;賴以為生的數據源。 但“消息進來了” ≠ “你就能處理好了”——不合理的 Topic 設計、接入方…

【繪制圖像輪廓|凸包特征檢測】圖像處理(OpenCV) -part7

15 繪制圖像輪廓 15.1 什么是輪廓 輪廓是一系列相連的點組成的曲線&#xff0c;代表了物體的基本外形。相對于邊緣&#xff0c;輪廓是連續的&#xff0c;邊緣不一定連續&#xff0c;如下圖所示。輪廓是一個閉合的、封閉的形狀。 輪廓的作用&#xff1a; 形狀分析 目標識別 …

uniapp中使用<cover-view>標簽

文章背景&#xff1a; uniapp中遇到了原生組件(canvas)優先級過高覆蓋vant組件 解決辦法&#xff1a; 使用<cover-view>標簽 踩坑&#xff1a; 我想實現的是一個vant組件庫中動作面板的效果&#xff0c;能夠從底部彈出框&#xff0c;讓用戶進行選擇&#xff0c;我直…

Kafka常見問題及解決方案

Kafka 是一個強大的分布式流處理平臺&#xff0c;廣泛用于高吞吐量的數據流處理&#xff0c;但在實際使用過程中&#xff0c;也會遇到一些常見問題。以下是一些常見的 Kafka 問題及其對應的解決辦法的詳細解答&#xff1a; 消息丟失 一、原因 1.生產端 網絡故障、生產者超時…

leetcode 二分查找應用

34. Find First and Last Position of Element in Sorted Array 代碼&#xff1a; class Solution { public:vector<int> searchRange(vector<int>& nums, int target) {int low lowwer_bound(nums,target);int high upper_bound(nums,target);if(low high…

【Docker】在容器中使用 NVIDIA GPU

解決容器 GPU 設備映射問題&#xff0c;實現 AI 應用加速 &#x1f517; 官方文檔&#xff1a;NVIDIA Container Toolkit GitHub 常見錯誤排查 若在運行測試容器時遇到以下錯誤&#xff1a; docker: Error response from daemon: could not select device driver ""…

通過Quartus II實現Nios II編程

目錄 一、認識Nios II二、使用Quartus II 18.0Lite搭建Nios II硬件部分三、軟件部分四、運行項目 一、認識Nios II Nios II軟核處理器簡介 Nios II是Altera公司推出的一款32位RISC嵌入式處理器&#xff0c;專門設計用于在FPGA上運行。作為軟核處理器&#xff0c;Nios II可以通…

JAVA設計模式——(三)橋接模式

JAVA設計模式——&#xff08;三&#xff09;橋接模式&#xff08;Bridge Pattern&#xff09; 介紹理解實現武器抽象類武器實現類涂裝顏色的行為接口具體顏色的行為實現讓行為影響武器修改武器抽象類修改實現類 測試 適用性 介紹 將抽象和實現解耦&#xff0c;使兩者可以獨立…

k8s 證書相關問題

1.重新生成新證書 kubeadm init phase certs apiserver-etcd-client --config ~/kubeadm.yaml這個命令表示生成 kube-apiserver 連接 etcd 使用的證書,生成后如下 -rw------- 1 root root 1.7K Apr 23 16:35 apiserver-etcd-client.key -rw-r--r-- 1 root root 1.2K Apr 23 …

比較:AWS VPC peering與 AWS Transit Gateway

簡述: VPC 對等連接和 Transit Gateway 用于連接多個 VPC。VPC 對等連接提供全網狀架構,而 Transit Gateway 提供中心輻射型架構。Transit Gateway 提供大規模 VPC 連接,并簡化了 VPC 間通信管理,相比 VPC 對等連接,支持大量 VPC 的 VPC 間通信管理。 VPC 對等連接 AWS V…