531 lines
16 KiB
C++
531 lines
16 KiB
C++
/*
|
|
* Copyright 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "RockitPlayer"
|
|
|
|
#include <stdint.h>
|
|
#include <dlfcn.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "RockitPlayer.h"
|
|
#include "RTMediaMetaKeys.h"
|
|
#include "media/mediaplayer.h"
|
|
#include "RockitExtCodecRegister.h"
|
|
|
|
namespace android {
|
|
|
|
/* must keep sync with rockit */
|
|
typedef enum _RTInvokeIds {
|
|
RT_INVOKE_ID_GET_TRACK_INFO = 1,
|
|
RT_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
|
|
RT_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
|
|
RT_INVOKE_ID_SELECT_TRACK = 4,
|
|
RT_INVOKE_ID_UNSELECT_TRACK = 5,
|
|
RT_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
|
|
RT_INVOKE_ID_GET_SELECTED_TRACK = 7
|
|
} RTInvokeIds;
|
|
|
|
typedef enum _RTInvokeExtIds {
|
|
INVOKE_ID_SET_SUB_VISIBLE = 969, // for compatible with previous apps(MediaCenter)
|
|
} RTInvokeExtIds;
|
|
|
|
class PlayerLibLoader {
|
|
public:
|
|
static PlayerLibLoader *getInstance() {
|
|
if (mInstance == NULL) {
|
|
Mutex::Autolock autoLock(mLock);
|
|
if (mInstance == NULL) {
|
|
mInstance = new PlayerLibLoader();
|
|
}
|
|
}
|
|
|
|
return mInstance;
|
|
}
|
|
|
|
private:
|
|
PlayerLibLoader() {
|
|
ALOGD("PlayerLibLoader(%p) construct", this);
|
|
mPlayerLibFd = dlopen(ROCKIT_PLAYER_LIB_NAME, RTLD_LAZY);
|
|
if (mPlayerLibFd == NULL) {
|
|
ALOGE("Cannot load library %s dlerror: %s", ROCKIT_PLAYER_LIB_NAME, dlerror());
|
|
}
|
|
|
|
mCreatePlayerFunc = (createRockitPlayerFunc *)dlsym(mPlayerLibFd,
|
|
CREATE_PLAYER_FUNC_NAME);
|
|
if(mCreatePlayerFunc == NULL) {
|
|
ALOGE("dlsym for create player failed, dlerror: %s", dlerror());
|
|
}
|
|
|
|
mDestroyPlayerFunc = (destroyRockitPlayerFunc *)dlsym(mPlayerLibFd,
|
|
DESTROY_PLAYER_FUNC_NAME);
|
|
if(mDestroyPlayerFunc == NULL) {
|
|
ALOGE("dlsym for destroy player failed, dlerror: %s", dlerror());
|
|
}
|
|
|
|
mCreateMetaDataFunc = (createRockitPlayerFunc *)dlsym(mPlayerLibFd,
|
|
CREATE_METADATA_FUNC_NAME);
|
|
if(mCreateMetaDataFunc == NULL) {
|
|
ALOGE("dlsym for create meta data failed, dlerror: %s", dlerror());
|
|
}
|
|
|
|
mDestroyMetaDataFunc = (destroyRockitPlayerFunc *)dlsym(mPlayerLibFd,
|
|
DESTROY_METADATA_FUNC_NAME);
|
|
if(mDestroyMetaDataFunc == NULL) {
|
|
ALOGE("dlsym for destroy meta data failed, dlerror: %s", dlerror());
|
|
}
|
|
|
|
mRegisterCodec = (registerDecoderFunc *)dlsym(mPlayerLibFd,
|
|
REGISTER_DECODER_FUNC_NAME);
|
|
if(mRegisterCodec == NULL) {
|
|
ALOGE("dlsym for register codec failed, dlerror: %s", dlerror());
|
|
}
|
|
|
|
mUnRegisterCodec = (unRegisterDecoderFunc *)dlsym(mPlayerLibFd,
|
|
UNREGISTER_DECODER_FUNC_NAME);
|
|
if(mUnRegisterCodec == NULL) {
|
|
ALOGE("dlsym for unregister codec failed, dlerror: %s", dlerror());
|
|
}
|
|
}
|
|
|
|
~PlayerLibLoader() {
|
|
ALOGD("~PlayerLibLoader(%p) destruct", this);
|
|
dlclose(mPlayerLibFd);
|
|
}
|
|
|
|
class GC {
|
|
public:
|
|
GC() {}
|
|
~GC() {
|
|
if (mInstance != NULL) {
|
|
delete mInstance;
|
|
mInstance = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
public:
|
|
createRockitPlayerFunc *mCreatePlayerFunc;
|
|
destroyRockitPlayerFunc *mDestroyPlayerFunc;
|
|
createRockitMetaDataFunc *mCreateMetaDataFunc;
|
|
destroyRockitMetaDataFunc *mDestroyMetaDataFunc;
|
|
registerDecoderFunc *mRegisterCodec;
|
|
unRegisterDecoderFunc *mUnRegisterCodec;
|
|
|
|
private:
|
|
static GC gc;
|
|
static PlayerLibLoader *mInstance;
|
|
static Mutex mLock;
|
|
void *mPlayerLibFd;
|
|
};
|
|
|
|
PlayerLibLoader* PlayerLibLoader::mInstance = NULL;
|
|
Mutex PlayerLibLoader::mLock;
|
|
PlayerLibLoader::GC PlayerLibLoader::gc;
|
|
|
|
RockitPlayer::RockitPlayer()
|
|
: mPlayerImpl(NULL),
|
|
mCreatePlayerFunc(NULL),
|
|
mDestroyPlayerFunc(NULL),
|
|
mCreateMetaDataFunc(NULL),
|
|
mDestroyMetaDataFunc(NULL) {
|
|
ALOGD("RockitPlayer(%p) construct", this);
|
|
}
|
|
|
|
RockitPlayer::~RockitPlayer() {
|
|
ALOGD("~RockitPlayer(%p) destruct", this);
|
|
}
|
|
|
|
status_t RockitPlayer::createPlayer() {
|
|
ALOGV("createPlayer");
|
|
mCreatePlayerFunc = PlayerLibLoader::getInstance()->mCreatePlayerFunc;
|
|
mDestroyPlayerFunc = PlayerLibLoader::getInstance()->mDestroyPlayerFunc;
|
|
mCreateMetaDataFunc = PlayerLibLoader::getInstance()->mCreateMetaDataFunc;
|
|
mDestroyMetaDataFunc = PlayerLibLoader::getInstance()->mDestroyMetaDataFunc;
|
|
|
|
registerDecoderFunc *registerFunc = PlayerLibLoader::getInstance()->mRegisterCodec;
|
|
|
|
mPlayerImpl = (RTMediaPlayerInterface *)mCreatePlayerFunc();
|
|
if (mPlayerImpl == NULL) {
|
|
ALOGE("create player failed, player is null");
|
|
}
|
|
|
|
RockitExtCodecRegister::rockitRegisterCodec(registerFunc);
|
|
|
|
ALOGV("player : %p", mPlayerImpl);
|
|
return OK;
|
|
}
|
|
|
|
status_t RockitPlayer::destroyPlayer() {
|
|
ALOGV("destroyPlayer");
|
|
mDestroyPlayerFunc((void **)&mPlayerImpl);
|
|
mPlayerImpl = NULL;
|
|
return OK;
|
|
}
|
|
|
|
status_t RockitPlayer::initCheck() {
|
|
ALOGV("initCheck in");
|
|
return OK;
|
|
}
|
|
|
|
status_t RockitPlayer::setDataSource(
|
|
void *httpService,
|
|
const char *url,
|
|
void *headers) {
|
|
(void)headers;
|
|
(void)httpService;
|
|
|
|
ALOGV("setDataSource url: %s", url);
|
|
mPlayerImpl->setDataSource(url, NULL);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::setDataSource(
|
|
int fd,
|
|
INT64 offset,
|
|
INT64 length) {
|
|
ALOGV("setDataSource url: fd = %d", fd);
|
|
return mPlayerImpl->setDataSource(fd, offset, length);
|
|
}
|
|
|
|
rt_status RockitPlayer::start() {
|
|
ALOGD("%s %d in", __FUNCTION__, __LINE__);
|
|
mPlayerImpl->start();
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::prepare() {
|
|
ALOGV("prepare in");
|
|
mPlayerImpl->prepare();
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::prepareAsync() {
|
|
ALOGV("prepareAsync in");
|
|
mPlayerImpl->prepareAsync();
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::stop() {
|
|
ALOGV("stop in");
|
|
mPlayerImpl->stop();
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::pause() {
|
|
ALOGV("pause in");
|
|
mPlayerImpl->pause();
|
|
return OK;
|
|
}
|
|
|
|
bool RockitPlayer::isPlaying() {
|
|
ALOGV("isPlaying in state: %d", mPlayerImpl->getState());
|
|
return (mPlayerImpl->getState() == 1 << 4/*RT_STATE_STARTED*/) ? true : false;
|
|
}
|
|
|
|
rt_status RockitPlayer::seekTo(INT32 msec, UINT32 mode) {
|
|
ALOGD("seekTo time: %d, mode: %d", msec, mode);
|
|
mPlayerImpl->seekTo(((INT64)msec) * 1000);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::getCurrentPosition(int *msec) {
|
|
INT64 usec = 0;
|
|
mPlayerImpl->getCurrentPosition(&usec);
|
|
ALOGV("getCurrentPosition usec: %lld in", (long long)usec);
|
|
*msec = (INT32)(usec / 1000);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::getDuration(int *msec) {
|
|
INT64 usec = 0;
|
|
mPlayerImpl->getDuration(&usec);
|
|
ALOGV("getDuration usec: %lld in", (long long)usec);
|
|
*msec = (INT32)(usec / 1000);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::reset() {
|
|
ALOGV("reset in");
|
|
mPlayerImpl->reset();
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::setLooping(INT32 loop) {
|
|
ALOGV("setLooping loop: %d", loop);
|
|
mPlayerImpl->setLooping(loop);
|
|
return OK;
|
|
}
|
|
|
|
INT32 RockitPlayer::playerType() {
|
|
ALOGV("playerType in");
|
|
return 6;
|
|
}
|
|
|
|
INT32 RockitPlayer::fillInvokeRequest(const Parcel &request, RtMetaData* meta, INT32& event) {
|
|
INT32 methodId;
|
|
status_t ret = request.readInt32(&methodId);
|
|
if (ret != OK) {
|
|
return ret;
|
|
}
|
|
|
|
event = methodId;
|
|
switch (methodId) {
|
|
case INVOKE_ID_GET_TRACK_INFO: {
|
|
meta->setInt32(kUserInvokeCmd, RT_INVOKE_ID_GET_TRACK_INFO);
|
|
} break;
|
|
|
|
case INVOKE_ID_SELECT_TRACK:
|
|
case INVOKE_ID_UNSELECT_TRACK: {
|
|
int index = request.readInt32();
|
|
int cmd = (methodId == INVOKE_ID_SELECT_TRACK)?
|
|
RT_INVOKE_ID_SELECT_TRACK:RT_INVOKE_ID_UNSELECT_TRACK;
|
|
meta->setInt32(kUserInvokeCmd, cmd);
|
|
meta->setInt32(kUserInvokeTracksIdx, index);
|
|
} break;
|
|
|
|
case INVOKE_ID_SET_VIDEO_SCALING_MODE: {
|
|
int mode = request.readInt32();
|
|
meta->setInt32(kUserInvokeCmd, RT_INVOKE_ID_SET_VIDEO_SCALING_MODE);
|
|
meta->setInt32(kUserInvokeVideoScallingMode, mode);
|
|
} break;
|
|
|
|
case INVOKE_ID_GET_SELECTED_TRACK: {
|
|
INT32 andrType = request.readInt32();
|
|
INT32 rtType = translateMediaType(andrType, false);
|
|
meta->setInt32(kUserInvokeCmd, RT_INVOKE_ID_GET_SELECTED_TRACK);
|
|
meta->setInt32(kUserInvokeGetSelectTrack, rtType);
|
|
} break;
|
|
|
|
case INVOKE_ID_SET_SUB_VISIBLE: {
|
|
INT32 visible = request.readInt32();
|
|
meta->setInt32(kUserInvokeCmd, RT_INVOKE_SET_SUB_VISIBLE);
|
|
meta->setInt32(kKeySubVisible, visible);
|
|
} break;
|
|
|
|
default:
|
|
ALOGD("RockitPlayer::fillInvokeRequest: methodid = %d not supprot, add codes here", methodId);
|
|
ret = BAD_VALUE;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
INT32 RockitPlayer::translateMediaType(INT32 sourceType, bool rtType) {
|
|
struct TrackTypeMap {
|
|
INT32 AndrType;
|
|
INT32 RTType;
|
|
};
|
|
|
|
static const TrackTypeMap kTrackTypeMap[] = {
|
|
{ MEDIA_TRACK_TYPE_UNKNOWN, RTTRACK_TYPE_UNKNOWN },
|
|
{ MEDIA_TRACK_TYPE_VIDEO, RTTRACK_TYPE_VIDEO },
|
|
{ MEDIA_TRACK_TYPE_AUDIO, RTTRACK_TYPE_AUDIO },
|
|
{ MEDIA_TRACK_TYPE_TIMEDTEXT, RTTRACK_TYPE_SUBTITLE },
|
|
{ MEDIA_TRACK_TYPE_SUBTITLE, RTTRACK_TYPE_SUBTITLE },
|
|
{ MEDIA_TRACK_TYPE_METADATA, RTTRACK_TYPE_ATTACHMENT },
|
|
};
|
|
|
|
static const size_t kNumTrackTypeMap =
|
|
sizeof(kTrackTypeMap) / sizeof(kTrackTypeMap[0]);
|
|
|
|
INT32 i;
|
|
for (i = 0; i < kNumTrackTypeMap; ++i) {
|
|
INT32 trackType =
|
|
rtType ? kTrackTypeMap[i].RTType : kTrackTypeMap[i].AndrType;
|
|
if (sourceType == trackType)
|
|
break;
|
|
}
|
|
|
|
if (i == kNumTrackTypeMap)
|
|
return rtType ? MEDIA_TRACK_TYPE_UNKNOWN : RTTRACK_TYPE_UNKNOWN;
|
|
|
|
return rtType ? kTrackTypeMap[i].AndrType : kTrackTypeMap[i].RTType;
|
|
}
|
|
|
|
void RockitPlayer::fillTrackInfor(Parcel *reply, int type,String16& mime, String16& lang) {
|
|
if(reply == NULL){
|
|
return;
|
|
}
|
|
// ALOGV("type = %d, mine = %s, lang = %s", type, mime.string(), lang.string());
|
|
reply->writeInt32(3);
|
|
/* track type */
|
|
reply->writeInt32(type);
|
|
/* mine */
|
|
reply->writeString16(mime);
|
|
/* language */
|
|
reply->writeString16(lang);
|
|
|
|
if(type == (int)MEDIA_TRACK_TYPE_SUBTITLE){
|
|
reply->writeInt32(0); // KEY_IS_AUTOSELECT
|
|
reply->writeInt32(0); // KEY_IS_DEFAULT
|
|
reply->writeInt32(0); // KEY_IS_FORCED_SUBTITLE
|
|
}
|
|
}
|
|
|
|
rt_status RockitPlayer::fillTrackInfoReply(RtMetaData* meta, Parcel* reply) {
|
|
int counter = 0;
|
|
void* tracks = NULL;
|
|
|
|
RT_BOOL status = meta->findInt32(kUserInvokeTracksCount, &counter);
|
|
if(status == RT_FALSE) {
|
|
ALOGE("fillTrackInfoReply : not find track in meta,counter = %d", counter);
|
|
return -1;
|
|
}
|
|
status = meta->findPointer(kUserInvokeTracksInfor, &tracks);
|
|
if(status == RT_FALSE) {
|
|
ALOGE("fillTrackInfoReply : not find trackInfor in meta");
|
|
return -1;
|
|
}
|
|
|
|
reply->writeInt32(counter);
|
|
|
|
char desc[100];
|
|
String16 mine, lang;
|
|
RockitTrackInfor* trackInfor = (RockitTrackInfor*)tracks;
|
|
for (INT32 i = 0; i < counter; ++i) {
|
|
int codecType = translateMediaType(trackInfor[i].mCodecType, true);
|
|
switch (codecType) {
|
|
case MEDIA_TRACK_TYPE_VIDEO: {
|
|
snprintf(desc, 100, ",%dx%d,%f", trackInfor[i].mWidth,
|
|
trackInfor[i].mHeight, trackInfor[i].mFrameRate);
|
|
String16 mine = String16(trackInfor[i].mine);
|
|
String16 lang = String16(desc) + mine;
|
|
fillTrackInfor(reply, MEDIA_TRACK_TYPE_VIDEO, mine, lang);
|
|
} break;
|
|
|
|
case MEDIA_TRACK_TYPE_AUDIO: {
|
|
snprintf(desc, 100, ",%d,%d,", trackInfor[i].mSampleRate,
|
|
trackInfor[i].mChannels);
|
|
String16 mine = String16(trackInfor[i].mine);
|
|
String16 lang = mine + String16(desc);
|
|
fillTrackInfor(reply, (int)MEDIA_TRACK_TYPE_AUDIO, mine, lang);
|
|
} break;
|
|
|
|
case MEDIA_TRACK_TYPE_SUBTITLE: {
|
|
mine = String16(trackInfor[i].mine);
|
|
lang = String16(trackInfor[i].lang);
|
|
fillTrackInfor(reply, (int)MEDIA_TRACK_TYPE_SUBTITLE, mine, lang);
|
|
} break;
|
|
|
|
case MEDIA_TRACK_TYPE_TIMEDTEXT: {
|
|
mine = String16(trackInfor[i].mine);
|
|
lang = String16(trackInfor[i].lang);
|
|
fillTrackInfor(reply, (int)MEDIA_TRACK_TYPE_TIMEDTEXT, mine, lang);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
rt_status RockitPlayer::fillGetSelectedTrackReply(RtMetaData* meta, Parcel* reply) {
|
|
int idx = 0;
|
|
RT_BOOL status = meta->findInt32(kUserInvokeTracksIdx, &idx);
|
|
if(status == RT_FALSE) {
|
|
ALOGE("fillTrackInfoReply : not find track in meta,counter = %d", idx);
|
|
idx = -1;
|
|
}
|
|
|
|
reply->writeInt32(idx);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::fillInvokeReply(INT32 event, RtMetaData* meta, Parcel* reply) {
|
|
rt_status ret = OK;
|
|
switch (event) {
|
|
case INVOKE_ID_GET_TRACK_INFO: {
|
|
ret = fillTrackInfoReply(meta, reply);
|
|
} break;
|
|
|
|
case INVOKE_ID_GET_SELECTED_TRACK: {
|
|
ret = fillGetSelectedTrackReply(meta, reply);
|
|
} break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
rt_status RockitPlayer::invoke(const Parcel &request, Parcel *reply) {
|
|
ALOGD("RockitPlayer::invoke");
|
|
if (reply == NULL) {
|
|
ALOGD("RockitPlayer::invoke, reply == NULL");
|
|
return OK;
|
|
}
|
|
|
|
RtMetaData* in = (RtMetaData *)mCreateMetaDataFunc();
|
|
RtMetaData* out = (RtMetaData *)mCreateMetaDataFunc();
|
|
INT32 event = -1;
|
|
// tranlate cmd to rockit can understand
|
|
fillInvokeRequest(request, in, event);
|
|
|
|
mPlayerImpl->invoke(in, out);
|
|
|
|
// tranlate result to mediaplayer can understand
|
|
fillInvokeReply(event, out, reply);
|
|
|
|
mDestroyMetaDataFunc((void **)&in);
|
|
mDestroyMetaDataFunc((void **)&out);
|
|
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::setVideoSink(const void *videoSink) {
|
|
ALOGV("setVideoSink videoSink: %p", videoSink);
|
|
return mPlayerImpl->setVideoSink(videoSink);
|
|
}
|
|
|
|
rt_status RockitPlayer::setAudioSink(const void *audioSink) {
|
|
ALOGV("setAudioSink audioSink: %p", audioSink);
|
|
return mPlayerImpl->setAudioSink(audioSink);
|
|
}
|
|
rt_status RockitPlayer::setSubteSink(const void *subteSink) {
|
|
ALOGV("setSubteSink subteSink: %p", subteSink);
|
|
return mPlayerImpl->setSubteSink(subteSink);
|
|
}
|
|
|
|
rt_status RockitPlayer::setParameter(INT32 key, const Parcel &request) {
|
|
(void)request;
|
|
ALOGV("setParameter key: %d", key);
|
|
return OK;
|
|
}
|
|
|
|
rt_status RockitPlayer::setListener(RTPlayerListener *listener) {
|
|
return mPlayerImpl->setListener(listener);
|
|
}
|
|
|
|
rt_status RockitPlayer::setPlaybackSettings(const AudioPlaybackRate& rate) {
|
|
RtMetaData* meta = (RtMetaData *)mCreateMetaDataFunc();
|
|
|
|
meta->setInt32(kUserInvokeCmd, RT_INVOKE_SET_PLAY_SPEED);
|
|
meta->setFloat(kUserInvokeSetPlaybackRate, rate.mSpeed);
|
|
|
|
rt_status status = mPlayerImpl->invoke(meta, NULL);
|
|
|
|
mDestroyMetaDataFunc((void **)&meta);
|
|
return status;
|
|
}
|
|
|
|
rt_status RockitPlayer::dump(int fd, const Vector<String16> &args) {
|
|
(void)args;
|
|
// TODO(@media-team): unsupport args.
|
|
return mPlayerImpl->dump(fd, NULL);
|
|
}
|
|
|
|
}
|
|
|