博客
关于我
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 2】
阅读量:673 次
发布时间:2019-03-15

本文共 7558 字,大约阅读时间需要 25 分钟。

Android 10.0 系统中媒体播放器(NuPlayer)的音频解码与渲染实现分析

5. canOffloadStream 函数实现分析

5.1 mSource->isStreaming() 实现

mSource->isStreaming() 方法返回的是 mIsStreaming 是否是网络数据源流媒体数据源标识值。非网络数据源时返回 false。

// [frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp]bool NuPlayer::GenericSource::isStreaming() const {    Mutex::Autolock _l(mLock);    return mIsStreaming;}

5.2 canOffloadStream 方法实现

canOffloadStream 方法用于检查是否可以通过硬解码器解码并播放音频流。其实现逻辑如下:

// [frameworks/av/media/libstagefright/Utils.cpp]bool canOffloadStream(const sp
& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType) { audio_offload_info_t info = AUDIO_INFO_INITIALIZER; if (OK != getAudioOffloadInfo(meta, hasVideo, isStreaming, streamType, &info)) { return false; } return AudioSystem::isOffloadSupported(info);}

5.3 audio_offload_info_t 定义与默认值

audio_offload_info_t 结构体定义在 system/media/audio/include/system/audio.h 文件中,主要用于存储音频解码和播放所需的配置信息。

// [system/media/audio/include/system/audio.h]typedef struct {    uint16_t version;    uint16_t size;    uint32_t sample_rate;    audio_channel_mask_t channel_mask;    audio_format_t format;    audio_stream_type_t stream_type;    uint32_t bit_rate;    int64_t duration_us;    bool has_video;    bool is_streaming;    uint32_t bit_width;    uint32_t offload_buffer_size;    audio_usage_t usage;} __attribute__((aligned(8))) audio_offload_info_t;#define AUDIO_INFO_INITIALIZER {    /* .version = */ AUDIO_OFFLOAD_INFO_VERSION_0_1,    /* .size = */ sizeof(audio_offload_info_t),    /* .sample_rate = */ 0,    /* .channel_mask = */ 0,    /* .format = */ AUDIO_FORMAT_DEFAULT,    /* .stream_type = */ AUDIO_STREAM_VOICE_CALL,    /* .bit_rate = */ 0,    /* .duration_us = */ 0,    /* .has_video = */ false,    /* .is_streaming = */ false,    /* .bit_width = */ 16,    /* .offload_buffer_size = */ 0,    /* .usage = */ AUDIO_USAGE_UNKNOWN};

5.4 getAudioOffloadInfo 方法实现

getAudioOffloadInfo 方法用于获取音频解码和播放所需的详细信息,主要包括 MIME 类型到音频格式的映射、AAC 配置级别的处理以及音频通道的配置。

// [frameworks/av/media/libstagefright/Utils.cpp]status_t getAudioOffloadInfo(const sp
& meta, bool hasVideo, bool isStreaming, audio_stream_type_t streamType, audio_offload_info_t* info) { const char* mime; if (meta == NULL) { return BAD_VALUE; } CHECK(meta->findCString(kKeyMIMEType, &mime)); *info = AUDIO_INFO_INITIALIZER; info->format = AUDIO_FORMAT_INVALID; if (mapMimeToAudioFormat(info->format, mime) != OK) { ALOGE("Couldn't map mime type \"%s\" to a valid AudioSystem::audio_format !", mime); return BAD_VALUE; } else { ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info->format); } if (AVUtils::get()->canOffloadStream(meta) != true) { return false; } int32_t aacaot = -1; if (meta->findInt32(kKeyAACAOT, &aacaot)) { bool isADTSSupported = false; if (!__NO_AVEXTENSIONS__) { isADTSSupported = AVUtils::get()->mapAACProfileToAudioFormat(meta, info->format, (OMX_AUDIO_AACPROFILETYPE) aacaot); } if (!isADTSSupported) { mapAACProfileToAudioFormat(info->format, (OMX_AUDIO_AACPROFILETYPE) aacaot); } } int32_t srate = -1; if (!meta->findInt32(kKeySampleRate, &srate)) { ALOGV("track of type '%s' does not publish sample rate", mime); } info->sample_rate = srate; int32_t cmask = 0; if (!meta->findInt32(kKeyChannelMask, &cmask) || cmask == CHANNEL_MASK_USE_CHANNEL_ORDER) { ALOGV("track of type '%s' does not publish channel mask", mime); int32_t channelCount; if (!meta->findInt32(kKeyChannelCount, &channelCount)) { ALOGV("track of type '%s' does not publish channel count", mime); } else { cmask = audio_channel_out_mask_from_count(channelCount); } ALOGW("track of type '%s' does not publish channel mask, channel count %d", mime, channelCount); } info->channel_mask = cmask; int64_t duration = 0; if (!meta->findInt64(kKeyDuration, &duration)) { ALOGV("track of type '%s' does not publish duration", mime); } info->duration_us = duration; int32_t brate = -1; if (!meta->findInt32(kKeyBitRate, &brate)) { ALOGV("track of type '%s' does not publish bitrate", mime); } info->bit_rate = brate; info->stream_type = streamType; info->has_video = hasVideo; info->is_streaming = isStreaming; return OK;}

