国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

macOS coreAudio 之 AudioQueue 播放本地音頻文件

這篇具有很好參考價值的文章主要介紹了macOS coreAudio 之 AudioQueue 播放本地音頻文件。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

macOS的音頻模塊使用還是和 iOS有細(xì)微差別的。

今天記錄是的是 使用 AudioQueue 配合 AudioFile 進行播放macOS 本地音頻文件

本文打倉庫代碼為: JBPlayLocalMusicFile.m

CoreAudio 作為Apple音頻系統(tǒng)中音頻庫的集合,今天需要使用到的庫為:

  • AudioQueue 位于 <AudioToolbox/AudioQueue.h>, 作為輸出模塊,輸入音頻到系統(tǒng)默認(rèn)揚聲器
  • AudioFile 位于 <AudioToolbox/AudioFile.h>, 讀取本地音頻文件,然后將讀取的Buffer塞入 AudioQueue的音頻隊列中,等待系統(tǒng)揚聲器寵幸。

讀取和播放的大致流程為:macOS coreAudio 之 AudioQueue 播放本地音頻文件,macos,AudioQueue,CoreAudio

1. 前置說明

全局設(shè)置兩個值分別為

//每個緩沖區(qū)0.5秒的數(shù)據(jù)量
#define kBufferDurationInSeconds 0.5
//分配三個緩沖區(qū)
#define kNumberBuffer 3
  • kBufferDurationInSeconds 代表AudioQueue 每個緩沖區(qū)存儲 0.5秒時間的數(shù)據(jù),最后我們代碼里面會通過計算轉(zhuǎn)換成0.5秒時間的數(shù)據(jù)量的 內(nèi)存控件
  • kNumberBuffer 代表 AudioQueue 中緩沖區(qū)的數(shù)量,我們知道至少需要兩個緩沖區(qū),其中一個采集數(shù)據(jù)的緩沖區(qū)A, 另外一個是 回調(diào)函數(shù)的緩沖區(qū)B。 當(dāng)采集的數(shù)據(jù)達到0.5秒的內(nèi)存大小后,A緩沖區(qū)會將所有數(shù)據(jù)轉(zhuǎn)移到B緩沖區(qū),然后A繼續(xù)采集,B在回調(diào)函數(shù)中供用戶使用。但是考慮數(shù)據(jù)的連貫性,如果哪個環(huán)節(jié)出問題,會導(dǎo)致數(shù)據(jù)A緩沖區(qū)不能及時進行數(shù)據(jù)采集,所以需要一個備用的緩沖區(qū)C來進行應(yīng)急。

2. 輔助宏

播放demo只負(fù)責(zé)調(diào)通邏輯和了解學(xué)習(xí)API,并沒有處理錯誤情況,我們將所有的錯誤只做了log輸出,

#include <TargetConditionals.h>

//負(fù)責(zé)將 OSStatus 轉(zhuǎn)成 fourcc
#if TARGET_RT_BIG_ENDIAN
#   define FourCC2Str(fourcc) (const char[]){*((char*)&fourcc), *(((char*)&fourcc)+1), *(((char*)&fourcc)+2), *(((char*)&fourcc)+3),0}
#else
#   define FourCC2Str(fourcc) (const char[]){*(((char*)&fourcc)+3), *(((char*)&fourcc)+2), *(((char*)&fourcc)+1), *(((char*)&fourcc)+0),0}
#endif

#define printErr(logStr, status) \
    if (status != noErr) {\
        NSLog(@"==== 出現(xiàn)錯誤: %@ code: %d(%s)", logStr, (int)status, FourCC2Str(status));\
    }

日志輸入大概這醬紫
CoreAudioDemo[37280:4192311] ==== 出現(xiàn)錯誤: AudioFileGetProperty kAudioFilePropertyPacketSizeUpperBound code: -50()

3. 類初始化與全局變量

