在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

OpenHarmony 3.2 Beta多媒體系列:音視頻播放框架

電子發燒友開源社區 ? 來源:未知 ? 2022-11-23 09:40 ? 次閱讀

巴延興

深圳開鴻數字產業發展有限公司

資深OS框架開發工程師

以下內容來自嘉賓分享,不代表開放原子開源基金會觀點

一、簡介

媒體子系統為開發者提供一套接口,方便開發者使用系統的媒體資源,主要包含音視頻開發、相機開發、流媒體開發等模塊。每個模塊都提供給上層應用對應的接口,本文會對音視頻開發中的音視頻播放框架做一個詳細的介紹。

二、目錄

foundation/multimedia/media_standard
├── frameworks                        #框架代碼
│ ├── js
│ │ ├── player
│ ├── native
│ │ ├── player                    #native實現
│ └── videodisplaymanager         #顯示管理
│     ├── include
│     └── src
├── interfaces
│ ├── inner_api                     #內部接口
│ │ └── native
│ └── kits                          #外部JS接口
├── sa_profile                        #服務配置文件
└── services
  ├── engine                        #engine代碼
  │ └── gstreamer
  ├── etc                           #服務配置文件
  ├── include                       #頭文件
  └── services
    ├── sa_media                  #media服務
    │ ├── client                #media客戶端
    │ ├── ipc                   #media ipc調用
    │ └── server                #media服務端
    ├── factory                   #engine工廠
    └── player                    #player服務
     ├── client                 #player客戶端
      ├── ipc                    #player ipc調用
└──server#player服務端

三、播放的總體流程

ab3cba20-6acf-11ed-8abf-dac502259ad0.png ?

四、Native接口使用

OpenHarmony系統中,音視頻播放通過N-API接口提供給上層JS調用,N-API相當于是JS和Native之間的橋梁,在OpenHarmony源碼中,提供了C++直接調用的音視頻播放例子,在foundation/multimedia/player_framework/test/nativedemo/player目錄中。
void PlayerDemo::RunCase(const string &path)
{
    player_ = OHOS::CreatePlayer();
    if (player_ == nullptr) {
        cout << "player_ is null" << endl;
        return;
    }
    RegisterTable();
    std::shared_ptr cb = std::make_shared();
    cb->SetBufferingOut(SelectBufferingOut());


    int32_t ret = player_->SetPlayerCallback(cb);
    if (ret != 0) {
        cout << "SetPlayerCallback fail" << endl;
    }
    if (SelectSource(path) != 0) {
        cout << "SetSource fail" << endl;
        return;
    }
    sptr producerSurface = nullptr;
    producerSurface = GetVideoSurface();
    if (producerSurface != nullptr) {
        ret = player_->SetVideoSurface(producerSurface);
        if (ret != 0) {
            cout << "SetVideoSurface fail" << endl;
        }
    }
    SetVideoScaleType();
    if (SelectRendererMode() != 0) {
        cout << "set renderer info fail" << endl;
    }
    ret = player_->PrepareAsync();
    if (ret !=  0) {
        cout << "PrepareAsync fail" << endl;
        return;
    }
    cout << "Enter your step:" << endl;
    DoNext();
}
首先根據RunCase可以大致了解一下播放音視頻的主要流程,創建播放器,設置播放源,設置回調方法(包含播放過程中的多種狀態的回調),設置播放顯示的Surface,這些準備工作做好之后,需要調用播放器的PrepareASync方法,這個方法完成后,播放狀態會變成Prepared狀態,這時就可以調用播放器的play接口,進行音視頻的播放了。 RegisterTable()方法中,將字符串和對應的方法映射到Map中,這樣后續的DoNext會根據輸入的命令,來決定播放器具體的操作。
void PlayerDemo::DoNext()
{
    std::string cmd;
    while (std::cin, cmd)) {
        auto iter = playerTable_.find(cmd);
        if (iter != playerTable_.end()) {
            auto func = iter->second;
            if (func() != 0) {
                cout << "Operation error" << endl;
            }
            if (cmd.find("stop") != std::npos && dataSrc_ != nullptr) {
                dataSrc_->Reset();
            }
            continue;
        } else if (cmd.find("quit") != std::npos || cmd == "q") {
            break;
        } else {
            DoCmd(cmd);
            continue;
        }
    }
}


