色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

OpenHarmony 3.2 Beta Audio:音頻渲染

電子發(fā)燒友開源社區(qū) ? 來源:未知 ? 2023-03-11 14:15 ? 次閱讀

一、簡介

Audio是多媒體子系統(tǒng)中的一個重要模塊,其涉及的內容比較多,有音頻的渲染、音頻的采集、音頻的策略管理等。本文主要針對音頻渲染功能進行詳細地分析,并通過源碼中提供的例子,對音頻渲染進行流程的梳理。

二、目錄

foundation/multimedia/audio_framework

audio_framework
├── frameworks
│  ├── js             #js 接口
│  │  └── napi
│  │    └── audio_renderer   #audio_renderer NAPI接口
│  │      ├── include
│  │      │  ├── audio_renderer_callback_napi.h
│  │      │  ├── renderer_data_request_callback_napi.h
│  │      │  ├── renderer_period_position_callback_napi.h
│  │      │  └── renderer_position_callback_napi.h
│  │      └── src
│  │        ├── audio_renderer_callback_napi.cpp
│  │        ├── audio_renderer_napi.cpp
│  │        ├── renderer_data_request_callback_napi.cpp
│  │        ├── renderer_period_position_callback_napi.cpp
│  │        └── renderer_position_callback_napi.cpp
│  └── native           #native 接口
│    └── audiorenderer
│      ├── BUILD.gn
│      ├── include
│      │  ├── audio_renderer_private.h
│      │  └── audio_renderer_proxy_obj.h
│      ├── src
│      │  ├── audio_renderer.cpp
│      │  └── audio_renderer_proxy_obj.cpp
│      └── test
│        └── example
│          └── audio_renderer_test.cpp
├── interfaces
│  ├── inner_api          #native實現的接口
│  │  └── native
│  │    └── audiorenderer    #audio渲染本地實現的接口定義
│  │      └── include
│  │        └── audio_renderer.h
│  └── kits            #js調用的接口
│    └── js
│      └── audio_renderer   #audio渲染NAPI接口的定義
│        └── include
│          └── audio_renderer_napi.h
└── services            #服務端
  └── audio_service
    ├── BUILD.gn
    ├── client         #IPC調用中的proxy端
    │  ├── include
    │  │  ├── audio_manager_proxy.h
    │  │  ├── audio_service_client.h
    │  └── src
    │    ├── audio_manager_proxy.cpp
    │    ├── audio_service_client.cpp
    └── server         #IPC調用中的server端
      ├── include
      │  └── audio_server.h
      └── src
        ├── audio_manager_stub.cpp
        └── audio_server.cpp

(左右移動查看全部內容)

三、音頻渲染總體流程

8946c0e8-bfd2-11ed-bfe3-dac502259ad0.png

四、Native接口使用

在OpenAtom OpenHarmony(以下簡稱“OpenHarmony”)系統(tǒng)中,音頻模塊提供了功能測試代碼,本文選取了其中的音頻渲染例子作為切入點來進行介紹,例子采用的是對wav格式的音頻文件進行渲染。wav格式的音頻文件是wav頭文件和音頻的原始數據,不需要進行數據解碼,所以音頻渲染直接對原始數據進行操作,文件路徑為:foundation/multimedia/audio_framework/frameworks/native/audiorenderer/test/example/audio_renderer_test.cpp

bool TestPlayback(int argc, char *argv[]) const
{
    FILE* wavFile = fopen(path, "rb");
    //讀取wav文件頭信息
    size_t bytesRead = fread(&wavHeader, 1, headerSize, wavFile);


    //設置AudioRenderer參數
    AudioRendererOptions rendererOptions = {};
    rendererOptions.streamInfo.encoding = AudioEncodingType::ENCODING_PCM;
    rendererOptions.streamInfo.samplingRate = static_cast(wavHeader.SamplesPerSec);
    rendererOptions.streamInfo.format = GetSampleFormat(wavHeader.bitsPerSample);
    rendererOptions.streamInfo.channels = static_cast(wavHeader.NumOfChan);
    rendererOptions.rendererInfo.contentType = contentType;
    rendererOptions.rendererInfo.streamUsage = streamUsage;
    rendererOptions.rendererInfo.rendererFlags = 0;


    //創(chuàng)建AudioRender實例
    unique_ptr audioRenderer = AudioRenderer::Create(rendererOptions);


    shared_ptr cb1 = make_shared();
    //設置音頻渲染回調
    ret = audioRenderer->SetRendererCallback(cb1);


    //InitRender方法主要調用了audioRenderer實例的Start方法,啟動音頻渲染
if(!InitRender(audioRenderer)) {
AUDIO_ERR_LOG("AudioRendererTest: Init render failed");
fclose(wavFile);
      return false;
}


    //StartRender方法主要是讀取wavFile文件的數據,然后通過調用audioRenderer實例的Write方法進行播放
if(!StartRender(audioRenderer, wavFile)) {
AUDIO_ERR_LOG("AudioRendererTest: Start render failed");
fclose(wavFile);
      return false;
}


    //停止渲染
if(!audioRenderer->Stop()) {
AUDIO_ERR_LOG("AudioRendererTest: Stop failed");
}


    //釋放渲染
if(!audioRenderer->Release()) {
AUDIO_ERR_LOG("AudioRendererTest: Release failed");
}


    //關閉wavFile
fclose(wavFile);
    return true;
}