- (void)start; start 為入口函數(shù)
- (void)stop stop 為結(jié)束函數(shù)
在初始化方法中監(jiān)聽 外部的 通知,進行 stop的調(diào)用

- (instancetype)init {
    self = [super init];
    _aspds = NULL;
    _isDone = FALSE;
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stop) name:JBStopNotification object:nil];
    return  self;
}

類聲明的變量

@interface JBPlayLocalMusicFile()
{
@public
	//這些C的struct 并沒有 get set 方法,不能設(shè)置為 property, 所以直接設(shè)置為成員變量
    AudioFileID _audioFile;
    AudioQueueRef _mQueue;
    AudioStreamPacketDescription *_aspds; //從文件中讀取的包秒數(shù),每次讀取后將其傳入 AudioQueue中,以便能正確解碼和播放
}

@property (nonatomic, assign) AudioStreamBasicDescription mASBD;
@property (nonatomic, assign) BOOL isDone; //是否播放完畢
@property (nonatomic, assign) UInt32 byteSizeInBuffer; //緩沖區(qū)應(yīng)有的字節(jié)數(shù)(0.5秒內(nèi))
@property (nonatomic, assign) UInt32 packetsNumInBuffer; // 緩沖區(qū)應(yīng)對應(yīng)的數(shù)據(jù)包數(shù)量(0.5秒內(nèi))
@property (nonatomic, assign) Float64 readOffsetOfPackets; //讀取了多少 packets
@end

4. 打開本地音頻文件

start函數(shù)內(nèi)首先調(diào)用openAudioFile, _audioFile 為聲明的 @public 的成員變量
AudioFileID _audioFile;
這里我們使用AudioFileOpenURL函數(shù) 只讀權(quán)限打開 flac 類型的音頻,并綁定到 _audioFile 的指針句柄中,以后我們操作 這個文件就通過這個全局成員變量進行控制。

//打開 音頻 文件
- (void)openAudioFile{
    NSURL *audioURL  = [[NSBundle mainBundle] URLForResource:@"G_E_M_ 鄧紫棋 - 句號" withExtension:@"flac"];
    OSStatus status =  AudioFileOpenURL((__bridge  CFURLRef)audioURL, kAudioFileReadPermission, 0, &(_audioFile));
    printErr(@"AudioFileOpenURL", status);
}

5. 獲取音頻文件里面的 基本流信息

在上一步中我們打開了 音頻文件,并獲取到了指向它的句柄,現(xiàn)在我們操控_audioFile, 從文件中獲取 AudioStreamBasicDescription的信息。
AudioStreamBasicDescription 作為 Apple 描述音頻流的基本格式,里面的值的含義就不具體說明了,調(diào)用[JBHelper printASBD:asbd];這個輔助函數(shù)能夠打印處 ASBD 的具體值信息。
值得說明的是,由于我們讀取的是 flac 格式,不是 PCM 這種線性的裸數(shù)據(jù), 所以某些值是空的以0表示,因為可能是VBR(可變比特率)等,需要我們在后面的步驟進行進一步提取。

在這個方法中中我們 將取出的 AudioStreamBasicDescription 保存到全局變量 self.mASBD 中。

- (void)getASBDInFile {
    /***
     mp3 flac 文件格式, 和PCM 有點差別
2023-07-21 14:58:34.893822+0800 CoreAudioDemo[3193:5836480] planar:false bitsPerchannel:0
2023-07-21 14:58:34.894105+0800 CoreAudioDemo[3193:5836480] flags: 
	kAppleLosslessFormatFlag_16BitSourceData
	kAudioFormatFlagIsFloat
2023-07-21 14:58:34.894247+0800 CoreAudioDemo[3193:5836480] 
ASBD: 
	mSampleRate = 44100
	mFormatID = 1718378851(flac)
	mFormatFlags = 1
	mBytesPerPacket = 0
	mFramesPerPacket = 4096
	mBytesPerFrame = 0
	mChannelsPerFrame = 2
	mBitsPerChannel = 0
	mReserved = 0
     */
    AudioStreamBasicDescription asbd;
    UInt32 asbdSize = sizeof(asbd);
    OSStatus status = AudioFileGetProperty(_audioFile, kAudioFilePropertyDataFormat, &asbdSize, &asbd);
    printErr(@"AudioFileOpenURL", status);
    [JBHelper printASBD:asbd];
    self.mASBD = asbd;
}