void PlayerDemo::RegisterTable()
{
    (void)playerTable_.emplace("prepare", std::bind(&Player::Prepare, player_));
    (void)playerTable_.emplace("prepareasync", std::bind(&Player::PrepareAsync, player_));
    (void)playerTable_.emplace("", std::bind(&Player::Play, player_)); // ENTER -> play
    (void)playerTable_.emplace("play", std::bind(&Player::Play, player_));
    (void)playerTable_.emplace("pause", std::bind(&Player::Pause, player_));
    (void)playerTable_.emplace("stop", std::bind(&Player::Stop, player_));
    (void)playerTable_.emplace("reset", std::bind(&Player::Reset, player_));
    (void)playerTable_.emplace("release", std::bind(&Player::Release, player_));
    (void)playerTable_.emplace("isplaying", std::bind(&PlayerDemo::GetPlaying, this));
    (void)playerTable_.emplace("isloop", std::bind(&PlayerDemo::GetLooping, this));
    (void)playerTable_.emplace("speed", std::bind(&PlayerDemo::GetPlaybackSpeed, this));
}
以上的DoNext方法中核心的代碼是func()的調用,這個func就是之前注冊進Map中字符串對應的方法,在RegisterTable方法中將空字符串""和"play"對綁定為Player::Play方法,默認不輸入命令參數時,是播放操作。

五、調用流程

ab47b74a-6acf-11ed-8abf-dac502259ad0.jpgab6a3888-6acf-11ed-8abf-dac502259ad0.jpg ? ?

左右滑動查看更多

本段落主要針對媒體播放的框架層代碼進行分析,所以在流程中涉及到了IPC調用相關的客戶端和服務端,代碼暫且分析到調用gstreamer引擎。 首先Sample通過PlayerFactory創建了一個播放器實例(PlayerImpl對象),創建過程中調用Init函數。
int32_t PlayerImpl::Init()
{
    playerService_ = MediaServiceFactory::GetInstance().CreatePlayerService();
    CHECK_AND_RETURN_RET_LOG(playerService_ != nullptr, MSERR_UNKNOWN, "failed to create player service");
    return MSERR_OK;
}
MediaServiceFactory::GetInstance()返回的是MediaClient對象,所以CreateplayerService函數實際上是調用了MediaClient對應的方法。
std::shared_ptr MediaClient::CreatePlayerService()
{
    std::lock_guard lock(mutex_);
    if (!IsAlived()) {
        MEDIA_LOGE("media service does not exist.");
        return nullptr;
    }


    sptr object = mediaProxy_->GetSubSystemAbility(
        IStandardMediaService::MEDIA_PLAYER, listenerStub_->AsObject());
    CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "player proxy object is nullptr.");


    sptr playerProxy = iface_cast(object);
    CHECK_AND_RETURN_RET_LOG(playerProxy != nullptr, nullptr, "player proxy is nullptr.");


    std::shared_ptr player = PlayerClient::Create(playerProxy);
    CHECK_AND_RETURN_RET_LOG(player != nullptr, nullptr, "failed to create player client.");


    playerClientList_.push_back(player);
    return player;
}
這個方法中主要通過PlayerClient::Create(playerProxy)方法創建了PlayerClient實例,并且將該實例一層層向上傳,最終傳給了PlayerImpl的playerService_變量,后續對于播放器的操作,PlayerImpl都是通過調用PlayerClient實例實現的。
int32_t PlayerImpl::Play()
{
    CHECK_AND_RETURN_RET_LOG(playerService_ != nullptr, MSERR_INVALID_OPERATION, "player service does not exist..");
    MEDIA_LOGW("KPI-TRACE: PlayerImpl Play in");
    return playerService_->Play();
}


int32_t PlayerImpl::Prepare()
{
    CHECK_AND_RETURN_RET_LOG(playerService_ != nullptr, MSERR_INVALID_OPERATION, "player service does not exist..");
    MEDIA_LOGW("KPI-TRACE: PlayerImpl Prepare in");
    return playerService_->Prepare();
}


