一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

電子發(fā)燒友開源社區(qū) ? 來源:未知 ? 2022-11-25 09:10 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

1f5e2716-6c5d-11ed-8abf-dac502259ad0.png

巴延興

深圳開鴻數(shù)字產(chǎn)業(yè)發(fā)展有限公司

資深OS框架開發(fā)工程師

一、 簡介

多媒體播放框架主要的實(shí)現(xiàn)在PlayerServer服務(wù)中,這個服務(wù)提供了媒體播放框架所需要的實(shí)現(xiàn)環(huán)境,繼續(xù)跟蹤代碼分析發(fā)現(xiàn),PlayerServer主要通過gstreamer適配層,對gstreamer進(jìn)行調(diào)用。gstreamer屬于更加具體的實(shí)現(xiàn),所以本篇文章主要是分析PlayerServer通過適配層調(diào)用到gstreamer的過程。

此前,我在《OpenHarmony 3.2 Beta多媒體系列-音視頻播放框架》一文中,主要分析了多媒體播放的框架層代碼,本地接口通過服務(wù)端的proxy代理類進(jìn)行IPC調(diào)用,最終調(diào)用到PlayerServer服務(wù)端。本篇主要分析了多媒體gstreamer的調(diào)用,涉及到從PlayerServer到gstreamer的整體流程。

二、 目錄

  gstreamer
    ├── BUILD.gn
    ├── common
    │   ├── BUILD.gn
    │   ├── playbin_adapter
    │   │   ├── i_playbin_ctrler.h
    │   │   ├── playbin2_ctrler.cpp
    │   │   ├── playbin2_ctrler.h
    │   │   ├── playbin_ctrler_base.cpp
    │   │   ├── playbin_ctrler_base.h
    │   │   ├── playbin_msg_define.h
    │   │   ├── playbin_sink_provider.h
    │   │   ├── playbin_state.cpp
    │   │   ├── playbin_state.h
    │   │   ├── playbin_task_mgr.cpp
    │   │   └── playbin_task_mgr.h
    │   ├── state_machine
    │   │   ├── state_machine.cpp
    │   │   └── state_machine.h
    ├── factory
    │   ├── BUILD.gn
    │   └── engine_factory.cpp
    └── player
        ├── BUILD.gn
        ├── player_codec_ctrl.cpp
        ├── player_codec_ctrl.h
        ├── player_engine_gst_impl.cpp
        ├── player_engine_gst_impl.h
        ├── player_sinkprovider.cpp
        ├── player_sinkprovider.h
        ├── player_track_parse.cpp
        └── player_track_parse.h

目錄主要是多媒體子系統(tǒng)中的engine部分,涉及到了gstreamer的適配層,gstreamer具體的實(shí)現(xiàn)是在third_party/gstreamer目錄中。

三 、Gstreamer介紹


1. 簡介
Gstreamer是一個跨平臺的多媒體框架,應(yīng)用程序可以通過管道(Pipeline)的方式,將多媒體處理的各個步驟串聯(lián)起來,達(dá)到預(yù)期的效果。每個步驟通過元素(Element)基于GObject對象系統(tǒng)通過插件(plugins)的方式實(shí)現(xiàn),方便了各項(xiàng)功能的擴(kuò)展。

1f86b4ce-6c5d-11ed-8abf-dac502259ad0.png

2.Gstreamer幾個重要的概念
Element

Element是Gstreamer中最重要的對象類型之一。一個element實(shí)現(xiàn)一個功能(讀取文件,解碼,輸出等),程序需要創(chuàng)建多個element,并按順序?qū)⑵浯?lián)起來,構(gòu)成一個完整的Pipeline。

Pad

Pad是一個element的輸入/輸出接口,分為src pad(生產(chǎn)數(shù)據(jù))和sink pad(消費(fèi)數(shù)據(jù))兩種。兩個element必須通過pad才能連接起來,pad擁有當(dāng)前element能處理數(shù)據(jù)類型的能力(capabilities),會在連接時通過比較src pad和sink pad中所支持的能力,來選擇最恰當(dāng)?shù)臄?shù)據(jù)類型用于傳輸,如果element不支持,程序會直接退出。在element通過pad連接成功后,數(shù)據(jù)會從上一個element的src pad傳到下一個element的sink pad然后進(jìn)行處理。