(左右移動查看全部內容)

首先讀取wav文件,通過讀取到wav文件的頭信息對AudioRendererOptions相關的參數進行設置,包括編碼格式、采樣率、采樣格式、通道數等。根據AudioRendererOptions設置的參數來創(chuàng)建AudioRenderer實例(實際上是AudioRendererPrivate),后續(xù)的音頻渲染主要是通過AudioRenderer實例進行。創(chuàng)建完成后,調用AudioRenderer的Start方法,啟動音頻渲染。啟動后,通過AudioRenderer實例的Write方法,將數據寫入,音頻數據會被播放。

五、調用流程

895ca62e-bfd2-11ed-bfe3-dac502259ad0.png

1、創(chuàng)建AudioRenderer

std::unique_ptrAudioRenderer::Create(const std::string cachePath,
  const AudioRendererOptions &rendererOptions, const AppInfo &appInfo)
{
  ContentType contentType = rendererOptions.rendererInfo.contentType;


  StreamUsage streamUsage = rendererOptions.rendererInfo.streamUsage;


  AudioStreamType audioStreamType = AudioStream::GetStreamType(contentType, streamUsage);
  auto audioRenderer = std::make_unique(audioStreamType, appInfo);
  if (!cachePath.empty()) {
    AUDIO_DEBUG_LOG("Set application cache path");
    audioRenderer->SetApplicationCachePath(cachePath);
  }


  audioRenderer->rendererInfo_.contentType = contentType;
  audioRenderer->rendererInfo_.streamUsage = streamUsage;
  audioRenderer->rendererInfo_.rendererFlags = rendererOptions.rendererInfo.rendererFlags;


  AudioRendererParams params;
  params.sampleFormat = rendererOptions.streamInfo.format;
  params.sampleRate = rendererOptions.streamInfo.samplingRate;
  params.channelCount = rendererOptions.streamInfo.channels;
  params.encodingType = rendererOptions.streamInfo.encoding;


  if (audioRenderer->SetParams(params) != SUCCESS) {
    AUDIO_ERR_LOG("SetParams failed in renderer");
    audioRenderer = nullptr;
    return nullptr;
  }


  return audioRenderer;
}

(左右移動查看全部內容)

首先通過AudioStream的GetStreamType方法獲取音頻流的類型,根據音頻流類型創(chuàng)建AudioRendererPrivate對象,AudioRendererPrivate是AudioRenderer的子類。緊接著對audioRenderer進行參數設置,其中包括采樣格式、采樣率、通道數、編碼格式。設置完成后返回創(chuàng)建的AudioRendererPrivate實例。

2、設置回調

int32_t AudioRendererPrivate::SetRendererCallback(const std::shared_ptr &callback)
{
  RendererState state = GetStatus();
  if (state == RENDERER_NEW || state == RENDERER_RELEASED) {
    return ERR_ILLEGAL_STATE;
  }
  if (callback == nullptr) {
    return ERR_INVALID_PARAM;
  }


  // Save reference for interrupt callback
  if (audioInterruptCallback_ == nullptr) {
    return ERROR;
  }
  std::shared_ptr cbInterrupt =
    std::static_pointer_cast(audioInterruptCallback_);
  cbInterrupt->SaveCallback(callback);


  // Save and Set reference for stream callback. Order is important here.
  if (audioStreamCallback_ == nullptr) {
    audioStreamCallback_ = std::make_shared();
    if (audioStreamCallback_ == nullptr) {
      return ERROR;
    }
  }
  std::shared_ptr cbStream =
std::static_pointer_cast(audioStreamCallback_);
  cbStream->SaveCallback(callback);
  (void)audioStream_->SetStreamCallback(audioStreamCallback_);


  return SUCCESS;
}

