386 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			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;
 | 
						|
} |