Bin和Pipeline

Bin是一個容器,用于管理多個element,改變bin的狀態(tài)時,bin會自動去修改所包含的element的狀態(tài),也會轉(zhuǎn)發(fā)所收到的消息。如果沒有bin,我們需要依次操作我們所使用的element。通過bin降低了應(yīng)用的復(fù)雜度。

Pipeline繼承自bin,為程序提供一個bus用于傳輸消息,并且對所有子element進(jìn)行同步。當(dāng)將Pipeline的狀態(tài)設(shè)置為PLAYING時,Pipeline會在一個/多個新的線程中通過element處理數(shù)據(jù)。

四、調(diào)用流程

1fadedbe-6c5d-11ed-8abf-dac502259ad0.jpg1fd356d0-6c5d-11ed-8abf-dac502259ad0.jpg ?

左右滑動查看更多

五、源碼分析

1. PrepareAsync分析


首先,在PlayerServer的PrepareAsync中會調(diào)用OnPrepare(false),具體是在OnPrepare(false)中實(shí)現(xiàn),參數(shù)傳入false,表明調(diào)用的是異步方法。

int32_tPlayerServer::PrepareAsync()
{
    std::lock_guard<std::mutex> lock(mutex_);
    MEDIA_LOGW("KPI-TRACE: PlayerServer PrepareAsync in");


    if (lastOpStatus_ == PLAYER_INITIALIZED || lastOpStatus_ == PLAYER_STOPPED) {
        return OnPrepare(false);
    } else {
        MEDIA_LOGE("Can not Prepare, currentState is %{public}s", GetStatusDescription(lastOpStatus_).c_str());
        return MSERR_INVALID_OPERATION;
    }
}


OnPrepare方法中,先通過playerEngine_調(diào)用SerVideoSurface的方法,將surface_設(shè)置到PlayerEngineGstImpl中(producerSurface_),接著啟動一個任務(wù),調(diào)用目前狀態(tài)的Prepare()方法。

int32_tPlayerServer::OnPrepare(boolsync)
{
    CHECK_AND_RETURN_RET_LOG(playerEngine_ != nullptr, MSERR_NO_MEMORY, "playerEngine_ is nullptr");
    int32_t ret = MSERR_OK;


#ifdef SUPPORT_VIDEO
    if (surface_ != nullptr) {
        ret = playerEngine_->SetVideoSurface(surface_);
        CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Engine SetVideoSurface Failed!");
    }
#endif


    lastOpStatus_ = PLAYER_PREPARED;


    auto preparedTask = std::make_sharedint32_t<>>([this]() {
        MediaTrace::TraceBegin("PlayerServer::PrepareAsync", FAKE_POINTER(this));
        auto currState = std::static_pointer_cast(GetCurrState());
        return currState->Prepare();
    });


    ret = taskMgr_.LaunchTask(preparedTask, PlayerServerTaskType::STATE_CHANGE);
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "Prepare launch task failed");


    if (sync) {
        (void)preparedTask->GetResult(); // wait HandlePrpare
    }
    return MSERR_OK;
}

進(jìn)入Preparing狀態(tài)后,會觸發(fā)PlayerServer的HandlePrepare()方法被調(diào)用,在這個方法里會通過playerEngine_調(diào)用PrepareAsync方法,這個方法調(diào)用的是PlayerEngineGstImpl對應(yīng)的PrepareAsync方法。

int32_tPlayerServer::HandlePrepare()
{
    int32_t ret = playerEngine_->PrepareAsync();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Server Prepare Failed!");
    if (config_.leftVolume <= 1.0f || config_.rightVolume <= 1.0f) {
        ret = playerEngine_->SetVolume(config_.leftVolume, config_.rightVolume);
        MEDIA_LOGD("Prepared SetVolume leftVolume:%{public}f rightVolume:%{public}f, ret:%{public}d", 
                   config_.leftVolume, config_.rightVolume, ret);
    }
    (void)playerEngine_->SetLooping(config_.looping);


    {
        auto rateTask = std::make_sharedvoid<>>([this]() {
            auto currState = std::static_pointer_cast(GetCurrState());
            (void)currState->SetPlaybackSpeed(config_.speedMode);
        });


        (void)taskMgr_.LaunchTask(rateTask, PlayerServerTaskType::RATE_CHANGE);
    }
    return MSERR_OK;
}