(左右移動查看全部內容)

參數傳入的回調主要涉及到兩個方面:一方面是AudioInterruptCallbackImpl中設置了我們傳入的渲染回調,另一方面是AudioStreamCallbackRenderer中也設置了渲染回調。

3、啟動渲染

bool AudioRendererPrivate::Start(StateChangeCmdType cmdType) const
{
  AUDIO_INFO_LOG("AudioRenderer::Start");
  RendererState state = GetStatus();


  AudioInterrupt audioInterrupt;
  switch (mode_) {
    case InterruptMode:
      audioInterrupt = sharedInterrupt_;
      break;
    case InterruptMode:
      audioInterrupt = audioInterrupt_;
      break;
    default:
      break;
  }
  AUDIO_INFO_LOG("AudioRenderer: %{public}d, streamType: %{public}d, sessionID: %{public}d",
    mode_, audioInterrupt.streamType, audioInterrupt.sessionID);


  if (audioInterrupt.streamType == STREAM_DEFAULT || audioInterrupt.sessionID == INVALID_SESSION_ID) {
    return false;
  }


  int32_t ret = AudioPolicyManager::GetInstance().ActivateAudioInterrupt(audioInterrupt);
  if (ret != 0) {
    AUDIO_ERR_LOG("AudioRendererPrivate::ActivateAudioInterrupt Failed");
    return false;
  }


  return audioStream_->StartAudioStream(cmdType);
}

(左右移動查看全部內容)

AudioPolicyManager::GetInstance().ActivateAudioInterrupt這個操作主要是根據AudioInterrupt來進行音頻中斷的激活,這里涉及了音頻策略相關的內容,后續(xù)會專門出關于音頻策略的文章進行分析。這個方法的核心是通過調用AudioStream的StartAudioStream方法來啟動音頻流。

bool AudioStream::StartAudioStream(StateChangeCmdType cmdType)
{
  int32_t ret = StartStream(cmdType);


  resetTime_ = true;
  int32_t retCode = clock_gettime(CLOCK_MONOTONIC, &baseTimestamp_);


  if (renderMode_ == RENDER_MODE_CALLBACK) {
    isReadyToWrite_ = true;
    writeThread_ = std::make_unique<std::thread>(&AudioStream::WriteCbTheadLoop, this);
  } else if (captureMode_ == CAPTURE_MODE_CALLBACK) {
    isReadyToRead_ = true;
    readThread_ = std::make_unique<std::thread>(&AudioStream::ReadCbThreadLoop, this);
  }


  isFirstRead_ = true;
  isFirstWrite_ = true;
  state_ = RUNNING;
  AUDIO_INFO_LOG("StartAudioStream SUCCESS");


  if (audioStreamTracker_) {
    AUDIO_DEBUG_LOG("AudioStream:Calling Update tracker for Running");
    audioStreamTracker_->UpdateTracker(sessionId_, state_, rendererInfo_, capturerInfo_);
  }
  return true;
}

(左右移動查看全部內容)

AudioStream的StartAudioStream主要的工作是調用StartStream方法,StartStream方法是AudioServiceClient類中的方法。AudioServiceClient類是AudioStream的父類。接下來看一下AudioServiceClient的StartStream方法。

int32_t AudioServiceClient::StartStream(StateChangeCmdType cmdType)
{
  int error;
  lock_guardlockdata(dataMutex);
  pa_operation *operation = nullptr;


  pa_threaded_mainloop_lock(mainLoop);


  pa_stream_state_t state = pa_stream_get_state(paStream);


  streamCmdStatus = 0;
  stateChangeCmdType_ = cmdType;
  operation = pa_stream_cork(paStream, 0, PAStreamStartSuccessCb, (void *)this);


  while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
    pa_threaded_mainloop_wait(mainLoop);
  }
  pa_operation_unref(operation);
  pa_threaded_mainloop_unlock(mainLoop);


  if (!streamCmdStatus) {
    AUDIO_ERR_LOG("Stream Start Failed");
    ResetPAAudioClient();
    return AUDIO_CLIENT_START_STREAM_ERR;
  } else {
    AUDIO_INFO_LOG("Stream Started Successfully");
    return AUDIO_CLIENT_SUCCESS;
  }
}

(左右移動查看全部內容)