6. 初始化 AudioQueue

在獲取了文件中的 ASBD 后,我們就可以初始化 AudioQueue 了。

  • 第一個參數(shù)為 我們在上一步獲取的 _mASBD 的引用
  • 第二個參數(shù)為 回調(diào)函數(shù)的名稱,實際上 AudioQueue 會在合適的時候 自動對該函數(shù)進行回調(diào),這也是 C 語言常用的回調(diào)模式,該回調(diào)我們會在 后面進行詳細(xì)介紹。
  • 第三個參數(shù)為 第二參數(shù)回調(diào)函數(shù) 里面作為參數(shù)回傳回來的值,這樣我們可以在回調(diào)函數(shù)回調(diào)回來的時候訪問我們特定的類的實例,這里橋接成 void * 傳入
  • 第四第五為 特定的Runloop 模式的值,可以不指定
  • 第六參數(shù),為預(yù)留參數(shù),只能傳 0
  • 最后一個參數(shù) _mQueue 傳入全局變量 AudioQueueRef 的地址, 只有傳入上一級的地址,才能改變當(dāng)前的地址,二級指針的操作。

這樣我們把 作為 輸出 Output 模式的 AudioQueue 的回調(diào)函數(shù)綁定好了,并且將 AudioQueue也初始化了,

    //init audio queue by output param
    OSStatus status = AudioQueueNewOutput(&_mASBD,
                                          jbAudioQueueOutputCallback,
                                          (__bridge void *)self,
                                          NULL,
                                          NULL,
                                          0,
                                          &_mQueue);
    printErr(@"AudioQueueNewOutput", status);

7. 將文件中的 Encoder Magic Cookie 拷貝到 音頻隊列中

magic cookieCoreAudio表示附加到音頻流中的元數(shù)據(jù)(metadata), 能夠為正常的解碼文件和流提供必要的信息。

某些音頻格式的文件,在播放過程中必須要有 Magic Cookie 的數(shù)據(jù)才能正常的解碼播放。
經(jīng)本地測試 mp3文件讀取不出Magic Cookie , 而flac格式的文件能夠正常讀取出來。
所以我們這里 會嘗試讀取一次,讀取不到就 返回,如果能夠讀取到就直接傳入 AudioQueue 中去。

具體過程詳看代碼和注釋

// MP3獲取不到 magic cookie
- (void)setFileMetaDataToAudioQueue{
    //先獲取長度
    UInt32 cookieDataSize = 0;
    UInt32 isWriteAble = 0;
    //注意這里是AudioFileGetPropertyInfo, 獲取長度和是否可以寫
    OSStatus status = AudioFileGetPropertyInfo(_audioFile, kAudioFilePropertyMagicCookieData, &cookieDataSize, &isWriteAble);
    
    //有些沒有 magic cookie ,所以不管
    if (status != noErr) {
        NSLog(@"magic cookie 不存在,忽略掉");
        return;
    }
    
    if (cookieDataSize <= 0) {
        NSLog(@"AudioFileGetPropertyInfo kAudioFilePropertyMagicCookieData get zero size data");
        return;
    }
    
    //根據(jù)長度獲取對應(yīng)的magic data 的內(nèi)容
    Byte *cookieData = malloc(cookieDataSize *sizeof(Byte));
    //這里是AudioFileGetProperty
    status = AudioFileGetProperty(_audioFile, kAudioFilePropertyMagicCookieData, &cookieDataSize, cookieData);
    printErr(@"AudioFileGetProperty kAudioFilePropertyMagicCookieData", status);
    
    //將獲取的MagicCookie 設(shè)置到 AudioQueue 中
    status = AudioQueueSetProperty(_mQueue, kAudioQueueProperty_MagicCookie, cookieData, cookieDataSize);
    printErr(@"AudioQueueSetProperty kAudioQueueProperty_MagicCookie", status);
    
    // malloc 后必須 free
    free(cookieData);
}