首先初始化playBinCtrler_,后續(xù)的操作都是通過PlayBinCtrlerBase對象來操作的,所以PlayBinCtrlerInit()方法會創(chuàng)建PlayBinCtrlerBase對象(playBinCtrler_),創(chuàng)建好以后通過playBinCtrler_進(jìn)行SetSource和SetXXXListener的設(shè)置。

int32_tPlayerEngineGstImpl::PrepareAsync()
{
    std::unique_lock<std::mutex> lock(mutex_);
    MEDIA_LOGD("Prepare in");


    int32_t ret = PlayBinCtrlerInit();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_VAL, "PlayBinCtrlerInit failed");


    CHECK_AND_RETURN_RET_LOG(playBinCtrler_ != nullptr, MSERR_INVALID_VAL, "playBinCtrler_ is nullptr");
    ret = playBinCtrler_->PrepareAsync();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "PrepareAsync failed");


    // The duration of some resources without header information cannot be obtained.
    MEDIA_LOGD("Prepared ok out");
    return MSERR_OK;
}

初始化完成以后,接下來進(jìn)行playBinCtrler_的PrepareAsync的調(diào)用,PlayBinCtrlerBase中的PrepareAsync的方法間接地調(diào)用了PrepareAsyncInternal。

int32_tPlayBinCtrlerBase::PrepareAsync()
{
    MEDIA_LOGD("enter");


    std::unique_lock<std::mutex> lock(mutex_);
    return PrepareAsyncInternal();
}

PrepareAsyncInternal首先判斷當(dāng)前的狀態(tài),如果是preparingState或preparedState,那么就直接返回成功,否則繼續(xù)向下調(diào)用。接下來會調(diào)用EnterInitializedState(),這個方法中會創(chuàng)建playbin,設(shè)置signal的回調(diào)以及gstreamer參數(shù)的設(shè)置。最后調(diào)用目前狀態(tài)的Prepare方法,此時的狀態(tài)是InitializedState。

int32_t PlayBinCtrlerBase::PrepareAsyncInternal()
{
    if ((GetCurrState() == preparingState_) || (GetCurrState() == preparedState_)) {
        MEDIA_LOGI("already at preparing state, skip");
        return MSERR_OK;
    }


    CHECK_AND_RETURN_RET_LOG((!uri_.empty() || appsrcWrap_), MSERR_INVALID_OPERATION, "Set uri firsty!");


    int32_t ret = EnterInitializedState();
    CHECK_AND_RETURN_RET(ret == MSERR_OK, ret);


    auto currState = std::static_pointer_cast(GetCurrState());
    ret = currState->Prepare();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, ret, "PrepareAsyncInternal failed");


    return MSERR_OK;
}

InitializedState的Prepare方法又通過ctrler_調(diào)回到PlayBinCtrlerBase的ChangeState方法,這個方法是在PlayBinCtrlerBase的父類StateMachine中,它是一個狀態(tài)機(jī),管理著各種狀態(tài)的切換。

int32_t PlayBinCtrlerBase::Prepare()
{
    ctrler_.ChangeState(ctrler_.preparingState_);
    return MSERR_OK;
}

很多表示狀態(tài)的類在PlayBinCtrlerBase中進(jìn)行聲明,這些子類的具體實(shí)現(xiàn)功能在playbin_state.cpp中。

private:
    class BaseState;
    class IdleState;
    class InitializedState;
    class PreparingState;
    class PreparedState;
    class PlayingState;
    class PausedState;
    class StoppedState;
    class StoppingState;
    class PlaybackCompletedState;

接下來看一下狀態(tài)機(jī)的ChangeState方法,可以看出切換狀態(tài)的時候,先調(diào)用切換前狀態(tài)的StateExit()方法,再調(diào)用切換后狀態(tài)的StateEnter()。如果需要一些操作,我們可以在狀態(tài)的StateEnter和StateExit中進(jìn)行。