StartStream方法中主要是調用了pulseaudio庫的pa_stream_cork方法進行流啟動,后續(xù)就調用到了pulseaudio庫中了。pulseaudio庫我們暫且不分析。

4、寫入數據

int32_t AudioRendererPrivate::Write(uint8_t *buffer, size_t bufferSize)
{
  return audioStream_->Write(buffer, bufferSize);
}

(左右移動查看全部內容)

通過調用AudioStream的Write方式實現功能,接下來看一下AudioStream的Write方法。

size_t AudioStream::Write(uint8_t *buffer, size_t buffer_size)
{
  int32_t writeError;
  StreamBuffer stream;
  stream.buffer = buffer;
  stream.bufferLen = buffer_size;
  isWriteInProgress_ = true;


  if (isFirstWrite_) {
    if (RenderPrebuf(stream.bufferLen)) {
      return ERR_WRITE_FAILED;
    }
    isFirstWrite_ = false;
  }


  size_t bytesWritten = WriteStream(stream, writeError);
  isWriteInProgress_ = false;
  if (writeError != 0) {
    AUDIO_ERR_LOG("WriteStream fail,writeError:%{public}d", writeError);
    return ERR_WRITE_FAILED;
  }
  return bytesWritten;
}

(左右移動查看全部內容)

Write方法中分成兩個階段,首次寫數據,先調用RenderPrebuf方法,將preBuf_的數據寫入后再調用WriteStream進行音頻數據的寫入。

size_t AudioServiceClient::WriteStream(const StreamBuffer &stream, int32_t &pError)
{


  size_t cachedLen = WriteToAudioCache(stream);
  if (!acache.isFull) {
    pError = error;
    return cachedLen;
  }


  pa_threaded_mainloop_lock(mainLoop);




  const uint8_t *buffer = acache.buffer.get();
  size_t length = acache.totalCacheSize;


  error = PaWriteStream(buffer, length);
  acache.readIndex += acache.totalCacheSize;
  acache.isFull = false;


  if (!error && (length >= 0) && !acache.isFull) {
    uint8_t *cacheBuffer = acache.buffer.get();
    uint32_t offset = acache.readIndex;
    uint32_t size = (acache.writeIndex - acache.readIndex);
    if (size > 0) {
      if (memcpy_s(cacheBuffer, acache.totalCacheSize, cacheBuffer + offset, size)) {
        AUDIO_ERR_LOG("Update cache failed");
        pa_threaded_mainloop_unlock(mainLoop);
        pError = AUDIO_CLIENT_WRITE_STREAM_ERR;
        return cachedLen;
      }
      AUDIO_INFO_LOG("rearranging the audio cache");
    }
    acache.readIndex = 0;
    acache.writeIndex = 0;


    if (cachedLen < stream.bufferLen) {
      StreamBuffer str;
      str.buffer = stream.buffer + cachedLen;
      str.bufferLen = stream.bufferLen - cachedLen;
      AUDIO_DEBUG_LOG("writing pending data to audio cache: %{public}d", str.bufferLen);
      cachedLen += WriteToAudioCache(str);
    }
  }


  pa_threaded_mainloop_unlock(mainLoop);
  pError = error;
  return cachedLen;
}

(左右移動查看全部內容)

WriteStream方法不是直接調用pulseaudio庫的寫入方法,而是通過WriteToAudioCache方法將數據寫入緩存中,如果緩存沒有寫滿則直接返回,不會進入下面的流程,只有當緩存寫滿后,才會調用下面的PaWriteStream方法。該方法涉及對pulseaudio庫寫入操作的調用,所以緩存的目的是避免對pulseaudio庫頻繁地做IO操作,提高了效率。

六、總結

本文主要對OpenHarmony 3.2 Beta多媒體子系統(tǒng)的音頻渲染模塊進行介紹,首先梳理了Audio Render的整體流程,然后對幾個核心的方法進行代碼的分析。整體的流程主要通過pulseaudio庫啟動流,然后通過pulseaudio庫的pa_stream_write方法進行數據的寫入,最后播放出音頻數據。

音頻渲染主要分為以下幾個層次:

  1. AudioRenderer的創(chuàng)建,實際創(chuàng)建的是它的子類AudioRendererPrivate實例。

  2. 通過AudioRendererPrivate設置渲染的回調。

  3. 啟動渲染,這一部分代碼最終會調用到pulseaudio庫中,相當于啟動了pulseaudio的流。

  4. 通過pulseaudio庫的pa_stream_write方法將數據寫入設備,進行播放。