5.5 mapMimeToAudioFormat 方法实现

mapMimeToAudioFormat 方法将 MIME 类型映射到对应的音频格式。

// [frameworks/av/media/libstagefright/Utils.cpp]status_t mapMimeToAudioFormat(audio_format_t* format, const char* mime) {    const struct mime_conv_t* p = &mimeLookup[0];    while (p->mime != NULL) {        if (0 == strcasecmp(mime, p->mime)) {            format = p->format;            return OK;        }        ++p;    }    if (!__NO_AVEXTENSIONS__) {        return AVUtils::get()->mapMimeToAudioFormat(format, mime);    }    return BAD_VALUE;}

5.6 AudioSystem::isOffloadSupported 方法实现

isOffloadSupported 方法检查系统是否支持音频解码的 offload 模式。

// [frameworks/av/media/libaudioclient/AudioSystem.cpp]bool AudioSystem::isOffloadSupported(const audio_offload_info_t* info) {    ALOGV("isOffloadSupported()");    const sp
&aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return false; return aps->isOffloadSupported(info);}

6. NuPlayer::Renderer 类声明与构造函数实现

NuPlayer::Renderer 类声明了与消息处理相关的接口。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h]struct NuPlayer::Renderer : public AHandler {};

7. NuPlayer::Renderer 构造函数实现

NuPlayer::Renderer 的构造函数初始化各个成员变量,包括音频源、媒体时钟、通知对象等。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp]NuPlayer::Renderer::Renderer(const sp
& sink, const sp
& mediaClock, const sp
& notify, uint32_t flags) : mAudioSink(sink), mUseVirtualAudioSink(false), mNotify(notify), mFlags(flags), mNumFramesWritten(0), mDrainAudioQueuePending(false), mDrainVideoQueuePending(false), mAudioQueueGeneration(0), mVideoQueueGeneration(0), mAudioDrainGeneration(0), mVideoDrainGeneration(0), mAudioEOSGeneration(0), mMediaClock(mediaClock), mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT), mAudioFirstAnchorTimeMediaUs(-1), mAnchorTimeMediaUs(-1), mAnchorNumFramesWritten(-1), mVideoLateByUs(0LL), mNextVideoTimeMediaUs(-1), mHasAudio(false), mHasVideo(false), mNotifyCompleteAudio(false), mNotifyCompleteVideo(false), mSyncQueues(false), mPaused(false), mPauseDrainAudioAllowedUs(0), mVideoSampleReceived(false), mVideoRenderingStarted(false), mVideoRenderingStartGeneration(0), mAudioRenderingStartGeneration(0), mRenderingDataDelivered(false), mNextAudioClockUpdateTimeUs(-1), mLastAudioMediaTimeUs(-1), mAudioOffloadPauseTimeoutGeneration(0), mAudioTornDown(false), mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER), mCurrentPcmInfo(AUDIO_PCMINFO_INITIALIZER), mTotalBuffersQueued(0), mLastAudioBufferDrained(0), mUseAudioCallback(false), mWakeLock(new AWakeLock()), mNeedVideoClearAnchor(false) { CHECK(mediaClock != NULL); mPlaybackRate = mPlaybackSettings.mSpeed; mMediaClock->setPlaybackRate(mPlaybackRate);}

8. mCurrentPcmInfo (AUDIO_PCMINFO_INITIALIZER) 实现

AUDIO_PCMINFO_INITIALIZER 初始化 PCM 信息,用于音频解码。

// [frameworks/av/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h]static const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER = {    AUDIO_CHANNEL_NONE,    AUDIO_OUTPUT_FLAG_NONE,    AUDIO_FORMAT_INVALID,    0,    0};

通过以上分析,可以清晰地了解 Android 10.0 系统中媒体播放器的音频解码与渲染实现的关键逻辑和技术细节。

转载地址:http://qopmz.baihongyu.com/

你可能感兴趣的文章
Mysql 数据类型一日期
查看>>
MySQL 数据类型和属性
查看>>
mysql 敲错命令 想取消怎么办?
查看>>
Mysql 整形列的字节与存储范围
查看>>
mysql 断电数据损坏,无法启动
查看>>
MySQL 日期时间类型的选择
查看>>
Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
查看>>
MySQL 是如何加锁的?
查看>>
MySQL 是怎样运行的 - InnoDB数据页结构
查看>>
mysql 更新子表_mysql 在update中实现子查询的方式
查看>>
MySQL 有什么优点?
查看>>
mysql 权限整理记录
查看>>
mysql 权限登录问题:ERROR 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)
查看>>
MYSQL 查看最大连接数和修改最大连接数
查看>>
MySQL 查看有哪些表
查看>>
mysql 查看锁_阿里/美团/字节面试官必问的Mysql锁机制,你真的明白吗
查看>>
MySql 查询以逗号分隔的字符串的方法(正则)
查看>>
MySQL 查询优化:提速查询效率的13大秘籍(避免使用SELECT 、分页查询的优化、合理使用连接、子查询的优化)(上)
查看>>
mysql 查询数据库所有表的字段信息
查看>>
【Java基础】什么是面向对象?
查看>>