voidStateMachine::ChangeState(conststd::shared_ptr&state)
{
    ......
    if (currState_ != nullptr && currState_->GetStateName() == "stopping_state" && state->GetStateName() != "stopped_state") {
        return;
    }
    if (currState_) {
        currState_->StateExit();
    }
    currState_ = state;
    state->StateEnter();
}

因?yàn)樯厦媲袚Q狀態(tài)調(diào)用的是ctrler_.ChangeState(ctrler_.preparingState_),所以接下來看一下PreparingState狀態(tài)的StateEnter方法。這個方法中首先是調(diào)用了ctrler_.ReportMessage(msg),字面上看是用來上報msg信息的。

voidPlayBinCtrlerBase::StateEnter()
{
    PlayBinMessage msg = { PLAYBIN_MSG_SUBTYPE, PLAYBIN_SUB_MSG_BUFFERING_START, 0, {} };
    ctrler_.ReportMessage(msg);


    GstStateChangeReturn ret;
    (void)ChangePlayBinState(GST_STATE_PAUSED, ret);


    MEDIA_LOGD("PreparingState::StateEnter finished");
}

ctrler_是PlayBinCtrlerBase類型的變量,直接看PlayBinCtrlerBase的ReportMessage方法,這個方法的核心,是創(chuàng)建一個任務(wù)后,將任務(wù)放入消息隊(duì)列中,等待消息被處理,這里我們最想知道的是這個消息會在什么地方被處理。msgReportHandler創(chuàng)建了TaskHandler,這個里面會調(diào)用notifier_(msg),這里的notifier_比較重要,我們可以順著這個變量向上分析。

voidPlayBinCtrlerBase::ReportMessage(constPlayBinMessage&msg)
{
    ......
    auto msgReportHandler = std::make_sharedvoid<>>([this, msg]() { notifier_(msg); });
    int32_t ret = msgQueue_->EnqueueTask(msgReportHandler);
    if (ret != MSERR_OK) {
        MEDIA_LOGE("async report msg failed, type: %{public}d, subType: %{public}d, code: %{public}d",
                   msg.type, msg.subType, msg.code);
    };


    if (msg.type == PlayBinMsgType::PLAYBIN_MSG_EOS) {
        ProcessEndOfStream();
    }
}

notifier_是在PlayBinCtrlerBase被創(chuàng)建的時候賦值的。

PlayBinCtrlerBase::PlayBinCtrlerBase(constPlayBinCreateParam&createParam)
    : renderMode_(createParam.renderMode),
    notifier_(createParam.notifier),
    sinkProvider_(createParam.sinkProvider)
{
    MEDIA_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR "", FAKE_POINTER(this));
}

在源碼分析的前期PlayerEngineGstImpl初始化PlayBinCtrlerBase的時候進(jìn)行了創(chuàng)建notifier = std::bind(&PlayerEngineGstImpl::OnNotifyMessage, this, std::_1) notifier相當(dāng)于是調(diào)用了PlayerEngineGstImpl::OnNotifyMessage方法。所以上述中的處理函數(shù)就是PlayerEngineGstImpl::OnNotifyMessage。

int32_tPlayerEngineGstImpl::PlayBinCtrlerPrepare()
{
    uint8_t renderMode = IPlayBinCtrler::DEFAULT_RENDER;
    auto notifier = std::bind(&PlayerEngineGstImpl::OnNotifyMessage, this, std::_1);


    {
        std::unique_lock<std::mutex> lk(trackParseMutex_);
        sinkProvider_ = std::make_shared(producerSurface_);
        sinkProvider_->SetAppInfo(appuid_, apppid_);
    }


    IPlayBinCtrler::PlayBinCreateParam createParam = {
        static_cast(renderMode), notifier, sinkProvider_
    };
    playBinCtrler_ = IPlayBinCtrler::PLAYBIN2, createParam);
    ......
    return MSERR_OK;
}

在OnNotifyMessage中指定了各種消息類型對應(yīng)的執(zhí)行函數(shù),上述代碼中創(chuàng)建的Message類型是PLAYBIN_MSG_SUBTYPE,子類型為PLAYBIN_SUB_MSG_BUFFERING_START。