int32_t PlayerImpl::PrepareAsync()
{
    CHECK_AND_RETURN_RET_LOG(playerService_ != nullptr, MSERR_INVALID_OPERATION, "player service does not exist..");
    MEDIA_LOGW("KPI-TRACE: PlayerImpl PrepareAsync in");
    return playerService_->PrepareAsync();
}
對于PlayerImpl來說,playerService_指向的PlayerClient就是具體的實現,PlayerClient的實現是通過IPC的遠程調用來實現的,具體地是通過IPC中的proxy端向遠端服務發起遠程調用請求。 我們以播放Play為例:
int32_t PlayerClient::Play()
{
    std::lock_guard lock(mutex_);
    CHECK_AND_RETURN_RET_LOG(playerProxy_ != nullptr, MSERR_NO_MEMORY, "player service does not exist..");
    return playerProxy_->Play();
}
int32_t PlayerServiceProxy::Play()
{
    MessageParcel data;
    MessageParcel reply;
    MessageOption option;


    if (!data.WriteInterfaceToken(PlayerServiceProxy::GetDescriptor())) {
        MEDIA_LOGE("Failed to write descriptor");
        return MSERR_UNKNOWN;
    }


    int error = Remote()->SendRequest(PLAY, data, reply, option);
    if (error != MSERR_OK) {
        MEDIA_LOGE("Play failed, error: %{public}d", error);
        return error;
    }
    return reply.ReadInt32();
}
proxy端發送調用請求后,對應的Stub端會在PlayerServiceStub::OnRemoteRequest接收到請求,根據請求的參數進行對應的函數調用。播放操作對應的調用Stub的Play方法。
int32_t PlayerServiceStub::Play()
{
    MediaTrace Trace("binder::Play");
    CHECK_AND_RETURN_RET_LOG(playerServer_ != nullptr, MSERR_NO_MEMORY, "player server is nullptr");
    return playerServer_->Play();
}
這里最終是通過playerServer_調用Play函數。playerServer_在Stub初始化的時候通過PlayerServer::Create()方式來獲取得到。也就是PlayerServer。
std::shared_ptr PlayerServer::Create()
{
    std::shared_ptr server = std::make_shared();
    CHECK_AND_RETURN_RET_LOG(server != nullptr, nullptr, "failed to new PlayerServer");


    (void)server->Init();
    return server;
}
最終我們的Play調用到了PlayerServer的Play()。在媒體播放的整個過程中會涉及到很多的狀態,所以在Play中進行一些狀態的判讀后調用OnPlay方法。這個方法中發起了一個播放的任務。
int32_t PlayerServer::Play()
{
    std::lock_guard lock(mutex_);


    if (lastOpStatus_ == PLAYER_PREPARED || lastOpStatus_ == PLAYER_PLAYBACK_COMPLETE ||
        lastOpStatus_ == PLAYER_PAUSED) {
        return OnPlay();
    } else {
        MEDIA_LOGE("Can not Play, currentState is %{public}s", GetStatusDescription(lastOpStatus_).c_str());
        return MSERR_INVALID_OPERATION;
    }
}


int32_t PlayerServer::OnPlay()
{
    auto playingTask = std::make_shared>([this]() {
        MediaTrace::TraceBegin("PlayerServer::Play", FAKE_POINTER(this));
        auto currState = std::static_pointer_cast(GetCurrState());
        (void)currState->Play();
    });


    int ret = taskMgr_.LaunchTask(playingTask, PlayerServerTaskType::STATE_CHANGE);
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Play failed");


    lastOpStatus_ = PLAYER_STARTED;
    return MSERR_OK;
}
在播放任務中調用了PlayerServer::Play()
int32_t PlayerServer::Play()
{
    return server_.HandlePlay();
}
在Play里面直接調用PlayerServer的HandlePlay方法,HandlePlay方法通過playerEngine_調用到了gstreamer引擎,gstreamer是最終播放的實現。
int32_t PlayerServer::HandlePlay()
{
    int32_t ret = playerEngine_->Play();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Engine Play Failed!");


    return MSERR_OK;
}

六、總結

本文主要對OpenHarmony 3.2 Beta多媒體子系統的媒體播放進行介紹,首先梳理了整體的播放流程,然后對播放的主要步驟進行了詳細地分析。 媒體播放主要分為以下幾個層次:

(1)提供給應用調用的Native接口,這個實際上通過OHOS::CreatePlayer()調用返回PlayerImpl實例。

(2)PlayerClient,這部分通過IPC的proxy調用,向遠程服務發起調用請求。

(3)PlayerServer,這部分是播放服務的實現端,提供給Client端調用。