8. 計算 每次讀取 需要的大小和包的數(shù)量

我們現(xiàn)在開始計算 每個緩沖區(qū)的大小和包的數(shù)量
這里我們在代碼中 為 兩個全局變量賦值

@property (nonatomic, assign) UInt32 byteSizeInBuffer; //緩沖區(qū)應(yīng)有的字節(jié)數(shù)(0.5秒內(nèi))
@property (nonatomic, assign) UInt32 packetsNumInBuffer; // 緩沖區(qū)應(yīng)對應(yīng)的數(shù)據(jù)包數(shù)量(0.5秒內(nèi))

了解了這個函數(shù)是為獲取上面兩個值后,就可以帶著目的的去看里面的函數(shù)了。
主要是考慮到 _mASBD.mBytesPerPacket 是否為 0 的兩種 case,所以代碼比較復(fù)雜,需要進行兩種判斷。

- (void)calculateSizeOfTime{
    
    //獲取kBufferDurationInSeconds時間的包的數(shù)量
    UInt32 totalNumerOfPackets = 0;
    if (_mASBD.mFramesPerPacket > 0) {
        //每次時間間隔內(nèi)需要收集的樣本數(shù)量
        Float64 totalNumberOfSamples =  _mASBD.mSampleRate * kBufferDurationInSeconds;
        UInt32 totalNumberOfFrames = ceil(totalNumberOfSamples); //將數(shù)據(jù)向上取整
        totalNumerOfPackets = totalNumberOfFrames / _mASBD.mFramesPerPacket;
    } else {
        // 如果mFramesPerPacket==0,則編解碼器在給定時間內(nèi)沒有可預(yù)測的數(shù)據(jù)包大小。
        // 在這種情況下,我們將假設(shè)在給定持續(xù)時間內(nèi)最多有 1 個數(shù)據(jù)包來調(diào)整緩沖區(qū)大小
        totalNumerOfPackets = 1;
    }
    
    UInt32 packetSizeUpperBound = 0;
    UInt32 packetSizeUpperBoundSize = sizeof(packetSizeUpperBound);
    // 獲取 計算出來的 理論上的 最大 package 大小。非讀取文件
    OSStatus status = AudioFileGetProperty(_audioFile,
                                           kAudioFilePropertyPacketSizeUpperBound,
                                           &packetSizeUpperBoundSize,
                                           &packetSizeUpperBound);
    printErr(@"AudioFileGetProperty kAudioFilePropertyPacketSizeUpperBound", status);
    
    if (_mASBD.mBytesPerPacket > 0) {
        //設(shè)置具體值
        self.byteSizeInBuffer = self.mASBD.mBytesPerPacket * totalNumerOfPackets;
    } else {
        // 獲取理論上最大值
        self.byteSizeInBuffer = packetSizeUpperBound * totalNumerOfPackets;
    }
    
    //定義一個最大值,以避免 RAM 消耗過大
    //并定義一個最小值,以確保我們有一個可以在播放時沒有問題的緩沖區(qū)。太小了會頻繁連續(xù)從文件讀取 IO 消耗比較大
    const int maxBufferSize = 0x100000; // 128KB
    const int minBufferSize = 0x4000;  // 16KB
    //調(diào)整成一個中間的適合的值
    if(self.byteSizeInBuffer > maxBufferSize) {
        self.byteSizeInBuffer = maxBufferSize;
    } else if (self.byteSizeInBuffer < minBufferSize) {
        self.byteSizeInBuffer = minBufferSize;
    }
    
    //調(diào)整后重新計算大小, 這樣可能多分配內(nèi)存,但至少不會內(nèi)存越界
    self.packetsNumInBuffer = self.byteSizeInBuffer / packetSizeUpperBound;
}