voidPlayerEngineGstImpl::OnNotifyMessage(constPlayBinMessage&msg)
{
    const std::unordered_map MSG_NOTIFY_FUNC_TABLE = {,>
        { PLAYBIN_MSG_ERROR, std::bind(&PlayerEngineGstImpl::HandleErrorMessage, this, std::_1) },
        { PLAYBIN_MSG_SEEKDONE, std::bind(&PlayerEngineGstImpl::HandleSeekDoneMessage, this, std::_1) },
        { PLAYBIN_MSG_SPEEDDONE, std::bind(&PlayerEngineGstImpl::HandleInfoMessage, this, std::_1) },
        { PLAYBIN_MSG_BITRATEDONE, std::bind(&PlayerEngineGstImpl::HandleInfoMessage, this, std::_1)},
        { PLAYBIN_MSG_EOS, std::bind(&PlayerEngineGstImpl::HandleInfoMessage, this, std::_1) },
        { PLAYBIN_MSG_STATE_CHANGE, std::bind(&PlayerEngineGstImpl::HandleInfoMessage, this, std::_1) },
        { PLAYBIN_MSG_SUBTYPE, std::bind(&PlayerEngineGstImpl::HandleSubTypeMessage, this, std::_1) },
        { PLAYBIN_MSG_AUDIO_SINK, std::bind(&PlayerEngineGstImpl::HandleAudioMessage, this, std::_1) },
        { PLAYBIN_MSG_POSITION_UPDATE, std::bind(&PlayerEngineGstImpl::HandlePositionUpdateMessage, this,
            std::_1) },
    };
    if (MSG_NOTIFY_FUNC_TABLE.count(msg.type) != 0) {
        MSG_NOTIFY_FUNC_TABLE.at(msg.type)(msg);
    }
}

最終的流程走到了PlayerEngineGstImpl::HandleBufferingStart(),在這個方法中,主要通過obs_將format傳給IPlayerEngineObs的OnInfo方法。

voidPlayerEngineGstImpl::HandleBufferingStart()
{
    percent_ = 0;
    Format format;
(void)format.PutIntValue(std::string(PlayerKeys::PLAYER_BUFFERING_START), 0);
    std::shared_ptr notifyObs = obs_.lock();
    if (notifyObs != nullptr) {
        notifyObs->OnInfo(INFO_TYPE_BUFFERING_UPDATE, 0, format);
    }
}

我們重點(diǎn)看一下obs_是哪里設(shè)置的,在PlayerServer的初始化InitPlayEngine。shared_from_this()相當(dāng)于是把PlayerServer自身賦值給obs,PlayerServer也是實(shí)現(xiàn)了IPlayerEngineObs對應(yīng)的接口。

int32_tPlayerServer::InitPlayEngine(conststd::string&url)
{
    ......
    int32_t ret = taskMgr_.Init();
    auto engineFactory = EngineFactoryRepo::SCENE_PLAYBACK, url);
    
    playerEngine_ = engineFactory->CreatePlayerEngine(appUid_, appPid_);


    if (dataSrc_ == nullptr) {
        ret = playerEngine_->SetSource(url);
    } else {
        ret = playerEngine_->SetSource(dataSrc_);
    }


    std::shared_ptr obs = shared_from_this();
    ret = playerEngine_->SetObs(obs);


    lastOpStatus_ = PLAYER_INITIALIZED;
    ChangeState(initializedState_);


    return MSERR_OK;
}

這樣我們就跟蹤到了PlayerServer的OnInfo()方法。

voidPlayerServer::OnInfo(PlayerOnInfoTypetype,int32_textra,constFormat&infoBody)
{
    std::lock_guard<std::mutex> lockCb(mutexCb_);


    int32_t ret = HandleMessage(type, extra, infoBody);
    if (playerCb_ != nullptr && ret == MSERR_OK) {
        playerCb_->OnInfo(type, extra, infoBody);
    }
}

2. Play分析

從PlayerServer開始跟蹤,調(diào)用到PlayerServer的OnPlay()方法。

