From 458341c9a38491f14a65f3c89f3ec6cd8ba2bd3e Mon Sep 17 00:00:00 2001 From: fuyangchenghu <1015138540@qq.com> Date: Tue, 30 Jan 2024 20:40:41 +0800 Subject: [PATCH 1/2] commit change --- Common/Common.cpp | 52 + Common/Common.h | 48 +- DVPPLite/CMakeLists.txt | 18 +- DVPPLite/include/{ImgProc.h => ImageProc.h} | 36 +- DVPPLite/include/VencHelper.h | 76 + DVPPLite/include/VideoCapBase.h | 54 - DVPPLite/include/VideoProc.h | 51 - .../include/{VideoCapVideo.h => VideoRead.h} | 509 +++-- DVPPLite/include/VideoWrite.h | 83 + DVPPLite/src/{ImgProc.cpp => ImageProc.cpp} | 67 +- DVPPLite/src/VencHelper.cpp | 369 ++++ .../src/{VideoCapVideo.cpp => VideoRead.cpp} | 1750 ++++++++--------- .../src/{VideoProc.cpp => VideoWrite.cpp} | 276 ++- Doc/common.md | 443 +++++ Doc/dvpplite.md | 180 ++ Doc/media.md | 61 + Doc/omexcute.md | 105 + Media/CMakeLists.txt | 60 + .../src/USBCamera.cpp => Media/CameraRead.cpp | 49 +- .../include/USBCamera.h => Media/CameraRead.h | 28 +- Media/README.md | 89 + OMExecute/include/ModelProc.h | 13 +- README.md | 71 +- build_so.sh | 7 + 24 files changed, 2957 insertions(+), 1538 deletions(-) rename DVPPLite/include/{ImgProc.h => ImageProc.h} (63%) create mode 100644 DVPPLite/include/VencHelper.h delete mode 100755 DVPPLite/include/VideoCapBase.h delete mode 100755 DVPPLite/include/VideoProc.h rename DVPPLite/include/{VideoCapVideo.h => VideoRead.h} (84%) mode change 100755 => 100644 create mode 100644 DVPPLite/include/VideoWrite.h rename DVPPLite/src/{ImgProc.cpp => ImageProc.cpp} (91%) create mode 100644 DVPPLite/src/VencHelper.cpp rename DVPPLite/src/{VideoCapVideo.cpp => VideoRead.cpp} (91%) mode change 100755 => 100644 rename DVPPLite/src/{VideoProc.cpp => VideoWrite.cpp} (51%) mode change 100755 => 100644 create mode 100644 Doc/common.md create mode 100644 Doc/dvpplite.md create mode 100644 Doc/media.md create mode 100644 Doc/omexcute.md create mode 100644 Media/CMakeLists.txt rename DVPPLite/src/USBCamera.cpp => Media/CameraRead.cpp (83%) rename DVPPLite/include/USBCamera.h => Media/CameraRead.h (55%) create mode 100644 Media/README.md diff --git a/Common/Common.cpp b/Common/Common.cpp index a9dfaf9..8354171 100644 --- a/Common/Common.cpp +++ b/Common/Common.cpp @@ -37,6 +37,58 @@ bool ReadBinFile(const string& fileName, void*& data, uint32_t& size) return true; } +void* CopyDataToDevice(void* data, uint32_t size) { + void* devicePtr = nullptr; + aclError aclRet = aclrtMalloc(&devicePtr, size, ACL_MEM_MALLOC_NORMAL_ONLY); + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc failed. ERROR: %d", aclRet); return nullptr); + aclrtRunMode runMode; + aclrtGetRunMode(&runMode); + if (runMode == ACL_HOST) { + aclRet = aclrtMemcpy(devicePtr, size, data, size, ACL_MEMCPY_HOST_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + aclrtFree(devicePtr); + devicePtr = nullptr; + return devicePtr; + } + } else { + aclRet = aclrtMemcpy(devicePtr, size, data, size, ACL_MEMCPY_DEVICE_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + aclrtFree(devicePtr); + devicePtr = nullptr; + return devicePtr; + } + } + return devicePtr; +} + +void* CopyDataToHost(void* data, uint32_t size) { + void* hostPtr = nullptr; + aclError aclRet = aclrtMallocHost(&hostPtr, size); + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMalloc failed. ERROR: %d", aclRet); return nullptr); + aclrtRunMode runMode; + aclrtGetRunMode(&runMode); + if (runMode == ACL_HOST) { + aclRet = aclrtMemcpy(hostPtr, size, data, size, ACL_MEMCPY_DEVICE_TO_HOST); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + aclrtFreeHost(hostPtr); + hostPtr = nullptr; + return hostPtr; + } + } else { + aclRet = aclrtMemcpy(hostPtr, size, data, size, ACL_MEMCPY_DEVICE_TO_HOST); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + aclrtFreeHost(hostPtr); + hostPtr = nullptr; + return hostPtr; + } + } + return hostPtr; +} + AclLiteResource::AclLiteResource(int32_t devId): isReleased_(false), deviceId_(devId), context_(nullptr) { diff --git a/Common/Common.h b/Common/Common.h index c46900e..212d4d0 100644 --- a/Common/Common.h +++ b/Common/Common.h @@ -66,26 +66,40 @@ enum memoryLocation { MEMORY_INVALID_TYPE }; -enum resizeType { +enum ResizeType { RESIZE_COMMON = 0, RESIZE_PROPORTIONAL_UPPER_LEFT = 1, RESIZE_PROPORTIONAL_CENTER = 2, }; -struct ImgSize { +enum StreamProperty { + FRAME_WIDTH = 1, + FRAME_HEIGHT = 2, + VIDEO_FPS = 3, + OUTPUT_IMAGE_FORMAT = 4, + RTSP_TRANSPORT = 5, + STREAM_FORMAT = 6 +}; + +struct ImageSize { uint32_t width = 0; uint32_t height = 0; + ImageSize() {} + ImageSize(uint32_t x, uint32_t y) : width(x), height(y) {} }; -struct ImgData { +struct ImageData { std::shared_ptr data = nullptr; uint32_t size = 0; uint32_t width = 0; uint32_t height = 0; uint32_t alignWidth = 0; uint32_t alignHeight = 0; - acldvppPixelFormat format; - memoryLocation location; + acldvppPixelFormat format = PIXEL_FORMAT_YUV_SEMIPLANAR_420; + ImageData() {} + ImageData(std::shared_ptr buf, uint32_t bufSize, + uint32_t x, uint32_t y, acldvppPixelFormat fmt) : data(buf), size(bufSize), + width(x), height(y), format(fmt) {} }; struct FrameData { @@ -95,12 +109,36 @@ struct FrameData { void* data = nullptr; }; +enum VencStatus { + STATUS_VENC_INIT = 0, + STATUS_VENC_WORK, + STATUS_VENC_FINISH, + STATUS_VENC_EXIT, + STATUS_VENC_ERROR +}; + +enum StreamType { + STREAM_VIDEO = 0, + STREAM_RTSP, +}; + +enum DecodeStatus { + DECODE_ERROR = -1, + DECODE_UNINIT = 0, + DECODE_READY = 1, + DECODE_START = 2, + DECODE_FFMPEG_FINISHED = 3, + DECODE_DVPP_FINISHED = 4, + DECODE_FINISHED = 5 +}; + typedef int Result; const int RES_OK = 0; const int RES_ERROR = 1; void SaveBinFile(const std::string& filename, const void* data, uint32_t size); bool ReadBinFile(const std::string& fileName, void*& data, uint32_t& size); +void* CopyDataToDevice(void* data, uint32_t size); aclrtContext GetContextByDevice(int32_t devId); bool SetCurContext(aclrtContext context); diff --git a/DVPPLite/CMakeLists.txt b/DVPPLite/CMakeLists.txt index bea77fb..b4e37fd 100644 --- a/DVPPLite/CMakeLists.txt +++ b/DVPPLite/CMakeLists.txt @@ -23,17 +23,16 @@ else () message(STATUS "env LIB_PATH: ${LIB_PATH}") endif() - link_directories( ${LIB_PATH} ) add_library(acllite_dvpp_lite SHARED - ./src/ImgProc.cpp + ./src/ImageProc.cpp ./src/VdecHelper.cpp - ./src/VideoCapVideo.cpp - ./src/VideoProc.cpp - ./src/USBCamera.cpp + ./src/VideoRead.cpp + ./src/VideoWrite.cpp + ./src/VencHelper.cpp ) include_directories(acllite_dvpp_lite ./include @@ -63,9 +62,8 @@ target_link_libraries(acllite_dvpp_lite ) INSTALL(TARGETS acllite_dvpp_lite LIBRARY DESTINATION lib) -INSTALL(FILES ./include/ImgProc.h DESTINATION include/acllite_dvpp_lite) +INSTALL(FILES ./include/ImageProc.h DESTINATION include/acllite_dvpp_lite) INSTALL(FILES ./include/VdecHelper.h DESTINATION include/acllite_dvpp_lite) -INSTALL(FILES ./include/VideoCapBase.h DESTINATION include/acllite_dvpp_lite) -INSTALL(FILES ./include/VideoCapVideo.h DESTINATION include/acllite_dvpp_lite) -INSTALL(FILES ./include/VideoProc.h DESTINATION include/acllite_dvpp_lite) -INSTALL(FILES ./include/USBCamera.h DESTINATION include/acllite_dvpp_lite) +INSTALL(FILES ./include/VideoRead.h DESTINATION include/acllite_dvpp_lite) +INSTALL(FILES ./include/VencHelper.h DESTINATION include/acllite_dvpp_lite) +INSTALL(FILES ./include/VideoWrite.h DESTINATION include/acllite_dvpp_lite) diff --git a/DVPPLite/include/ImgProc.h b/DVPPLite/include/ImageProc.h similarity index 63% rename from DVPPLite/include/ImgProc.h rename to DVPPLite/include/ImageProc.h index 656ddb8..75c1a29 100644 --- a/DVPPLite/include/ImgProc.h +++ b/DVPPLite/include/ImageProc.h @@ -13,38 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. -* File ImgProc.h +* File ImageProc.h * Description: handle dvpp process */ -#ifndef IMGPROC_H -#define IMGPROC_H +#ifndef IMAGEPROC_H +#define IMAGEPROC_H #pragma once #include "acllite_common/Common.h" #include "acl/acl.h" #include "acl/ops/acl_dvpp.h" namespace acllite { -class ImgProc { +class ImageProc { public: - ImgProc(int deviceId = 0); - ~ImgProc(); - ImgData ImRead(const std::string& fileName, acldvppPixelFormat imgFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420); - void Resize(ImgData& src, ImgData& dst, ImgSize dsize, double fx = 0, double fy = 0, resizeType type = RESIZE_COMMON); - bool ImWrite(const std::string& fileName, ImgData& img); + ImageProc(int deviceId = 0); + ~ImageProc(); + ImageData Read(const std::string& fileName, acldvppPixelFormat imgFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420); + void Resize(ImageData& src, ImageData& dst, ImageSize dsize, ResizeType type = RESIZE_COMMON); + bool Write(const std::string& fileName, ImageData& img); private: bool Init(); void DestroyResource(); bool SetJpegdPicDescNV12(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat); - ImgData JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420); + ImageData JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420); bool SetPngdPicDescRGB(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat); - ImgData PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat = PIXEL_FORMAT_RGB_888); - bool SetVpcInputPicDescYUV420SP(ImgData& src); - bool SetVpcInputPicDescYUV422P(ImgData& src); - bool SetVpcOutputPicDescYUV420SP(ImgSize dsize, acldvppPixelFormat format); - void ResizeCommon(ImgData& src, ImgData& dst, ImgSize dsize); - void ResizeProportionalUpperLeft(ImgData& src, ImgData& dst, ImgSize dsize); - void ResizeProportionalCenter(ImgData& src, ImgData& dst, ImgSize dsize); - bool SetJpgePicDescNV12(ImgData& src); + ImageData PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat = PIXEL_FORMAT_RGB_888); + bool SetVpcInputPicDescYUV420SP(ImageData& src); + bool SetVpcInputPicDescYUV422P(ImageData& src); + bool SetVpcOutputPicDescYUV420SP(ImageSize dsize, acldvppPixelFormat format); + void ResizeCommon(ImageData& src, ImageData& dst, ImageSize dsize); + void ResizeProportionalUpperLeft(ImageData& src, ImageData& dst, ImageSize dsize); + void ResizeProportionalCenter(ImageData& src, ImageData& dst, ImageSize dsize); + bool SetJpgePicDescNV12(ImageData& src); private: bool isReleased_; diff --git a/DVPPLite/include/VencHelper.h b/DVPPLite/include/VencHelper.h new file mode 100644 index 0000000..ec6cbde --- /dev/null +++ b/DVPPLite/include/VencHelper.h @@ -0,0 +1,76 @@ +/** +* @file VencHelper.h +* +* Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ +#ifndef VENC_HELPER_H +#define VENC_HELPER_H +#pragma once +#include +#include +#include +#include "acl/acl.h" +#include "acl/ops/acl_dvpp.h" +#include "acllite_common/Common.h" +#include "acllite_common/ThreadSafeQueue.h" + +namespace acllite { +class VencHelper { +public: + VencHelper(std::string outFile, uint32_t maxWidth, + uint32_t maxHeight, int32_t deviceId, + acldvppPixelFormat format, acldvppStreamFormat enType); + ~VencHelper(); + Result Init(); + Result Process(ImageData &image); + void Finish(); + VencStatus GetStatus() + { + return status_; + } + + void DestroyResource(); +private: + void SetStatus(VencStatus status) + { + status_ = status; + } + Result CreateVencChannel(); + Result CreateInputPicDesc(ImageData& image); + Result CreateFrameConfig(); + Result SetFrameConfig(uint8_t eos, uint8_t forceIFrame); + Result SaveVencFile(void* vencData, uint32_t size); + + static void Callback(acldvppPicDesc *input, + acldvppStreamDesc *output, void *userData); + static void* SubscribleThreadFunc(void *arg); + +private: + VencStatus status_; + aclvencChannelDesc *vencChannelDesc_; + aclvencFrameConfig *vencFrameConfig_; + aclrtStream vencStream_; + acldvppPicDesc *inputPicDesc_; + FILE *outFp_; + bool isFinished_; + pthread_t threadId_; + uint32_t finFrameCnt_; + uint32_t frameId_; + bool isReleased_; + + int32_t deviceId_; + aclrtContext context_; + aclrtRunMode runMode_; + std::string outFile_; + uint32_t maxWidth_; + uint32_t maxHeight_; + acldvppPixelFormat format_; + acldvppStreamFormat enType_; + +}; +} // namespace acllite +#endif \ No newline at end of file diff --git a/DVPPLite/include/VideoCapBase.h b/DVPPLite/include/VideoCapBase.h deleted file mode 100755 index b4e341e..0000000 --- a/DVPPLite/include/VideoCapBase.h +++ /dev/null @@ -1,54 +0,0 @@ -/** -* Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. -* -* 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. - -* File utils.h -* Description: handle file operations -*/ -#ifndef VIDEO_CAP_BASE_H -#define VIDEO_CAP_BASE_H -#pragma once -#include "acllite_common/Common.h" -#define RTSP_TRANS_UDP ((uint32_t)0) -#define RTSP_TRANS_TCP ((uint32_t)1) - -namespace acllite { -enum StreamProperty { - FRAME_WIDTH = 1, - FRAME_HEIGHT = 2, - VIDEO_FPS = 3, - OUTPUT_IMAGE_FORMAT = 4, - RTSP_TRANSPORT = 5, - STREAM_FORMAT = 6 -}; - -class VideoCapBase { -public: - VideoCapBase() {} - virtual ~VideoCapBase(){}; - virtual bool IsOpened() = 0; - virtual bool Set(int propId, uint32_t value) - { - return true; - } - virtual uint32_t Get(int propId) - { - return 0; - } - virtual bool Read(ImgData& frame) = 0; - virtual void Release() = 0; - virtual Result Open() = 0; -}; -} // namespace acllite -#endif \ No newline at end of file diff --git a/DVPPLite/include/VideoProc.h b/DVPPLite/include/VideoProc.h deleted file mode 100755 index 8776af5..0000000 --- a/DVPPLite/include/VideoProc.h +++ /dev/null @@ -1,51 +0,0 @@ -/** -* Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. -* -* 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. - -* File utils.h -* Description: handle file operations -*/ -#ifndef VIDEO_CAPTURE_H -#define VIDEO_CAPTURE_H -#pragma once - -#include -#include "acllite_common/Common.h" -#include "VideoCapBase.h" - -namespace acllite { -class VideoProc { -public: - VideoProc(int32_t deviceId = 0, aclrtContext context = nullptr); - VideoProc(const std::string& filePath, int32_t deviceId = 0, - aclrtContext context = nullptr); - ~VideoProc(); - bool Open(const std::string& filePath, int32_t deviceId = 0, - aclrtContext context = nullptr); - bool IsOpened(); - bool Set(int propId, uint32_t value); - uint32_t Get(int propId); - bool Read(ImgData& frame); - void Release(); - -private: - Result Open(); - -private: - int32_t deviceId_; - aclrtContext context_; - VideoCapBase* cap_; -}; -} // namespace acllite -#endif \ No newline at end of file diff --git a/DVPPLite/include/VideoCapVideo.h b/DVPPLite/include/VideoRead.h old mode 100755 new mode 100644 similarity index 84% rename from DVPPLite/include/VideoCapVideo.h rename to DVPPLite/include/VideoRead.h index 507b7f7..5cf1438 --- a/DVPPLite/include/VideoCapVideo.h +++ b/DVPPLite/include/VideoRead.h @@ -1,265 +1,244 @@ -/** - * ============================================================================ - * - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1 Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2 Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3 Neither the names of the copyright holders nor the names of the - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * ============================================================================ - */ - -#ifndef VIDEO_DECODE_H -#define VIDEO_DECODE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include "acllite_common/ThreadSafeQueue.h" -#include "VdecHelper.h" -#include "VideoProc.h" - -extern "C" { -#include -#include -} - -#define INVALID_CHANNEL_ID (-1) -#define INVALID_STREAM_FORMAT (-1) -#define VIDEO_CHANNEL_MAX (256) -#define RTSP_TRANSPORT_UDP "udp" -#define RTSP_TRANSPORT_TCP "tcp" - -namespace acllite { -typedef int (*FrameProcessCallBack)(void* callback_param, void *frame_data, - int frame_size); - -enum StreamType { - STREAM_VIDEO = 0, - STREAM_RTSP, -}; - -enum DecodeStatus { - DECODE_ERROR = -1, - DECODE_UNINIT = 0, - DECODE_READY = 1, - DECODE_START = 2, - DECODE_FFMPEG_FINISHED = 3, - DECODE_DVPP_FINISHED = 4, - DECODE_FINISHED = 5 -}; - -class ChannelIdGenerator { -public: - ChannelIdGenerator() - { - for (int i = 0; i < VIDEO_CHANNEL_MAX; i++) { - channelId_[i] = INVALID_CHANNEL_ID; - } - } - ~ChannelIdGenerator(){}; - - int GenerateChannelId(void) - { - std::lock_guard lock(mutex_lock_); - for (int i = 0; i < VIDEO_CHANNEL_MAX; i++) { - if (channelId_[i] == INVALID_CHANNEL_ID) { - channelId_[i] = i; - return i; - } - } - - return INVALID_CHANNEL_ID; - } - - void ReleaseChannelId(int channelId) - { - std::lock_guard lock(mutex_lock_); - if ((channelId >= 0) && (channelId < VIDEO_CHANNEL_MAX)) { - channelId_[channelId] = INVALID_CHANNEL_ID; - } - } - -private: - int channelId_[VIDEO_CHANNEL_MAX]; - mutable std::mutex mutex_lock_; -}; - -class FFmpegDecoder { -public: - FFmpegDecoder(const std::string& name); - ~FFmpegDecoder() {} - void Decode(FrameProcessCallBack callback_func, void *callback_param); - int GetFrameWidth() - { - return frameWidth_; - } - int GetFrameHeight() - { - return frameHeight_; - } - int GetVideoType() - { - return videoType_; - } - int GetFps() - { - return fps_; - } - int IsFinished() - { - return isFinished_; - } - int GetProfile() - { - return profile_; - } - void SetTransport(const std::string& transportType); - void StopDecode() - { - isStop_ = true; - } - -private: - int GetVideoIndex(AVFormatContext* av_format_context); - void GetVideoInfo(); - void InitVideoStreamFilter(const AVBitStreamFilter* &video_filter); - bool OpenVideo(AVFormatContext*& av_format_context); - void SetDictForRtsp(AVDictionary* &avdic); - bool InitVideoParams(int videoIndex, - AVFormatContext* av_format_context, - AVBSFContext* &bsf_ctx); - -private: - bool isFinished_; - bool isStop_; - int frameWidth_; - int frameHeight_; - int videoType_; - int profile_; - int fps_; - std::string streamName_; - std::string rtspTransport_; -}; - -class VideoCapVideo : public VideoCapBase { -public: - /** - * @brief VideoCapVideo constructor - */ - VideoCapVideo(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr); - - /** - * @brief VideoCapVideo destructor - */ - ~VideoCapVideo(); - - static void FrameDecodeThreadFunction(void* decoderSelf); - static Result FrameDecodeCallback(void* context, void* frameData, - int frameSize); - static void DvppVdecCallback(acldvppStreamDesc *input, - acldvppPicDesc *output, void *userdata); - void ProcessDecodedImage(std::shared_ptr frameData); - bool Read(ImgData& image); - - void FFmpegDecode() - { - ffmpegDecoder_->Decode(&VideoCapVideo::FrameDecodeCallback, (void*) this); - } - - bool IsOpened(); - Result Open(); - - void SetEnd() - { - isFrameDecodeEnd_ = true; - } - - bool GetEnd() - { - return isFrameDecodeEnd_; - } - - void SetStatus(DecodeStatus status) - { - status_ = status; - } - DecodeStatus GetStatus() - { - return status_; - } - - bool Set(int propId, int value); - uint32_t Get(int propId); - - void SleeptoNextFrameTime(); - Result SetAclContext(); - void Release(); - - void DestroyResource(); - bool IsStop() - { - return isStop_; - } - -private: - Result InitResource(); - Result InitVdecDecoder(); - Result InitFFmpegDecoder(); - void StartFrameDecoder(); - int GetVdecType(); - Result FrameImageEnQueue(std::shared_ptr frameData); - std::shared_ptr FrameImageOutQueue(bool noWait = false); - Result SetRtspTransType(uint32_t transCode); - -private: - bool isStop_; - bool isReleased_; - bool isFrameDecodeEnd_; - StreamType streamType_; - DecodeStatus status_; - int32_t deviceId_; - aclrtContext context_; - aclrtRunMode runMode_; - int channelId_; - int streamFormat_; - uint32_t frameId_; - uint32_t finFrameCnt_; - int64_t lastDecodeTime_; - int64_t fpsInterval_; - std::string streamName_; - std::thread decodeThread_; - FFmpegDecoder* ffmpegDecoder_; - VdecHelper* dvppVdec_; - ThreadSafeQueue> frameImageQueue_; - int videoChannelMax_; -}; -} // namespace acllite -#endif /* VIDEO_DECODE_H_ */ +/** + * ============================================================================ + * + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2 Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3 Neither the names of the copyright holders nor the names of the + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + */ + +#ifndef VIDEO_READ_H +#define VIDEO_READ_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "acllite_common/Common.h" +#include "acllite_common/ThreadSafeQueue.h" +#include "VdecHelper.h" + +extern "C" { +#include +#include +} + +#define RTSP_TRANS_UDP ((uint32_t)0) +#define RTSP_TRANS_TCP ((uint32_t)1) +#define INVALID_CHANNEL_ID (-1) +#define INVALID_STREAM_FORMAT (-1) +#define VIDEO_CHANNEL_MAX (256) +#define RTSP_TRANSPORT_UDP "udp" +#define RTSP_TRANSPORT_TCP "tcp" + +namespace acllite { +typedef int (*FrameProcessCallBack)(void* callback_param, void *frame_data, + int frame_size); + +class ChannelIdGenerator { +public: + ChannelIdGenerator() + { + for (int i = 0; i < VIDEO_CHANNEL_MAX; i++) { + channelId_[i] = INVALID_CHANNEL_ID; + } + } + ~ChannelIdGenerator(){}; + + int GenerateChannelId(void) + { + std::lock_guard lock(mutex_lock_); + for (int i = 0; i < VIDEO_CHANNEL_MAX; i++) { + if (channelId_[i] == INVALID_CHANNEL_ID) { + channelId_[i] = i; + return i; + } + } + + return INVALID_CHANNEL_ID; + } + + void ReleaseChannelId(int channelId) + { + std::lock_guard lock(mutex_lock_); + if ((channelId >= 0) && (channelId < VIDEO_CHANNEL_MAX)) { + channelId_[channelId] = INVALID_CHANNEL_ID; + } + } + +private: + int channelId_[VIDEO_CHANNEL_MAX]; + mutable std::mutex mutex_lock_; +}; + +class FFmpegDecoder { +public: + FFmpegDecoder(const std::string& name); + ~FFmpegDecoder() {} + void Decode(FrameProcessCallBack callback_func, void *callback_param); + int GetFrameWidth() + { + return frameWidth_; + } + int GetFrameHeight() + { + return frameHeight_; + } + int GetVideoType() + { + return videoType_; + } + int GetFps() + { + return fps_; + } + int IsFinished() + { + return isFinished_; + } + int GetProfile() + { + return profile_; + } + void SetTransport(const std::string& transportType); + void StopDecode() + { + isStop_ = true; + } + +private: + int GetVideoIndex(AVFormatContext* av_format_context); + void GetVideoInfo(); + void InitVideoStreamFilter(const AVBitStreamFilter* &video_filter); + bool OpenVideo(AVFormatContext*& av_format_context); + void SetDictForRtsp(AVDictionary* &avdic); + bool InitVideoParams(int videoIndex, + AVFormatContext* av_format_context, + AVBSFContext* &bsf_ctx); + +private: + bool isFinished_; + bool isStop_; + int frameWidth_; + int frameHeight_; + int videoType_; + int profile_; + int fps_; + std::string streamName_; + std::string rtspTransport_; +}; + +class VideoRead { +public: + /** + * @brief VideoRead constructor + */ + VideoRead(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr); + + /** + * @brief VideoRead destructor + */ + ~VideoRead(); + bool Read(ImageData& image); + bool IsOpened(); + bool Set(StreamProperty propId, int value); + uint32_t Get(StreamProperty propId); + void Release(); + + +private: + Result Open(); + Result SetAclContext(); + Result InitResource(); + Result InitVdecDecoder(); + Result InitFFmpegDecoder(); + static void FrameDecodeThreadFunction(void* decoderSelf); + static Result FrameDecodeCallback(void* context, void* frameData, + int frameSize); + static void DvppVdecCallback(acldvppStreamDesc *input, + acldvppPicDesc *output, void *userdata); + void ProcessDecodedImage(std::shared_ptr frameData); + void StartFrameDecoder(); + int GetVdecType(); + void FFmpegDecode() + { + ffmpegDecoder_->Decode(&VideoRead::FrameDecodeCallback, (void*) this); + } + Result FrameImageEnQueue(std::shared_ptr frameData); + std::shared_ptr FrameImageOutQueue(bool noWait = false); + void SleeptoNextFrameTime(); + void SetStatus(DecodeStatus status) + { + status_ = status; + } + DecodeStatus GetStatus() + { + return status_; + } + void SetEnd() + { + isFrameDecodeEnd_ = true; + } + bool GetEnd() + { + return isFrameDecodeEnd_; + } + bool IsStop() + { + return isStop_; + } + Result SetRtspTransType(uint32_t transCode); + void DestroyResource(); + +private: + bool isStop_; + bool isReleased_; + bool isFrameDecodeEnd_; + StreamType streamType_; + DecodeStatus status_; + int32_t deviceId_; + aclrtContext context_; + aclrtRunMode runMode_; + int channelId_; + int streamFormat_; + uint32_t frameId_; + uint32_t finFrameCnt_; + int64_t lastDecodeTime_; + int64_t fpsInterval_; + std::string streamName_; + std::thread decodeThread_; + FFmpegDecoder* ffmpegDecoder_; + VdecHelper* dvppVdec_; + ThreadSafeQueue> frameImageQueue_; + int videoChannelMax_; +}; +} // namespace acllite +#endif /* VIDEO_READ_H_ */ diff --git a/DVPPLite/include/VideoWrite.h b/DVPPLite/include/VideoWrite.h new file mode 100644 index 0000000..ebf41ce --- /dev/null +++ b/DVPPLite/include/VideoWrite.h @@ -0,0 +1,83 @@ +/** + * ============================================================================ + * + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2 Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3 Neither the names of the copyright holders nor the names of the + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + */ + +#ifndef VIDEO_WRITE_H +#define VIDEO_WRITE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "acllite_common/Common.h" +#include "acllite_common/ThreadSafeQueue.h" +#include "VencHelper.h" + +namespace acllite { + +class VideoWrite { +public: + /** + * @brief VideoWrite constructor + */ + VideoWrite(std::string outFile, uint32_t maxWidth, + uint32_t maxHeight, int32_t deviceId = 0); + /** + * @brief VideoWrite destructor + */ + ~VideoWrite(); + bool IsOpened(); + bool Write(ImageData& image); + void Release(); + +private: + Result Open(); + Result InitResource(); + void DestroyResource(); + +private: + bool isReleased_; + VencStatus status_; + int32_t deviceId_; + VencHelper* dvppVenc_; + std::string outFile_; + uint32_t maxWidth_; + uint32_t maxHeight_; + acldvppPixelFormat format_; + acldvppStreamFormat enType_; +}; +} // namespace acllite +#endif /* VIDEO_WRITE_H */ diff --git a/DVPPLite/src/ImgProc.cpp b/DVPPLite/src/ImageProc.cpp similarity index 91% rename from DVPPLite/src/ImgProc.cpp rename to DVPPLite/src/ImageProc.cpp index e6faa94..8c533dc 100644 --- a/DVPPLite/src/ImgProc.cpp +++ b/DVPPLite/src/ImageProc.cpp @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. -* File ImgProc.cpp +* File ImageProc.cpp * Description: handle dvpp process */ #include -#include "ImgProc.h" +#include "ImageProc.h" using namespace std; namespace acllite { -ImgProc::ImgProc(int deviceId):isReleased_(false), stream_(nullptr), +ImageProc::ImageProc(int deviceId):isReleased_(false), stream_(nullptr), dvppChannelDesc_(nullptr), jpegeConfig_(nullptr), resizeConfig_(nullptr), cropArea_(nullptr), pasteArea_(nullptr), srcPicDesc_(nullptr), dstPicDesc_(nullptr), dstBuffer_(nullptr) @@ -30,12 +30,12 @@ ImgProc::ImgProc(int deviceId):isReleased_(false), stream_(nullptr), Init(); } -ImgProc::~ImgProc() +ImageProc::~ImageProc() { DestroyResource(); } -void ImgProc::DestroyResource() +void ImageProc::DestroyResource() { if (isReleased_) { return; @@ -56,7 +56,7 @@ void ImgProc::DestroyResource() isReleased_ = true; } -bool ImgProc::Init() +bool ImageProc::Init() { aclError aclRet; aclRet = aclrtCreateStream(&stream_); @@ -78,8 +78,8 @@ bool ImgProc::Init() return true; } -/************************imread fun************************/ -bool ImgProc::SetJpegdPicDescNV12(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat) +/************************Read fun************************/ +bool ImageProc::SetJpegdPicDescNV12(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat) { // case YUV420SP NV12 8bit / YUV420SP NV21 8bit dstWidth_ = ALIGN_UP2(srcWidth); @@ -106,11 +106,11 @@ bool ImgProc::SetJpegdPicDescNV12(uint32_t srcWidth, uint32_t srcHeight, acldvpp return true; } -ImgData ImgProc::JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat) +ImageData ImageProc::JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat) { - // struct ImgData + // struct ImageData // get image info - ImgData dst; + ImageData dst; uint32_t width = 0; uint32_t height = 0; int32_t ch = 0; @@ -149,7 +149,6 @@ ImgData ImgProc::JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFor dst.alignWidth = dstWidthStride_; dst.alignHeight = dstHeightStride_; dst.format = dstFormat; - dst.location = MEMORY_DVPP; // release jpegd input mem and output pic desc acldvppFree(deviceMem); if (dstPicDesc_ != nullptr) { @@ -159,7 +158,7 @@ ImgData ImgProc::JpegD(void*& hostData, uint32_t size, acldvppPixelFormat dstFor return dst; } -bool ImgProc::SetPngdPicDescRGB(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat) +bool ImageProc::SetPngdPicDescRGB(uint32_t srcWidth, uint32_t srcHeight, acldvppPixelFormat dstFormat) { // case RGB888 dstWidth_ = srcWidth; @@ -181,11 +180,11 @@ bool ImgProc::SetPngdPicDescRGB(uint32_t srcWidth, uint32_t srcHeight, acldvppPi return true; } -ImgData ImgProc::PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat) +ImageData ImageProc::PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstFormat) { - // struct ImgData + // struct ImageData // get image info - ImgData dst; + ImageData dst; uint32_t width = 0; uint32_t height = 0; int32_t ch = 0; @@ -223,7 +222,6 @@ ImgData ImgProc::PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstForm dst.alignWidth = dstWidthStride_; dst.alignHeight = dstHeightStride_; dst.format = dstFormat; - dst.location = MEMORY_DVPP; // release pngd input mem and output pic desc acldvppFree(deviceMem); if (dstPicDesc_ != nullptr) { @@ -233,7 +231,7 @@ ImgData ImgProc::PngD(void*& hostData, uint32_t size, acldvppPixelFormat dstForm return dst; } -ImgData ImgProc::ImRead(const string& filePath, acldvppPixelFormat imgFormat) +ImageData ImageProc::Read(const string& filePath, acldvppPixelFormat imgFormat) { // read file to host void* hostDataBuf = nullptr; @@ -250,14 +248,14 @@ ImgData ImgProc::ImRead(const string& filePath, acldvppPixelFormat imgFormat) } else if (fileType=="png") { return PngD(hostDataBuf, hostDataSize, imgFormat); } else { - LOG_PRINT("[ERROR] ImRead file type not supported."); - ImgData dst; + LOG_PRINT("[ERROR] Read file type not supported."); + ImageData dst; return dst; } } /************************resize fun************************/ -bool ImgProc::SetVpcInputPicDescYUV422P(ImgData& src) +bool ImageProc::SetVpcInputPicDescYUV422P(ImageData& src) { // case YUV422Packed 8bit srcWidth_ = ALIGN_UP2(src.width); @@ -301,7 +299,7 @@ bool ImgProc::SetVpcInputPicDescYUV422P(ImgData& src) return true; } -bool ImgProc::SetVpcInputPicDescYUV420SP(ImgData& src) +bool ImageProc::SetVpcInputPicDescYUV420SP(ImageData& src) { // case YUV420SP NV12 8bit / YUV420SP NV21 8bit srcWidth_ = ALIGN_UP2(src.width); @@ -336,7 +334,7 @@ bool ImgProc::SetVpcInputPicDescYUV420SP(ImgData& src) return true; } -bool ImgProc::SetVpcOutputPicDescYUV420SP(ImgSize dsize, acldvppPixelFormat format) +bool ImageProc::SetVpcOutputPicDescYUV420SP(ImageSize dsize, acldvppPixelFormat format) { // case YUV420SP NV12 8bit / YUV420SP NV21 8bit dstWidth_ = ALIGN_UP2(dsize.width); @@ -365,7 +363,7 @@ bool ImgProc::SetVpcOutputPicDescYUV420SP(ImgSize dsize, acldvppPixelFormat form return true; } -void ImgProc::ResizeCommon(ImgData& src, ImgData& dst, ImgSize dsize) +void ImageProc::ResizeCommon(ImageData& src, ImageData& dst, ImageSize dsize) { acldvppPixelFormat format; switch (src.format) { @@ -405,7 +403,6 @@ void ImgProc::ResizeCommon(ImgData& src, ImgData& dst, ImgSize dsize) dst.alignWidth = dstWidthStride_; dst.alignHeight = dstHeightStride_; dst.format = format; - dst.location = MEMORY_DVPP; if (resizeConfig_ != nullptr) { (void)acldvppDestroyResizeConfig(resizeConfig_); @@ -422,7 +419,7 @@ void ImgProc::ResizeCommon(ImgData& src, ImgData& dst, ImgSize dsize) return; } -void ImgProc::ResizeProportionalUpperLeft(ImgData& src, ImgData& dst, ImgSize dsize) +void ImageProc::ResizeProportionalUpperLeft(ImageData& src, ImageData& dst, ImageSize dsize) { acldvppPixelFormat format; switch (src.format) { @@ -504,7 +501,6 @@ void ImgProc::ResizeProportionalUpperLeft(ImgData& src, ImgData& dst, ImgSize ds dst.alignWidth = dstWidthStride_; dst.alignHeight = dstHeightStride_; dst.format = format; - dst.location = MEMORY_DVPP; if (cropArea_ != nullptr) { (void)acldvppDestroyRoiConfig(cropArea_); cropArea_ = nullptr; @@ -524,7 +520,7 @@ void ImgProc::ResizeProportionalUpperLeft(ImgData& src, ImgData& dst, ImgSize ds return; } -void ImgProc::ResizeProportionalCenter(ImgData& src, ImgData& dst, ImgSize dsize) +void ImageProc::ResizeProportionalCenter(ImageData& src, ImageData& dst, ImageSize dsize) { acldvppPixelFormat format; switch (src.format) { @@ -608,7 +604,6 @@ void ImgProc::ResizeProportionalCenter(ImgData& src, ImgData& dst, ImgSize dsize dst.alignWidth = dstWidthStride_; dst.alignHeight = dstHeightStride_; dst.format = format; - dst.location = MEMORY_DVPP; if (cropArea_ != nullptr) { (void)acldvppDestroyRoiConfig(cropArea_); cropArea_ = nullptr; @@ -628,15 +623,11 @@ void ImgProc::ResizeProportionalCenter(ImgData& src, ImgData& dst, ImgSize dsize return; } -void ImgProc::Resize(ImgData& src, ImgData& dst, ImgSize dSize, double fx, double fy, resizeType type) +void ImageProc::Resize(ImageData& src, ImageData& dst, ImageSize dSize, ResizeType type) { - if ((dSize.width==0 || dSize.height==0) && (fx == 0 || fy == 0)) { + if (dSize.width==0 || dSize.height==0) { LOG_PRINT("[ERROR] dsize(%d, %d) not supported", dSize.width, dSize.height); } - if (dSize.width==0 && dSize.height==0) { - dSize.width = static_cast(round(fx * (src.width))); - dSize.height = static_cast(round(fy * (src.height))); - } switch (type) { case RESIZE_COMMON: ResizeCommon(src, dst, dSize); @@ -654,8 +645,8 @@ void ImgProc::Resize(ImgData& src, ImgData& dst, ImgSize dSize, double fx, doubl return; } -/************************ImWrite fun************************/ -bool ImgProc::SetJpgePicDescNV12(ImgData& src) +/************************Write fun************************/ +bool ImageProc::SetJpgePicDescNV12(ImageData& src) { // case YUV420SP NV12 8bit / YUV420SP NV21 8bit srcWidth_ = ALIGN_UP2(src.width); @@ -680,7 +671,7 @@ bool ImgProc::SetJpgePicDescNV12(ImgData& src) return true; } -bool ImgProc::ImWrite(const string& fileName, ImgData& img) +bool ImageProc::Write(const string& fileName, ImageData& img) { bool ret = SetJpgePicDescNV12(img); CHECK_RET(ret, LOG_PRINT("[ERROR] SetJpgePicDescNV12 failed."); return false); diff --git a/DVPPLite/src/VencHelper.cpp b/DVPPLite/src/VencHelper.cpp new file mode 100644 index 0000000..04f5ae9 --- /dev/null +++ b/DVPPLite/src/VencHelper.cpp @@ -0,0 +1,369 @@ +/** +* @file VencHelper.cpp +* +* Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ +#include +#include +#include +#include + +#include "VencHelper.h" + +using namespace std; +namespace acllite { + uint32_t kKeyFrameInterval = 16; + uint32_t kRcMode = 2; + uint32_t kMaxBitRate = 10000; + uint32_t kVencQueueSize = 256; + uint32_t kImageEnQueueRetryTimes = 3; + uint32_t kEnqueueWait = 10000; + uint32_t kOutqueueWait = 10000; + uint32_t kAsyncWait = 10000; + bool g_runFlag = true; + +VencHelper::VencHelper(string outFile, uint32_t maxWidth, + uint32_t maxHeight, int32_t deviceId, + acldvppPixelFormat format, acldvppStreamFormat enType) + :status_(STATUS_VENC_INIT), vencChannelDesc_(nullptr), + vencFrameConfig_(nullptr), vencStream_(nullptr), + inputPicDesc_(nullptr), outFp_(nullptr), + isFinished_(false), threadId_(0), + finFrameCnt_(0), frameId_(0), isReleased_(false), + outFile_(outFile), maxWidth_(maxWidth), maxHeight_(maxHeight), + format_(format), enType_(enType), context_(nullptr) +{ +} + +VencHelper::~VencHelper() +{ + DestroyResource(); +} + +Result VencHelper::SaveVencFile(void* vencData, uint32_t size) +{ + Result ret = RES_OK; + void* hostData = vencData; + if (runMode_ == ACL_HOST) { + aclError aclRet = aclrtMallocHost(&hostData, size); + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] aclrtMallocHost failed. ERROR: %d", aclRet); return false); + // copy to host + aclRet = aclrtMemcpy(hostData, size, vencData, size, ACL_MEMCPY_DEVICE_TO_HOST); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + aclrtFreeHost(hostData); + return false; + } + } + size_t checkSize = fwrite(hostData, 1, size, outFp_); + if (checkSize != size) { + LOG_PRINT("[ERROR] Save venc file %s failed, need write %u bytes, " + "but only write %zu bytes, error: %s", + outFile_.c_str(), size, checkSize, strerror(errno)); + ret = RES_ERROR; + } else { + fflush(outFp_); + } + + if (runMode_ == ACL_HOST) { + aclrtFreeHost(hostData); + } + + return ret; +} + +void VencHelper::Callback(acldvppPicDesc *input, + acldvppStreamDesc *output, void *userData) +{ + VencHelper* venc = (VencHelper*)userData; + void* data = acldvppGetStreamDescData(output); + uint32_t retCode = acldvppGetStreamDescRetCode(output); + if (retCode == 0) { + // encode success, then process output pic + uint32_t size = acldvppGetStreamDescSize(output); + Result ret = venc->SaveVencFile(data, size); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Save venc file failed, error %d", ret); + } else { + LOG_PRINT("[INFO] success to callback, stream size:%u", size); + } + } else { + LOG_PRINT("[ERROR] venc encode frame failed, ret = %u.", retCode); + } + void* inputData = acldvppGetPicDescData(input); + if (inputData!=nullptr) { + acldvppFree(inputData); + } + acldvppDestroyPicDesc(input); + venc->finFrameCnt_++; +} + +void* VencHelper::SubscribleThreadFunc(aclrtContext sharedContext) +{ + if (sharedContext == nullptr) { + LOG_PRINT("[ERROR] sharedContext can not be nullptr"); + return ((void*)(-1)); + } + LOG_PRINT("[INFO] use shared context for this thread"); + aclError ret = aclrtSetCurrentContext(sharedContext); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtSetCurrentContext failed, errorCode = %d", static_cast(ret)); + return ((void*)(-1)); + } + + while (g_runFlag) { + // Notice: timeout 1000ms + (void)aclrtProcessReport(1000); + } + + return (void*)0; +} + +Result VencHelper::CreateVencChannel() +{ + // create vdec channelDesc + vencChannelDesc_ = aclvencCreateChannelDesc(); + if (vencChannelDesc_ == nullptr) { + LOG_PRINT("[ERROR] Create venc channel desc failed"); + return RES_ERROR; + } + + aclvencSetChannelDescThreadId(vencChannelDesc_, threadId_); + aclvencSetChannelDescCallback(vencChannelDesc_, &VencHelper::Callback); + aclvencSetChannelDescEnType(vencChannelDesc_, enType_); + aclvencSetChannelDescPicFormat(vencChannelDesc_, format_); + aclvencSetChannelDescPicWidth(vencChannelDesc_, maxWidth_); + aclvencSetChannelDescPicHeight(vencChannelDesc_, maxHeight_); + aclvencSetChannelDescKeyFrameInterval(vencChannelDesc_, kKeyFrameInterval); + aclvencSetChannelDescRcMode(vencChannelDesc_, kRcMode); + aclvencSetChannelDescMaxBitRate(vencChannelDesc_, kMaxBitRate); + aclError ret = aclvencCreateChannel(vencChannelDesc_); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to create venc channel"); + return RES_ERROR; + } + return RES_OK; +} + +Result VencHelper::CreateFrameConfig() +{ + vencFrameConfig_ = aclvencCreateFrameConfig(); + if (vencFrameConfig_ == nullptr) { + LOG_PRINT("[ERROR] Create frame config"); + return RES_ERROR; + } + + Result ret = SetFrameConfig(0, 1); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Set frame config failed, error %d", ret); + return ret; + } + + return RES_OK; +} + +Result VencHelper::SetFrameConfig(uint8_t eos, uint8_t forceIFrame) +{ + // set eos + aclError ret = aclvencSetFrameConfigEos(vencFrameConfig_, eos); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to set eos, ret = %d", ret); + return RES_ERROR; + } + + ret = aclvencSetFrameConfigForceIFrame(vencFrameConfig_, forceIFrame); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to set venc ForceIFrame"); + return RES_ERROR; + } + + return RES_OK; +} + +Result VencHelper::Init() +{ + if (status_ != STATUS_VENC_INIT) { + return RES_ERROR; + } + outFp_ = fopen(outFile_.c_str(), "wb+"); + if (outFp_ == nullptr) { + LOG_PRINT("[ERROR] Open file %s failed, error %s", + outFile_.c_str(), strerror(errno)); + return RES_ERROR; + } + + aclError aclRet; + // Get current run mode + aclRet = aclrtGetRunMode(&runMode_); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] acl get run mode failed"); + return RES_ERROR; + } + + if (context_ == nullptr) { + aclRet = aclrtGetCurrentContext(&context_); + if ((aclRet != ACL_SUCCESS) || (context_ == nullptr)) { + LOG_PRINT("[ERROR] Get current acl context error:%d", aclRet); + return RES_ERROR; + } + } + aclRet = aclrtSetCurrentContext(context_); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Video decoder set context failed, error: %d", aclRet); + return RES_ERROR; + } + + // create process callback thread + Result ret = pthread_create(&threadId_, nullptr, + &VencHelper::SubscribleThreadFunc, context_); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Create venc subscrible thread failed, error %d", ret); + return RES_ERROR; + } + + ret = CreateVencChannel(); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Create venc channel failed, error %d", ret); + return ret; + } + + aclRet = aclrtCreateStream(&vencStream_); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Create venc stream failed, error %d", aclRet); + return RES_ERROR; + } + + aclRet = aclrtSubscribeReport(threadId_, vencStream_); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Venc subscrible report failed, error %d", aclRet); + return RES_ERROR; + } + + ret = CreateFrameConfig(); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Create venc frame config failed, error %d", ret); + return ret; + } + SetStatus(STATUS_VENC_WORK); + LOG_PRINT("[INFO] venc init resource success"); + return RES_OK; +} + +Result VencHelper::CreateInputPicDesc(ImageData& image) +{ + inputPicDesc_ = acldvppCreatePicDesc(); + if (inputPicDesc_ == nullptr) { + LOG_PRINT("[ERROR] Create input pic desc failed"); + return RES_ERROR; + } + void* deviceMem = nullptr; + aclError aclRet = acldvppMalloc(&deviceMem, image.size); + CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("[ERROR] acldvppMalloc failed. ERROR: %d", aclRet); return RES_ERROR); + // copy to device + aclRet = aclrtMemcpy(deviceMem, image.size, image.data.get(), image.size, ACL_MEMCPY_DEVICE_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d", aclRet); + acldvppFree(deviceMem); + return RES_ERROR; + } + acldvppSetPicDescFormat(inputPicDesc_, format_); + acldvppSetPicDescWidth(inputPicDesc_, image.width); + acldvppSetPicDescHeight(inputPicDesc_, image.height); + acldvppSetPicDescWidthStride(inputPicDesc_, ALIGN_UP16(image.width)); + acldvppSetPicDescHeightStride(inputPicDesc_, ALIGN_UP2(image.height)); + acldvppSetPicDescData(inputPicDesc_, deviceMem); + acldvppSetPicDescSize(inputPicDesc_, image.size); + + return RES_OK; +} + +Result VencHelper::Process(ImageData& image) +{ + if (status_ != STATUS_VENC_WORK) { + LOG_PRINT("[ERROR] The venc(status %d) is not working", status_); + return RES_ERROR; + } + // create picture desc + Result ret = CreateInputPicDesc(image); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] fail to create picture description"); + return ret; + } + + // send frame + acldvppStreamDesc *outputStreamDesc = nullptr; + + ret = aclvencSendFrame(vencChannelDesc_, inputPicDesc_, + static_cast(outputStreamDesc), vencFrameConfig_, (void *)this); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] send venc frame failed, error %d", ret); + return RES_ERROR; + } + frameId_++; + return RES_OK; +} + +void VencHelper::Finish() +{ + if (isFinished_) { + return; + } + // set frame config, eos frame + Result ret = SetFrameConfig(1, 0); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Set eos frame config failed, error %d", ret); + return; + } + // send eos frame + ret = aclvencSendFrame(vencChannelDesc_, nullptr, + nullptr, vencFrameConfig_, nullptr); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to send eos frame, ret=%u", ret); + return; + } + fclose(outFp_); + outFp_ = nullptr; + while (finFrameCnt_ < frameId_) { + usleep(100); + } + isFinished_ = true; + LOG_PRINT("[INFO] venc process success"); + return; +} + +void VencHelper::DestroyResource() +{ + if (isReleased_) { + return; + } + + Finish(); + if (vencChannelDesc_ != nullptr) { + (void)aclvencDestroyChannel(vencChannelDesc_); + (void)aclvencDestroyChannelDesc(vencChannelDesc_); + vencChannelDesc_ = nullptr; + } + if (inputPicDesc_ != nullptr) { + (void)acldvppDestroyPicDesc(inputPicDesc_); + inputPicDesc_ = nullptr; + } + if (vencStream_ != nullptr) { + aclError ret = aclrtDestroyStream(vencStream_); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Vdec destroy stream failed, error %d", ret); + } + vencStream_ = nullptr; + } + + if (vencFrameConfig_ != nullptr) { + (void)aclvencDestroyFrameConfig(vencFrameConfig_); + vencFrameConfig_ = nullptr; + } + isReleased_ = true; +} + +} // namespace acllite diff --git a/DVPPLite/src/VideoCapVideo.cpp b/DVPPLite/src/VideoRead.cpp old mode 100755 new mode 100644 similarity index 91% rename from DVPPLite/src/VideoCapVideo.cpp rename to DVPPLite/src/VideoRead.cpp index 8e85e53..a0b3c82 --- a/DVPPLite/src/VideoCapVideo.cpp +++ b/DVPPLite/src/VideoRead.cpp @@ -1,877 +1,875 @@ -/** - * ============================================================================ - * - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1 Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2 Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3 Neither the names of the copyright holders nor the names of the - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * ============================================================================ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "acllite_common/Common.h" -#include "VideoCapVideo.h" - -using namespace std; -#define DEVICE_MAX 4 - -namespace acllite { - const int64_t kUsec = 1000000; - const uint32_t kDecodeFrameQueueSize = 256; - const int kDecodeQueueOpWait = 10000; // decode wait 10ms/frame - const int kFrameEnQueueRetryTimes = 1000; // max wait time for the frame to enter in queue - const int kQueueOpRetryTimes = 1000; - const int kOutputJamWait = 10000; - const int kInvalidTpye = -1; - const int kWaitDecodeFinishInterval = 1000; - const int kDefaultFps = 1; - const int kReadSlow = 5; - const uint32_t kVideoChannelMax310 = 32; - const uint32_t kVideoChannelMax310P = 256; - const uint32_t kVideoChannelMax310B = 128; - - ChannelIdGenerator channelIdGenerator[DEVICE_MAX] = {}; - - const int kNoFlag = 0; // no flag - const int kInvalidVideoIndex = -1; // invalid video index - const string kRtspTransport = "rtsp_transport"; // rtsp transport - const string kUdp = "udp"; // video format udp - const string kTcp = "tcp"; - const string kBufferSize = "buffer_size"; // buffer size string - const string kMaxBufferSize = "10485760"; // maximum buffer size:10MB - const string kMaxDelayStr = "max_delay"; // maximum delay string - const string kMaxDelayValue = "100000000"; // maximum delay time:100s - const string kTimeoutStr = "stimeout"; // timeout string - const string kTimeoutValue = "5000000"; // timeout:5s - const string kPktSize = "pkt_size"; // ffmpeg pakect size string - const string kPktSizeValue = "10485760"; // ffmpeg packet size value:10MB - const string kReorderQueueSize = "reorder_queue_size"; // reorder queue size - const string kReorderQueueSizeValue = "0"; // reorder queue size value - const int kErrorBufferSize = 1024; // buffer size for error info - const uint32_t kDefaultStreamFps = 5; - const uint32_t kOneSecUs = 1000 * 1000; -} - -namespace acllite { -FFmpegDecoder::FFmpegDecoder(const std::string& streamName):streamName_(streamName) -{ - rtspTransport_.assign(kTcp.c_str()); - isFinished_ = false; - isStop_ = false; - GetVideoInfo(); -} - -void FFmpegDecoder::SetTransport(const std::string& transportType) -{ - rtspTransport_.assign(transportType.c_str()); -}; - -int FFmpegDecoder::GetVideoIndex(AVFormatContext* avFormatContext) -{ - if (avFormatContext == nullptr) { // verify input pointer - return kInvalidVideoIndex; - } - - // get video index in streams - for (uint32_t i = 0; i < avFormatContext->nb_streams; i++) { - if (avFormatContext->streams[i]->codecpar->codec_type - == AVMEDIA_TYPE_VIDEO) { // check is media type is video - return i; - } - } - - return kInvalidVideoIndex; -} - -void FFmpegDecoder::InitVideoStreamFilter(const AVBitStreamFilter*& videoFilter) -{ - if (videoType_ == AV_CODEC_ID_H264) { // check video type is h264 - videoFilter = av_bsf_get_by_name("h264_mp4toannexb"); - } else { // the video type is h265 - videoFilter = av_bsf_get_by_name("hevc_mp4toannexb"); - } -} - -void FFmpegDecoder::SetDictForRtsp(AVDictionary*& avdic) -{ - LOG_PRINT("[INFO] Set parameters for %s", streamName_.c_str()); - - av_dict_set(&avdic, kRtspTransport.c_str(), rtspTransport_.c_str(), kNoFlag); - av_dict_set(&avdic, kBufferSize.c_str(), kMaxBufferSize.c_str(), kNoFlag); - av_dict_set(&avdic, kMaxDelayStr.c_str(), kMaxDelayValue.c_str(), kNoFlag); - av_dict_set(&avdic, kTimeoutStr.c_str(), kTimeoutValue.c_str(), kNoFlag); - av_dict_set(&avdic, kReorderQueueSize.c_str(), - kReorderQueueSizeValue.c_str(), kNoFlag); - av_dict_set(&avdic, kPktSize.c_str(), kPktSizeValue.c_str(), kNoFlag); - LOG_PRINT("[INFO] Set parameters for %s end", streamName_.c_str()); -} - -bool FFmpegDecoder::OpenVideo(AVFormatContext*& avFormatContext) -{ - bool ret = true; - AVDictionary* avdic = nullptr; - - av_log_set_level(AV_LOG_DEBUG); - - LOG_PRINT("[INFO] Open video %s ...", streamName_.c_str()); - SetDictForRtsp(avdic); - int openRet = avformat_open_input(&avFormatContext, - streamName_.c_str(), nullptr, - &avdic); - if (openRet < 0) { // check open video result - char buf_error[kErrorBufferSize]; - av_strerror(openRet, buf_error, kErrorBufferSize); - - LOG_PRINT("[ERROR] Could not open video:%s, return :%d, error info:%s", - streamName_.c_str(), openRet, buf_error); - ret = false; - } - - if (avdic != nullptr) { // free AVDictionary - av_dict_free(&avdic); - } - - return ret; -} - -bool FFmpegDecoder::InitVideoParams(int videoIndex, - AVFormatContext* avFormatContext, - AVBSFContext*& bsfCtx) -{ - const AVBitStreamFilter* videoFilter = nullptr; - InitVideoStreamFilter(videoFilter); - if (videoFilter == nullptr) { // check video fileter is nullptr - LOG_PRINT("[ERROR] Unkonw bitstream filter, videoFilter is nullptr!"); - return false; - } - - // checke alloc bsf context result - if (av_bsf_alloc(videoFilter, &bsfCtx) < 0) { - LOG_PRINT("[ERROR] Fail to call av_bsf_alloc!"); - return false; - } - - // check copy parameters result - if (avcodec_parameters_copy(bsfCtx->par_in, - avFormatContext->streams[videoIndex]->codecpar) < 0) { - LOG_PRINT("[ERROR] Fail to call avcodec_parameters_copy!"); - return false; - } - - bsfCtx->time_base_in = avFormatContext->streams[videoIndex]->time_base; - - // check initialize bsf contextreult - if (av_bsf_init(bsfCtx) < 0) { - LOG_PRINT("[ERROR] Fail to call av_bsf_init!"); - return false; - } - - return true; -} - -void FFmpegDecoder::Decode(FrameProcessCallBack callback, - void *callbackParam) -{ - LOG_PRINT("[INFO] Start ffmpeg decode video %s ...", streamName_.c_str()); - avformat_network_init(); // init network - - AVFormatContext* avFormatContext = avformat_alloc_context(); - - // check open video result - if (!OpenVideo(avFormatContext)) { - return; - } - - int videoIndex = GetVideoIndex(avFormatContext); - if (videoIndex == kInvalidVideoIndex) { // check video index is valid - LOG_PRINT("[ERROR] Rtsp %s index is -1", streamName_.c_str()); - return; - } - - AVBSFContext* bsfCtx = nullptr; - // check initialize video parameters result - if (!InitVideoParams(videoIndex, avFormatContext, bsfCtx)) { - return; - } - - LOG_PRINT("[INFO] Start decode frame of video %s ...", streamName_.c_str()); - - AVPacket avPacket; - int processOk = true; - // loop to get every frame from video stream - while ((av_read_frame(avFormatContext, &avPacket) == 0) && processOk && !isStop_) { - if (avPacket.stream_index == videoIndex) { // check current stream is video - // send video packet to ffmpeg - if (av_bsf_send_packet(bsfCtx, &avPacket)) { - LOG_PRINT("[ERROR] Fail to call av_bsf_send_packet, channel id:%s", - streamName_.c_str()); - } - - // receive single frame from ffmpeg - while ((av_bsf_receive_packet(bsfCtx, &avPacket) == 0) && !isStop_) { - int ret = callback(callbackParam, avPacket.data, avPacket.size); - if (ret != 0) { - processOk = false; - break; - } - } - } - av_packet_unref(&avPacket); - } - - av_bsf_free(&bsfCtx); // free AVBSFContext pointer - avformat_close_input(&avFormatContext); // close input video - - isFinished_ = true; - LOG_PRINT("[INFO] Ffmpeg decoder %s finished", streamName_.c_str()); -} - -void FFmpegDecoder::GetVideoInfo() -{ - avformat_network_init(); // init network - AVFormatContext* avFormatContext = avformat_alloc_context(); - bool ret = OpenVideo(avFormatContext); - if (ret == false) { - LOG_PRINT("[ERROR] Open %s failed", streamName_.c_str()); - return; - } - - if (avformat_find_stream_info(avFormatContext, NULL)<0) { - LOG_PRINT("[ERROR] Get stream info of %s failed", streamName_.c_str()); - return; - } - - int videoIndex = GetVideoIndex(avFormatContext); - if (videoIndex == kInvalidVideoIndex) { // check video index is valid - LOG_PRINT("[ERROR] Video index is %d, current media stream has no " - "video info:%s", - kInvalidVideoIndex, streamName_.c_str()); - avformat_close_input(&avFormatContext); - return; - } - - AVStream* inStream = avFormatContext->streams[videoIndex]; - - frameWidth_ = inStream->codecpar->width; - frameHeight_ = inStream->codecpar->height; - if (inStream->avg_frame_rate.den) { - fps_ = inStream->avg_frame_rate.num / inStream->avg_frame_rate.den; - } else { - fps_ = kDefaultStreamFps; - } - - videoType_ = inStream->codecpar->codec_id; - profile_ = inStream->codecpar->profile; - - avformat_close_input(&avFormatContext); - - LOG_PRINT("[INFO] Video %s, type %d, profile %d, width:%d, height:%d, fps:%d", - streamName_.c_str(), videoType_, profile_, frameWidth_, frameHeight_, fps_); - return; -} - -VideoCapVideo::VideoCapVideo(const std::string& videoName, int32_t deviceId, aclrtContext context) - :isStop_(false), isReleased_(false), isFrameDecodeEnd_(false), - streamType_(STREAM_VIDEO), status_(DECODE_UNINIT), - deviceId_(deviceId), context_(context), - channelId_(INVALID_CHANNEL_ID), streamFormat_(H264_MAIN_LEVEL), - frameId_(0), finFrameCnt_(0), lastDecodeTime_(0), - fpsInterval_(0), streamName_(videoName), ffmpegDecoder_(nullptr), - dvppVdec_(nullptr), frameImageQueue_(kDecodeFrameQueueSize) -{ - const string kRegexRtsp = "^rtsp://.*"; - regex regexRtspAddress(kRegexRtsp.c_str()); - if(regex_match(streamName_, regexRtspAddress)) { - streamType_ = STREAM_RTSP; - } - -} - -VideoCapVideo::~VideoCapVideo() -{ - DestroyResource(); -} - -void VideoCapVideo::DestroyResource() -{ - if (isReleased_) return; - // 1. stop ffmpeg - isStop_ = true; - - // 2. delete ffmpeg decoder - if(ffmpegDecoder_ != nullptr){ - ffmpegDecoder_->StopDecode(); - while ((status_ >= DECODE_START) && (status_ < DECODE_FFMPEG_FINISHED)) { - usleep(kWaitDecodeFinishInterval); - } - delete ffmpegDecoder_; - ffmpegDecoder_ = nullptr; - } - - // 3. release dvpp vdec - if(dvppVdec_ != nullptr) { - while (!isFrameDecodeEnd_) { - usleep(kWaitDecodeFinishInterval); - } - delete dvppVdec_; - dvppVdec_ = nullptr; - } - // 4. release image memory in decode output queue - do { - shared_ptr frame = FrameImageOutQueue(true); - if (frame == nullptr) { - break; - } - - if (frame->data != nullptr) { - acldvppFree(frame->data.get()); - frame->data = nullptr; - } - } while (1); - // 5. release channel id - channelIdGenerator[deviceId_].ReleaseChannelId(channelId_); - - isReleased_ = true; -} - -Result VideoCapVideo::InitResource() -{ - aclError aclRet; - // use current thread context default - if (context_ == nullptr) { - aclRet = aclrtGetCurrentContext(&context_); - if ((aclRet != ACL_SUCCESS) || (context_ == nullptr)) { - LOG_PRINT("[ERROR] Get current acl context error:%d", aclRet); - return RES_ERROR; - } - } - // Get current run mode - aclRet = aclrtGetRunMode(&runMode_); - if (aclRet != ACL_SUCCESS) { - LOG_PRINT("[ERROR] acl get run mode failed"); - return RES_ERROR; - } - - return RES_OK; -} - -Result VideoCapVideo::InitVdecDecoder() -{ - string socVersion = aclrtGetSocName(); - size_t pos310P = socVersion.find("Ascend310P"); - size_t pos310B = socVersion.find("Ascend310B"); - if (pos310P != socVersion.npos) { - videoChannelMax_ = kVideoChannelMax310P; - } else if (pos310B != socVersion.npos) { - videoChannelMax_ = kVideoChannelMax310B; - } else { - videoChannelMax_ = kVideoChannelMax310; - } - - // Generate a unique channel id for video decoder - channelId_ = channelIdGenerator[deviceId_].GenerateChannelId(); - if (channelId_ == INVALID_CHANNEL_ID || channelId_ >= videoChannelMax_) { - LOG_PRINT("[ERROR] Decoder number excessive %d", videoChannelMax_); - return RES_ERROR; - } - - // Create dvpp vdec to decode h26x data - dvppVdec_ = new VdecHelper(channelId_, ffmpegDecoder_->GetFrameWidth(), - ffmpegDecoder_->GetFrameHeight(), - streamFormat_, VideoCapVideo::DvppVdecCallback); - Result ret = dvppVdec_->Init(); - if (ret != RES_OK) { - LOG_PRINT("[ERROR] Dvpp vdec init failed"); - } - - return ret; -} - -Result VideoCapVideo::InitFFmpegDecoder() -{ - // Create ffmpeg decoder to parse video stream to h26x frame data - ffmpegDecoder_ = new FFmpegDecoder(streamName_); - if (kInvalidTpye == GetVdecType()) { - this->SetStatus(DECODE_ERROR); - if (ffmpegDecoder_ != nullptr) { - delete ffmpegDecoder_; - ffmpegDecoder_ = nullptr; - } - LOG_PRINT("[ERROR] Video %s type is invalid", streamName_.c_str()); - return RES_ERROR; - } - - // Get video fps, if no fps, use 1 as default - int fps = ffmpegDecoder_->GetFps(); - if (fps == 0) { - fps = kDefaultFps; - LOG_PRINT("[INFO] Video %s fps is 0, change to %d", - streamName_.c_str(), fps); - } - // Cal the frame interval time(us) - fpsInterval_ = kUsec / fps; - - return RES_OK; -} - -Result VideoCapVideo::Open() -{ - // Open video stream, if open failed before, return error directly - if (status_ == DECODE_ERROR) - return RES_ERROR; - // If open ok already - if (status_ != DECODE_UNINIT) - return RES_OK; - // Init acl resource - Result ret = InitResource(); - if (ret != RES_OK) { - this->SetStatus(DECODE_ERROR); - LOG_PRINT("[ERROR] Open %s failed for init resource error: %d", - streamName_.c_str(), ret); - return ret; - } - // Init ffmpeg decoder - ret = InitFFmpegDecoder(); - if (ret != RES_OK) { - this->SetStatus(DECODE_ERROR); - LOG_PRINT("[ERROR] Open %s failed for init ffmpeg error: %d", - streamName_.c_str(), ret); - return ret; - } - // Init dvpp vdec decoder - ret = InitVdecDecoder(); - if (ret != RES_OK) { - this->SetStatus(DECODE_ERROR); - LOG_PRINT("[ERROR] Open %s failed for init vdec error: %d", - streamName_.c_str(), ret); - return ret; - } - // Set init ok - this->SetStatus(DECODE_READY); - LOG_PRINT("[INFO] Video %s decode init ok", streamName_.c_str()); - return RES_OK; -} - -int VideoCapVideo::GetVdecType() -{ - // VDEC only support H265 main level�?64 baseline level,main level,high level - int type = ffmpegDecoder_->GetVideoType(); - int profile = ffmpegDecoder_->GetProfile(); - if (type == AV_CODEC_ID_HEVC) { - streamFormat_ = H265_MAIN_LEVEL; - } else if (type == AV_CODEC_ID_H264) { - switch (profile) { - case FF_PROFILE_H264_BASELINE: - streamFormat_ = H264_BASELINE_LEVEL; - break; - case FF_PROFILE_H264_MAIN: - streamFormat_ = H264_MAIN_LEVEL; - break; - case FF_PROFILE_H264_HIGH: - case FF_PROFILE_H264_HIGH_10: - case FF_PROFILE_H264_HIGH_10_INTRA: - case FF_PROFILE_H264_MULTIVIEW_HIGH: - case FF_PROFILE_H264_HIGH_422: - case FF_PROFILE_H264_HIGH_422_INTRA: - case FF_PROFILE_H264_STEREO_HIGH: - case FF_PROFILE_H264_HIGH_444: - case FF_PROFILE_H264_HIGH_444_PREDICTIVE: - case FF_PROFILE_H264_HIGH_444_INTRA: - streamFormat_ = H264_HIGH_LEVEL; - break; - default: - LOG_PRINT("[INFO] Not support h264 profile %d, use as mp", profile); - streamFormat_ = H264_MAIN_LEVEL; - break; - } - } else { - streamFormat_ = kInvalidTpye; - LOG_PRINT("[ERROR] Not support stream, type %d, profile %d", type, profile); - } - - return streamFormat_; -} - -// dvpp vdec callback -void VideoCapVideo::DvppVdecCallback(acldvppStreamDesc *input, - acldvppPicDesc *output, void *userData) -{ - VideoCapVideo* decoder = (VideoCapVideo*)userData; - if (decoder->GetEnd()) { - return; - } - // Get decoded image parameters - shared_ptr image = make_shared(); - image->format = acldvppGetPicDescFormat(output); - image->width = acldvppGetPicDescWidth(output); - image->height = acldvppGetPicDescHeight(output); - image->alignWidth = acldvppGetPicDescWidthStride(output); - image->alignHeight = acldvppGetPicDescHeightStride(output); - image->size = acldvppGetPicDescSize(output); - - void* vdecOutBufferDev = acldvppGetPicDescData(output); - image->data = SHARED_PTR_DVPP_BUF(vdecOutBufferDev); - - // Put the decoded image to queue for read - decoder->ProcessDecodedImage(image); - // Release resouce - aclError ret = acldvppDestroyPicDesc(output); - if (ret != ACL_SUCCESS) { - LOG_PRINT("[ERROR] fail to destroy pic desc, error %d", ret); - } - - if (input != nullptr) { - void* inputBuf = acldvppGetStreamDescData(input); - if (inputBuf != nullptr) { - acldvppFree(inputBuf); - } - aclError ret = acldvppDestroyStreamDesc(input); - if (ret != ACL_SUCCESS) { - LOG_PRINT("[ERROR] fail to destroy input stream desc"); - } - } -} - -void VideoCapVideo::ProcessDecodedImage(shared_ptr frameData) -{ - finFrameCnt_++; - if (YUV420SP_SIZE(frameData->alignWidth, frameData->alignHeight) != frameData->size) { - LOG_PRINT("[ERROR] Invalid decoded frame parameter, " - "width %d, height %d, size %d, buffer %p\n", - frameData->width, frameData->height, - frameData->size, frameData->data.get()); - return; - } - - FrameImageEnQueue(frameData); - - if ((status_ == DECODE_FFMPEG_FINISHED) && (finFrameCnt_ >= frameId_)) { - LOG_PRINT("[INFO] Last frame decoded by dvpp, change status to %d", - DECODE_DVPP_FINISHED); - this->SetStatus(DECODE_DVPP_FINISHED); - } -} - -Result VideoCapVideo::FrameImageEnQueue(shared_ptr frameData) -{ - for (int count = 0; count < kFrameEnQueueRetryTimes; count++) { - if (frameImageQueue_.Push(frameData)) - return RES_OK; - usleep(kDecodeQueueOpWait); - } - LOG_PRINT("[ERROR] Video %s lost decoded image for queue full", - streamName_.c_str()); - - return RES_ERROR; -} - -// start decoder -void VideoCapVideo::StartFrameDecoder() -{ - if (status_ == DECODE_READY) { - decodeThread_ = thread(FrameDecodeThreadFunction, (void*)this); - decodeThread_.detach(); - status_ = DECODE_START; - } -} - -// ffmpeg decoder entry -void VideoCapVideo::FrameDecodeThreadFunction(void* decoderSelf) -{ - VideoCapVideo* thisPtr = (VideoCapVideo*)decoderSelf; - - aclError aclRet = thisPtr->SetAclContext(); - if (aclRet != ACL_SUCCESS) { - LOG_PRINT("[ERROR] Set frame decoder context failed, errorno:%d", aclRet); - return; - } - // start decode until complete - thisPtr->FFmpegDecode(); - if (thisPtr->IsStop()) { - thisPtr->SetEnd(); - thisPtr->SetStatus(DECODE_FINISHED); - return; - } - thisPtr->SetStatus(DECODE_FFMPEG_FINISHED); - // when ffmpeg decode finish, send eos to vdec - shared_ptr videoFrame = make_shared(); - videoFrame->isFinished = true; - videoFrame->data = nullptr; - videoFrame->size = 0; - thisPtr->dvppVdec_->Process(videoFrame, decoderSelf); - while ((thisPtr->GetStatus() != DECODE_DVPP_FINISHED)) { - usleep(kWaitDecodeFinishInterval); - } - thisPtr->SetEnd(); -} - -// callback of ffmpeg decode frame -Result VideoCapVideo::FrameDecodeCallback(void* decoder, void* frameData, int frameSize) -{ - if ((frameData == NULL) || (frameSize == 0)) { - LOG_PRINT("[ERROR] Frame data is null"); - return RES_ERROR; - } - - // copy data to dvpp memory - VideoCapVideo* videoDecoder = (VideoCapVideo*)decoder; - void* buffer = nullptr; - aclError aclRet = acldvppMalloc(&buffer, frameSize); - if (aclRet != ACL_SUCCESS) { - LOG_PRINT("[ERROR] acldvppMalloc failed. ERROR: %d\n", aclRet); - return RES_ERROR; - } - aclRet = aclrtMemcpy(buffer, frameSize, frameData, frameSize, ACL_MEMCPY_HOST_TO_DEVICE); - if (aclRet != ACL_SUCCESS) { - LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d\n", aclRet); - acldvppFree(frameData); - return RES_ERROR; - } - - shared_ptr videoFrame = make_shared(); - videoDecoder->frameId_++; - videoFrame->frameId = videoDecoder->frameId_; - videoFrame->data = buffer; - videoFrame->size = frameSize; - // decode data by dvpp vdec - Result ret = videoDecoder->dvppVdec_->Process(videoFrame, decoder); - if (ret != RES_OK) { - LOG_PRINT("[ERROR] Dvpp vdec process %dth frame failed, error:%d", - videoDecoder->frameId_, ret); - return ret; - } - - // wait next frame by fps - videoDecoder->SleeptoNextFrameTime(); - return RES_OK; -} - -void VideoCapVideo::SleeptoNextFrameTime() -{ - while (frameImageQueue_.Size() > kReadSlow) { - if (isStop_) { - return; - } - usleep(kOutputJamWait); - } - - if (streamType_ == STREAM_RTSP) { - usleep(0); - return; - } - - // get current time - timeval tv; - gettimeofday(&tv, 0); - int64_t now = (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec; - - if (lastDecodeTime_ == 0) { - lastDecodeTime_ = now; - return; - } - // calculate interval - int64_t lastInterval = (now - lastDecodeTime_); - int64_t sleepTime = (lastInterval < fpsInterval_)?(fpsInterval_-lastInterval):0; - // consume rest time - usleep(sleepTime); - // record start time of next frame - gettimeofday(&tv, 0); - lastDecodeTime_ = (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec; - - return; -} - -// check decoder status -bool VideoCapVideo::IsOpened() -{ - LOG_PRINT("[INFO] Video %s decode status %d", streamName_.c_str(), status_); - return (status_ == DECODE_READY) || (status_ == DECODE_START); -} - -// read decoded frame -bool VideoCapVideo::Read(ImgData& image) -{ - // return nullptr,if decode fail/finish - if (status_ == DECODE_ERROR) { - LOG_PRINT("[ERROR] Read failed for decode %s failed", - streamName_.c_str()); - return false; - } - - if (status_ == DECODE_FINISHED) { - LOG_PRINT("[INFO] No frame to read for decode %s finished", - streamName_.c_str()); - return false; - } - // start decode if status is ok - if (status_ == DECODE_READY) { - StartFrameDecoder(); - usleep(kDecodeQueueOpWait); - } - // read frame from decode queue - bool noWait = (status_ == DECODE_DVPP_FINISHED); - shared_ptr frame = FrameImageOutQueue(noWait); - if (noWait && (frame == nullptr)) { - while (!isFrameDecodeEnd_) { - usleep(kWaitDecodeFinishInterval); - } - SetStatus(DECODE_FINISHED); - LOG_PRINT("[INFO] No frame to read anymore"); - return false; - } - - if (frame == nullptr) { - LOG_PRINT("[ERROR] No frame image to read abnormally"); - return false; - } - - image.format = frame->format; - image.width = frame->width; - image.height = frame->height; - image.alignWidth = frame->alignWidth; - image.alignHeight = frame->alignHeight; - image.size = frame->size; - image.data = frame->data; - - return true; -} - -shared_ptr VideoCapVideo::FrameImageOutQueue(bool noWait) -{ - shared_ptr image = frameImageQueue_.Pop(); - - if (noWait || (image != nullptr)) return image; - - for (int count = 0; count < kQueueOpRetryTimes - 1; count++) { - usleep(kDecodeQueueOpWait); - - image = frameImageQueue_.Pop(); - if (image != nullptr) - return image; - } - - return nullptr; -} - -bool VideoCapVideo::Set(int propId, int value) -{ - bool setRet = true; - Result ret = RES_OK; - StreamProperty key = (StreamProperty)propId; - switch (key) { - case OUTPUT_IMAGE_FORMAT: - ret = dvppVdec_->SetFormat(value); - if (ret != RES_OK) { - setRet = false; - } - break; - case RTSP_TRANSPORT: - ret = SetRtspTransType(value); - if (ret != RES_OK) { - setRet = false; - } - break; - default: - setRet = false; - LOG_PRINT("[ERROR] Unsurpport property %d to set for video %s", - (int)key, streamName_.c_str()); - break; - } - - return setRet; -} - -Result VideoCapVideo::SetRtspTransType(uint32_t transCode) -{ - Result ret = RES_OK; - - if (transCode == RTSP_TRANS_UDP) - ffmpegDecoder_->SetTransport(RTSP_TRANSPORT_UDP); - else if (transCode == RTSP_TRANS_TCP) - ffmpegDecoder_->SetTransport(RTSP_TRANSPORT_TCP); - else { - ret = RES_ERROR; - LOG_PRINT("[ERROR] Unsurport rtsp transport property value %d", - transCode); - } - - return ret; -} - -uint32_t VideoCapVideo::Get(int propId) -{ - uint32_t value = 0; - StreamProperty key = (StreamProperty)propId; - - switch (key) { - case FRAME_WIDTH: - value = ffmpegDecoder_->GetFrameWidth(); - break; - case FRAME_HEIGHT: - value = ffmpegDecoder_->GetFrameHeight(); - break; - case VIDEO_FPS: - value = ffmpegDecoder_->GetFps(); - break; - default: - LOG_PRINT("[ERROR] Unsurpport property %d to get for video", key); - break; - } - - return value; -} - -Result VideoCapVideo::SetAclContext() -{ - if (context_ == nullptr) { - LOG_PRINT("[ERROR] Video decoder context is null"); - return RES_ERROR; - } - - aclError ret = aclrtSetCurrentContext(context_); - if (ret != ACL_SUCCESS) { - LOG_PRINT("[ERROR] Video decoder set context failed, error: %d", ret); - return RES_ERROR; - } - - return RES_OK; -} - -void VideoCapVideo::Release() -{ - DestroyResource(); - return; -} +/** + * ============================================================================ + * + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2 Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3 Neither the names of the copyright holders nor the names of the + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acllite_common/Common.h" +#include "VideoRead.h" + +using namespace std; +#define DEVICE_MAX 4 + +namespace acllite { + const int64_t kUsec = 1000000; + const uint32_t kDecodeFrameQueueSize = 256; + const int kDecodeQueueOpWait = 10000; // decode wait 10ms/frame + const int kFrameEnQueueRetryTimes = 1000; // max wait time for the frame to enter in queue + const int kQueueOpRetryTimes = 1000; + const int kOutputJamWait = 10000; + const int kInvalidTpye = -1; + const int kWaitDecodeFinishInterval = 1000; + const int kDefaultFps = 1; + const int kReadSlow = 5; + const uint32_t kVideoChannelMax310 = 32; + const uint32_t kVideoChannelMax310P = 256; + const uint32_t kVideoChannelMax310B = 128; + + ChannelIdGenerator channelIdGenerator[DEVICE_MAX] = {}; + + const int kNoFlag = 0; // no flag + const int kInvalidVideoIndex = -1; // invalid video index + const string kRtspTransport = "rtsp_transport"; // rtsp transport + const string kUdp = "udp"; // video format udp + const string kTcp = "tcp"; + const string kBufferSize = "buffer_size"; // buffer size string + const string kMaxBufferSize = "10485760"; // maximum buffer size:10MB + const string kMaxDelayStr = "max_delay"; // maximum delay string + const string kMaxDelayValue = "100000000"; // maximum delay time:100s + const string kTimeoutStr = "stimeout"; // timeout string + const string kTimeoutValue = "5000000"; // timeout:5s + const string kPktSize = "pkt_size"; // ffmpeg pakect size string + const string kPktSizeValue = "10485760"; // ffmpeg packet size value:10MB + const string kReorderQueueSize = "reorder_queue_size"; // reorder queue size + const string kReorderQueueSizeValue = "0"; // reorder queue size value + const int kErrorBufferSize = 1024; // buffer size for error info + const uint32_t kDefaultStreamFps = 5; + const uint32_t kOneSecUs = 1000 * 1000; +} + +namespace acllite { +FFmpegDecoder::FFmpegDecoder(const std::string& streamName):streamName_(streamName) +{ + rtspTransport_.assign(kTcp.c_str()); + isFinished_ = false; + isStop_ = false; + GetVideoInfo(); +} + +void FFmpegDecoder::SetTransport(const std::string& transportType) +{ + rtspTransport_.assign(transportType.c_str()); +}; + +int FFmpegDecoder::GetVideoIndex(AVFormatContext* avFormatContext) +{ + if (avFormatContext == nullptr) { // verify input pointer + return kInvalidVideoIndex; + } + + // get video index in streams + for (uint32_t i = 0; i < avFormatContext->nb_streams; i++) { + if (avFormatContext->streams[i]->codecpar->codec_type + == AVMEDIA_TYPE_VIDEO) { // check is media type is video + return i; + } + } + + return kInvalidVideoIndex; +} + +void FFmpegDecoder::InitVideoStreamFilter(const AVBitStreamFilter*& videoFilter) +{ + if (videoType_ == AV_CODEC_ID_H264) { // check video type is h264 + videoFilter = av_bsf_get_by_name("h264_mp4toannexb"); + } else { // the video type is h265 + videoFilter = av_bsf_get_by_name("hevc_mp4toannexb"); + } +} + +void FFmpegDecoder::SetDictForRtsp(AVDictionary*& avdic) +{ + LOG_PRINT("[INFO] Set parameters for %s", streamName_.c_str()); + + av_dict_set(&avdic, kRtspTransport.c_str(), rtspTransport_.c_str(), kNoFlag); + av_dict_set(&avdic, kBufferSize.c_str(), kMaxBufferSize.c_str(), kNoFlag); + av_dict_set(&avdic, kMaxDelayStr.c_str(), kMaxDelayValue.c_str(), kNoFlag); + av_dict_set(&avdic, kTimeoutStr.c_str(), kTimeoutValue.c_str(), kNoFlag); + av_dict_set(&avdic, kReorderQueueSize.c_str(), + kReorderQueueSizeValue.c_str(), kNoFlag); + av_dict_set(&avdic, kPktSize.c_str(), kPktSizeValue.c_str(), kNoFlag); + LOG_PRINT("[INFO] Set parameters for %s end", streamName_.c_str()); +} + +bool FFmpegDecoder::OpenVideo(AVFormatContext*& avFormatContext) +{ + bool ret = true; + AVDictionary* avdic = nullptr; + + av_log_set_level(AV_LOG_DEBUG); + + LOG_PRINT("[INFO] Open video %s ...", streamName_.c_str()); + SetDictForRtsp(avdic); + int openRet = avformat_open_input(&avFormatContext, + streamName_.c_str(), nullptr, + &avdic); + if (openRet < 0) { // check open video result + char buf_error[kErrorBufferSize]; + av_strerror(openRet, buf_error, kErrorBufferSize); + + LOG_PRINT("[ERROR] Could not open video:%s, return :%d, error info:%s", + streamName_.c_str(), openRet, buf_error); + ret = false; + } + + if (avdic != nullptr) { // free AVDictionary + av_dict_free(&avdic); + } + + return ret; +} + +bool FFmpegDecoder::InitVideoParams(int videoIndex, + AVFormatContext* avFormatContext, + AVBSFContext*& bsfCtx) +{ + const AVBitStreamFilter* videoFilter = nullptr; + InitVideoStreamFilter(videoFilter); + if (videoFilter == nullptr) { // check video fileter is nullptr + LOG_PRINT("[ERROR] Unkonw bitstream filter, videoFilter is nullptr!"); + return false; + } + + // checke alloc bsf context result + if (av_bsf_alloc(videoFilter, &bsfCtx) < 0) { + LOG_PRINT("[ERROR] Fail to call av_bsf_alloc!"); + return false; + } + + // check copy parameters result + if (avcodec_parameters_copy(bsfCtx->par_in, + avFormatContext->streams[videoIndex]->codecpar) < 0) { + LOG_PRINT("[ERROR] Fail to call avcodec_parameters_copy!"); + return false; + } + + bsfCtx->time_base_in = avFormatContext->streams[videoIndex]->time_base; + + // check initialize bsf contextreult + if (av_bsf_init(bsfCtx) < 0) { + LOG_PRINT("[ERROR] Fail to call av_bsf_init!"); + return false; + } + + return true; +} + +void FFmpegDecoder::Decode(FrameProcessCallBack callback, + void *callbackParam) +{ + LOG_PRINT("[INFO] Start ffmpeg decode video %s ...", streamName_.c_str()); + avformat_network_init(); // init network + + AVFormatContext* avFormatContext = avformat_alloc_context(); + + // check open video result + if (!OpenVideo(avFormatContext)) { + return; + } + + int videoIndex = GetVideoIndex(avFormatContext); + if (videoIndex == kInvalidVideoIndex) { // check video index is valid + LOG_PRINT("[ERROR] Rtsp %s index is -1", streamName_.c_str()); + return; + } + + AVBSFContext* bsfCtx = nullptr; + // check initialize video parameters result + if (!InitVideoParams(videoIndex, avFormatContext, bsfCtx)) { + return; + } + + LOG_PRINT("[INFO] Start decode frame of video %s ...", streamName_.c_str()); + + AVPacket avPacket; + int processOk = true; + // loop to get every frame from video stream + while ((av_read_frame(avFormatContext, &avPacket) == 0) && processOk && !isStop_) { + if (avPacket.stream_index == videoIndex) { // check current stream is video + // send video packet to ffmpeg + if (av_bsf_send_packet(bsfCtx, &avPacket)) { + LOG_PRINT("[ERROR] Fail to call av_bsf_send_packet, channel id:%s", + streamName_.c_str()); + } + + // receive single frame from ffmpeg + while ((av_bsf_receive_packet(bsfCtx, &avPacket) == 0) && !isStop_) { + int ret = callback(callbackParam, avPacket.data, avPacket.size); + if (ret != 0) { + processOk = false; + break; + } + } + } + av_packet_unref(&avPacket); + } + + av_bsf_free(&bsfCtx); // free AVBSFContext pointer + avformat_close_input(&avFormatContext); // close input video + + isFinished_ = true; + LOG_PRINT("[INFO] Ffmpeg decoder %s finished", streamName_.c_str()); +} + +void FFmpegDecoder::GetVideoInfo() +{ + avformat_network_init(); // init network + AVFormatContext* avFormatContext = avformat_alloc_context(); + bool ret = OpenVideo(avFormatContext); + if (ret == false) { + LOG_PRINT("[ERROR] Open %s failed", streamName_.c_str()); + return; + } + + if (avformat_find_stream_info(avFormatContext, NULL)<0) { + LOG_PRINT("[ERROR] Get stream info of %s failed", streamName_.c_str()); + return; + } + + int videoIndex = GetVideoIndex(avFormatContext); + if (videoIndex == kInvalidVideoIndex) { // check video index is valid + LOG_PRINT("[ERROR] Video index is %d, current media stream has no " + "video info:%s", + kInvalidVideoIndex, streamName_.c_str()); + avformat_close_input(&avFormatContext); + return; + } + + AVStream* inStream = avFormatContext->streams[videoIndex]; + + frameWidth_ = inStream->codecpar->width; + frameHeight_ = inStream->codecpar->height; + if (inStream->avg_frame_rate.den) { + fps_ = inStream->avg_frame_rate.num / inStream->avg_frame_rate.den; + } else { + fps_ = kDefaultStreamFps; + } + + videoType_ = inStream->codecpar->codec_id; + profile_ = inStream->codecpar->profile; + + avformat_close_input(&avFormatContext); + + LOG_PRINT("[INFO] Video %s, type %d, profile %d, width:%d, height:%d, fps:%d", + streamName_.c_str(), videoType_, profile_, frameWidth_, frameHeight_, fps_); + return; +} + +VideoRead::VideoRead(const std::string& videoName, int32_t deviceId, aclrtContext context) + :isStop_(false), isReleased_(false), isFrameDecodeEnd_(false), + streamType_(STREAM_VIDEO), status_(DECODE_UNINIT), + deviceId_(deviceId), context_(context), + channelId_(INVALID_CHANNEL_ID), streamFormat_(H264_MAIN_LEVEL), + frameId_(0), finFrameCnt_(0), lastDecodeTime_(0), + fpsInterval_(0), streamName_(videoName), ffmpegDecoder_(nullptr), + dvppVdec_(nullptr), frameImageQueue_(kDecodeFrameQueueSize) +{ + const string kRegexRtsp = "^rtsp://.*"; + regex regexRtspAddress(kRegexRtsp.c_str()); + if(regex_match(streamName_, regexRtspAddress)) { + streamType_ = STREAM_RTSP; + } + Open(); + +} + +VideoRead::~VideoRead() +{ + DestroyResource(); +} + +void VideoRead::DestroyResource() +{ + if (isReleased_) return; + // 1. stop ffmpeg + isStop_ = true; + + // 2. delete ffmpeg decoder + if(ffmpegDecoder_ != nullptr){ + ffmpegDecoder_->StopDecode(); + while ((status_ >= DECODE_START) && (status_ < DECODE_FFMPEG_FINISHED)) { + usleep(kWaitDecodeFinishInterval); + } + delete ffmpegDecoder_; + ffmpegDecoder_ = nullptr; + } + + // 3. release dvpp vdec + if(dvppVdec_ != nullptr) { + while (!isFrameDecodeEnd_) { + usleep(kWaitDecodeFinishInterval); + } + delete dvppVdec_; + dvppVdec_ = nullptr; + } + // 4. release image memory in decode output queue + do { + shared_ptr frame = FrameImageOutQueue(true); + if (frame == nullptr) { + break; + } + + if (frame->data != nullptr) { + acldvppFree(frame->data.get()); + frame->data = nullptr; + } + } while (1); + // 5. release channel id + channelIdGenerator[deviceId_].ReleaseChannelId(channelId_); + + isReleased_ = true; +} + +Result VideoRead::InitResource() +{ + aclError aclRet; + // use current thread context default + if (context_ == nullptr) { + aclRet = aclrtGetCurrentContext(&context_); + if ((aclRet != ACL_SUCCESS) || (context_ == nullptr)) { + LOG_PRINT("[ERROR] Get current acl context error:%d", aclRet); + return RES_ERROR; + } + } + // Get current run mode + aclRet = aclrtGetRunMode(&runMode_); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] acl get run mode failed"); + return RES_ERROR; + } + + return RES_OK; +} + +Result VideoRead::InitVdecDecoder() +{ + string socVersion = aclrtGetSocName(); + size_t pos310P = socVersion.find("Ascend310P"); + size_t pos310B = socVersion.find("Ascend310B"); + if (pos310P != socVersion.npos) { + videoChannelMax_ = kVideoChannelMax310P; + } else if (pos310B != socVersion.npos) { + videoChannelMax_ = kVideoChannelMax310B; + } else { + videoChannelMax_ = kVideoChannelMax310; + } + + // Generate a unique channel id for video decoder + channelId_ = channelIdGenerator[deviceId_].GenerateChannelId(); + if (channelId_ == INVALID_CHANNEL_ID || channelId_ >= videoChannelMax_) { + LOG_PRINT("[ERROR] Decoder number excessive %d", videoChannelMax_); + return RES_ERROR; + } + + // Create dvpp vdec to decode h26x data + dvppVdec_ = new VdecHelper(channelId_, ffmpegDecoder_->GetFrameWidth(), + ffmpegDecoder_->GetFrameHeight(), + streamFormat_, VideoRead::DvppVdecCallback); + Result ret = dvppVdec_->Init(); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Dvpp vdec init failed"); + } + + return ret; +} + +Result VideoRead::InitFFmpegDecoder() +{ + // Create ffmpeg decoder to parse video stream to h26x frame data + ffmpegDecoder_ = new FFmpegDecoder(streamName_); + if (kInvalidTpye == GetVdecType()) { + this->SetStatus(DECODE_ERROR); + if (ffmpegDecoder_ != nullptr) { + delete ffmpegDecoder_; + ffmpegDecoder_ = nullptr; + } + LOG_PRINT("[ERROR] Video %s type is invalid", streamName_.c_str()); + return RES_ERROR; + } + + // Get video fps, if no fps, use 1 as default + int fps = ffmpegDecoder_->GetFps(); + if (fps == 0) { + fps = kDefaultFps; + LOG_PRINT("[INFO] Video %s fps is 0, change to %d", + streamName_.c_str(), fps); + } + // Cal the frame interval time(us) + fpsInterval_ = kUsec / fps; + + return RES_OK; +} + +Result VideoRead::Open() +{ + // Open video stream, if open failed before, return error directly + if (status_ == DECODE_ERROR) + return RES_ERROR; + // If open ok already + if (status_ != DECODE_UNINIT) + return RES_OK; + // Init acl resource + Result ret = InitResource(); + if (ret != RES_OK) { + this->SetStatus(DECODE_ERROR); + LOG_PRINT("[ERROR] Open %s failed for init resource error: %d", + streamName_.c_str(), ret); + return ret; + } + // Init ffmpeg decoder + ret = InitFFmpegDecoder(); + if (ret != RES_OK) { + this->SetStatus(DECODE_ERROR); + LOG_PRINT("[ERROR] Open %s failed for init ffmpeg error: %d", + streamName_.c_str(), ret); + return ret; + } + // Init dvpp vdec decoder + ret = InitVdecDecoder(); + if (ret != RES_OK) { + this->SetStatus(DECODE_ERROR); + LOG_PRINT("[ERROR] Open %s failed for init vdec error: %d", + streamName_.c_str(), ret); + return ret; + } + // Set init ok + this->SetStatus(DECODE_READY); + LOG_PRINT("[INFO] Video %s decode init ok", streamName_.c_str()); + return RES_OK; +} + +int VideoRead::GetVdecType() +{ + // VDEC only support H265 main level�?64 baseline level,main level,high level + int type = ffmpegDecoder_->GetVideoType(); + int profile = ffmpegDecoder_->GetProfile(); + if (type == AV_CODEC_ID_HEVC) { + streamFormat_ = H265_MAIN_LEVEL; + } else if (type == AV_CODEC_ID_H264) { + switch (profile) { + case FF_PROFILE_H264_BASELINE: + streamFormat_ = H264_BASELINE_LEVEL; + break; + case FF_PROFILE_H264_MAIN: + streamFormat_ = H264_MAIN_LEVEL; + break; + case FF_PROFILE_H264_HIGH: + case FF_PROFILE_H264_HIGH_10: + case FF_PROFILE_H264_HIGH_10_INTRA: + case FF_PROFILE_H264_MULTIVIEW_HIGH: + case FF_PROFILE_H264_HIGH_422: + case FF_PROFILE_H264_HIGH_422_INTRA: + case FF_PROFILE_H264_STEREO_HIGH: + case FF_PROFILE_H264_HIGH_444: + case FF_PROFILE_H264_HIGH_444_PREDICTIVE: + case FF_PROFILE_H264_HIGH_444_INTRA: + streamFormat_ = H264_HIGH_LEVEL; + break; + default: + LOG_PRINT("[INFO] Not support h264 profile %d, use as mp", profile); + streamFormat_ = H264_MAIN_LEVEL; + break; + } + } else { + streamFormat_ = kInvalidTpye; + LOG_PRINT("[ERROR] Not support stream, type %d, profile %d", type, profile); + } + + return streamFormat_; +} + +// dvpp vdec callback +void VideoRead::DvppVdecCallback(acldvppStreamDesc *input, + acldvppPicDesc *output, void *userData) +{ + VideoRead* decoder = (VideoRead*)userData; + if (decoder->GetEnd()) { + return; + } + // Get decoded image parameters + shared_ptr image = make_shared(); + image->format = acldvppGetPicDescFormat(output); + image->width = acldvppGetPicDescWidth(output); + image->height = acldvppGetPicDescHeight(output); + image->alignWidth = acldvppGetPicDescWidthStride(output); + image->alignHeight = acldvppGetPicDescHeightStride(output); + image->size = acldvppGetPicDescSize(output); + + void* vdecOutBufferDev = acldvppGetPicDescData(output); + image->data = SHARED_PTR_DVPP_BUF(vdecOutBufferDev); + + // Put the decoded image to queue for read + decoder->ProcessDecodedImage(image); + // Release resouce + aclError ret = acldvppDestroyPicDesc(output); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to destroy pic desc, error %d", ret); + } + + if (input != nullptr) { + void* inputBuf = acldvppGetStreamDescData(input); + if (inputBuf != nullptr) { + acldvppFree(inputBuf); + } + aclError ret = acldvppDestroyStreamDesc(input); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] fail to destroy input stream desc"); + } + } +} + +void VideoRead::ProcessDecodedImage(shared_ptr frameData) +{ + finFrameCnt_++; + if (YUV420SP_SIZE(frameData->alignWidth, frameData->alignHeight) != frameData->size) { + LOG_PRINT("[ERROR] Invalid decoded frame parameter, " + "width %d, height %d, size %d, buffer %p\n", + frameData->width, frameData->height, + frameData->size, frameData->data.get()); + return; + } + + FrameImageEnQueue(frameData); + + if ((status_ == DECODE_FFMPEG_FINISHED) && (finFrameCnt_ >= frameId_)) { + LOG_PRINT("[INFO] Last frame decoded by dvpp, change status to %d", + DECODE_DVPP_FINISHED); + this->SetStatus(DECODE_DVPP_FINISHED); + } +} + +Result VideoRead::FrameImageEnQueue(shared_ptr frameData) +{ + for (int count = 0; count < kFrameEnQueueRetryTimes; count++) { + if (frameImageQueue_.Push(frameData)) + return RES_OK; + usleep(kDecodeQueueOpWait); + } + LOG_PRINT("[ERROR] Video %s lost decoded image for queue full", + streamName_.c_str()); + + return RES_ERROR; +} + +// start decoder +void VideoRead::StartFrameDecoder() +{ + if (status_ == DECODE_READY) { + decodeThread_ = thread(FrameDecodeThreadFunction, (void*)this); + decodeThread_.detach(); + status_ = DECODE_START; + } +} + +// ffmpeg decoder entry +void VideoRead::FrameDecodeThreadFunction(void* decoderSelf) +{ + VideoRead* thisPtr = (VideoRead*)decoderSelf; + + aclError aclRet = thisPtr->SetAclContext(); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Set frame decoder context failed, errorno:%d", aclRet); + return; + } + // start decode until complete + thisPtr->FFmpegDecode(); + if (thisPtr->IsStop()) { + thisPtr->SetEnd(); + thisPtr->SetStatus(DECODE_FINISHED); + return; + } + thisPtr->SetStatus(DECODE_FFMPEG_FINISHED); + // when ffmpeg decode finish, send eos to vdec + shared_ptr videoFrame = make_shared(); + videoFrame->isFinished = true; + videoFrame->data = nullptr; + videoFrame->size = 0; + thisPtr->dvppVdec_->Process(videoFrame, decoderSelf); + while ((thisPtr->GetStatus() != DECODE_DVPP_FINISHED)) { + usleep(kWaitDecodeFinishInterval); + } + thisPtr->SetEnd(); +} + +// callback of ffmpeg decode frame +Result VideoRead::FrameDecodeCallback(void* decoder, void* frameData, int frameSize) +{ + if ((frameData == NULL) || (frameSize == 0)) { + LOG_PRINT("[ERROR] Frame data is null"); + return RES_ERROR; + } + + // copy data to dvpp memory + VideoRead* videoDecoder = (VideoRead*)decoder; + void* buffer = nullptr; + aclError aclRet = acldvppMalloc(&buffer, frameSize); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] acldvppMalloc failed. ERROR: %d\n", aclRet); + return RES_ERROR; + } + aclRet = aclrtMemcpy(buffer, frameSize, frameData, frameSize, ACL_MEMCPY_HOST_TO_DEVICE); + if (aclRet != ACL_SUCCESS) { + LOG_PRINT("[ERROR] aclrtMemcpy failed. ERROR: %d\n", aclRet); + acldvppFree(frameData); + return RES_ERROR; + } + + shared_ptr videoFrame = make_shared(); + videoDecoder->frameId_++; + videoFrame->frameId = videoDecoder->frameId_; + videoFrame->data = buffer; + videoFrame->size = frameSize; + // decode data by dvpp vdec + Result ret = videoDecoder->dvppVdec_->Process(videoFrame, decoder); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Dvpp vdec process %dth frame failed, error:%d", + videoDecoder->frameId_, ret); + return ret; + } + + // wait next frame by fps + videoDecoder->SleeptoNextFrameTime(); + return RES_OK; +} + +void VideoRead::SleeptoNextFrameTime() +{ + while (frameImageQueue_.Size() > kReadSlow) { + if (isStop_) { + return; + } + usleep(kOutputJamWait); + } + + if (streamType_ == STREAM_RTSP) { + usleep(0); + return; + } + + // get current time + timeval tv; + gettimeofday(&tv, 0); + int64_t now = (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec; + + if (lastDecodeTime_ == 0) { + lastDecodeTime_ = now; + return; + } + // calculate interval + int64_t lastInterval = (now - lastDecodeTime_); + int64_t sleepTime = (lastInterval < fpsInterval_)?(fpsInterval_-lastInterval):0; + // consume rest time + usleep(sleepTime); + // record start time of next frame + gettimeofday(&tv, 0); + lastDecodeTime_ = (int64_t)tv.tv_sec * 1000000 + (int64_t)tv.tv_usec; + + return; +} + +// check decoder status +bool VideoRead::IsOpened() +{ + LOG_PRINT("[INFO] Video %s decode status %d", streamName_.c_str(), status_); + return (status_ == DECODE_READY) || (status_ == DECODE_START); +} + +// read decoded frame +bool VideoRead::Read(ImageData& image) +{ + // return nullptr,if decode fail/finish + if (status_ == DECODE_ERROR) { + LOG_PRINT("[ERROR] Read failed for decode %s failed", + streamName_.c_str()); + return false; + } + + if (status_ == DECODE_FINISHED) { + LOG_PRINT("[INFO] No frame to read for decode %s finished", + streamName_.c_str()); + return false; + } + // start decode if status is ok + if (status_ == DECODE_READY) { + StartFrameDecoder(); + usleep(kDecodeQueueOpWait); + } + // read frame from decode queue + bool noWait = (status_ == DECODE_DVPP_FINISHED); + shared_ptr frame = FrameImageOutQueue(noWait); + if (noWait && (frame == nullptr)) { + while (!isFrameDecodeEnd_) { + usleep(kWaitDecodeFinishInterval); + } + SetStatus(DECODE_FINISHED); + LOG_PRINT("[INFO] No frame to read anymore"); + return false; + } + + if (frame == nullptr) { + LOG_PRINT("[ERROR] No frame image to read abnormally"); + return false; + } + + image.format = frame->format; + image.width = frame->width; + image.height = frame->height; + image.alignWidth = frame->alignWidth; + image.alignHeight = frame->alignHeight; + image.size = frame->size; + image.data = frame->data; + + return true; +} + +shared_ptr VideoRead::FrameImageOutQueue(bool noWait) +{ + shared_ptr image = frameImageQueue_.Pop(); + + if (noWait || (image != nullptr)) return image; + + for (int count = 0; count < kQueueOpRetryTimes - 1; count++) { + usleep(kDecodeQueueOpWait); + + image = frameImageQueue_.Pop(); + if (image != nullptr) + return image; + } + + return nullptr; +} + +bool VideoRead::Set(StreamProperty propId, int value) +{ + bool setRet = true; + Result ret = RES_OK; + switch (propId) { + case OUTPUT_IMAGE_FORMAT: + ret = dvppVdec_->SetFormat(value); + if (ret != RES_OK) { + setRet = false; + } + break; + case RTSP_TRANSPORT: + ret = SetRtspTransType(value); + if (ret != RES_OK) { + setRet = false; + } + break; + default: + setRet = false; + LOG_PRINT("[ERROR] Unsurpport property %d to set for video %s", + (int)propId, streamName_.c_str()); + break; + } + + return setRet; +} + +Result VideoRead::SetRtspTransType(uint32_t transCode) +{ + Result ret = RES_OK; + + if (transCode == RTSP_TRANS_UDP) + ffmpegDecoder_->SetTransport(RTSP_TRANSPORT_UDP); + else if (transCode == RTSP_TRANS_TCP) + ffmpegDecoder_->SetTransport(RTSP_TRANSPORT_TCP); + else { + ret = RES_ERROR; + LOG_PRINT("[ERROR] Unsurport rtsp transport property value %d", + transCode); + } + + return ret; +} + +uint32_t VideoRead::Get(StreamProperty propId) +{ + uint32_t value = 0; + switch (propId) { + case FRAME_WIDTH: + value = ffmpegDecoder_->GetFrameWidth(); + break; + case FRAME_HEIGHT: + value = ffmpegDecoder_->GetFrameHeight(); + break; + case VIDEO_FPS: + value = ffmpegDecoder_->GetFps(); + break; + default: + LOG_PRINT("[ERROR] Unsurpport property %d to get for video", propId); + break; + } + + return value; +} + +Result VideoRead::SetAclContext() +{ + if (context_ == nullptr) { + LOG_PRINT("[ERROR] Video decoder context is null"); + return RES_ERROR; + } + + aclError ret = aclrtSetCurrentContext(context_); + if (ret != ACL_SUCCESS) { + LOG_PRINT("[ERROR] Video decoder set context failed, error: %d", ret); + return RES_ERROR; + } + + return RES_OK; +} + +void VideoRead::Release() +{ + DestroyResource(); + return; +} } // namespace acllite \ No newline at end of file diff --git a/DVPPLite/src/VideoProc.cpp b/DVPPLite/src/VideoWrite.cpp old mode 100755 new mode 100644 similarity index 51% rename from DVPPLite/src/VideoProc.cpp rename to DVPPLite/src/VideoWrite.cpp index 6cd90e4..cf51896 --- a/DVPPLite/src/VideoProc.cpp +++ b/DVPPLite/src/VideoWrite.cpp @@ -1,149 +1,127 @@ -/** - * ============================================================================ - * - * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1 Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2 Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3 Neither the names of the copyright holders nor the names of the - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * ============================================================================ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "acllite_common/Common.h" -#include "VideoProc.h" -#include "VideoCapVideo.h" -#include "USBCamera.h" - -using namespace std; - -namespace acllite { -VideoProc::VideoProc(int32_t deviceId, aclrtContext context):deviceId_(deviceId), - context_(context), cap_(nullptr) -{ -} - -VideoProc::VideoProc(const string& filePath, int32_t deviceId, aclrtContext context):deviceId_(deviceId), - context_(context), cap_(nullptr) -{ - size_t pos = filePath.find("/dev/video"); - if (pos != filePath.npos) { - cap_ = new USBCamera(filePath); - Open(); - } else { - cap_ = new VideoCapVideo(filePath, deviceId, context); - Open(); - } -} - -VideoProc::~VideoProc() -{ - if (cap_ != nullptr) { - Release(); - delete cap_; - cap_ = nullptr; - } -} - -bool VideoProc::IsOpened() -{ - if (cap_ != nullptr) { - return cap_->IsOpened(); - } else { - return false; - } -} - -bool VideoProc::Set(int propId, uint32_t value) -{ - if (cap_ != nullptr) { - return cap_->Set(propId, value); - } else { - return false; - } -} - -uint32_t VideoProc::Get(int propId) -{ - if (cap_ != nullptr) { - return cap_->Get(propId); - } else { - return 0; - } -} - -bool VideoProc::Read(ImgData& frame) -{ - if (cap_ != nullptr) { - return cap_->Read(frame); - } else { - return false; - } -} - -void VideoProc::Release() -{ - if (cap_ != nullptr) { - cap_->Release(); - return; - } else { - return; - } -} - -bool VideoProc::Open(const string& filePath, int32_t deviceId, aclrtContext context) -{ - size_t pos = filePath.find("/dev/video"); - if (pos != filePath.npos) { - cap_ = new USBCamera(filePath, deviceId, context); - Result ret = Open(); - if (ret != RES_OK) { - return false; - } - } else { - cap_ = new VideoCapVideo(filePath, deviceId, context); - Result ret = Open(); - if (ret != RES_OK) { - return false; - } - } - return true; -} - -Result VideoProc::Open() -{ - if (cap_ != nullptr) { - return cap_->Open(); - } else { - return RES_ERROR; - } -} -} // namespace acllite +/** + * ============================================================================ + * + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2022. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1 Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2 Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3 Neither the names of the copyright holders nor the names of the + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "acllite_common/Common.h" +#include "VideoWrite.h" + +using namespace std; + +namespace acllite { +VideoWrite::VideoWrite(string outFile, uint32_t maxWidth, + uint32_t maxHeight, int32_t deviceId) + :isReleased_(false), status_(STATUS_VENC_INIT), deviceId_(deviceId), + dvppVenc_(nullptr), outFile_(outFile), + maxWidth_(maxWidth), maxHeight_(maxHeight), + format_(PIXEL_FORMAT_YUV_SEMIPLANAR_420), + enType_(H264_MAIN_LEVEL) +{ + Open(); +} + +VideoWrite::~VideoWrite() +{ + DestroyResource(); +} + +void VideoWrite::DestroyResource() +{ + if (isReleased_) return; + dvppVenc_->DestroyResource(); + // release dvpp venc + delete dvppVenc_; + dvppVenc_ = nullptr; + isReleased_ = true; +} + +Result VideoWrite::InitResource() +{ + dvppVenc_ = new VencHelper(outFile_, maxWidth_, maxHeight_, + deviceId_, format_, enType_); + Result ret = dvppVenc_->Init(); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Video encoder init failed"); + return RES_ERROR; + } + return RES_OK; +} + +Result VideoWrite::Open() +{ + // Init acl resource + Result ret = InitResource(); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] Init resource failed"); + return RES_ERROR; + } + // Set init ok + string outvideo = outFile_; + LOG_PRINT("[INFO] Encoded Video %s init ok", outvideo.c_str()); + return RES_OK; +} + +// check decoder status +bool VideoWrite::IsOpened() +{ + string outvideo = outFile_; + status_ = dvppVenc_->GetStatus(); + LOG_PRINT("[INFO] Video %s encode status %d", outvideo.c_str(), status_); + return (status_ == STATUS_VENC_INIT) || (status_ == STATUS_VENC_WORK); +} + +bool VideoWrite::Write(ImageData& image) +{ + Result ret = dvppVenc_->Process(image); + if (ret != RES_OK) { + LOG_PRINT("[ERROR] fail to Write encode image"); + return false; + } + return true; +} + +void VideoWrite::Release() +{ + DestroyResource(); + return; +} + +} // namespace acllite \ No newline at end of file diff --git a/Doc/common.md b/Doc/common.md new file mode 100644 index 0000000..0b4e3a1 --- /dev/null +++ b/Doc/common.md @@ -0,0 +1,443 @@ +### common模块API说明 +该模块为资源管理及公共函数模块,主要包含以下功能: +1. 资源管理 +2. 公共函数 +3. 工具宏 +4. 公共数据结构 + +#### 资源管理 +- AclLiteResource类:命名空间为acllite,所属类为AclLiteResource + 1. **AclLiteResource(int32_t devId = 0)** + - 功能说明 + 构造函数,创建一个AclLiteResource对象 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | devId | 输入 | 设备id | + - 返回值说明 + 无 + + 2. **~AclLiteResource()** + - 功能说明 + 析构函数,销毁AclLiteResource对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **bool Init()** + - 功能说明 + 初始化函数,初始化Acl相关资源device、context + - 参数说明 + 无 + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 4. **aclrtContext GetContext()** + - 功能说明 + 获取程序运行的context + - 参数说明 + 无 + - 返回值说明 + 返回获取到的context;返回nullptr表示无效context,返回非nullptr表示有效context + + 5. **void Release()** + - 功能说明 + 资源释放函数,释放Acl相关资源device、context + - 参数说明 + 无 + - 返回值说明 + 无 + +#### 公共函数 +- 其它模块需要使用的公共函数:命名空间为acllite,未封装为类 + 1. **void SaveBinFile(const std::string& filename, const void\* data, uint32_t size)** + - 功能说明 + 将数据存为二进制文件 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | filename | 输入 | 文件名 | + | data | 输入 | 待保存数据 | + | size | 输入 | 待保存数据大小 | + - 返回值说明 + 无 + + 2. **bool ReadBinFile(const std::string& fileName, void\*& data, uint32_t& size)** + - 功能说明 + 读取二进制文件 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | filename | 输入 | 文件名 | + | data | 输出 | 待读取数据 | + | size | 输入 | 待读取数据大小 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 3. **void\* CopyDataToDevice(void\* data, uint32_t size);** + - 功能说明 + 将数据拷贝到Device侧 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | data| 输入 | 待拷贝数据 | + | size| 输入 | 待拷贝数据大小 | + - 返回值说明 + 返回拷贝后的Device内存地址;返回nullptr表示拷贝失败,返回非nullptr表示拷贝成功 + + 4. **aclrtContext GetContextByDevice(int32_t devId)** + - 功能说明 + 获取对应device上的context + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | devId | 输入 | 设备id | + - 返回值说明 + 返回获取到的context;返回nullptr表示无效context,返回非nullptr表示有效context + + 5. **bool SetCurContext(aclrtContext context);** + - 功能说明 + 设置当前线程的context + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | context | 输入 | 待设置的context | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + +#### 工具宏 +- 宏封装函数:无命名空间 + 1. **ALIGN_UP(num, align)** + - 功能说明 + 计算对齐后的数值 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | num | 原始数值 | + | align| 要对齐的数 | + + 2. **ALIGN_UP2(num, align)** + - 功能说明 + 将数据按2对齐 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | num | 原始数值 | + | align| 要对齐的数 | + + 3. **ALIGN_UP16(num, align)** + - 功能说明 + 将数据按16对齐 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | num | 原始数值 | + | align| 要对齐的数 | + + 4. **ALIGN_UP64(num, align)** + - 功能说明 + 将数据按64对齐 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | num | 原始数值 | + | align| 要对齐的数 | + + 5. **ALIGN_UP128(num, align)** + - 功能说明 + 将数据按128对齐 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | num | 原始数值 | + | align| 要对齐的数 | + + 6. **YUV420SP_SIZE(width, height)** + - 功能说明 + 计算YUV420SP图片数据大小 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | width | 图片宽 | + | height | 图片高 | + + 7. **YUV422P_SIZE(width, height)** + - 功能说明 + 计算YUV422P图片数据大小 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | width | 图片宽 | + | height | 图片高 | + + 8. **SHARED_PTR_U8_BUF(buf)** + - 功能说明 + 新建指向一般内存的智能指针 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | buf | 指向一般内存的指针,用delete释放 | + + 9. **SHARED_PTR_HOST_BUF(buf)** + - 功能说明 + 新建指向HOST内存的智能指针 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | buf | 指向HOST内存的指针,用aclrtFreeHost释放 | + + 10. **SHARED_PTR_DEV_BUF(buf)** + - 功能说明 + 新建指向DEV内存的智能指针 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | buf | 指向DEV内存的指针,用aclrtFree释放 | + + 11. **SHARED_PTR_DVPP_BUF(buf)** + - 功能说明 + 新建指向DVPP内存的智能指针 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | buf | 指向DVPP内存的指针,用acldvppFree释放 | + + 12. **CHECK_RET(cond, return_expr)** + - 功能说明 + 函数返回值判断 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | cond | 执行语句,判断返回失败则执行return_expr | + | return_expr | 异常返回执行操作 | + + 13. **LOG_PRINT(message, ...)** + - 功能说明 + 打印日志 + - 参数说明 + | 参数名 | 说明 | + |---|---| + | message | 打印的日志内容 | + +#### 公共数据结构 +- ACLLite中使用到的全局变量:命名空间为acllite + 1. **Result** + - 结构展示 + ``` + typedef int Result; + ``` + - 说明 + 用来表述返回值,一般用于函数定义或调用 + + 2. **RES_OK** + - 结构展示 + ``` + const int RES_OK = 0; + ``` + - 说明 + 用来表述正常返回 + + 3. **RES_ERROR** + - 结构展示 + ``` + const int RES_ERROR = 1; + ``` + - 说明 + 用来表述异常返回 + +- ACLLite中需要使用到的数据结构:命名空间为acllite + 1. **struct DataInfo** + - 结构展示 + ``` + struct DataInfo { + void* data; + uint32_t size; + }; + ``` + - 功能说明 + 数据信息,存储数据内容及数据大小,用来生成模型输入输出 + - 数据成员说明 + | 成员名 | 说明 | + |---|---| + | data | 数据 | + | size | 数据大小 | + + 2. **struct InferenceOutput** + - 结构展示 + ``` + struct InferenceOutput { + std::shared_ptr data = nullptr; + uint32_t size; + }; + ``` + - 功能说明 + 存放模型推理结果数据 + - 数据成员说明 + | 成员名 | 说明 | + |---|---| + | data | 数据,格式为共享指针,默认指向nullptr | + | size | 数据大小 | + + 3. **struct ImageSize** + - 结构展示 + ``` + struct ImageSize { + uint32_t width = 0; + uint32_t height = 0; + ImageSize() {} + ImageSize(uint32_t x, uint32_t y) : width(x), height(y) {} + }; + ``` + - 功能说明 + 图像宽高组合,主要用于VPC中目标图片宽高取值 + - 数据成员说明 + | 成员名 | 说明 | + |---|---| + | width | 图像宽,默认为0 | + | height | 图像高,默认为0 | + - 构造方式 + ``` + uint32_t x = 1920; + uint32_t y = 1080; + // 1. 通过构造函数 + ImageSize z1 = ImageSize(x, y); + + // 2. 通过结构体构造 + ImageSize z2; + z2.width = x; + z2.height = y; + ``` + + 4. **struct ImageData** + - 结构展示 + ``` + struct ImageData { + std::shared_ptr data = nullptr; + uint32_t size = 0; + uint32_t width = 0; + uint32_t height = 0; + uint32_t alignWidth = 0; + uint32_t alignHeight = 0; + acldvppPixelFormat format; + ImageData() {} + ImageData(std::shared_ptr buf, uint32_t bufSize, + uint32_t x, uint32_t y, acldvppPixelFormat fmt) : data(buf), size(bufSize), + width(x), height(y), format(fmt) {} + }; + ``` + - 功能说明 + 图像数据和属性 + - 数据成员说明 + | 成员名 | 说明 | + |---|---| + | data | 数据,格式为共享指针,默认指向nullptr | + | size | 数据大小,默认为0 | + | width | 图像宽,默认为0 | + | height | 图像高,默认为0 | + | alignWidth | 图像对齐宽,默认为0 | + | alignHeight | 图像对齐高,默认为0 | + | format| 图像格式,默认为PIXEL_FORMAT_YUV_SEMIPLANAR_420(YUV420SP),目前支持如下格式:
PIXEL_FORMAT_YUV_SEMIPLANAR_420(YUV420SP)
PIXEL_FORMAT_YVU_SEMIPLANAR_420(YVU420SP)
PIXEL_FORMAT_YUYV_PACKED_422(YUV422) | + + - 构造方式 + ``` + // image为通过ReadBinFile读入的图片数据 + uint32_t width = 1920; + uint32_t height = 1080; + uint32_t imageInfoSize = YUV420SP_SIZE(1920,1080); + void* imageInfoBuf = CopyDataToDevice((image, imageInfoSize); + // 1. 通过构造函数 + ImageData dst(SHARED_PTR_DVPP_BUF(imageInfoBuf), imageInfoSize, width, height, PIXEL_FORMAT_YUV_SEMIPLANAR_420); + + // 2. 通过结构体构造 + ImageData dst; + dst.data = SHARED_PTR_DVPP_BUF(imageInfoBuf); + dst.size = imageInfoSize; + dst.width = width; + dst.height = height; + dst.format = PIXEL_FORMAT_YUV_SEMIPLANAR_420; + ``` + + 5. **struct FrameData** + - 结构展示 + ``` + struct FrameData { + bool isFinished = false; + uint32_t frameId = 0; + uint32_t size = 0; + void* data = nullptr; + }; + ``` + - 功能说明 + 帧数据,主要用于队列传输 + - 数据成员说明 + | 成员名 | 说明 | + |---|---| + | isFinished | 是否为结束帧,默认为false | + | frameId | 帧Id,默认为0 | + | size | 帧图像大小,默认为0 | + | data | 帧图像数据,默认为nullptr | + + 6. **enum memoryLocation** + - 结构展示 + ``` + enum memoryLocation { + MEMORY_NORMAL = 0, + MEMORY_HOST, + MEMORY_DEVICE, + MEMORY_DVPP, + MEMORY_INVALID_TYPE + }; + ``` + - 功能说明 + 内存所在位置 + - 数据成员说明 + | 枚举 | 取值 | 说明 | + |---|---|---| + | MEMORY_NORMAL | 0| 一般内存,用new/delete申请/释放 | | + | MEMORY_HOST | 1 | host侧内存,用aclrtMallocHost/aclrtFreeHost申请/释放 | + | MEMORY_DEVICE | 2 | device侧内存,用aclrtMalloc/aclrtFree申请/释放 | + | MEMORY_DVPP | 3 | dvpp内存,用acldvppMalloc/acldvppFree申请/释放 | + | MEMORY_INVALID_TYPE| 4 | 无效内存类型 | + + 6. **enum ResizeType** + - 结构展示 + ``` + enum ResizeType { + RESIZE_COMMON = 0, + RESIZE_PROPORTIONAL_UPPER_LEFT = 1, + RESIZE_PROPORTIONAL_CENTER = 2, + }; + ``` + - 功能说明 + resize方式 + - 数据成员说明 + | 枚举 | 取值 | 说明 | + |---|---|---| + | RESIZE_COMMON | 0 | 普通方式缩放 | | + | RESIZE_PROPORTIONAL_UPPER_LEFT | 1 | 等比例缩放,图像位于左上方 | + | RESIZE_PROPORTIONAL_CENTER | 2 | 等比例缩放,图像位于中心区域 | + + 7. **enum StreamProperty** + - 结构展示 + ``` + enum StreamProperty { + FRAME_WIDTH = 1, + FRAME_HEIGHT = 2, + VIDEO_FPS = 3, + OUTPUT_IMAGE_FORMAT = 4, + RTSP_TRANSPORT = 5, + STREAM_FORMAT = 6 + }; + ``` + - 功能说明 + 需要设置/获取的流属性,用于视频处理过程 + - 数据成员说明 + | 枚举 | 取值 | 说明 | + |---|---|---| + | FRAME_WIDTH | 1 | 帧宽 | | + | FRAME_HEIGHT | 2 | 帧高 | + | VIDEO_FPS | 3 | 视频帧率 | + | OUTPUT_IMAGE_FORMAT | 4 | 输出图像格式 | + | RTSP_TRANSPORT | 5 | RTSP流格式 | + | STREAM_FORMAT | 6 | 视频码流格式 | \ No newline at end of file diff --git a/Doc/dvpplite.md b/Doc/dvpplite.md new file mode 100644 index 0000000..3f0bce9 --- /dev/null +++ b/Doc/dvpplite.md @@ -0,0 +1,180 @@ +### DVPPLite模块API说明 +该模块为资源管理及公共函数模块,主要包含以下功能: +1. 视频解码 +2. 视频编码 +3. 图像编解码及VPC处理 + +#### 视频解码 +- VideoRead类:命名空间为acllite + 1. **VideoRead(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr)** + - 功能说明 + 构造函数,创建一个VideoRead对象 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | videoName | 输入 | MP4视频/RTSP流地址 | + | deviceId | 输入 | 设备id,缺省为0 | + | context | 输入 | 解码器进行vdec时使用的context;缺省为nullptr,此时使用当前线程的context | + - 返回值说明 + 无 + + 2. **~VideoRead()** + - 功能说明 + 析构函数,销毁VideoRead对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **bool Read(ImageData& image)** + - 功能说明 + 获取要被处理的一帧图像数据 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | image| 输出 | 读取的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 4. **bool IsOpened()** + - 功能说明 + 判断摄像头或者视频流是否已经打开 + - 参数说明 + 无 + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 5. **bool Set(StreamProperty propId, int value)** + - 功能说明 + 设置解码属性 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | propId| 输入 | 需要设置的属性,StreamProperty结构数据详见[StreamProperty](./common.md#公共数据结构) | + | value| 输入 | 需要设置的属性的具体值| + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 6. **uint32_t Get(StreamProperty propId)** + - 功能说明 + 获取解码视频流信息 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | propId| 输入 | 需要获取的属性,StreamProperty结构数据详见[StreamProperty](./common.md#公共数据结构) | + - 返回值说明 + 返回获取到的属性的具体值。 + + 7. **void Release()** + - 功能说明 + 资源释放函数 + - 参数说明 + 无 + - 返回值说明 + 无 + +#### 视频编码 + +- VideoWrite类:命名空间为acllite + 1. **VideoWrite(std::string outFile, uint32_t maxWidth, uint32_t maxHeight, int32_t deviceId = 0)** + - 功能说明 + 构造函数,创建一个VideoWrite对象 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | outFile | 输入 | h264/h264文件地址 | + | maxWidth | 输入 | 输出文件宽 | + | maxHeight | 输入 | 输出文件高 | + | deviceId | 输入 | 设备id,缺省为0 | + - 返回值说明 + 无 + + 2. **~VideoWrite()** + - 功能说明 + 析构函数,销毁VideoRead对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **bool Write(ImageData& image)** + - 功能说明 + 写入一帧图像数据进行编码 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | image| 输出 | 写入的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 4. **bool IsOpened()** + - 功能说明 + 判断写入文件是否已经打开 + - 参数说明 + 无 + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 5. **void Release()** + - 功能说明 + 资源释放函数 + - 参数说明 + 无 + - 返回值说明 + 无 + +#### 图像编解码及VPC处理 +- VideoRead类:命名空间为acllite + 1. **ImageProc(int deviceId = 0)** + - 功能说明 + 构造函数,创建一个ImageProc对象 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | deviceId | 输入 | 设备id,缺省为0 | + - 返回值说明 + 无 + + 2. **~ImageProc()** + - 功能说明 + 析构函数,销毁ImageProc对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **ImageData Read(const std::string& fileName, acldvppPixelFormat imgFormat = PIXEL_FORMAT_YUV_SEMIPLANAR_420)** + - 功能说明 + 读取一帧图片,将JPG图片解码为YUV + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | fileName | 输入 | 输入的JPG文件路径 | + | imgFormat | 输入 | 解码后的图像格式,默认为YUV420SP | + + - 返回值说明 + 返回解码后的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构)。 + + 4. **void Resize(ImageData& src, ImageData& dst, ImageSize dsize, ResizeType type = RESIZE_COMMON)** + - 功能说明 + 对图片进行缩放 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | src | 输入 | 输入的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + | dst | 输出 | 输出的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + | dsize | 输入 | 输出图片分辨率,ImageSize结构数据详见[ImageSize](./common.md#公共数据结构) | + | type | 输入 | 缩放类型,ResizeType结构数据详见[ResizeType](./common.md#公共数据结构) | + - 返回值说明 + 无 + + 5. **bool Write(const std::string& fileName, ImageData& img)** + - 功能说明 + 对图片进行编码,写成图片文件 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | fileName | 输入 | 输出的JPG文件路径 | + | img | 输入 | 输入图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + - 返回值说明 + 返回true表示成功,返回false表示失败。 \ No newline at end of file diff --git a/Doc/media.md b/Doc/media.md new file mode 100644 index 0000000..653afa5 --- /dev/null +++ b/Doc/media.md @@ -0,0 +1,61 @@ +### Media模块API说明 +该模块为媒体处理模块,当前主要包含以下功能: +1. USB摄像头读取 + +#### USB摄像头读取 +- CameraRead类:命名空间为acllite + 1. **CameraRead(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr)** + - 功能说明 + 构造函数,创建一个VideoRead对象 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | videoName | 输入 | MP4视频/RTSP流地址 | + | deviceId | 输入 | 设备id,缺省为0 | + | context | 输入 | 解码器进行vdec时使用的context;缺省为nullptr,此时使用当前线程的context | + - 返回值说明 + 无 + + 2. **~CameraRead()** + - 功能说明 + 析构函数,销毁VideoRead对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **bool Read(ImageData& image)** + - 功能说明 + 获取要被处理的一帧图像数据 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | image| 输出 | 读取的图像数据和属性,ImageData结构数据详见[ImageData](./common.md#公共数据结构) | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 4. **bool IsOpened()** + - 功能说明 + 判断摄像头或者视频流是否已经打开 + - 参数说明 + 无 + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 5. **void Release()** + - 功能说明 + 资源释放函数 + - 参数说明 + 无 + - 返回值说明 + 无 + + 6. **uint32_t Get(StreamProperty propId)** + - 功能说明 + 获取解码视频流信息 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | propId| 输入 | 需要获取的属性,StreamProperty结构数据详见[StreamProperty](./common.md#公共数据结构) | + - 返回值说明 + 返回获取到的属性的具体值。 \ No newline at end of file diff --git a/Doc/omexcute.md b/Doc/omexcute.md new file mode 100644 index 0000000..575f60d --- /dev/null +++ b/Doc/omexcute.md @@ -0,0 +1,105 @@ +### OMExcute模块API说明 +该模块为模型管理模块,主要包含模型加载、输入输出创建、推理等功能。 + +- ModelProc类:命名空间为acllite + 1. **ModelProc()** + - 功能说明 + 构造函数,创建一个ModelProc对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 2. **~ModelProc()** + - 功能说明 + 析构函数,销毁ModelProc对象 + - 参数说明 + 无 + - 返回值说明 + 无 + + 3. **void DestroyResource()** + - 功能说明 + 销毁模型处理过程中的相关资源 + - 参数说明 + 无 + - 返回值说明 + 无 + + 4. **bool Load(const std::string& modelPath)** + - 功能说明 + 模型加载函数 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | modelPath | 输入 | 模型路径 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 5. **bool CreateInput(void \*input, uint32_t size)** + - 功能说明 + 创建模型输入(模型单输入场景) + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | input | 输入 | 输入数据 | + | size | 输入 | 输入数据大小 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 6. **bool CreateInput(void \*input1, uint32_t input1size, void \*input2, uint32_t input2size)** + - 功能说明 + 创建模型输入(模型两个输入场景) + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | input1 | 输入 | 首个输入数据 | + | input1size | 输入 | 首个输入数据大小 | + | input2 | 输入 | 第二个输入数据大小 | + | input2size | 输入 | 第二个输入数据大小 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 7. **bool CreateInput(std::vector& inputData)** + - 功能说明 + 创建模型输入(模型多输入场景) + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | inputData | 输入 | 输入数据,vector结构 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 8. **bool Execute(std::vector& inferOutputs)** + - 功能说明 + 模型执行函数 + - 参数说明 + | 参数名 | 输入/输出 | 说明 | + |---|---|---| + | inferOutputs | 输出 | 输出数据,vector结构 | + - 返回值说明 + 返回true表示成功,返回false表示失败。 + + 9. **void DestroyInput()** + - 功能说明 + 释放模型输入 + - 参数说明 + 无 + - 返回值说明 + 无 + + 10. **void DestroyOutput()** + - 功能说明 + 释放模型输出 + - 参数说明 + 无 + - 返回值说明 + 无 + + 11. **void Unload()** + - 功能说明 + 卸载模型 + - 参数说明 + 无 + - 返回值说明 + 无 \ No newline at end of file diff --git a/Media/CMakeLists.txt b/Media/CMakeLists.txt new file mode 100644 index 0000000..f3de576 --- /dev/null +++ b/Media/CMakeLists.txt @@ -0,0 +1,60 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. + +# CMake lowest version requirement +cmake_minimum_required(VERSION 3.5.1) + +# project information +project(camera_interface) + +add_definitions(-DENABLE_DVPP_INTERFACE) +set(INC_PATH $ENV{DDK_PATH}) +if (NOT DEFINED ENV{DDK_PATH}) + set(INC_PATH "/usr/local/Ascend/ascend-toolkit/latest/aarch64-linux") + message(STATUS "set default INC_PATH: ${INC_PATH}") +else () + message(STATUS "env INC_PATH: ${INC_PATH}") +endif() + +set(LIB_PATH $ENV{NPU_HOST_LIB}) +if (NOT DEFINED ENV{NPU_HOST_LIB}) + set(LIB_PATH "/usr/local/Ascend/ascend-toolkit/latest/aarch64-linux/runtime/lib64/stub") + message(STATUS "set default LIB_PATH: ${LIB_PATH}") +else () + message(STATUS "env LIB_PATH: ${LIB_PATH}") +endif() + +link_directories( + ${LIB_PATH} +) + +add_library(acllite_media SHARED + ./CameraRead.cpp +) +include_directories(acllite_media + ./ + ${INC_PATH}/runtime/include/ + ${INC_PATH}/include/ +) + +add_compile_options(acllite_media + -O2 + -Wall + -fpic +) + +target_link_libraries(acllite_media + ascendcl + stdc++ + acllite_common + pthread + avcodec + avformat + avutil + swresample + swscale + avdevice + dl +) + +INSTALL(TARGETS acllite_media LIBRARY DESTINATION lib) +INSTALL(FILES ./CameraRead.h DESTINATION include/acllite_media) \ No newline at end of file diff --git a/DVPPLite/src/USBCamera.cpp b/Media/CameraRead.cpp similarity index 83% rename from DVPPLite/src/USBCamera.cpp rename to Media/CameraRead.cpp index 571a0d4..100ec84 100644 --- a/DVPPLite/src/USBCamera.cpp +++ b/Media/CameraRead.cpp @@ -1,4 +1,3 @@ - #include #include extern "C" { @@ -8,25 +7,27 @@ extern "C" { #include #include } -#include "USBCamera.h" +#include "CameraRead.h" +#include "acllite_common/Common.h" using namespace std; namespace acllite { const int kWait = 10000; -USBCamera::USBCamera(const std::string& videoName, int32_t deviceId, aclrtContext context) +CameraRead::CameraRead(const std::string& videoName, int32_t deviceId, aclrtContext context) :deviceId_(deviceId), context_(context), streamName_(videoName), formatContext_(nullptr), isReleased_(false), isOpened_(false), isStop_(false), isStarted_(false), frameQueue_(10) { + Open(); } -USBCamera::~USBCamera() +CameraRead::~CameraRead() { DestroyResource(); } -void USBCamera::DestroyResource() +void CameraRead::DestroyResource() { if (isReleased_) return; isOpened_ = false; @@ -34,22 +35,15 @@ void USBCamera::DestroyResource() return; } -bool USBCamera::IsOpened() +bool CameraRead::IsOpened() { return isOpened_; } -bool USBCamera::Set(int propId, uint32_t value) -{ - LOG_PRINT("[INFO] Set property Unsurpport for usbcamera"); - return true; -} -uint32_t USBCamera::Get(int propId) +uint32_t CameraRead::Get(StreamProperty propId) { uint32_t value = 0; - StreamProperty key = (StreamProperty)propId; - - switch (key) { + switch (propId) { case FRAME_WIDTH: value = width_; break; @@ -60,15 +54,13 @@ uint32_t USBCamera::Get(int propId) value = fps_; break; default: - LOG_PRINT("[ERROR] Unsurpport property %d to get for video", key); + LOG_PRINT("[ERROR] Unsurpport property %d to get for video", propId); break; } - return value; - return 0; } -bool USBCamera::Read(ImgData& frame) +bool CameraRead::Read(ImageData& frame) { if (!isOpened_) { return false; @@ -79,14 +71,13 @@ bool USBCamera::Read(ImgData& frame) usleep(1000); isStarted_ = true; } - shared_ptr image = frameQueue_.Pop(); + shared_ptr image = frameQueue_.Pop(); if (image != nullptr) { frame.data = image->data; frame.width = image->width; frame.height = image->height; frame.format = image->format; frame.size = image->size; - frame.location = MEMORY_NORMAL; return true; } for (int count = 0; count < kWait - 1; count++) { @@ -98,21 +89,20 @@ bool USBCamera::Read(ImgData& frame) frame.height = image->height; frame.format = image->format; frame.size = image->size; - frame.location = MEMORY_NORMAL; return true; } } return false; } -void USBCamera::Release() +void CameraRead::Release() { isStop_ = true; DestroyResource(); return; } -bool USBCamera::SendFrame(void* frameData, int frameSize) { +bool CameraRead::SendFrame(void* frameData, int frameSize) { // frameId_++ record framenum; if ((frameData == NULL) || (frameSize == 0)) { LOG_PRINT("Frame data is null"); @@ -137,20 +127,19 @@ bool USBCamera::SendFrame(void* frameData, int frameSize) { acldvppFree(deviceMem); return false; } - shared_ptr videoFrame = make_shared(); + shared_ptr videoFrame = make_shared(); videoFrame->data = SHARED_PTR_DEV_BUF(deviceMem); videoFrame->size = frameSize; videoFrame->width = width_; videoFrame->height = height_; videoFrame->format = PIXEL_FORMAT_YUYV_PACKED_422; - videoFrame->location = MEMORY_NORMAL; frameQueue_.Push(videoFrame); return true; } -void USBCamera::DecodeFrameThread(void* decoderSelf) +void CameraRead::DecodeFrameThread(void* decoderSelf) { - USBCamera* thisPtr = (USBCamera*)decoderSelf; + CameraRead* thisPtr = (CameraRead*)decoderSelf; int videoStreamIndex = -1; for (int i = 0; i < thisPtr->formatContext_->nb_streams; ++i) { if (thisPtr->formatContext_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -216,13 +205,13 @@ void USBCamera::DecodeFrameThread(void* decoderSelf) return; } -void USBCamera::StartFrameDecoder() +void CameraRead::StartFrameDecoder() { decodeThread_ = thread(DecodeFrameThread, (void*)this); decodeThread_.detach(); } -Result USBCamera::Open() +Result CameraRead::Open() { avdevice_register_all(); AVDictionary *options = NULL; diff --git a/DVPPLite/include/USBCamera.h b/Media/CameraRead.h similarity index 55% rename from DVPPLite/include/USBCamera.h rename to Media/CameraRead.h index 99611ab..e9c09b3 100644 --- a/DVPPLite/include/USBCamera.h +++ b/Media/CameraRead.h @@ -1,21 +1,25 @@ -#ifndef USB_CAMERA_DECODE_H -#define USB_CAMERA_DECODE_H +#ifndef CAMERA_READ_H +#define CAMERA_READ_H +#include "acllite_common/Common.h" #include "acllite_common/ThreadSafeQueue.h" -#include "VideoCapBase.h" + +extern "C" { +#include +#include +} namespace acllite { -class USBCamera : public VideoCapBase { +class CameraRead { public: - USBCamera(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr); - ~USBCamera(); + CameraRead(const std::string& videoName, int32_t deviceId = 0, aclrtContext context = nullptr); + ~CameraRead(); bool IsOpened(); - bool Set(int propId, uint32_t value); - uint32_t Get(int propId); - bool Read(ImgData& frame); - Result Open(); + uint32_t Get(StreamProperty propId); + bool Read(ImageData& frame); void Release(); private: + Result Open(); void DestroyResource(); void StartFrameDecoder(); bool SendFrame(void* frameData, int frameSize); @@ -34,7 +38,7 @@ private: uint32_t width_; uint32_t height_; uint32_t fps_; - ThreadSafeQueue> frameQueue_; + ThreadSafeQueue> frameQueue_; }; } // namespace acllite -#endif /* USB_CAMERA_DECODE_H */ +#endif /* CAMERA_READ_H */ diff --git a/Media/README.md b/Media/README.md new file mode 100644 index 0000000..acdd790 --- /dev/null +++ b/Media/README.md @@ -0,0 +1,89 @@ +## 目录 + + - [工具介绍](#工具介绍) + - [获取源码包](#获取源码包) + - [第三方依赖安装](#第三方依赖安装) + - [编译安装](#编译安装) + - [其他资源](#其他资源) + - [更新说明](#更新说明) + - [已知issue](#已知issue) + +## 工具介绍 + +Media库对USBCamera设备使用进行了接口封装操作,通过安装Media动态库,方便开发者快速上手,使用USBCamera摄像头功能。 + +## 获取源码包 + + 可以使用以下两种方式下载,请选择其中一种进行源码准备。 + + - 命令行方式下载(下载时间较长,但步骤简单)。 + + ``` + # 开发环境,非root用户命令行中执行以下命令下载源码仓。 + cd ${HOME} + git clone https://gitee.com/ascend/ACLLite.git + ``` + - 压缩包方式下载(下载时间较短,但步骤稍微复杂)。 + **注:如果需要下载其它版本代码,请先请根据前置条件说明进行samples仓分支切换。** + ``` + # 1. ACLLite仓右上角选择 【克隆/下载】 下拉框并选择 【下载ZIP】。 + # 2. 将ZIP包上传到开发环境中的普通用户家目录中,【例如:${HOME}/acllite-master.zip】。 + # 3. 开发环境中,执行以下命令,解压zip包。 + cd ${HOME} + unzip acllite-master.zip + ``` + +## 第三方依赖安装 + + 设置环境变量,配置程序编译依赖的头文件,库文件路径。“$HOME/Ascend”请替换“Ascend-cann-toolkit”包的实际安装路径。 + + ``` + export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest + export NPU_HOST_LIB=$DDK_PATH/runtime/lib64/stub + ``` + +- ffmpeg + + 执行以下命令安装ffmpeg + + ``` + apt-get install libavcodec-dev libswscale-dev libavdevice-dev + ``` + +## 编译安装 + + - 库编译 + + 执行以下命令,执行编译命令,开始库编译。 + ``` + cd $HOME/ACLLite/Media + mkdir build + cd build + cmake -DCMAKE_INSTALL_PREFIX=/usr .. -DCMAKE_C_COMPILER=gcc -DCMAKE_SKIP_RPATH=TRUE + make + ``` + - 库安装 + + 执行安装命令,开始安装动态库。 + ``` + sudo make install + ``` + + 执行成功后,生成的so文件会被拷贝安装到/usr/lib目录下,对应的头文件会被拷贝安装到/usr/include/acllite_media目录下。 + +## 其他资源 + +以下资源提供了对USBCamera相关更详细的信息: + +**Documentation** +- [昇腾文档](https://www.hiascend.com/document?tag=community-developer) + +## 更新说明 + | 时间 | 更新事项 | + |----|------| + | 2024/01/25 | 新增README.md | + + +## 已知issue + + 暂无 diff --git a/OMExecute/include/ModelProc.h b/OMExecute/include/ModelProc.h index b435fb9..90cd06a 100644 --- a/OMExecute/include/ModelProc.h +++ b/OMExecute/include/ModelProc.h @@ -33,17 +33,18 @@ public: ~ModelProc(); void DestroyResource(); bool Load(const std::string& modelPath); - bool CreateInput(void *input, uint32_t size); - bool CreateInput(void *input1, uint32_t input1size, - void* input2, uint32_t input2size); + bool CreateInput(void* input, uint32_t size); + bool CreateInput(void* input1, uint32_t input1size, + void* input2, uint32_t input2size); bool CreateInput(std::vector& inputData); - bool AddDatasetBuffer(aclmdlDataset *dataset, - void* buffer, uint32_t bufferSize); bool Execute(std::vector& inferOutputs); - bool GetOutputItem(InferenceOutput& out, uint32_t idx); void DestroyInput(); void DestroyOutput(); void Unload(); +private: + bool AddDatasetBuffer(aclmdlDataset* dataset, + void* buffer, uint32_t bufferSize); + bool GetOutputItem(InferenceOutput& out, uint32_t idx); private: aclrtRunMode runMode_; bool loadFlag_; diff --git a/README.md b/README.md index 41dd92a..7b04f6b 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,62 @@ # ACLLite -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +## 介绍 +ACLLite库是对CANN提供的ACL接口进行的高阶封装,简化用户调用流程,为用户提供一组简易的公共接口。当前主要针对边缘场景设计。 -#### 软件架构 -软件架构说明 +## 软件架构 + + + + + + + + +
命名空间模块说明
acllitecommon 资源管理及公共函数模块
DVPPLite DVPP高阶封装模块
OMExecute 离线模型执行高阶封装模块
Media 媒体功能高阶封装模块
-#### 安装教程 -1. xxxx -2. xxxx -3. xxxx +## 安装教程 -#### 使用说明 +- **环境要求:** Ascend边缘设备。 +- **CANN版本要求:** 7.0及以上社区版本。 +- **安装步骤:** + 1. 安装所有模块 + ``` + # 拉取ACLLite仓库,并进入目录 + git clone https://gitee.com/ascend/ACLLite.git + cd ACLLite -1. xxxx -2. xxxx -3. xxxx + # 安装ffmpeg + apt-get install libavcodec-dev libswscale-dev libavdevice-dev + + # 设置环境变量,其中DDK_PATH中/usr/local请替换为实际CANN包的安装路径 + export DDK_PATH=/usr/local/Ascend/ascend-toolkit/latest + export NPU_HOST_LIB=$DDK_PATH/runtime/lib64/stub + + # 安装,编译过程中会将库文件安装到/lib目录下,所以会有sudo命令,需要输入密码 + bash build_so.sh + ``` + 2. 安装单模块 + 打开需要安装的模块,根据模块中Readme进行安装。 + +## API说明 + +- [common模块API说明](Doc/common.md) +- [DVPPLite模块API说明](Doc/dvpplite.md) +- [OMExcute模块API说明](Doc/omexcute.md) +- [Media模块API说明](Doc/media.md) #### 参与贡献 1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +2. 提交代码 +3. 新建 Pull Request + +#### 修订记录 -#### 特技 +| 日期 | 更新事项 | +|---|---| +| 2022/1/25 | 首次发布 | -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/build_so.sh b/build_so.sh index 55b35c0..8c5f006 100644 --- a/build_so.sh +++ b/build_so.sh @@ -15,6 +15,13 @@ cmake -DCMAKE_INSTALL_PREFIX=/usr .. -DCMAKE_C_COMPILER=gcc -DCMAKE_SKIP_RPATH=T make sudo make install +cd ${ScriptPath}/Media +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=/usr .. -DCMAKE_C_COMPILER=gcc -DCMAKE_SKIP_RPATH=TRUE +make +sudo make install + cd ${ScriptPath}/OMExecute mkdir build cd build -- Gitee From 90272779a563ff35c27bafb0a31f5733e5efc6aa Mon Sep 17 00:00:00 2001 From: fuyangchenghu <1015138540@qq.com> Date: Tue, 30 Jan 2024 12:43:03 +0000 Subject: [PATCH 2/2] add OWNERS. Signed-off-by: fuyangchenghu <1015138540@qq.com> --- OWNERS | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 OWNERS diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..513ef67 --- /dev/null +++ b/OWNERS @@ -0,0 +1,6 @@ +approvers: +- fuyangchenghu +- alvin_yan +reviewers: +- fuyangchenghu +- alvin_yan \ No newline at end of file -- Gitee