9. 獲取額外的 AudioStreamPacketDescription 信息

由于我們是非 PCM 的數(shù)據(jù),所以獲取了上面的數(shù)據(jù)后,還不能知己開始數(shù)據(jù)采集,還需要 獲取 除了 AudioStreamBasicDescription 這種音頻流信息外,還需要獲取 Packet 的基本信息。
_aspdsAudioStreamPacketDescription 的數(shù)組, 包含了 _packetsNumInBuffer 個元素

具體見代碼和注釋

/**
 如果音頻基本流描述沒有告訴任何有關(guān)每個數(shù)據(jù)包的字節(jié)數(shù)或每個數(shù)據(jù)包的幀的信息,
 那么我們就會遇到 VBR 編碼或通道大小不等的 CBR 的情況。
 在任何這些情況下,我們都必須為額外的數(shù)據(jù)包描述分配緩沖區(qū),
 這些描述將在處理音頻文件并將其數(shù)據(jù)包讀入緩沖區(qū)時填充。
 */
- (void)allocPacketArray {
    BOOL isNeedASPD = _mASBD.mBytesPerPacket == 0 || _mASBD.mFramesPerPacket == 0;
    if(isNeedASPD) {
    	//calloc能夠?qū)?開辟的內(nèi)存自動 設(shè)為0
        _aspds = (AudioStreamPacketDescription *)calloc(sizeof(AudioStreamPacketDescription), _packetsNumInBuffer);
    } else {
        _aspds = NULL;
    }
}

10. 開辟AudioQueue 隊列

在我們前面完成一些必要的數(shù)據(jù)計算和AudioQueue的配置,現(xiàn)在可以進行AudioQueue的內(nèi)存申請和配置了。

我們這里使用了kNumberBuffer3個緩沖區(qū),并將其buffers 保存到這個數(shù)組里面,注意buffers 不使用引用計數(shù),所以在函數(shù)返回后并不會析構(gòu),所以這個使用的局部變量。

  • 這里我們使用了AudioQueueAllocateBuffer 來開辟了 self.byteSizeInBuffer 這么多Byte的內(nèi)存,并關(guān)聯(lián)到_mQueue中,并對內(nèi)存里面的值進行合適的賦值。最終將開辟的內(nèi)存的首地址保存到 buffers[i] 變量中
  • jbAudioQueueOutputCallback 這里開辟內(nèi)存后手動調(diào)用了一下這個回調(diào)函數(shù),是為了在回調(diào)中讀取一次 0.5 秒的文件數(shù)據(jù),來進行填充我們剛剛開辟出來的內(nèi)存。
  • self.isDone 代表著,上一步回調(diào)中就把文件的數(shù)據(jù)讀完了,或者出錯了,直接break,然后再 上一級方法中 調(diào)用stop 函數(shù)。

三次循環(huán),代表著開辟出的三個緩沖隊列都按我們的要求,填充完畢。也意味著我們現(xiàn)在的內(nèi)存中包含了 0.5 * 3 = 1.5秒的數(shù)據(jù)。是時候在下一步調(diào)用 Audio start 方法,正式開始播放了.

- (void)allocAudioQueue {
    AudioQueueBufferRef buffers[kNumberBuffer];
    
    OSStatus status = noErr;
    for(int i = 0 ; i< kNumberBuffer; i++) {
        status = AudioQueueAllocateBuffer(_mQueue,
                                          self.byteSizeInBuffer,
                                          &buffers[i]);
        printErr(@"AudioQueueAllocateBuffer", status);
        
        //手動調(diào)用回調(diào),用音頻文件中的音頻數(shù)據(jù)填充緩沖區(qū)。
        //后續(xù)調(diào)用AudioQueueStart后,會自動觸發(fā)回調(diào)進行調(diào)用
        jbAudioQueueOutputCallback((__bridge  void *)self, _mQueue, buffers[i]);
        if (self.isDone) {
            //回調(diào)函數(shù)中設(shè)置為true后,代表剩余時間小于1.5秒
            break;
        }
    }
}