int32_tPlayerServer::Play()
{
    ......
    if (lastOpStatus_ == PLAYER_PREPARED || lastOpStatus_ == PLAYER_PLAYBACK_COMPLETE ||
        lastOpStatus_ == PLAYER_PAUSED) {
        return OnPlay();
    } else {
        return MSERR_INVALID_OPERATION;
    }
}

在OnPlay中會啟動一個任務(wù),在任務(wù)中獲取當(dāng)前的狀態(tài),然后調(diào)用當(dāng)前狀態(tài)的Play()方法。

int32_tPlayerServer::OnPlay()
{
    ......
    auto playingTask = std::make_sharedvoid<>>([this]() {
        auto currState = std::static_pointer_cast(GetCurrState());
        (void)currState->Play();
    });


    int ret = taskMgr_.LaunchTask(playingTask, PlayerServerTaskType::STATE_CHANGE);


    lastOpStatus_ = PLAYER_STARTED;
    return MSERR_OK;
}

前面調(diào)用了PrepareAsync,所以當(dāng)前的狀態(tài)是Prepared,調(diào)用到了PreparedState的Play()方法,這個方法還是按照之前Prepare的方式,調(diào)回到PlayerServer的HandlePlay()。

int32_tPlayerServer::Play()
{
    return server_.HandlePlay();
}

在PlayServer中通過播放引擎繼續(xù)向下調(diào)用。

int32_tPlayerServer::HandlePlay()
{
    int32_t ret = playerEngine_->Play();
    CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Engine Play Failed!");


    return MSERR_OK;
}

在PlayerEngineGstImpl的Play()方法會繼續(xù)調(diào)用playBinCtrler_的Play()方法。

int32_tPlayerEngineGstImpl::Play()
{
    ......
    playBinCtrler_->Play();
    return MSERR_OK;
}

PlayBinCtrlerBase的Play()方法根據(jù)當(dāng)前的State,調(diào)用currSate->Play()。

int32_tPlayBinCtrlerBase::Play()
{
    ......
    auto currState =    std::static_pointer_cast(GetCurrState());
    int32_t ret = currState->Play();


    return MSERR_OK;
}

在PreparedState的Play()方法中改變了PlayBin的狀態(tài)為playing。

int32_tPlayBinCtrlerBase::Play()
{
    GstStateChangeReturn ret;
    return ChangePlayBinState(GST_STATE_PLAYING, ret);
}

ChangePlayBinState主要是調(diào)用了gst_element_set_state(GST_ELEMENT_CAST(ctrler_.playbin_),GST_STATE_PLAYING),這個直接調(diào)用了gstreamer三方庫的實(shí)現(xiàn),調(diào)用完這個方法以后,gstreamer就開始進(jìn)行播放了。

int32_tPlayBinCtrlerBase::ChangePlayBinState(GstStatetargetState,GstStateChangeReturn&ret)
{
    ......
    ret = gst_element_set_state(GST_ELEMENT_CAST(ctrler_.playbin_), targetState);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        MEDIA_LOGE("Failed to change playbin's state to %{public}s", gst_element_state_get_name(targetState));
        return MSERR_INVALID_OPERATION;
    }


    return MSERR_OK;
}

六、總結(jié)

本篇文章主要從PlayerServer播放服務(wù)開始分析音視頻播放的流程,涉及到gstreamer引擎的調(diào)用,相對于多媒體播放框架來說,更加底層,便于熟悉從框架到gstreamer的整體流程。

更多熱點(diǎn)文章閱讀

  • 玩嗨OpenHarmony:基于OpenHarmony的智能助老服務(wù)機(jī)器人
  • 玩嗨OpenHarmony:基于OpenHarmony的智慧農(nóng)業(yè)環(huán)境監(jiān)控系統(tǒng)
  • 首個通過OpenHarmony兼容性測評的全場景實(shí)驗(yàn)箱
  • 基于OpenHarmony的智能門禁系統(tǒng),讓出行更便捷
  • OpenHarmony 3.2 Beta多媒體系列:音視頻播放框架

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


原文標(biāo)題:OpenHarmony 3.2 Beta多媒體系列:音視頻播放gstreamer

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


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 電子發(fā)燒友
    +關(guān)注

    關(guān)注

    33

    文章

    566

    瀏覽量

    33520
  • 開源社區(qū)
    +關(guān)注

    關(guān)注

    0

    文章

    95

    瀏覽量

    629