(4)Gstreamer,這部分是提供給PlayerServer調用,真正實現媒體播放的功能。

更多熱點文章閱讀

  • 玩嗨OpenHarmony:基于OpenHarmony的智能助老服務機器人
  • 玩嗨OpenHarmony:基于OpenHarmony的智慧農業環境監控系統
  • 基于OpenHarmony的智慧牧場方案:生物姿態檢測篇
  • 基于OpenHarmony的智慧牧場方案:生物心率檢測篇
  • 使用ADS1115擴展ROC-RK3568-PC開發板ADC功能

提示:本文由電子發燒友社區發布,轉載請注明以上來源。如需社區合作及入群交流,請添加微信EEFans0806,或者發郵箱[email protected]


原文標題:OpenHarmony 3.2 Beta多媒體系列:音視頻播放框架

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


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

    關注

    33

    文章

    557

    瀏覽量

    33311
  • 開源社區
    +關注

    關注

    0

    文章

    95

    瀏覽量

    573

原文標題:OpenHarmony 3.2 Beta多媒體系列:音視頻播放框架

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

收藏 人收藏

    評論

    相關推薦

    實用調試技能:全志T113-i 音視頻測試

    前言:音視頻功能是現代嵌入式系統中的核心應用之一,尤其在全志T113-i開發板中,其豐富的音視頻接口為開發者提供了強大的開發能力。本篇文章將帶你快速掌握T113-i平臺下音視頻模塊的調試技能,通過
    的頭像 發表于 03-06 08:31 ?1098次閱讀
    實用調試技能:全志T113-i <b class='flag-5'>音視頻</b>測試

    【北京迅為】itop-3568 開發板openharmony鴻蒙燒寫及測試-第2章OpenHarmony v3.2-Beta4版本測試

    【北京迅為】itop-3568 開發板openharmony鴻蒙燒寫及測試-第2章OpenHarmony v3.2-Beta4版本測試
    的頭像 發表于 03-05 10:53 ?278次閱讀
    【北京迅為】itop-3568 開發板<b class='flag-5'>openharmony</b>鴻蒙燒寫及測試-第2章<b class='flag-5'>OpenHarmony</b> v<b class='flag-5'>3.2-Beta</b>4版本測試

    RK628H:高端音視頻處理與傳輸芯片詳解

    RK628H是一款集高清音視頻處理與傳輸功能于一體的高端芯片,專為滿足現代多媒體設備對高分辨率、高幀率視頻以及高質量音頻的需求而設計。其強大的音視頻處理能力和多樣化的輸入輸出接口,使得
    的頭像 發表于 02-10 17:56 ?860次閱讀

    RK3588核心板多媒體功能一覽

    前言:RK3588支持8K視頻編碼和解碼,以及多路視頻源同時解碼,為視頻處理和多媒體應用提供了強大的支持,本文則從音視頻兩個功能測試上來認識
    的頭像 發表于 12-12 08:31 ?1302次閱讀
    RK3588核心板<b class='flag-5'>多媒體</b>功能一覽

    AMS-HE200:HDMI音視頻網絡延長器,開啟傳輸新時代

    在數字化時代,高清音視頻傳輸已經成為各行各業不可或缺的重要技術。無論是安防監控、視頻會議,還是戶外廣告、家庭影院,高清音視頻信號的無縫傳輸都扮演著至關重要的角色。深圳市程達科技有限公司,作為高清
    的頭像 發表于 11-27 10:04 ?435次閱讀
    AMS-HE200:HDMI<b class='flag-5'>音視頻</b>網絡延長器,開啟傳輸新時代

    如何在音頻播放時插播音頻

    ZDP14x0系列芯片是內置開源GUI引擎的圖像顯示專用驅動芯片,內部集成16MB/64MB顯示內存、2D圖形加速器、音視頻解碼器等豐富多媒體功能。不僅支持音視頻
    的頭像 發表于 11-25 15:40 ?994次閱讀
    如何在音頻<b class='flag-5'>播放</b>時插播音頻

    Amoonsky創新音視頻連接技術:全新推出AMS-HE200 HDMI網線延長器

    簡介: 在不斷向高清多媒體體驗邁進的世界中,強大的音視頻連接需求變得前所未有的重要。AMS-HE200,Amoonsky開創性的HDMI網線延長器,成為重新定義音視頻網絡格局的解決方案。這款創新
    的頭像 發表于 10-24 16:09 ?413次閱讀
    Amoonsky創新<b class='flag-5'>音視頻</b>連接技術:全新推出AMS-HE200 HDMI網線延長器

    dm368錄制音視頻后用vlc播放不同步是怎么回事?

    目前我們用其他的開發板 能夠錄制音視頻,但是用vlc播放的時候發現每次都是視頻播放完成了音頻還要播放一會,隨著錄制時間加上,延后的這個時間
    發表于 10-15 06:56

    基于ArkTS語言的OpenHarmony APP應用開發:多媒體管理2

    播放按鈕,視頻開始播放。再次點擊視頻進入視頻全屏頁。 首頁下滑500vp后,視頻小窗口化。 4.
    發表于 09-20 13:47

    盤點那些常見音視頻接口

    我們熟知的一些常見音視頻接口,發展至今在日常使用中已經漸漸少了。但是在工業領域的音視頻連接,依然能看到其身影。這些看似消失的接口,它們現在發展成什么樣子了?本期我們將做一個大盤點。
    的頭像 發表于 09-09 14:34 ?946次閱讀

    常見音視頻接口的靜電浪涌防護和濾波方案

    音視頻接口在現代多媒體設備中扮演著至關重要的角色,它們確保了音視頻信號在不同設備間的順暢傳輸,各種類型的音視頻接口滿足了多樣化的應用場景需求。 在
    的頭像 發表于 06-25 11:28 ?1006次閱讀

    音視頻產品EMC整改案例解析

    音視頻產品EMCRE整改案例解析
    的頭像 發表于 05-20 16:49 ?632次閱讀
    <b class='flag-5'>音視頻</b>產品EMC整改案例解析

    分享一款高清HDMI音視頻采集編碼卡,支持雙碼流

    “靈卡CAS”系列HDMI音視頻采集卡。獨具匠心的設計與功能配置,適用于各種規模的商務會議、多媒體教育以及數字化展示等各類場景。
    的頭像 發表于 05-07 11:43 ?596次閱讀
    分享一款高清HDMI<b class='flag-5'>音視頻</b>采集編碼卡,支持雙碼流

    【RTC程序設計:實時音視頻權威指南】音視頻的編解碼壓縮技術

    音視頻所載有的信息在通過傳輸的時候就需要壓縮編碼。 其中,文本壓縮是指通過使用各種算法和技術,將文本數據表示為更緊湊的形式,以減少存儲空間。 霍夫曼編碼是一種無損壓縮算法,它可以根據字符出現
    發表于 04-28 21:04

    音視頻SoC與AI技術融合,帶來更智能的音視頻處理解決方案

    電子發燒友網報道(文/李彎彎)音視頻SoC,即音視頻系統級芯片或片上系統,是一種高度集成化的芯片,它將電路板上的多塊芯片以及嵌入式軟件全部集成到一塊芯片中。音視頻SoC芯片廣泛應用于各種嵌入式系統
    的頭像 發表于 04-26 01:20 ?4992次閱讀
    主站蜘蛛池模板: 欧美午夜在线视频 | 91视频色 | 色天使在线观看 | 精品三级在线 | 俺去啦网婷婷 | 性喷潮久久久久久久久 | 欧美一级在线观看 | 免费大秀视频在线播放 | 韩彩英三级无删版甜性涩爱 | 天天在线天天看成人免费视频 | 欧美美女福利视频 | 激情五月激情综合网 | 人操人摸 | 亚洲黄站 | 午夜日批 | 欧美色欧美亚洲高清在线观看 | 5g影院天天爽| 有码视频在线观看 | 国产精品毛片在线大全 | 色在线播放 | 欧美三级中文字幕hd | 日日夜操 | 新天堂| aaa一级黄色片 | 欧美一区二区三区男人的天堂 | 成人区精品一区二区毛片不卡 | 丁香午夜婷婷 | 天天综合射 | 国产大片免费观看中文字幕 | 玖玖玖精品视频免费播放 | 免费看h的网站 | 欧美黄色片在线 | 日本一区二区三区免费看 | 中文字幕一区二区三区 精品 | 亚洲不卡视频 | xxx亚洲日本 | bt天堂资源种子在线 | 亚洲 另类色区 欧美日韩 | 五月综合激情 | 黄色美女网站免费 | 国产在线观看午夜不卡 |