11. 正式播放

前面所有的都配置齊全后就可以直接啟動 音頻隊列了。這時候就可以在默認(rèn)揚聲器里面聽到我們的音樂聲音了。
啟動后 音頻隊列會先消耗上一步,我們手動塞入隊列緩沖區(qū)的樣本。
然后會在特定的時間回調(diào)調(diào)用 jbAudioQueueOutputCallback 這個函數(shù)。

status = AudioQueueStart(_mQueue, NULL);
printErr(@"AudioQueueStart", status);

12. 回調(diào)函數(shù)

我們前面所有的都講了,現(xiàn)在開始理一理回調(diào)函數(shù)里面究竟做了啥。
首先定義這個函數(shù)使用了C的Static 靜態(tài)函數(shù)。

  • inUserData形參為我們在AudioQueueNewOutput里面?zhèn)魅氲膮?shù),這個原封不動的回傳了回來
  • inAQ對音頻隊列的引用, 我們不關(guān)心是3個隊里中的哪一個,系統(tǒng)會自動調(diào)度
  • inBuffer我們將文件中的音頻數(shù)據(jù)讀取后,需要將數(shù)據(jù)寫入這個內(nèi)存區(qū)域,然后系統(tǒng)會自動解碼播放。

這里的主要流程為:

  • 獲取JBPlayLocalMusicFile 實例對象
  • AudioFileReadPacketData從文件中讀取音頻數(shù)據(jù),并會填充_aspds這個音頻格式。最后numberBytes,numberPackets這兩個本地變量的值會被改變成實際本地從文件里面讀取的長度和包數(shù)量
  • 如果前面無誤的話,需要將上一步獲取的數(shù)據(jù),通過調(diào)用AudioQueueEnqueueBuffer 填充到 音頻隊列的緩沖區(qū)中,音頻隊列會按照以前設(shè)置的音頻流格式,和本地包的特定的_aspds數(shù)據(jù)進行綜合解碼和播放。
static void jbAudioQueueOutputCallback(void * inUserData,
                                       AudioQueueRef inAQ, //對音頻隊列的引用
                                       AudioQueueBufferRef inBuffer //需要填充的緩沖區(qū)播放數(shù)據(jù)的引用
) {
    
    JBPlayLocalMusicFile *playClass = (__bridge JBPlayLocalMusicFile *)inUserData;
    if (playClass->_isDone) {
        return;
    }
    
    // 存在局部變量中后,read數(shù)據(jù)的時候會 自動更新讀取到的值
    UInt32 numberBytes = playClass.byteSizeInBuffer;
    UInt32 numberPackets = playClass.packetsNumInBuffer;
    
    //讀取音頻包內(nèi)容,并在最后一個字段中將讀取到的數(shù)據(jù)填充到 inBuffer 中去
    OSStatus status = AudioFileReadPacketData(playClass->_audioFile,
                                              false,
                                              &numberBytes,
                                              playClass->_aspds,
                                              playClass.readOffsetOfPackets,
                                              &numberPackets,
                                              inBuffer->mAudioData);
    printErr(@"AudioFileReadPacketData", status);
    if (numberBytes <= 0 || numberPackets <= 0) {
        NSLog(@"數(shù)據(jù)讀取完畢");
        playClass->_isDone = true;
        dispatch_async(dispatch_get_main_queue(), ^{
            [playClass stop];
        });
        return;
    }
    
    inBuffer->mAudioDataByteSize = numberBytes;
    AudioQueueEnqueueBuffer(inAQ,
                            inBuffer,
                            (playClass->_aspds ? numberPackets : 0),
                            playClass->_aspds);
    //消費完后,更新下次需要讀取的文件的位置
    playClass.readOffsetOfPackets += numberPackets;
}

