/* * Copyright (c) 2023 Fancy Code. * 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. */ #include "MediaHandle.h" #include "IHalCpp.h" #include "ILog.h" #include "IMediaManager.h" #include "RecordMp4.h" #include "StatusCode.h" #include #include #include #include #include #include #include #include constexpr int MEDIA_TASK_NOT_START = 0; one_frame_stream::one_frame_stream() : mType(FrameType::END), mData(nullptr), mLength(0), mTimeStamp(0) { } one_frame_stream::~one_frame_stream() { } MediaHandle::MediaHandle(const MediaChannel &mediaChannel, const std::shared_ptr &cameraHal) : mMediaChannel(mediaChannel), mCameraHal(cameraHal), mTaskRuning(false), mFirstFrameTimeStamp(MEDIA_TASK_NOT_START) { } void MediaHandle::Init(void) { if (mCameraHal == nullptr) { LogError("CameraHal is null.\n"); return; } auto audioFunc = std::bind(&MediaHandle::GetAudioStreamCallback, this, _1, _2, _3); mCameraHal->SetAudioStreamCallback(audioFunc); auto videoFunc = std::bind(&MediaHandle::GetVideoStreamCallback, this, _1, _2, _3); mCameraHal->SetVideoStreamCallback(videoFunc); } void MediaHandle::UnInit(void) { mTaskRuning = false; mCvTaskHandle.notify_one(); mCvFrameHandle.notify_one(); if (mTaskTimerThread.joinable()) { mTaskTimerThread.join(); } if (mFrameHandleThread.joinable()) { mFrameHandleThread.join(); } if (mCameraHal) { /** * @brief Before releasing the class instance, it is necessary to call the UnInit function to ensure that the * callback function is cleared elsewhere, otherwise it will crash. */ mCameraHal->SetAudioStreamCallback(nullptr); mCameraHal->SetVideoStreamCallback(nullptr); } } StatusCode MediaHandle::ExecuteTask(std::shared_ptr &task) { std::lock_guard locker(mMutex); LogInfo("CameraHandle::ExecuteTask.\n"); auto runingTask = mCurrentTask.lock(); if (!mCurrentTask.expired()) { if (!runingTask->IsTaskFinished()) { LogError("Camera is runing task, can't execute more task.\n"); return CreateStatusCode(STATUS_CODE_NOT_OK); } } mStreamHandle = std::make_shared(task); if (nullptr == mStreamHandle) { LogError("Create stream handle failed.\n"); mStreamHandle.reset(); return CreateStatusCode(STATUS_CODE_NOT_OK); } auto code2 = mStreamHandle->Init(); if (!IsCodeOK(code2)) { LogError("StreamHandle init failed.\n"); return code2; } CameraTaskType taskType = TaskTypeConvert(task->GetTaskType()); CameraTaskParam data(taskType); auto code = mCameraHal->StartSingleTask(data); if (IsCodeOK(code)) { mCurrentTask = task; StartTaskTimer(); StartFrameHandle(); } else { LogError("Execute task failed.\n"); } return code; } StatusCode MediaHandle::StopTask(void) { return CreateStatusCode(STATUS_CODE_OK); } StatusCode MediaHandle::ClearTask(void) { return CreateStatusCode(STATUS_CODE_OK); } void MediaHandle::StartTaskTimer(void) { auto taskTimerThread = [=](std::shared_ptr media) { LogInfo("StartTaskTimer start.\n"); media->TaskTimer(); }; std::shared_ptr media = shared_from_this(); mTaskTimerThread = std::thread(taskTimerThread, media); } void MediaHandle::TaskTimer(void) { constexpr int TASK_TIME_OUT = 1000 * 10; mTaskRuning = true; while (mTaskRuning) { std::unique_lock lock(mMutex); mCvTaskHandle.wait_for(lock, std::chrono::milliseconds(TASK_TIME_OUT), [&] { return !mTaskRuning; }); /** * @brief If the recording time is over, you need to stop the recording timer here. */ mTaskRuning = false; } mStreamHandle->StopHandleStream(); std::vector files; mStreamHandle->GetAllFiles(files); mStreamHandle->UnInit(); if (mCameraHal) { mCameraHal->StopTask(); } mMutex.lock(); mStreamHandle.reset(); mFirstFrameTimeStamp = MEDIA_TASK_NOT_START; auto runingTask = mCurrentTask.lock(); if (mCurrentTask.expired()) { LogWarning("mCurrentTask is expired.\n"); return; } LogInfo("Task finished response to application.\n"); runingTask->Response(files); mCurrentTask.reset(); mMutex.unlock(); } void MediaHandle::StartFrameHandle(void) { auto taskTimerThread = [=](std::shared_ptr media) { LogInfo("StartFrameHandle start.\n"); media->FrameHandle(); }; std::shared_ptr media = shared_from_this(); mFrameHandleThread = std::thread(taskTimerThread, media); } void MediaHandle::FrameHandle(void) { constexpr int TASK_TIMER = 1000 * 1000; mTaskRuning = true; while (mTaskRuning) { std::unique_lock lock(mMutex); mCvFrameHandle.wait_for(lock, std::chrono::milliseconds(TASK_TIMER), [&] { return !mTaskRuning || !mFrameList.empty(); }); /** * @brief * NOTE: From here on the code will be re-locked. */ if (!mStreamHandle) { LogWarning("mStreamHandle is nullptr, will not handle frame.\n"); break; } if (mFrameList.size() > 0) { HandleListFrame(); } } } void MediaHandle::HandleListFrame(void) { int leftFrameCount = -1; do { OneFrameStream &frontFrame = mFrameList.front(); // OneFrameStream handleIt; // handleIt.mData = frontFrame.mData; // handleIt.mLength = frontFrame.mLength; // handleIt.mType = frontFrame.mType; if (FrameType::VIDEO == frontFrame.mType) { mStreamHandle->GetVideoStream(frontFrame.mData, frontFrame.mLength, frontFrame.mTimeStamp); } else if (FrameType::AUDIO == frontFrame.mType) { mStreamHandle->GetAudioStream(frontFrame.mData, frontFrame.mLength, frontFrame.mTimeStamp); } free(frontFrame.mData); frontFrame.mData = nullptr; mFrameList.pop_front(); leftFrameCount = mFrameList.size(); } while (leftFrameCount > 0); } CameraTaskType MediaHandle::TaskTypeConvert(const MediaTaskType &type) { return CameraTaskType::END; } void MediaHandle::GetVideoStreamCallback(const void *stream, const int &length, const unsigned long long &timeStamp) { GetAVStream(FrameType::VIDEO, stream, length, timeStamp); } void MediaHandle::GetAudioStreamCallback(const void *stream, const int &length, const unsigned long long &timeStamp) { GetAVStream(FrameType::AUDIO, stream, length, timeStamp); } void MediaHandle::GetAVStream(const FrameType &type, const void *stream, const int &length, const unsigned long long &timeStamp) { std::unique_lock lock(mMutex); if (MEDIA_TASK_NOT_START == mFirstFrameTimeStamp) { mFirstFrameTimeStamp = timeStamp; } OneFrameStream addFrame; addFrame.mData = malloc(length); // TODO: detected memory leaks addFrame.mLength = length; memcpy(addFrame.mData, stream, length); addFrame.mType = type; addFrame.mTimeStamp = timeStamp - mFirstFrameTimeStamp; mFrameList.push_back(addFrame); mCvFrameHandle.notify_one(); }