更多熱點文章閱讀
  • OS內核及視窗分論壇詳解之OpenHarmony 3D顯示支持
  • 應用模型開發(fā)指南上新介紹
  • 技術構筑萬物智聯,第一屆OpenHarmony技術峰會圓滿舉行
  • OpenHarmony L1(3.0)串口功能開發(fā)
  • 小白指南:手把手教你用低代碼開發(fā)一個應用頁面

提示:本文由電子發(fā)燒友論壇發(fā)布,轉載請注明來源。如需社區(qū)合作及入群交流,請?zhí)砑游⑿臙EFans0806,或者發(fā)郵箱liuyong@huaqiu.com。


原文標題:OpenHarmony 3.2 Beta Audio:音頻渲染

文章出處:【微信公眾號:電子發(fā)燒友開源社區(qū)】歡迎添加關注!文章轉載請注明出處。


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯系本站處理。 舉報投訴

原文標題:OpenHarmony 3.2 Beta Audio:音頻渲染

文章出處:【微信號:HarmonyOS_Community,微信公眾號:電子發(fā)燒友開源社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    請問cc3200 audio boosterpack音頻采集是不是底噪很大?

    基于TLV320AIC3254的音頻開發(fā)辦,我燒入wifi_audio_app例程(例程中關掉板載咪頭輸入,并將音量調到最大),另兩入輸入接口沒有接音頻信號,但是板子一直吱吱吱的響,是板子本身底噪就這么大嗎?
    發(fā)表于 10-25 06:28

    TPS6595 Audio Codec輸出音頻偶發(fā)混入7Khz雜波是怎么回事?

    主芯片是DM3730, 音頻使用的是TPS65950的Audio 外設。 DM3730使用MCBSP輸出8Khz音頻數據,通過I2C設置 TPS65950相關寄存器。 采用Audio
    發(fā)表于 10-15 07:08

    【龍芯2K0300蜂鳥板試用】OpenHarmony代碼

    fetch origin OpenHarmony-3.2-Release:OpenHarmony-3.2-Release git switch OpenHarmony-3.2
    發(fā)表于 09-18 11:42

    HarmonyOS NEXT Developer Beta1中的Kit

    管理服務)、Network Kit(網絡服務)等。 媒體相關Kit開放能力:Audio Kit(音頻服務)、Media Library Kit(媒體文件管理服務)等。 圖形相關Kit開放能力
    發(fā)表于 06-26 10:47

    使用提供的esp_audio_codec 的庫組件時,不能將AAC音頻解碼回PCM音頻,為什么?

    使用提供的esp_audio_codec 的庫組件時,能夠將PCM音頻編碼為AAC音頻,但是不能將AAC音頻解碼回PCM音頻,是為什么導致的
    發(fā)表于 06-05 06:39

    鴻蒙開發(fā)接口媒體:【@ohos.multimedia.audio (音頻管理)】

    音頻管理提供管理音頻的一些基礎能力,包括對音頻音量、音頻設備的管理,以及對音頻數據的采集和渲染
    的頭像 發(fā)表于 05-31 09:53 ?2465次閱讀
    鴻蒙開發(fā)接口媒體:【@ohos.multimedia.<b class='flag-5'>audio</b> (<b class='flag-5'>音頻</b>管理)】

    【RTC程序設計:實時音視頻權威指南】音頻采集與渲染

    在進行視頻的采集與渲染的同時,我們還需要對音頻進行實時的采集和渲染。對于rtc來說,音頻的實時性和流暢性更加重要。 聲音是由于物體在空氣中振動而產生的壓力波,聲波的存在依賴于空氣介質,
    發(fā)表于 04-28 21:00

    【開源鴻蒙】下載OpenHarmony 4.1 Release源代碼

    本文介紹了如何下載開源鴻蒙(OpenHarmony)操作系統(tǒng) 4.1 Release版本的源代碼,該方法同樣可以用于下載OpenHarmony最新開發(fā)版本(master分支)或者4.0 Release、3.2 Release等發(fā)
    的頭像 發(fā)表于 04-27 23:16 ?904次閱讀
    【開源鴻蒙】下載<b class='flag-5'>OpenHarmony</b> 4.1 Release源代碼

    鴻蒙ArkUI開發(fā)學習:【渲染控制語法】

    ArkUI開發(fā)框架是一套構建 HarmonyOS / OpenHarmony 應用界面的聲明式UI開發(fā)框架,它支持程序使用?`if/else`?條件渲染,?`ForEach`?循環(huán)渲染以及?`LazyForEach`?懶加載
    的頭像 發(fā)表于 04-09 16:40 ?981次閱讀
    鴻蒙ArkUI開發(fā)學習:【<b class='flag-5'>渲染</b>控制語法】

    潤開鴻全場景應用開發(fā)實訓平臺通過OpenHarmony兼容性測評

    近日,江蘇潤開鴻數字科技有限公司(以下簡稱“潤開鴻”)基于OpenHarmony的全場景應用開發(fā)實訓平臺通過OpenHarmony 3.2. Release版本兼容性測評,為高校開展
    的頭像 發(fā)表于 01-22 10:08 ?702次閱讀

    潤開鴻基于OpenHarmony的全場景應用開發(fā)實訓平臺通過兼容性測評

    近日,江蘇潤開鴻數字科技有限公司(以下簡稱“潤開鴻”)基于OpenHarmony的全場景應用開發(fā)實訓平臺通過OpenHarmony3.2.Release版本兼容性測評,為高校開展
    的頭像 發(fā)表于 01-20 08:02 ?544次閱讀
    潤開鴻基于<b class='flag-5'>OpenHarmony</b>的全場景應用開發(fā)實訓平臺通過兼容性測評

    藍牙m(xù)idi和藍牙音頻或者藍牙audio有什么區(qū)別呢

    藍牙m(xù)idi和藍牙音頻或者藍牙audio有什么區(qū)別呢 首先這里分為三個概念,也就是什么是藍牙?什么是藍牙m(xù)idi?什么是藍牙音頻audio? 1、什么是藍牙,這個就不用贅述了,大家
    的頭像 發(fā)表于 01-09 15:22 ?1165次閱讀
    藍牙m(xù)idi和藍牙<b class='flag-5'>音頻</b>或者藍牙<b class='flag-5'>audio</b>有什么區(qū)別呢

    OpenHarmony Sheet 表格渲染引擎

    基于 Canvas 實現的高性能 Excel 表格引擎組件 [OpenHarmonySheet]。 由于大部分前端項目渲染層是使用框架根據排版模型樹結構逐層渲染的,整棵渲染樹也是與排版
    發(fā)表于 01-05 16:32

    揭秘:實時渲染、離線渲染、云渲染和混合渲染的區(qū)別

    渲染,就是將3D模型轉換成2D圖像,并最終呈現在屏幕上的過程。常見的渲染類型有以下幾種:實時渲染離線渲染渲染混合
    的頭像 發(fā)表于 12-26 08:27 ?810次閱讀
    揭秘:實時<b class='flag-5'>渲染</b>、離線<b class='flag-5'>渲染</b>、云<b class='flag-5'>渲染</b>和混合<b class='flag-5'>渲染</b>的區(qū)別

    OpenHarmony開源GPU庫Mesa3D適配說明

    本文檔主要講解在OpenHarmony中,Mesa3D的適配方法及原理說明。 環(huán)境說明: OHOS版本: 適用3.2-Beta3及以上 內核版本: linux-5.10 硬件環(huán)境
    發(fā)表于 12-25 11:38
    主站蜘蛛池模板: 国产GV无码A片在线观看| 在线国内自拍精品视频| 久久久久久88色偷偷| av无码在线日本天堂| 日日夜夜狠狠干| 国产在线高清亚洲精品一区| 直插下身完整的欧美版| 日本人六九视频| 国内精品久久久久影院男同志| 最新国产在线视频| 日韩亚洲视频一区二区三区| 黄色亚洲片| avove主播| 亚洲AV天堂无码麻豆电影| 久久五月综合婷婷中文云霸高清| 把腿张开再深点好爽宝贝动态图| 亚洲AV色香蕉一区二区9255| 美女黄图大全| 国产成人在线视频免费观看| 伊人影院2019| 日本一在线中文字幕| 精品国产手机视频在在线| gv肉片视频免费观看| 亚洲成人99| 欧美人成人亚洲专区中文字幕| 国产精品久久久久久久AV下载 | 国产精品亚洲专一区二区三区| 亚洲中文有码字幕日本| 情欲.美女高潮| 精品国产在线手机在线| 把腿张开老子CAO烂你动态图| 亚洲色婷婷久久精品AV蜜桃久久| 欧美18videosex初次| 花蝴蝶在线观看免费8| ava云直播| 亚洲一区免费看| 日韩欧美一区二区三区在线视频 | 再插深点嗯好大好爽| 日本最新免费区中文| 久久理伦片琪琪电影院| 国产精品AV视频一二三区|