13. 停止音頻

意外停止和正常播完停止都需要調(diào)用這個函數(shù)。

  • AudioQueueStop停止隊列
  • AudioQueueDispose 處理音頻隊列,這里會處置其中的資源和緩沖區(qū)等,包括里面會自動調(diào)用AudioQueueAllocateBuffer對應(yīng)的析構(gòu)函數(shù)AudioQueueFreeBuffer
  • _aspds 如果有,就釋放
  • AudioFileClose最后關(guān)閉文件。
- (void)stop {
    
    OSStatus status = AudioQueueStop(_mQueue, true);
    printErr(@"AudioQueueStop", status);
    status = AudioQueueDispose(_mQueue, true);
    printErr(@"AAudioQueueDispose", status);
    if(_aspds) {
        free(_aspds);
    }
    status = AudioFileClose(_audioFile);
    printErr(@"AudioFileClose", status);
    self.isDone = true;
    NSLog(@"播放結(jié)束");
}

本文地址: https://blog.csdn.net/goldWave01/article/details/131834259 ??文章來源地址http://www.zghlxwxcb.cn/news/detail-607045.html

到了這里,關(guān)于macOS coreAudio 之 AudioQueue 播放本地音頻文件的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 一鍵搭建本地Wordpress環(huán)境 - MacOS

    一鍵搭建本地Wordpress環(huán)境 - MacOS

    寫在前面:博主是一只經(jīng)過實戰(zhàn)開發(fā)歷練后投身培訓(xùn)事業(yè)的“小山豬”,昵稱取自動畫片《獅子王》中的“彭彭”,總是以樂觀、積極的心態(tài)對待周邊的事物。本人的技術(shù)路線從Java全棧工程師一路奔向大數(shù)據(jù)開發(fā)、數(shù)據(jù)挖掘領(lǐng)域,如今終有小成,愿將昔日所獲與大家交流一二

    2024年02月03日
    瀏覽(11)
  • 【AIGC】MacOS 本地部署 Stable Diffusion

    【AIGC】MacOS 本地部署 Stable Diffusion

    其實要在本地部署 stable-diffusion 不難,只要有“魔法”一切都水到渠成,如下圖: 如果沒有魔法就建議到 gitee 中找一下是否有對應(yīng)的鏡像倉庫,我在 gitee 中找到的是: https://gitee.com/ai-liam/AUTOMATIC1111-stable-diffusion-webui.git 接著就是通過 brew 進行必要軟件的安裝了…這個 homebr

    2024年02月21日
    瀏覽(26)
  • MACOS Ventura 本地安裝HDFS 3.1.4

    MACOS Ventura 本地安裝HDFS 3.1.4

    1、終端,輸入第一條命令一直回車即可,然后將生成的將公鑰內(nèi)容寫入到 ~/.ssh/authorized_keys 中 2、系統(tǒng)登錄-共享-遠(yuǎn)程登錄,打開。如下: 3、官網(wǎng)下載安裝包并且解壓: Apache Hadoop? 4、修改 core-site.xml 5、修改 hdfs-site.xml 6、修改 yarn-site.xml 7、修改?mapred-site.xml 8、配置環(huán)境變

    2024年02月07日
    瀏覽(22)
  • macOS下ToDesk提示“正在重新連接本地服務(wù)...”

    macOS下ToDesk提示“正在重新連接本地服務(wù)...”

    之前在自己的Mac上安裝了ToDesk,用來遠(yuǎn)程家里的虛擬機。安裝完成之后第一次打開是可以用的,后面再打開發(fā)現(xiàn)提示“正在重新連接本地服務(wù)…”,重啟ToDesk和重啟電腦N多次也不管用,重裝ToDesk管用,但是遠(yuǎn)程一次之后又不行了,官網(wǎng)也沒有找到解決辦法。一次偶爾發(fā)現(xiàn),找

    2024年02月08日
    瀏覽(12)
  • 公網(wǎng)遠(yuǎn)程訪問macOS本地web服務(wù)器

    公網(wǎng)遠(yuǎn)程訪問macOS本地web服務(wù)器

    # 公網(wǎng)訪問macOS本地web服務(wù)器【內(nèi)網(wǎng)穿透】 以macOS自帶的Apache為例,在本地啟用apache服務(wù)器,并通過cpolar內(nèi)網(wǎng)穿透將其暴露至公網(wǎng),實現(xiàn)在公網(wǎng)環(huán)境下訪問本地web服務(wù)。 1. 啟動Apache服務(wù)器 在macOS上打開終端,執(zhí)行命令啟動Apache服務(wù)器,提示 Passwod ,輸入密碼 瀏覽器訪問localh

    2024年02月08日
    瀏覽(22)
  • DaVinci Resolve Studio 18.6.2 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作

    DaVinci Resolve Studio 18.6.2 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作

    DaVinci Resolve Studio 18.6.2 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作 Blackmagic Design DaVinci Resolve Studio 請訪問原文鏈接:https://sysin.org/blog/davinci-resolve-18/,查看最新版。原創(chuàng)作品,轉(zhuǎn)載請保留出處。 作者主頁:sysin.org 免費! 專業(yè)的剪輯、調(diào)色、特效和音頻后期制作 DaVinci

    2024年02月01日
    瀏覽(23)
  • DaVinci Resolve Studio 18.6.5 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作

    DaVinci Resolve Studio 18.6.5 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作

    DaVinci Resolve Studio 18.6.5 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作 Blackmagic Design DaVinci Resolve Studio 請訪問原文鏈接:DaVinci Resolve Studio 18.6.5 (macOS, Windows) - 剪輯、調(diào)色、特效和音頻后期制作,查看最新版。原創(chuàng)作品,轉(zhuǎn)載請保留出處。 作者主頁:sysin.org 免費! 專業(yè)的剪

    2024年02月21日
    瀏覽(19)
  • 如何在 macOS 中刪除 Time Machine 本地快照

    如何在 macOS 中刪除 Time Machine 本地快照

    看到這個可用82GB(458.3MB可清除) 頓時感覺清爽,之前的還是可用82GB(65GB可清除),安裝個xcode都安裝不上,費解半天,怎么都解決不了這個問題,就是買磁盤情理軟件也解決不了。 第一步:打開終端 第二步:輸入 這個命令是查找出來備份的哪些,按照日期來記錄。 第三

    2024年01月23日
    瀏覽(16)
  • Python實現(xiàn)本地視頻/音頻播放器

    Python實現(xiàn)本地視頻/音頻播放器

    在Python中,有幾個庫可以用于視頻播放,但是沒有一個庫是完美的,因為它們可能依賴于外部軟件或有一些限制。 先看介紹用Python實現(xiàn)本地視頻播放器,再介紹用Python實現(xiàn)本地音樂播放器。 Python 實現(xiàn)本地視頻播放器 與HTML5+JavaScript實現(xiàn)本地視頻播放器相比,使用Python實現(xiàn)比

    2024年04月26日
    瀏覽(15)
  • 如何在 macOS 使用 AList + RCLONE 把網(wǎng)盤掛載到本地

    如何在 macOS 使用 AList + RCLONE 把網(wǎng)盤掛載到本地

    之前接觸最多的可能還是百度網(wǎng)盤,它的免費容量比較大,我們在下載和分享一些文件的時候經(jīng)常會用到,但是如果文件比較大,加上限速,使用體驗并不算太好。其實除了下載文件,我很少使用百度網(wǎng)盤存儲文件,影視資源之類的內(nèi)容又經(jīng)常被和諧,所以就覺得網(wǎng)盤似乎也

    2024年01月19日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包