原文標(biāo)題:OpenHarmony 3.2 Beta多媒體系列:音視頻播放gstreamer

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    泰芯半導(dǎo)體推出星閃音視頻無線SOC芯片TXW828

    在短距離無線通信技術(shù)加速迭代的浪潮中,珠海泰芯半導(dǎo)體有限公司全球首先發(fā)布支持星閃(NearLink)標(biāo)準(zhǔn)的音視頻無線SOC芯片——TXW828。這款集WiFi/藍(lán)牙BLE/星閃三模融合音視頻無線芯片
    的頭像 發(fā)表于 06-20 15:51 ?1177次閱讀

    樂鑫ESP-RTC實(shí)時音視頻通信方案

    ESP-RTC樂鑫科技推出ESP-RTC(Real-TimeCommunication)音視頻通信方案,能夠?qū)崿F(xiàn)穩(wěn)定流暢、超低延時的語音和視頻實(shí)時通信。ESP-RTC以樂鑫
    的頭像 發(fā)表于 05-26 18:07 ?288次閱讀
    樂鑫ESP-RTC實(shí)時<b class='flag-5'>音視頻</b>通信方案

    中國音視頻產(chǎn)業(yè)邁向高質(zhì)量發(fā)展

    隨著超高清先鋒計劃的逐步推進(jìn),截至2024年底,中國音視頻產(chǎn)業(yè)規(guī)模超5萬億,包括個人消費(fèi)電子、家庭影音娛樂、行業(yè)多媒體應(yīng)用及車載視聽產(chǎn)業(yè)和相關(guān)衍生應(yīng)用等行業(yè)企業(yè)超過百萬家,音視頻產(chǎn)業(yè)已經(jīng)成為國家數(shù)字經(jīng)濟(jì)發(fā)展的重要支柱。
    的頭像 發(fā)表于 04-24 11:10 ?647次閱讀

    音視頻一體化解決方案

    。在應(yīng)急指揮中心、多媒體會議室、移動指揮車、多媒體教室、數(shù)字法庭等場景中,用戶亟需一套高度集成、智能管控、互聯(lián)互通的一體化解決方案,以實(shí)現(xiàn)音視頻信號的綜合調(diào)度與高效協(xié)作。
    的頭像 發(fā)表于 04-24 09:14 ?438次閱讀

    實(shí)用調(diào)試技能:全志T113-i 音視頻測試

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

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

    【北京迅為】itop-3568 開發(fā)板openharmony鴻蒙燒寫及測試-第2章OpenHarmony v3.2-Beta4版本測試
    的頭像 發(fā)表于 03-05 10:53 ?459次閱讀
    【北京迅為】itop-3568 開發(fā)板<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是一款集高清音視頻處理與傳輸功能于一體的高端芯片,專為滿足現(xiàn)代多媒體設(shè)備對高分辨率、高幀率視頻以及高質(zhì)量音頻的需求而設(shè)計。其強(qiáng)大的音視頻處理能力和多樣化的輸入輸出接口,使得
    的頭像 發(fā)表于 02-10 17:56 ?1235次閱讀

    國科微榮獲音視頻領(lǐng)域關(guān)鍵技術(shù)突破一等獎

    近日,第五屆“馬欄山杯”國際音視頻算法大賽-2024音視頻領(lǐng)域關(guān)鍵技術(shù)突破獎揭曉,國科微8K超高清視頻系列芯片憑借優(yōu)異的產(chǎn)品性能及示范性應(yīng)用獲評一等獎。
    的頭像 發(fā)表于 12-26 15:11 ?614次閱讀

    RK3588核心板多媒體功能一覽

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

    AMS-HE200:HDMI音視頻網(wǎng)絡(luò)延長器,開啟傳輸新時代

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

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

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

    Amoonsky創(chuàng)新音視頻連接技術(shù):全新推出AMS-HE200 HDMI網(wǎng)線延長器

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

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

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

    基于ArkTS語言的OpenHarmony APP應(yīng)用開發(fā):多媒體管理2

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

    盤點(diǎn)那些常見音視頻接口

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