AndroidQ播放器(编译报错处理)
最新在Bring up公司的播放器从Android 4.4到Android Q,期间遇到很多“坑”,总结出来记录⼀下。期间也会简单介绍⼀下在Android 系统中新建⼀个类似Nuplayer的播放器⼤概需要哪些步骤。
代码⽬录:frameworks/av/media/libmediaplayerservice/
最先动的地⽅是MediaPlayerFactory.cpp,我的做法是根据项⽬需求,选择是否⾛⾃⼰的播放器还是Android原⽣播放器(因为过XTS认证会⾛Android原⽣flow),改动如下(记得把RAIN_PLAYER的define放在跟NuPlayer⼀样的地⽅,以后这样简单的事情就不在赘述啦^_^):
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
IFactory* factory = new NuPlayerFactory();
if (registerFactory_l(factory, NU_PLAYER) != OK)
delete factory;
factory = new TestPlayerFactory();
if (registerFactory_l(factory, TEST_PLAYER) != OK)
delete factory;
#ifdef BUILD_WITH_XXXX_MM
registerFactory_l(new RainPlayerFactory(), RAIN_PLAYER);
#endif
sInitComplete = true;
}
分享⼀个⼩技巧,我们公司的coding style是如果有动到Android原⽣的部分,要在改动上下加上如下打印:
// xxxx Android Patch Begin
// xxxx Android Patch End
RainPlayerFactory部分如下,⾄于⾃⼰的player放在哪⾥,完全由⾃⼰决定,可以选择放在frameworks/av/media/libmedia或是其他什么地⽅,我放在了vendor⽬录。
// xxxx Android Patch Begin
class RainPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /* client */,
const char* url,
const sp<IMediaHTTPService>& /* httpService */,
float curScore) {
static const float kOurScore = 2.0;  // 定义⼀个⽐较⾼的分数,PK赢了会⾛⾃⼰的player
if (kOurScore <= curScore)
return 0.0;
if (!strncasecmp("", url, 7)
|| !strncasecmp("", url, 8)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
#ifdef SPECIAL_STREAM_USE_NUPLAYER
if (strstr(url, "/sample_aes/")) {
return 0.0;
}
#endif
return kOurScore;
}
if (strstr(url,"m3u8")) {
#ifdef SPECIAL_STREAM_USE_NUPLAYER
if (strstr(url, "/sample_aes/")) {
return 0.0;
}
#endif
return kOurScore;
}
}
if (!strncasecmp("rtsp://", url, 7)) {
return kOurScore;
}
return 0.0;
}
virtual float scoreFactory(const sp<IMediaPlayer>& /* client */,
const sp<IStreamSource>& /* source */,
float /* curScore */) {
return 1.0;
}
virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
ALOGV("Create RainPlyer");
return new RainPlyer;
}
};
#ifdef SUPPORT_RAINPLAYER
class RainPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
ALOGV("Create RainPlyer");
return new RainPlyer;
}
};
#endif
// xxxx Android Patch End
编译部分,我在mediaplayerservice加⼊了soong,这样可以根据BoardConfig.mk来进⾏动态编译,简单来说就是编译中的环境变量会传给⽐如可以加变量来动态选择⾛NuPlayer还是RainPlayer,只在BoardConfig.mk中改⼀⾏配置信息即可。BoardConfig.mk修改之后,编译系统会⾃动去检测:
device/xxx/xxx/BoardConfig.mk was modified,
修改frameworks/av/media/libmediaplayerservice/Android.bp:
// xxx Android Patch Begin
defaults: [
"mediaplayerservicedefaults",
]
,
// xxx Android Patch End
添加frameworks/av/media/libmediaplayerservice/soong/Android.bp:
bootstrap_go_package {
name: "soong-mediaplayerservice",
pkgPath: "android/soong/vendor/xxx/mediaplayerservice",
deps: [
"blueprint",
"blueprint-pathtools",
"soong",
"soong-android",
"soong-cc",
],
srcs: [
"",
],
pluginFor: ["soong_build"],
}
mediaplayerservicedefaults {
name: "mediaplayerservicedefaults",
}
添加frameworks/av/media/libmediaplayerservice/:
package libmediaplayerservice
import (
"fmt"
"android/soong/android"
"android/soong/cc"
)
//Build Option
const BUILD_WITH_RIAN    string = "BUILD_WITH_RIAN"
func init() {
android.RegisterModuleType("mediaplayerservicedefaults",
mediaplayerserviceDefaultsFactory)
}
func mediaplayerserviceDefaultsFactory() android.Module {
module := cc.DefaultsFactory()
android.AddLoadHook(module, globalMediaPlayerServiceDefault)
return module
}
func globalMediaPlayerServiceDefault(ctx android.LoadHookContext) {
type props struct {
Srcs []string
Include_dirs []string
Shared_libs []string
Static_libs []string
Cflags []string
}
p := &props{}
p.Srcs        = globalMediaPlayerServiceSrcs(ctx)
p.Include_dirs = globalMediaPlayerServiceIncludeDirs(ctx)
p.Shared_libs = globalMediaPlayerServiceSharedLibs(ctx)
p.Static_libs = globalMediaPlayerServiceStaticLibs(ctx)
p.Cflags      = globalMediaPlayerServiceCflags(ctx)
ctx.AppendProperties(p)
}
func globalMediaPlayerServiceSrcs(ctx android.BaseContext) ([]string) {
var srcs []string
return srcs
}
func globalMediaPlayerServiceIncludeDirs(ctx android.BaseContext) ([]string) {
var includeDirs []string
var tmp string
if (envIsTrue(ctx, BUILD_WITH_RIAN) {
// 在这⾥可以加⼊你新建Player的相关头⽂件
includeDirs = append(includeDirs, "external/skia/include")
includeDirs = append(includeDirs, "external/skia/include/core")
includeDirs = append(includeDirs, "vendor/XXX/common/libraries/media/mmplayer/")    }
return includeDirs
}
func globalMediaPlayerServiceSharedLibs(ctx android.BaseContext) ([]string) {
var shared_libs []string
if (envIsTrue(ctx, BUILD_WITH_RIAN) {
// 在这⾥可以加⼊你新建Player的相关动态链接库
shared_libs = append(shared_libs, "librainplayer")
}
return shared_libs
}
func globalMediaPlayerServiceStaticLibs(ctx android.BaseContext) ([]string) {
var static_libs []string
if envIsTrue(ctx, BUILD_WITH_MARLIN) {
// 在这⾥可以加⼊你新建Player的相关静态链接库
static_libs = append(static_libs, "libstagefright_nuplayer_wasabi")
static_libs = append(static_libs, "libWasabi")
}
return static_libs
}
func globalMediaPlayerServiceCflags(ctx android.BaseContext) ([]string) {
var cflags []string
/
/ 如果没成功,可以在这⾥加打印,看看env有没有设置下来
// 如果没成功,可以在这⾥加打印,看看env有没有设置下来
fmt.Println("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
fmt.Println("BUILD_WITH_RIAN:",
ctx.AConfig().IsEnvTrue("BUILD_WITH_RIAN"))
if (envIsTrue(ctx, BUILD_WITH_RAIN) {
// 在这⾥可以加⼊你新建Player的条件编译
// 与Android.mk的LOCAL_CFLAGS += -DBUILD_WITH_RAIN类似
cflags = append(cflags, "-BUILD_WITH_RAIN")
}
return cflags
}
func envDefault(ctx android.BaseContext, key string, defaultValue string) string {
ret := ctx.AConfig().Getenv(key)
if ret == "" {
return defaultValue
}
return ret
}
func envIsOptionValue(ctx android.BaseContext, key string, value string) bool {
return ctx.AConfig().Getenv(key) == value
}
func envIsNotOptionValue(ctx android.BaseContext, key string, value string) bool {
return ctx.AConfig().Getenv(key) != value
}
func envIsTrue(ctx android.BaseContext, key string) bool { //ctx android.LoadHookContext) {
return ctx.AConfig().IsEnvTrue(key);
}
func printLog(msg string) {
fmt.Println(msg)
}
func print2Log(msg string, param string) {
if param != "" {
fmt.Errorf(msg + ", %s", param)
}
}
mediaplayerservice的⼯作量基本就这些,剩下再往下就是播放器本⾝的部分,还有OpenMax、这些部分涉及公司的代码太多,不好粘贴了。接下说⼀下遇到的坑...
android最新版
坑1:
如果编译的模块开始vndk,你⼜修改了他的API,那么VNDK就会报错,出错信息⼀般长这样:
******************************************************
error: VNDK library: libmedia_omx's ABI has EXTENDING CHANGES Please check compatiblity report at :
out/soong/.intermediates/frameworks/av/media/libmedia/libmedia_omx/android_arm_armv8-a_cortex-
a53_vendor_shared/.abidiff
******************************************************
---- Please update abi references by running platform/development/vndk/tools/header-
checker/utils/create_reference_dumps.py -l libmedia_omx ----

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。