android13/hardware/rockchip/tv_input/enc/MppEncodeServer.cpp

386 lines
11 KiB
C++
Executable File

/*
* Copyright 2021 Rockchip Electronics Co. LTD
*
* 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.
*
* author: zj@rock-chips.com
*/
//#define OPEN_DEBUG 1
#define LOG_TAG "MppEncodeServer"
#include "Log.h"
#include "MppEncodeServer.h"
#include <android-base/properties.h>
#include <cutils/properties.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include "MpiDebug.h"
#include "RKMppEncApi.h"
#include "Tools.h"
using namespace android;
#define _ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
uint32_t enc_debug = 0;
RKMppEncApi::EncCfgInfo_t encInfo;
uint32_t mFrameCount = 0;
char videoPath[30] = "/data/video/";
MppEncodeServer::MppEncodeServer()
: mEncoder(NULL),
mOutFrameThread("OutFrameThread"),
mLooper(new ALooper),
mHandler(new WorkHandler) {
Trace();
mLooper->setName("MppEncodeServer");
(void)mLooper->registerHandler(mHandler);
mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
ALOGD("MppEncodeServer enter");
}
bool MppEncodeServer::init(MetaInfo *meta) {
Trace();
Mutexed<ExecState>::Locked state(mExecState);
state->mState = UNINITIALIZED;
// bool needsInit = (state->mState == UNINITIALIZED);
state.unlock();
mEncoder = new RKMppEncApi();
mHandler->setComponent(this);
if (meta == NULL) {
ALOGE("Failed to get metaData");
return false;
}
/*if (nullptr == mOutputFile) {
if (access(videoPath, 0)) {
ALOGI("videoPath %s not found,build it", videoPath);
mkdir(videoPath, 0777);
}
char h264FilePath[256];
struct tm *ptime;
time_t the_time;
//get current time
time(&the_time);
ptime = localtime(&the_time);
sprintf(h264FilePath, "%s/%02d-%02d-%02d-%02d-%02d-%02d.h264",
videoPath, ptime->tm_year % 100, ptime->tm_mon + 1,
ptime->tm_mday, ptime->tm_hour, ptime->tm_min, ptime->tm_sec);
ALOGI("h264FilePath is %s", h264FilePath);
mOutputFile = fopen(h264FilePath, "w+b");
}*/
get_env_u32("enc_debug", &enc_debug, 0);
// if (needsInit) {
// sp<AMessage> reply;
// (new AMessage(WorkHandler::kWhatInit,
// mHandler))->postAndAwaitResponse(&reply);
// int32_t err;
// CHECK(reply->findInt32("err", &err));
// if (err != 0) {
// return (bool)err;
// }
// }else{
// //(new AMessage(WorkHandler::kWhatStart, mHandler))->post();
// }
if (initOther(meta)) {
state.lock();
state->mState = STOPPED;
return true;
} else {
return false;
}
}
bool MppEncodeServer::setNotifyCallback(NotifyCallback callback,
void *userdata) {
mNotifyCallback = callback;
(void)userdata;
return true;
}
// TODO: Expand the parameters
bool MppEncodeServer::initOther(MetaInfo *meta) {
encInfo.width = meta->width;
encInfo.height = meta->height;
encInfo.scaleWidth = _ALIGN((meta->width) / 2, 2);
encInfo.scaleHeight = _ALIGN((meta->height) / 2, 2);
encInfo.format = MPP_FMT_YUV420SP;
encInfo.framerate = meta->fps; // 60fps
encInfo.bitRate = 20000000; // 200M default
encInfo.IDRInterval = 1;
encInfo.bitrateMode =
BITRATE_CONST; /* 0 - VBR mode; 1 - CBR mode; 2 - FIXQP mode */
encInfo.qp = 30; // 1~51
encInfo.profile = H264_PROFILE_BASELINE;
encInfo.level = AVC_LEVEL4_1;
encInfo.rotation = MPP_ENC_ROT_0;
if (!mEncoder->init(&encInfo)) {
ALOGE("Failed to init mEncoder");
return false;
}
return true;
}
void MppEncodeServer::run() {
//usleep(32000);
mThreadExited.exchange(false);
while (mThreadEnabled.load()) {
usleep(100);
processQueue();
ALOGD("run()");
}
mThreadExited.exchange(true);
ALOGD("exit");
}
// TODO: reserved
bool MppEncodeServer::start() {
Trace();
int32_t err;
(void)err;
Mutexed<ExecState>::Locked state(mExecState);
if (state->mState == UNINITIALIZED) {
ALOGE("MppEncodeServer has not been initialized");
return false;
}
// bool needsInit = (state->mState == UNINITIALIZED);
// state.unlock();
// if (needsInit) {
// sp<AMessage> reply;
// (new AMessage(WorkHandler::kWhatInit,
// mHandler))->postAndAwaitResponse(&reply); int32_t err;
// CHECK(reply->findInt32("err", &err));
// if (err != 0) {
// return (bool)err;
// }
// } else {
(new AMessage(WorkHandler::kWhatStart, mHandler))->post();
// }
state.lock();
state->mState = RUNNING;
(new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
return true;
}
// TODO: reserved
bool MppEncodeServer::stop() {
Trace();
{
bool result = true;
mThreadEnabled.exchange(false);
// clear flag that tells thread to loop
while (true) {
if(mThreadExited.load()){
ALOGD("zj add file: %s func %s line %d \n",__FILE__,__FUNCTION__,__LINE__);
result = mOutFrameThread.stop();
break;
}else{
ALOGD("zj add file: %s func %s line %d \n",__FILE__,__FUNCTION__,__LINE__);
usleep(5000);
continue;
}
}
Mutexed<ExecState>::Locked state(mExecState);
if (state->mState != RUNNING) {
return false;
}
state->mState = STOPPED;
}
{
// Mutexed<WorkQueue>::Locked queue(mWorkQueue);
// queue->clear();
// queue->pending().clear();
}
sp<AMessage> reply;
(new AMessage(WorkHandler::kWhatStop, mHandler))
->postAndAwaitResponse(&reply);
int32_t err;
CHECK(reply->findInt32("err", &err));
if (err != 0) {
return (bool)err;
}
return true;
}
bool MppEncodeServer::reset() {
Trace();
{
Mutexed<ExecState>::Locked state(mExecState);
state->mState = UNINITIALIZED;
}
{
// Mutexed<WorkQueue>::Locked queue(mWorkQueue);
// queue->clear();
// queue->pending().clear();
}
sp<AMessage> reply;
(new AMessage(WorkHandler::kWhatReset, mHandler))
->postAndAwaitResponse(&reply);
return true;
}
bool MppEncodeServer::release() {
Trace();
sp<AMessage> reply;
if (mEncoder != NULL) {
ALOGD("Exit mEncoder");
delete mEncoder;
mEncoder = NULL;
}
(new AMessage(WorkHandler::kWhatRelease, mHandler))
->postAndAwaitResponse(&reply);
return true;
}
MppEncodeServer::~MppEncodeServer() {
Trace();
release();
if (nullptr != mOutputFile) {
fclose(mOutputFile);
mOutputFile = nullptr;
}
mLooper->unregisterHandler(mHandler->id());
(void)mLooper->stop();
ALOGD("~MppEncodeServer out");
}
////////////////////////////////////////////////////////////////////////////////
MppEncodeServer::WorkHandler::WorkHandler() {}
void MppEncodeServer::WorkHandler::setComponent(MppEncodeServer *thiz) {
Trace();
mThiz = thiz;
}
static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
sp<AReplyToken> replyId;
CHECK(msg->senderAwaitsResponse(&replyId));
sp<AMessage> reply = new AMessage;
if (err) {
reply->setInt32("err", *err);
}
reply->postReply(replyId);
}
void MppEncodeServer::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
if (!mThiz) {
ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
sp<AReplyToken> replyId;
if (msg->senderAwaitsResponse(&replyId)) {
sp<AMessage> reply = new AMessage;
reply->setInt32("err", EFAULT);
reply->postReply(replyId);
}
return;
}
switch (msg->what()) {
case kWhatProcess: {
mThiz->mThreadEnabled.store(true);
break;
}
case kWhatInit: {
int32_t err = mThiz->mEncoder->onInit();
Reply(msg, &err);
break;
}
case kWhatStart: {
mThiz->mThreadExited.store(false);
mThiz->mThreadEnabled.store(true);
bool err = mThiz->mOutFrameThread.start(mThiz);
if (err != true) {
ALOGE("mOutFrameThread err: %d", err);
break;
}
break;
}
case kWhatStop: {
int32_t err = mThiz->mEncoder->onStop();
// mThiz->mOutputBlockPool.reset();
Reply(msg, &err);
break;
}
case kWhatReset: {
mThiz->mEncoder->onReset();
// mThiz->mOutputBlockPool.reset();
mThiz->mThreadEnabled.exchange(false);
Reply(msg);
break;
}
case kWhatRelease: {
// mThiz->mOutputBlockPool.reset();
mThiz->mThreadEnabled.exchange(false);
Reply(msg);
break;
}
default: {
ALOGE("Unrecognized msg: %d", msg->what());
break;
}
}
}
extern nsecs_t now;
extern nsecs_t mLastTime;
extern nsecs_t diff;
bool MppEncodeServer::processQueue() {
Trace();
bool ret = false;
RKMppEncApi::OutWorkEntry entry;
memset(&entry, 0, sizeof(RKMppEncApi::OutWorkEntry));
// mLastTime = systemTime();
ALOGD("zj add file: %s func %s line %d \n",__FILE__,__FUNCTION__,__LINE__);
ret = mEncoder->getoutpacket(&entry);
ALOGD("zj add file: %s func %s line %d \n",__FILE__,__FUNCTION__,__LINE__);
now = systemTime();
diff = now - mLastTime;
// ALOGD("getoutpacket diff %" PRIu64, diff);
if (ret == true && NULL != entry.outPacket) {
void *data = mpp_packet_get_data(entry.outPacket);
size_t len = mpp_packet_get_length(entry.outPacket);
if (len != 0 && (nullptr != mOutputFile)) {
fwrite(data, 1, len, mOutputFile);
fflush(mOutputFile);
}
ALOGD("getoutput pts %d", entry.frameIndex);
} else {
ALOGD("no new packet this call,continue");
return false;
}
mNotifyCallback.onInputAvailable(entry.index);
if (NULL != entry.outPacket) {
mpp_packet_deinit(&entry.outPacket);
entry.outPacket = NULL;
}
return true;
}