diff --git a/BUILD.gn b/BUILD.gn index f41d67edd..5e2e783b8 100755 --- a/BUILD.gn +++ b/BUILD.gn @@ -17,6 +17,6 @@ import("//build/ohos.gni") group("av_codec_packages") { public_deps = [ "interfaces/inner_api/native:av_codec_client", - "services:av_codec_service", + "services/services:av_codec_service", ] } diff --git a/bundle.json b/bundle.json index b31f7b95a..f8840de1c 100644 --- a/bundle.json +++ b/bundle.json @@ -77,9 +77,10 @@ } } ], - "test": [ - "//foundation/multimedia/av_codec/test:av_codec_demo_test" - ] + "test": [ + "//foundation/multimedia/av_codec/test:av_codec_demo_test", + "//foundation/multimedia/av_codec/test:av_codec_unit_test" + ] } } } diff --git a/config.gni b/config.gni index 34de9c35e..0b31fcf6c 100644 --- a/config.gni +++ b/config.gni @@ -13,12 +13,12 @@ declare_args() { multimedia_av_codec_support_capi = true - multimedia_av_codec_support_codec = true + multimedia_av_codec_support_codec = false multimedia_av_codec_support_codeclist = false multimedia_av_codec_support_demuxer = false multimedia_av_codec_support_muxer = true multimedia_av_codec_support_ffmpeg_demuxer = false - multimedia_av_codec_support_test = false + multimedia_av_codec_support_test = true } av_codec_defines = [] diff --git a/frameworks/native/avmuxer/avmuxer_impl.cpp b/frameworks/native/avmuxer/avmuxer_impl.cpp index 1a4861c31..2136a7b4d 100644 --- a/frameworks/native/avmuxer/avmuxer_impl.cpp +++ b/frameworks/native/avmuxer/avmuxer_impl.cpp @@ -14,15 +14,14 @@ */ #include "avmuxer_impl.h" -#include #include -#include -#include +#include #include "securec.h" +#include "i_avcodec_service.h" #include "avcodec_log.h" #include "avsharedmemorybase.h" #include "avcodec_dfx.h" -#include "i_avcodec_service.h" +#include "avcodec_errors.h" namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerImpl"}; @@ -30,9 +29,9 @@ namespace { namespace OHOS { namespace Media { -std::shared_ptr AVMuxerFactory::CreateAVMuxer(int32_t fd, AVOutputFormat format) +std::shared_ptr AVMuxerFactory::CreateAVMuxer(int32_t fd, OutputFormat format) { - AVCodecTrace trace(std::string(__FUNCTION__)); + AVCodecTrace trace("AVMuxerFactory::CreateAVMuxer"); CHECK_AND_RETURN_RET_LOG((fcntl(fd, F_GETFL, 0) & O_RDWR) == O_RDWR, nullptr, "No permission to read and write fd"); CHECK_AND_RETURN_RET_LOG(lseek(fd, 0, SEEK_CUR) != -1, nullptr, "The fd is not seekable"); @@ -44,7 +43,7 @@ std::shared_ptr AVMuxerFactory::CreateAVMuxer(int32_t fd, AVOutputForma return impl; } -AVMuxerImpl::AVMuxerImpl(int32_t fd, AVOutputFormat format) : fd_(fd), format_(format) +AVMuxerImpl::AVMuxerImpl(int32_t fd, OutputFormat format) : fd_(fd), format_(format) { (void)fd_; (void)format_; @@ -53,77 +52,77 @@ AVMuxerImpl::AVMuxerImpl(int32_t fd, AVOutputFormat format) : fd_(fd), format_(f AVMuxerImpl::~AVMuxerImpl() { - if (muxerClient_ != nullptr) { - (void)AVCodecServiceFactory::GetInstance().DestroyMuxerService(muxerClient_); - muxerClient_ = nullptr; + if (muxerService_ != nullptr) { + (void)muxerService_->Release(); + (void)AVCodecServiceFactory::GetInstance().DestroyMuxerService(muxerService_); + muxerService_ = nullptr; } AVCODEC_LOGD("AVMuxerImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); } int32_t AVMuxerImpl::Init() { - AVCodecTrace trace(std::string(__FUNCTION__)); - muxerClient_ = AVCodecServiceFactory::GetInstance().CreateMuxerService(); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Create avmuxer engine failed"); - return AVCS_ERR_OK; + AVCodecTrace trace("AVMuxer::Init"); + AVCODEC_LOGI("Init"); + muxerService_ = AVCodecServiceFactory::GetInstance().CreateMuxerService(); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_NO_MEMORY, "Create AVMuxer Service failed"); + return muxerService_->InitParameter(fd_, format_); } int32_t AVMuxerImpl::SetLocation(float latitude, float longitude) { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->SetLocation(latitude, longitude); + AVCodecTrace trace("AVMuxer::SetLocation"); + AVCODEC_LOGI("SetLocation"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + return muxerService_->SetLocation(latitude, longitude); } int32_t AVMuxerImpl::SetRotation(int32_t rotation) { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->SetRotation(rotation); + AVCodecTrace trace("AVMuxer::SetRotation"); + AVCODEC_LOGI("SetRotation"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + return muxerService_->SetRotation(rotation); } -int32_t AVMuxerImpl::SetParameter(const Format &generalFormat) +int32_t AVMuxerImpl::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->SetParameter(generalFormat); -} - -int32_t AVMuxerImpl::AddTrack(uint32_t &trackIndex, const Format &trackFormat) -{ - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->AddTrack(trackIndex, trackFormat); + AVCodecTrace trace("AVMuxer::AddTrack"); + AVCODEC_LOGI("AddTrack"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + return muxerService_->AddTrack(trackIndex, trackDesc); } int32_t AVMuxerImpl::Start() { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->Start(); + AVCodecTrace trace("AVMuxer::Start"); + AVCODEC_LOGI("Start"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + return muxerService_->Start(); } -int32_t AVMuxerImpl::WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info) +int32_t AVMuxerImpl::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.offset >= 0 && info.size >= 0, - AVCS_ERR_INVALID_VAL, "Invalid memory"); + AVCodecTrace trace("AVMuxer::WriteSampleBuffer"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.timeUs >= 0, AVCS_ERR_INVALID_VAL, "Invalid memory"); - std::shared_ptr sharedSampleBuffer = - AVSharedMemoryBase::CreateFromLocal(info.size, AVSharedMemory::FLAGS_READ_ONLY, "SampleBuffer"); - CHECK_AND_RETURN_RET_LOG(sharedSampleBuffer == nullptr, AVCS_ERR_NO_MEMORY, "Create AVSharedMemoryBase failed"); - errno_t rc = memcpy_s(sharedSampleBuffer->GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer + info.offset, info.size); + std::shared_ptr sharedSampleBuffer = + std::make_shared(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleBuffer"); + int32_t ret = sharedSampleBuffer->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_NO_MEMORY, "create AVSharedMemoryBase failed"); + errno_t rc = memcpy_s(sharedSampleBuffer->GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer, info.size); CHECK_AND_RETURN_RET_LOG(rc == EOK, AVCS_ERR_UNKNOWN, "memcpy_s failed"); - return muxerClient_->WriteSampleBuffer(trackIndex, sharedSampleBuffer, info); + return muxerService_->WriteSampleBuffer(sharedSampleBuffer, info); } int32_t AVMuxerImpl::Stop() { - AVCodecTrace trace(std::string(__FUNCTION__)); - CHECK_AND_RETURN_RET_LOG(muxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Engine does not exist"); - return muxerClient_->Stop(); + AVCodecTrace trace("AVMuxer::Stop"); + AVCODEC_LOGI("Stop"); + CHECK_AND_RETURN_RET_LOG(muxerService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "AVMuxer Service does not exist"); + return muxerService_->Stop(); } } // namespace Media } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/avmuxer/avmuxer_impl.h b/frameworks/native/avmuxer/avmuxer_impl.h index 377bf3e4e..6623e677d 100644 --- a/frameworks/native/avmuxer/avmuxer_impl.h +++ b/frameworks/native/avmuxer/avmuxer_impl.h @@ -16,28 +16,27 @@ #define AVMUXER_IMPL_H #include "avmuxer.h" -#include "i_avmuxer.h" +#include "i_muxer_service.h" #include "nocopyable.h" namespace OHOS { namespace Media { class AVMuxerImpl : public AVMuxer, public NoCopyable { public: - AVMuxerImpl(int32_t fd, AVOutputFormat format); + AVMuxerImpl(int32_t fd, OutputFormat format); ~AVMuxerImpl() override; int32_t Init(); int32_t SetLocation(float latitude, float longitude) override; int32_t SetRotation(int32_t rotation) override; - int32_t SetParameter(const Format &generalFormat) override; - int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; int32_t Start() override; - int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info) override; + int32_t WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) override; int32_t Stop() override; private: - std::shared_ptr muxerClient_ = nullptr; + std::shared_ptr muxerService_ = nullptr; int32_t fd_ = -1; - AVOutputFormat format_ = AV_OUTPUT_FORMAT_UNKNOWN; + OutputFormat format_ = OUTPUT_FORMAT_UNKNOWN; }; } // namespace Media } // namespace OHOS diff --git a/frameworks/native/capi/avcodec/native_avcodec_base.cpp b/frameworks/native/capi/avcodec/native_avcodec_base.cpp index 978661b83..f092222fb 100644 --- a/frameworks/native/capi/avcodec/native_avcodec_base.cpp +++ b/frameworks/native/capi/avcodec/native_avcodec_base.cpp @@ -20,7 +20,12 @@ extern "C" { #endif const char *OH_AVCODEC_MIMETYPE_VIDEO_AVC = "video/avc"; +const char *OH_AVCODEC_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; const char *OH_AVCODEC_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm"; +const char *OH_AVCODEC_MIMETYPE_AUDIO_MPEG = "audio/mpeg"; +const char *OH_AVCODEC_MIMETYPE_IMAGE_JPG = "image/jpeg"; +const char *OH_AVCODEC_MIMETYPE_IMAGE_PNG = "image/png"; +const char *OH_AVCODEC_MIMETYPE_IMAGE_BMP = "image/bmp"; const char *OH_ED_KEY_TIME_STAMP = "timeStamp"; const char *OH_ED_KEY_EOS = "endOfStream"; const char *OH_MD_KEY_TRACK_TYPE = "track_type"; @@ -39,6 +44,7 @@ const char *OH_MD_KEY_AUD_CHANNEL_COUNT = "channel_count"; const char *OH_MD_KEY_AUD_SAMPLE_RATE = "sample_rate"; const char *OH_MD_KEY_I_FRAME_INTERVAL = "i_frame_interval"; const char *OH_MD_KEY_ROTATION = "rotation_angle"; +const char *OH_MD_KEY_CODEC_CONFIG = "codec_config"; #ifdef __cplusplus } diff --git a/frameworks/native/capi/avmuxer/native_avmuxer.cpp b/frameworks/native/capi/avmuxer/native_avmuxer.cpp index 8852c6527..307c6d4df 100644 --- a/frameworks/native/capi/avmuxer/native_avmuxer.cpp +++ b/frameworks/native/capi/avmuxer/native_avmuxer.cpp @@ -17,6 +17,7 @@ #include "native_avmagic.h" #include "avmuxer.h" #include "avcodec_log.h" +#include "avcodec_errors.h" namespace { constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAVMuxer"}; @@ -34,7 +35,7 @@ struct AVMuxerObject : public OH_AVMuxer { struct OH_AVMuxer *OH_AVMuxer_Create(int32_t fd, OH_AVOutputFormat format) { CHECK_AND_RETURN_RET_LOG(fd >= 0, nullptr, "fd %{public}d is error!", fd); - std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd, static_cast(format)); + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd, static_cast(format)); CHECK_AND_RETURN_RET_LOG(avmuxer != nullptr, nullptr, "create muxer failed!"); struct AVMuxerObject *object = new(std::nothrow) AVMuxerObject(avmuxer); return object; @@ -60,23 +61,18 @@ OH_AVErrCode OH_AVMuxer_SetRotation(OH_AVMuxer *muxer, int32_t rotation) { struct AVMuxerObject *object = reinterpret_cast(muxer); CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); - if (rotation != VIDEO_ROTATION_0 && rotation != VIDEO_ROTATION_90 && - rotation != VIDEO_ROTATION_180 &&rotation != VIDEO_ROTATION_270) { - CHECK_AND_RETURN_RET_LOG(false, AV_ERR_INVALID_VAL, "rotation is invalid value!"); - } - int32_t ret = object->muxer_->SetRotation(rotation); CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ SetRotation failed!"); return AV_ERR_OK; } -OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, uint32_t *trackIndex, OH_AVFormat *trackFormat) { +OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, int32_t *trackIndex, OH_AVFormat *trackFormat) { CHECK_AND_RETURN_RET_LOG(muxer != nullptr, AV_ERR_INVALID_VAL, "input muxer is nullptr!"); CHECK_AND_RETURN_RET_LOG(muxer->magic_ == AVMagic::AVCODEC_MAGIC_AVMUXER, AV_ERR_INVALID_VAL, "magic error!"); CHECK_AND_RETURN_RET_LOG(trackIndex != nullptr, AV_ERR_INVALID_VAL, "input track index is nullptr!"); CHECK_AND_RETURN_RET_LOG(trackFormat != nullptr, AV_ERR_INVALID_VAL, "input track format is nullptr!"); - CHECK_AND_RETURN_RET_LOG(trackFormat->magic_ == AVMagic::AVCODEC_MAGIC_AVMUXER, AV_ERR_INVALID_VAL, "magic error!"); + CHECK_AND_RETURN_RET_LOG(trackFormat->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!"); struct AVMuxerObject *object = reinterpret_cast(muxer); CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); @@ -106,11 +102,14 @@ OH_AVErrCode OH_AVMuxer_WriteSampleBuffer(OH_AVMuxer *muxer, uint32_t trackIndex struct AVMuxerObject *object = reinterpret_cast(muxer); CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); - AVCodecBufferInfo innerInfo; - innerInfo.presentationTimeUs = info.pts; - innerInfo.offset = info.offset; - innerInfo.size = info.size; - int32_t ret = object->muxer_->WriteSampleBuffer(trackIndex, sampleBuffer, innerInfo); + + TrackSampleInfo sampleInfo; + sampleInfo.trackIndex = trackIndex; + sampleInfo.timeUs = info.pts; + sampleInfo.size = info.size; + sampleInfo.flags = info.flags; + + int32_t ret = object->muxer_->WriteSampleBuffer(sampleBuffer, sampleInfo); CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ WriteSampleBuffer failed!"); return AV_ERR_OK; diff --git a/frameworks/native/capi/common/native_avmagic.h b/frameworks/native/capi/common/native_avmagic.h index 1ca37897d..5bebb39a0 100644 --- a/frameworks/native/capi/common/native_avmagic.h +++ b/frameworks/native/capi/common/native_avmagic.h @@ -21,7 +21,6 @@ #include "avsharedmemory.h" #include "avcodec_common.h" #include "format.h" -#include "avcodec_info.h" #define AV_MAGIC(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + ((d) << 0)) diff --git a/interfaces/inner_api/native/BUILD.gn b/interfaces/inner_api/native/BUILD.gn index 62788f63d..5b3f5327f 100644 --- a/interfaces/inner_api/native/BUILD.gn +++ b/interfaces/inner_api/native/BUILD.gn @@ -100,6 +100,16 @@ config("av_codec_client_local_config") { ] } +config("av_codec_client_ipc_config") { + include_dirs = [ + "$AV_CODEC_ROOT_DIR/services/services/sa_avcodec/client", + "$AV_CODEC_ROOT_DIR/services/services/sa_avcodec/ipc", + "$AV_CODEC_ROOT_DIR/services/services/common", + "$AV_CODEC_ROOT_DIR/services/services/muxer/client", + "$AV_CODEC_ROOT_DIR/services/services/muxer/ipc", + ] +} + config("av_codec_client_public_config") { include_dirs = [ "$AV_CODEC_ROOT_DIR/frameworks/native/avcodec", @@ -111,6 +121,7 @@ config("av_codec_client_public_config") { "$AV_CODEC_ROOT_DIR/services/utils", "$AV_CODEC_ROOT_DIR/services/include", "$AV_CODEC_ROOT_DIR/services/dfx/include", + "$AV_CODEC_ROOT_DIR/services/utils/include", "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", "//utils/system/safwk/native/include", "//third_party/bounds_checking_function/include", @@ -159,6 +170,7 @@ ohos_shared_library("av_codec_client") { install_enable = true public_configs = [ ":av_codec_client_local_config", + ":av_codec_client_ipc_config", ":av_codec_client_public_config", ":av_codec_packege_include", ] @@ -202,8 +214,8 @@ ohos_shared_library("av_codec_client") { if (multimedia_av_codec_support_muxer) { sources += [ "$AV_CODEC_ROOT_DIR/frameworks/native/avmuxer/avmuxer_impl.cpp", - "$AV_CODEC_ROOT_DIR/services/services/muxer/client/avmuxer_client.cpp", - "$AV_CODEC_ROOT_DIR/services/services/muxer/ipc/avmuxer_proxy.cpp", + "$AV_CODEC_ROOT_DIR/services/services/muxer/client/muxer_client.cpp", + "$AV_CODEC_ROOT_DIR/services/services/muxer/ipc/muxer_service_proxy.cpp", ] } diff --git a/interfaces/inner_api/native/av_common.h b/interfaces/inner_api/native/av_common.h index 4eb1f30b5..f36e77f64 100644 --- a/interfaces/inner_api/native/av_common.h +++ b/interfaces/inner_api/native/av_common.h @@ -118,20 +118,20 @@ enum AVSeekMode : uint8_t { */ enum VideoRotation : uint32_t { /** - * Video without rotation - */ + * Video without rotation + */ VIDEO_ROTATION_0 = 0, /** - * Video rotated 90 degrees - */ + * Video rotated 90 degrees + */ VIDEO_ROTATION_90 = 90, /** - * Video rotated 180 degrees - */ + * Video rotated 180 degrees + */ VIDEO_ROTATION_180 = 180, /** - * Video rotated 270 degrees - */ + * Video rotated 270 degrees + */ VIDEO_ROTATION_270 = 270, }; @@ -151,6 +151,53 @@ enum StateChangeReason { */ BACKGROUND = 2, }; + +/** + * @brief Enumerates the output format. + * + * @since 10 + * @version 4.0 + */ +enum OutputFormat : uint32_t{ + /** + * output format unknown + */ + OUTPUT_FORMAT_UNKNOWN = 0, + /** + * output format mp4 + */ + OUTPUT_FORMAT_MPEG_4 = 1, + /** + * output format m4a + */ + OUTPUT_FORMAT_M4A = 2, +}; + +/** + * @brief Description information of a sample associated a media track. + * + * @since 10 + * @version 4.0 + */ +struct TrackSampleInfo { + /** + * @brief the id of track that this sample belongs to. + */ + uint32_t trackIndex; + /** + * @brief the presentation timestamp in microseconds. + */ + int64_t timeUs; + /** + * @brief the size in bytes. + */ + uint32_t size; + /** + * @brief the flags associated with the sample, this + * maybe be a combination of multiple {@link AVCodecBufferFlag}. + */ + uint32_t flags; +}; } // namespace Media } // namespace OHOS #endif // AV_COMMOM_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avcodec_common.h b/interfaces/inner_api/native/avcodec_common.h index 258c16c0d..d63ac90eb 100644 --- a/interfaces/inner_api/native/avcodec_common.h +++ b/interfaces/inner_api/native/avcodec_common.h @@ -57,16 +57,11 @@ struct AVCodecBufferInfo { int32_t offset = 0; }; -typedef enum AVOutputFormat { - AV_OUTPUT_FORMAT_UNKNOWN = 0, - AV_OUTPUT_FORMAT_MPEG_4 = 1, - AV_OUTPUT_FORMAT_M4A = 2, -} AVOutputFormat; - struct AVBufferElement { std::shared_ptr buffer; std::shared_ptr metaData; }; + class AVCodecCallback { public: virtual ~AVCodecCallback() = default; diff --git a/interfaces/inner_api/native/avcodec_errors.h b/interfaces/inner_api/native/avcodec_errors.h index 1f3fd3272..2ac7f11d0 100644 --- a/interfaces/inner_api/native/avcodec_errors.h +++ b/interfaces/inner_api/native/avcodec_errors.h @@ -16,7 +16,6 @@ #ifndef AVCODEC_ERRORS_H #define AVCODEC_ERRORS_H -#include #include #include "errors.h" #include "native_averrors.h" diff --git a/interfaces/inner_api/native/avcodec_info.h b/interfaces/inner_api/native/avcodec_info.h index e70786ced..d3459fb9f 100644 --- a/interfaces/inner_api/native/avcodec_info.h +++ b/interfaces/inner_api/native/avcodec_info.h @@ -508,6 +508,9 @@ public: static constexpr std::string_view AUDIO_OPUS = "audio/opus"; static constexpr std::string_view AUDIO_FLAC = "audio/flac"; static constexpr std::string_view AUDIO_RAW = "audio/raw"; + static constexpr std::string_view IMAGE_JPG = "image/jpeg"; + static constexpr std::string_view IMAGE_PNG = "image/png"; + static constexpr std::string_view IMAGE_BMP = "image/bmp"; }; /** diff --git a/interfaces/inner_api/native/avmuxer.h b/interfaces/inner_api/native/avmuxer.h index abd496c73..fe89b3b02 100644 --- a/interfaces/inner_api/native/avmuxer.h +++ b/interfaces/inner_api/native/avmuxer.h @@ -16,9 +16,8 @@ #ifndef AVMUXER_H #define AVMUXER_H -#include "format.h" -#include "avcodec_errors.h" -#include "avcodec_common.h" +#include "media_description.h" +#include "av_common.h" namespace OHOS { namespace Media { @@ -27,21 +26,20 @@ public: virtual ~AVMuxer() = default; virtual int32_t SetLocation(float latitude, float longitude) = 0; virtual int32_t SetRotation(int32_t rotation) = 0; - virtual int32_t SetParameter(const Format &generalFormat) = 0; - virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0; + virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0; virtual int32_t Start() = 0; - virtual int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, AVCodecBufferInfo info) = 0; + virtual int32_t WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) = 0; virtual int32_t Stop() = 0; }; class __attribute__((visibility("default"))) AVMuxerFactory { public: - static std::shared_ptr CreateAVMuxer(int32_t fd, AVOutputFormat format); + static std::shared_ptr CreateAVMuxer(int32_t fd, OutputFormat format); private: AVMuxerFactory() = default; ~AVMuxerFactory() = default; }; -} // namespace MediaAVCodec +} // namespace Media } // namespace OHOS #endif // AVMUXER_H diff --git a/interfaces/inner_api/native/avsharedmemory.h b/interfaces/inner_api/native/avsharedmemory.h index cb1131123..f37b33479 100644 --- a/interfaces/inner_api/native/avsharedmemory.h +++ b/interfaces/inner_api/native/avsharedmemory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/interfaces/inner_api/native/format.h b/interfaces/inner_api/native/format.h index d5fd97d0e..4f8e9eb1d 100644 --- a/interfaces/inner_api/native/format.h +++ b/interfaces/inner_api/native/format.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Huawei Device Co., Ltd. + * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -68,7 +68,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value, which is a 32-bit integer. * @return Returns true if the setting is successful; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutIntValue(const std::string_view &key, int32_t value); @@ -79,7 +79,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value, which is a 64-bit integer. * @return Returns true if the setting is successful; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutLongValue(const std::string_view &key, int64_t value); @@ -90,7 +90,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value, which is a single-precision floating-point number. * @return Returns true if the metadata is successfully set; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutFloatValue(const std::string_view &key, float value); @@ -101,7 +101,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value, which is a double-precision floating-point number. * @return Returns true if the setting is successful; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutDoubleValue(const std::string_view &key, double value); @@ -112,7 +112,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value, which is a string. * @return Returns true if the metadata is successfully set; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutStringValue(const std::string_view &key, const std::string_view &value); @@ -124,7 +124,7 @@ public: * @param addr Indicates the metadata addr, which is a uint8_t *. * @param size Indicates the metadata addr size, which is a size_t. * @return Returns true if the metadata is successfully set; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size); @@ -135,7 +135,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value to obtain, which is a 32-bit integer. * @return Returns true if the integer is successfully obtained; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetIntValue(const std::string_view &key, int32_t &value) const; @@ -146,7 +146,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value to obtain, which is a 64-bit long integer. * @return Returns true if the integer is successfully obtained; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetLongValue(const std::string_view &key, int64_t &value) const; @@ -158,7 +158,7 @@ public: * @param value Indicates the metadata value to obtain, which is a single-precision floating-point number. * @return Returns true if the single-precision number is successfully obtained; returns * false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetFloatValue(const std::string_view &key, float &value) const; @@ -170,7 +170,7 @@ public: * @param value Indicates the metadata value to obtain, which is a double-precision floating-point number. * @return Returns true if the double-precision number is successfully obtained; returns * false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetDoubleValue(const std::string_view &key, double &value) const; @@ -181,7 +181,7 @@ public: * @param key Indicates the metadata key. * @param value Indicates the metadata value to obtain, which is a string. * @return Returns true if the string is successfully obtained; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetStringValue(const std::string_view &key, std::string &value) const; @@ -193,7 +193,7 @@ public: * @param addr Indicates the metadata addr to obtain, which is a uint8_t **. * @param size Indicates the metadata addr size to obtain, which is a size_t. * @return Returns true if the string is successfully obtained; returns false otherwise. - * @since 1.0 + * @since 10 * @version 1.0 */ bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) const; @@ -233,7 +233,7 @@ public: * @brief Obtains the metadata map. * * @return Returns the map object. - * @since 1.0 + * @since 10 * @version 1.0 */ const FormatDataMap &GetFormatMap() const; @@ -242,7 +242,7 @@ public: * @brief Convert the metadata map to string. * * @return Returns a converted string. - * @since 1.0 + * @since 10 * @version 1.0 */ std::string Stringify() const; diff --git a/interfaces/inner_api/native/media_description.h b/interfaces/inner_api/native/media_description.h new file mode 100644 index 000000000..757c410d9 --- /dev/null +++ b/interfaces/inner_api/native/media_description.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEDIA_DESCRIPTION_H +#define MEDIA_DESCRIPTION_H + +#include "format.h" + +namespace OHOS { +namespace Media { +/** + * @brief Provides the uniform container for storing the media description. + */ +using MediaDescription = Format; + +/** + * @brief Provides the key's definition for MediaDescription. + */ +class MediaDescriptionKey { +public: + /** + * Key for track index, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_TRACK_INDEX = "track_index"; + + /** + * Key for track type, value type is uint8_t, see {link @MediaTrackType} + */ + static constexpr std::string_view MD_KEY_TRACK_TYPE = "track_type"; + + /** + * Key for codec mime type, value type is string + */ + static constexpr std::string_view MD_KEY_CODEC_MIME = "codec_mime"; + + /** + * Key for duration, value type is int64_t + */ + static constexpr std::string_view MD_KEY_DURATION = "duration"; + + /** + * Key for bitrate, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_BITRATE = "bitrate"; + + /** + * Key for max input size, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_MAX_INPUT_SIZE = "max_input_size"; + + /** + * Key for video width, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_WIDTH = "width"; + + /** + * Key for video height, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_HEIGHT = "height"; + + /** + * Key for video pixelformat, value type is int32_t, see {link @MediaPixelFormat} + */ + static constexpr std::string_view MD_KEY_PIXEL_FORMAT = "pixel_format"; + + /** + * Key for video frame rate, value type is double. + */ + static constexpr std::string_view MD_KEY_FRAME_RATE = "frame_rate"; + + /** + * Key for video capture rate, value type is double + */ + static constexpr std::string_view MD_KEY_CAPTURE_RATE = "capture_rate"; + + /** + * Key for the interval of key frame. value type is int32_t, the unit is milliseconds. + * A negative value means no key frames are requested after the first frame. A zero + * value means a stream containing all key frames is requested. + */ + static constexpr std::string_view MD_KEY_I_FRAME_INTERVAL = "i_frame_interval"; + + /** + * Key for the request a I-Frame immediately. value type is boolean + */ + static constexpr std::string_view MD_KEY_REQUEST_I_FRAME = "req_i_frame"; + + /** + * Key for audio channel count, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_CHANNEL_COUNT = "channel_count"; + + /** + * Key for audio sample rate, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_SAMPLE_RATE = "sample_rate"; + + /** + * Key for track count in the container, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_TRACK_COUNT = "track_count"; + + /** + * Key for container format type, value type is string + */ + static constexpr std::string_view MD_KEY_CONTAINER_FORMAT = "container_format"; + + /** + * custom key prefix, media service will pass through to HAL. + */ + static constexpr std::string_view MD_KEY_CUSTOM_PREFIX = "vendor.custom"; + + /** + * Key for codec specific data buffer, vlaue type is uint8_t* + */ + static constexpr std::string_view MD_KEY_CODEC_CONFIG = "codec_config"; + +private: + MediaDescriptionKey() = delete; + ~MediaDescriptionKey() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // MEDIA_DESCRIPTION_H diff --git a/interfaces/kits/c/BUILD.gn b/interfaces/kits/c/BUILD.gn index bac01cc63..173221d1b 100644 --- a/interfaces/kits/c/BUILD.gn +++ b/interfaces/kits/c/BUILD.gn @@ -206,6 +206,9 @@ ohos_shared_library("native_av_codec_codec") { ohos_shared_library("native_av_codec_avmuxer") { install_enable = true sources = [ + "$AV_CODEC_ROOT_DIR/frameworks/native/capi/avcodec/native_avcodec_base.cpp", + "$AV_CODEC_ROOT_DIR/frameworks/native/capi/common/native_avformat.cpp", + "$AV_CODEC_ROOT_DIR/frameworks/native/capi/common/native_avmemory.cpp", "$AV_CODEC_ROOT_DIR/frameworks/native/capi/avmuxer/native_avmuxer.cpp", ] @@ -214,14 +217,11 @@ ohos_shared_library("native_av_codec_avmuxer") { deps = [ "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", "//foundation/multimedia/av_codec/services/utils:av_codec_format", - "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_core", ] external_deps = [ "c_utils:utils", - "graphic_standard:surface", "hiviewdfx_hilog_native:libhilog", - "graphic_standard:surface", ] output_extension = "so" subsystem_name = "multimedia" diff --git a/interfaces/kits/c/avmuxer/BUILD.gn b/interfaces/kits/c/avmuxer/BUILD.gn index c8c0af87f..175dd423c 100644 --- a/interfaces/kits/c/avmuxer/BUILD.gn +++ b/interfaces/kits/c/avmuxer/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (C) 2022 Huawei Device Co., Ltd. +# Copyright (C) 2023 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -20,6 +20,7 @@ ohos_ndk_headers("native_av_codec_avmuxer_header") { "//foundation/multimedia/av_codec/interfaces/kits/c/native_avbase.h", "//foundation/multimedia/av_codec/interfaces/kits/c/native_averrors.h", "//foundation/multimedia/av_codec/interfaces/kits/c/native_avformat.h", + "//foundation/multimedia/av_codec/interfaces/kits/c/native_avmemory.h", "//foundation/multimedia/av_codec/interfaces/kits/c/native_avmuxer.h", ] } @@ -35,6 +36,7 @@ ohos_ndk_library("libnative_av_codec_avmuxer") { "native_av_codec_avmuxer/native_avbase.h", "native_av_codec_avmuxer/native_averrors.h", "native_av_codec_avmuxer/native_avformat.h", + "native_av_codec_avmuxer/native_avmemory.h", "native_av_codec_avmuxer/native_avmuxer.h", ] } diff --git a/interfaces/kits/c/avmuxer/libnative_av_codec_avmuxer.ndk.json b/interfaces/kits/c/avmuxer/libnative_av_codec_avmuxer.ndk.json index 365428b41..4501a7a54 100644 --- a/interfaces/kits/c/avmuxer/libnative_av_codec_avmuxer.ndk.json +++ b/interfaces/kits/c/avmuxer/libnative_av_codec_avmuxer.ndk.json @@ -15,6 +15,8 @@ { "name": "OH_AVFormat_GetStringValue" }, { "name": "OH_AVFormat_GetBuffer" }, { "name": "OH_AVFormat_DumpInfo" }, + { "name": "OH_AVMemory_GetAddr" }, + { "name": "OH_AVMemory_GetSize" }, { "name": "OH_AVMuxer_Create" }, { "name": "OH_AVMuxer_SetLocation" }, { "name": "OH_AVMuxer_SetRotation" }, diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h index eaef3581d..b59cceaf2 100644 --- a/interfaces/kits/c/native_avcodec_base.h +++ b/interfaces/kits/c/native_avcodec_base.h @@ -47,6 +47,18 @@ typedef enum OH_AVCodecBufferFlags { AVCODEC_BUFFER_FLAGS_CODEC_DATA = 1 << 3, } OH_AVCodecBufferFlags; +/** + * @brief Enumerates the muxer ouputfile format + * + * @since 10 + * @version 1.0 + */ +typedef enum OH_AVOutputFormat { + AV_OUTPUT_FORMAT_UNKNOWN = 0, + AV_OUTPUT_FORMAT_MPEG_4 = 1, + AV_OUTPUT_FORMAT_M4A = 2, +} OH_AVOutputFormat; + /** * @brief Define the Buffer description information of OH_AVCodec * @syscap SystemCapability.Multimedia.Media.CodecBase @@ -64,18 +76,6 @@ typedef struct OH_AVCodecBufferAttr { uint32_t flags; } OH_AVCodecBufferAttr; -/** - * @brief Enumerates the muxer ouputfile format - * - * @since 10 - * @version 1.0 - */ -typedef enum OH_AVOutputFormat { - AV_OUTPUT_FORMAT_UNKNOWN = 0, - AV_OUTPUT_FORMAT_MPEG_4 = 1, - AV_OUTPUT_FORMAT_M4A = 2, -} OH_AVOutputFormat; - /** * @brief When an error occurs in the running of the OH_AVCodec instance, the function pointer will be called * to report specific error information. @@ -157,7 +157,12 @@ typedef struct OH_AVCodecAsyncCallback { * @version 1.0 */ extern const char *OH_AVCODEC_MIMETYPE_VIDEO_AVC; +extern const char *OH_AVCODEC_MIMETYPE_VIDEO_MPEG4; extern const char *OH_AVCODEC_MIMETYPE_AUDIO_AAC; +extern const char *OH_AVCODEC_MIMETYPE_AUDIO_MPEG; +extern const char *OH_AVCODEC_MIMETYPE_IMAGE_JPG; +extern const char *OH_AVCODEC_MIMETYPE_IMAGE_PNG; +extern const char *OH_AVCODEC_MIMETYPE_IMAGE_BMP; /** * @brief The extra data's key of surface Buffer @@ -208,6 +213,8 @@ extern const char *OH_MD_KEY_AUD_SAMPLE_RATE; extern const char *OH_MD_KEY_I_FRAME_INTERVAL; /* Key of the surface rotation angle. value type is int32_t: should be {0, 90, 180, 270}, default is 0. */ extern const char *OH_MD_KEY_ROTATION; +/* Key of the codec specific data. value type is uint8_t*. */ +extern const char *OH_MD_KEY_CODEC_CONFIG; /** * @brief Media type. diff --git a/interfaces/kits/c/native_averrors.h b/interfaces/kits/c/native_averrors.h index e49b84014..0e64d6e90 100644 --- a/interfaces/kits/c/native_averrors.h +++ b/interfaces/kits/c/native_averrors.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Huawei Device Co., Ltd. + * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -21,8 +21,8 @@ extern "C" { /** * @brief AV error code - * @syscap SystemCapability.Multimedia.Media.Core - * @since 9 + * @syscap SystemCapability.Multimedia.Media.AVCodec + * @since 10 * @version 1.0 */ typedef enum OH_AVErrCode { diff --git a/interfaces/kits/c/native_avformat.h b/interfaces/kits/c/native_avformat.h index 47f90b5dc..79c1ac3fe 100644 --- a/interfaces/kits/c/native_avformat.h +++ b/interfaces/kits/c/native_avformat.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Huawei Device Co., Ltd. + * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -26,219 +26,190 @@ extern "C" { typedef struct OH_AVFormat OH_AVFormat; -/** - * @brief Enumerates AVPixel Format. - * @syscap SystemCapability.Multimedia.Media.Core - * @since 9 - * @version 1.0 - */ -typedef enum OH_AVPixelFormat { - /** - * yuv 420 planar. - */ - AV_PIXEL_FORMAT_YUVI420 = 1, - /** - * NV12. yuv 420 semiplanar. - */ - AV_PIXEL_FORMAT_NV12 = 2, - /** - * NV21. yvu 420 semiplanar. - */ - AV_PIXEL_FORMAT_NV21 = 3, - /** - * format from surface. - */ - AV_PIXEL_FORMAT_SURFACE_FORMAT = 4, - /** - * RGBA8888 - */ - AV_PIXEL_FORMAT_RGBA = 5, -} OH_AVPixelFormat; - /** * @briefCreate an OH_AVFormat handle pointer to read and write data - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @return Returns a pointer to an OH_AVFormat instance - * @since 9 + * @since 10 * @version 1.0 */ struct OH_AVFormat *OH_AVFormat_Create(void); /** * @brief Destroy the specified OH_AVFormat handle resource - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @return void - * @since 9 + * @since 10 * @version 1.0 */ void OH_AVFormat_Destroy(struct OH_AVFormat *format); /** * @brief Copy OH_AVFormat handle resource - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param to OH_AVFormat handle pointer to receive data * @param from pointer to the OH_AVFormat handle of the copied data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from); /** * @brief Write Int data to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param value written data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetIntValue(struct OH_AVFormat *format, const char *key, int32_t value); /** * @brief Write Long data to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param value written data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetLongValue(struct OH_AVFormat *format, const char *key, int64_t value); /** * @brief Write Float data to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param value written data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetFloatValue(struct OH_AVFormat *format, const char *key, float value); /** * @brief Write Double data to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param value written data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetDoubleValue(struct OH_AVFormat *format, const char *key, double value); /** * @brief Write String data to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param value written data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetStringValue(struct OH_AVFormat *format, const char *key, const char *value); /** * @brief Writes a block of data of a specified length to OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key key to write data * @param addr written data addr * @param size written data length * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_SetBuffer(struct OH_AVFormat *format, const char *key, const uint8_t *addr, size_t size); /** * @brief Read Int data from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key read key value * @param out read data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetIntValue(struct OH_AVFormat *format, const char *key, int32_t *out); /** * @brief Read Long data from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key read key value * @param out read data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetLongValue(struct OH_AVFormat *format, const char *key, int64_t *out); /** * @brief Read Float data from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key read key value * @param out read data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetFloatValue(struct OH_AVFormat *format, const char *key, float *out); /** * @brief Read Double data from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key read key value * @param out read data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetDoubleValue(struct OH_AVFormat *format, const char *key, double *out); /** * @brief Read Double data from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key read key value * @param out The read string pointer, the data life cycle pointed to is updated with GetString, * and Format is destroyed. If the caller needs to hold it for a long time, it must copy the memory * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetStringValue(struct OH_AVFormat *format, const char *key, const char **out); /** * @brief Read a block of data of specified length from OH_AVFormat - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @param key Key value for reading and writing data * @param addr The life cycle is held by the format, with the destruction of the format, * if the caller needs to hold it for a long time, it must copy the memory * @param size Length of read and write data * @return The return value is TRUE for success, FALSE for failure - * @since 9 + * @since 10 * @version 1.0 */ bool OH_AVFormat_GetBuffer(struct OH_AVFormat *format, const char *key, uint8_t **addr, size_t *size); /** * @brief Output the information contained in OH_AVFormat as a string. - * @syscap SystemCapability.Multimedia.Media.Core + * @syscap SystemCapability.Multimedia.Media.AVCodec * @param format pointer to an OH_AVFormat instance * @return Returns a string consisting of key and data - * @since 9 + * @since 10 * @version 1.0 */ const char *OH_AVFormat_DumpInfo(struct OH_AVFormat *format); diff --git a/interfaces/kits/c/native_avmemory.h b/interfaces/kits/c/native_avmemory.h index 0f536341d..d2504bb3e 100644 --- a/interfaces/kits/c/native_avmemory.h +++ b/interfaces/kits/c/native_avmemory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Huawei Device Co., Ltd. + * Copyright (C) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -29,7 +29,7 @@ typedef struct OH_AVMemory OH_AVMemory; * @syscap SystemCapability.Multimedia.Media.Core * @param mem Encapsulate OH_AVMemory structure instance pointer * @return the memory's virtual address if the memory is valid, otherwise nullptr. - * @since 9 + * @since 10 * @version 1.0 */ uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem); @@ -39,7 +39,7 @@ uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem); * @syscap SystemCapability.Multimedia.Media.Core * @param mem Encapsulate OH_AVMemory structure instance pointer * @return the memory's size if the memory is valid, otherwise -1. - * @since 9 + * @since 10 * @version 1.0 */ int32_t OH_AVMemory_GetSize(struct OH_AVMemory *mem); diff --git a/interfaces/kits/c/native_avmuxer.h b/interfaces/kits/c/native_avmuxer.h index d1e21a8f2..4836c6dc4 100644 --- a/interfaces/kits/c/native_avmuxer.h +++ b/interfaces/kits/c/native_avmuxer.h @@ -74,15 +74,16 @@ OH_AVErrCode OH_AVMuxer_SetRotation(OH_AVMuxer *muxer, int32_t rotation); * Note: This interface can only be called before OH_AVMuxer_Start. * @syscap SystemCapability.Multimedia.Media.AVMuxer * @param muxer Pointer to an OH_AVMuxer instance - * @param trackIndex The uint32_t handle pointer used to get the track index for this newly added track, - * and it should be used in the OH_AVMuxer_WriteSampleBuffer. The track index is greater than or equal to 0. + * @param trackIndex The int32_t handle pointer used to get the track index for this newly added track, + * and it should be used in the OH_AVMuxer_WriteSampleBuffer. The track index is greater than or equal to 0, + * others is error index. * @param trackFormat OH_AVFormat handle pointer contain track format * @return Returns AV_ERR_OK if the execution is successful, * otherwise returns a specific error code, refer to {@link OH_AVErrCode} * @since 10 * @version 1.0 */ -OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, uint32_t *trackIndex, OH_AVFormat *trackFormat); +OH_AVErrCode OH_AVMuxer_AddTrack(OH_AVMuxer *muxer, int32_t *trackIndex, OH_AVFormat *trackFormat); /** * @brief Start the muxer. diff --git a/services/BUILD.gn b/services/BUILD.gn index 40b287893..bd79aaaa7 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -16,8 +16,6 @@ import("//build/ohos.gni") group("av_codec_services_package") { deps = [ "etc:av_codec_service.cfg", - "engine:av_codec_engine_package", "services:av_codec_service", ] } - diff --git a/services/engine/BUILD.gn b/services/engine/BUILD.gn index d6f71528b..5af4f2b1a 100644 --- a/services/engine/BUILD.gn +++ b/services/engine/BUILD.gn @@ -16,7 +16,7 @@ import("//foundation/multimedia/av_codec/config.gni") group("av_codec_engine_package") { deps = [ - "plugin:av_codec_engine_plugins", + "plugin:av_codec_plugin", #"avcodeclist:av_codec_engine_avcodeclist", ] } diff --git a/services/engine/muxer/muxer_engine_impl.cpp b/services/engine/muxer/muxer_engine_impl.cpp new file mode 100644 index 000000000..769683ff9 --- /dev/null +++ b/services/engine/muxer/muxer_engine_impl.cpp @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer_engine_impl.h" +#include +#include +#include +#include "securec.h" +#include "avcodec_log.h" +#include "muxer_factory.h" +#include "avcodec_dfx.h" +#include "avcodec_info.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerEngineImpl"}; + constexpr int32_t MAX_LATITUDE = 90; + constexpr int32_t MIN_LATITUDE = -90; + constexpr int32_t MAX_LONGITUDE = 180; + constexpr int32_t MIN_LONGITUDE = -180; + constexpr int32_t ERR_TRACK_INDEX = -1; +} + +namespace OHOS { +namespace Media { +const std::map> MUX_FORMAT_INFO = { + {OUTPUT_FORMAT_MPEG_4, {CodecMimeType::AUDIO_MPEG, CodecMimeType::AUDIO_AAC, + CodecMimeType::VIDEO_AVC, CodecMimeType::VIDEO_MPEG4, + CodecMimeType::IMAGE_JPG, CodecMimeType::IMAGE_PNG, CodecMimeType::IMAGE_BMP}}, + {OUTPUT_FORMAT_M4A, {CodecMimeType::AUDIO_AAC, + CodecMimeType::VIDEO_AVC, CodecMimeType::VIDEO_MPEG4, + CodecMimeType::IMAGE_JPG, CodecMimeType::IMAGE_PNG, CodecMimeType::IMAGE_BMP}}, +}; + +const std::map> MUX_MIME_INFO = { + {CodecMimeType::AUDIO_MPEG, {MediaDescriptionKey::MD_KEY_SAMPLE_RATE, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}}, + {CodecMimeType::AUDIO_AAC, {MediaDescriptionKey::MD_KEY_SAMPLE_RATE, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}}, + {CodecMimeType::VIDEO_AVC, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}}, + {CodecMimeType::VIDEO_MPEG4, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}}, + {CodecMimeType::IMAGE_JPG, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}}, + {CodecMimeType::IMAGE_PNG, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}}, + {CodecMimeType::IMAGE_BMP, {MediaDescriptionKey::MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_HEIGHT}}, +}; + +std::shared_ptr IMuxerEngineFactory::CreateMuxerEngine(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format) +{ + AVCodecTrace trace("IMuxerEngineFactory::CreateMuxerEngine"); + CHECK_AND_RETURN_RET_LOG((fcntl(fd, F_GETFL, 0) & O_RDWR) == O_RDWR, nullptr, "no permission to read and write fd"); + CHECK_AND_RETURN_RET_LOG(lseek(fd, 0, SEEK_CUR) != -1, nullptr, "the fd is not seekable"); + std::shared_ptr muxerEngineImpl = std::make_shared(appUid, appPid, fd, format); + CHECK_AND_RETURN_RET_LOG(muxerEngineImpl != nullptr, nullptr, "create MuxerEngine implementation failed"); + return muxerEngineImpl; +} + +MuxerEngineImpl::MuxerEngineImpl(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format) + : appUid_(appUid), appPid_(appPid), fd_(fd), format_(format), que_("muxer_write_queue") +{ + AVCodecTrace trace("MuxerEngine::Create"); + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + muxer_ = Plugin::MuxerFactory::Instance().CreatePlugin(fd_, format_); + if (muxer_ != nullptr && fd_ >= 0) { + state_ = INITIALIZED; + AVCODEC_LOGI("state_ is INITIALIZED"); + } else { + AVCODEC_LOGE("state_ is UNINITIALIZED"); + } +} + +MuxerEngineImpl::~MuxerEngineImpl() +{ + AVCODEC_LOGD("Destroy"); + + if (state_ == STARTED) { + que_.SetActive(false); + StopThread(); + } + + appUid_ = -1; + appPid_ = -1; + muxer_ = nullptr; + tracks_.clear(); + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t MuxerEngineImpl::SetLocation(float latitude, float longitude) +{ + AVCodecTrace trace("MuxerEngine::SetLocation"); + AVCODEC_LOGI("SetLocation"); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION, + "The state is not INITIALIZED, the interface must be called after constructor and before Start(). " + "The current state is %{public}s", ConvertStateToString(state_).c_str()); + if (latitude < MIN_LATITUDE || latitude > MAX_LATITUDE || + longitude < MIN_LONGITUDE || longitude > MAX_LONGITUDE) { + AVCODEC_LOGW("Invalid GeoLocation, latitude must be greater than %{public}d and less than %{public}d," + "longitude must be greater than %{public}d and less than %{public}d", + MIN_LATITUDE, MAX_LATITUDE, MIN_LONGITUDE, MAX_LONGITUDE); + return AVCS_ERR_INVALID_VAL; + } + + return TranslatePluginStatus(muxer_->SetLocation(latitude, longitude)); +} + +int32_t MuxerEngineImpl::SetRotation(int32_t rotation) +{ + AVCodecTrace trace("MuxerEngine::SetRotation"); + AVCODEC_LOGI("SetRotation"); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION, + "The state is not INITIALIZED, the interface must be called after constructor and before Start(). " + "The current state is %{public}s", ConvertStateToString(state_).c_str()); + if (rotation != VIDEO_ROTATION_0 && rotation != VIDEO_ROTATION_90 && + rotation != VIDEO_ROTATION_180 && rotation != VIDEO_ROTATION_270) { + AVCODEC_LOGW("Invalid rotation: %{public}d, keep default 0", rotation); + return AVCS_ERR_INVALID_VAL; + } + + return TranslatePluginStatus(muxer_->SetRotation(rotation)); +} + +int32_t MuxerEngineImpl::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + AVCodecTrace trace("MuxerEngine::AddTrack"); + AVCODEC_LOGI("AddTrack"); + std::unique_lock lock(mutex_); + trackIndex = ERR_TRACK_INDEX; + CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION, + "The state is not INITIALIZED, the interface must be called after constructor and before Start(). " + "The current state is %{public}s", ConvertStateToString(state_).c_str()); + std::string mimeType = {}; + CHECK_AND_RETURN_RET_LOG(trackDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, mimeType), + AVCS_ERR_INVALID_VAL, "track format does not contain mime"); + CHECK_AND_RETURN_RET_LOG(CanAddTrack(mimeType), AVCS_ERR_UNSUPPORT_CONTAINER_TYPE, + "track mime is unsupported: %{public}s", mimeType.c_str()); + CHECK_AND_RETURN_RET_LOG(CheckKeys(mimeType, trackDesc), AVCS_ERR_INVALID_VAL, + "track format keys not contained"); + + int32_t trackId = -1; + Plugin::Status ret = muxer_->AddTrack(trackId, trackDesc); + CHECK_AND_RETURN_RET_LOG(ret == Plugin::Status::NO_ERROR, TranslatePluginStatus(ret), "AddTrack failed"); + CHECK_AND_RETURN_RET_LOG(trackId >= 0, AVCS_ERR_INVALID_OPERATION, + "The track index is greater than or equal to 0, less than 99"); + trackIndex = trackId; + tracks_[trackIndex] = mimeType; + + return AVCS_ERR_OK; +} + +int32_t MuxerEngineImpl::Start() +{ + AVCodecTrace trace("MuxerEngine::Start"); + AVCODEC_LOGI("Start"); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(state_ == INITIALIZED, AVCS_ERR_INVALID_OPERATION, + "The state is not INITIALIZED, the interface must be called after AddTrack() and before WriteSampleBuffer(). " + "The current state is %{public}s", ConvertStateToString(state_).c_str()); + CHECK_AND_RETURN_RET_LOG(tracks_.size() > 0, AVCS_ERR_INVALID_OPERATION, + "The track count is error, count is %{public}d", tracks_.size()); + Plugin::Status ret = muxer_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == Plugin::Status::NO_ERROR, TranslatePluginStatus(ret), "Start failed"); + state_ = STARTED; + StartThread("muxer_write_loop"); + return AVCS_ERR_OK; +} + +int32_t MuxerEngineImpl::WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) +{ + AVCodecTrace trace("MuxerEngine::WriteSampleBuffer"); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(state_ == STARTED, AVCS_ERR_INVALID_OPERATION, + "The state is not STARTED, the interface must be called after Start() and before Stop(). " + "The current state is %{public}s", ConvertStateToString(state_).c_str()); + CHECK_AND_RETURN_RET_LOG(tracks_.find(info.trackIndex) != tracks_.end(), AVCS_ERR_INVALID_VAL, + "The track index does not exist"); + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr && info.timeUs >= 0, AVCS_ERR_INVALID_VAL, "Invalid memory"); + + std::shared_ptr blockBuffer = std::make_shared(); + blockBuffer->buffer_ = sampleBuffer; + blockBuffer->info_ = info; + que_.Push(blockBuffer); + + return AVCS_ERR_OK; +} + +int32_t MuxerEngineImpl::Stop() +{ + AVCodecTrace trace("MuxerEngine::Stop"); + AVCODEC_LOGI("Stop"); + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_RET_LOG(state_ == STARTED, AVCS_ERR_INVALID_OPERATION, + "The state is not STARTED. The current state is %{public}s", ConvertStateToString(state_).c_str()); + state_ = STOPPED; + que_.SetActive(false, false); + cond_.wait(lock, [this] { return que_.Empty(); }); + StopThread(); + return TranslatePluginStatus(muxer_->Stop()); +} + +int32_t MuxerEngineImpl::DumpInfo(int32_t fd) +{ + std::string dumpString; + dumpString += "In MuxerEngine::DumpInfo\n"; + dumpString += "Current MuxerEngine state is: " + ConvertStateToString(state_) + "\n"; + dumpString += "Current MuxerEngine output format is: " + std::to_string(format_) + "\n"; + write(fd, dumpString.c_str(), dumpString.size()); + + return AVCS_ERR_OK; +} + +int32_t MuxerEngineImpl::StartThread(std::string name) +{ + threadName_ = name; + if (thread_ != nullptr) { + AVCODEC_LOGW("Started already! [%{public}s]", threadName_.c_str()); + return AVCS_ERR_OK; + } + isThreadExit_ = false; + thread_ = std::make_unique(&MuxerEngineImpl::ThreadProcessor, this); + AVCodecTrace::TraceBegin("muxer_write_thread", FAKE_POINTER(thread_.get())); + AVCODEC_LOGD("thread started! [%{public}s]", threadName_.c_str()); + return AVCS_ERR_OK; +} + +int32_t MuxerEngineImpl::StopThread() noexcept +{ + if (isThreadExit_) { + AVCODEC_LOGD("Stopped already! [%{public}s]", threadName_.c_str()); + return AVCS_ERR_OK; + } + if (std::this_thread::get_id() == thread_->get_id()) { + AVCODEC_LOGD("Stop at the task thread, reject"); + return AVCS_ERR_INVALID_OPERATION; + } + + std::unique_ptr t; + isThreadExit_ = true; + cond_.notify_all(); + std::swap(thread_, t); + if (t != nullptr && t->joinable()) { + t->join(); + } + thread_ = nullptr; + return AVCS_ERR_OK; +} + +void MuxerEngineImpl::ThreadProcessor() +{ + AVCODEC_LOGD("Enter ThreadProcessor [%{public}s]", threadName_.c_str()); + constexpr uint32_t nameSizeMax = 15; + pthread_setname_np(pthread_self(), threadName_.substr(0, nameSizeMax).c_str()); + int32_t taskId = FAKE_POINTER(thread_.get()); + for (;;) { + AVCodecTrace trace(threadName_); + if (isThreadExit_) { + AVCodecTrace::TraceEnd("muxer_write_thread", taskId); + AVCODEC_LOGD("Exit ThreadProcessor [%{public}s]", threadName_.c_str()); + return; + } + auto buffer = que_.Pop(); + if (buffer != nullptr) { + (void)muxer_->WriteSampleBuffer(buffer->buffer_->GetBase(), buffer->info_); + } + if (que_.Empty()) { + cond_.notify_all(); + } + } +} + +bool MuxerEngineImpl::CanAddTrack(std::string &mimeType) +{ + auto it = MUX_FORMAT_INFO.find(format_); + if (it == MUX_FORMAT_INFO.end()) { + return false; + } + return it->second.find(mimeType) != it->second.end(); +} + +bool MuxerEngineImpl::CheckKeys(std::string &mimeType, const MediaDescription &trackDesc) +{ + bool ret = true; + auto it = MUX_MIME_INFO.find(mimeType); + if (it == MUX_MIME_INFO.end()) { + return ret; // 不做检查 + } + + for (auto &key : it->second) { + if(!trackDesc.ContainKey(key)) { + ret = false; + AVCODEC_LOGE("the MediaDescriptionKey %{public}s not contained", key.data()); + } + } + return ret; +} + +std::string MuxerEngineImpl::ConvertStateToString(int32_t state) +{ + std::string stateInfo {}; + switch (state) + { + case UNINITIALIZED: + stateInfo = "UNINITIALIZED"; + break; + case INITIALIZED: + stateInfo = "INITIALIZED"; + break; + case STARTED: + stateInfo = "STARTED"; + break; + case STOPPED: + stateInfo = "STOPPED"; + break; + default: + break; + } + return stateInfo; +} + +int32_t MuxerEngineImpl::TranslatePluginStatus(Plugin::Status error) +{ + const static std::map g_transTable = { + {Plugin::Status::END_OF_STREAM, AVCodecServiceErrCode::AVCS_ERR_OK}, + {Plugin::Status::OK, AVCodecServiceErrCode::AVCS_ERR_OK}, + {Plugin::Status::NO_ERROR, AVCodecServiceErrCode::AVCS_ERR_OK}, + {Plugin::Status::ERROR_UNKNOWN, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_PLUGIN_ALREADY_EXISTS, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_INCOMPATIBLE_VERSION, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_NO_MEMORY, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY}, + {Plugin::Status::ERROR_WRONG_STATE, AVCodecServiceErrCode::AVCS_ERR_INVALID_OPERATION}, + {Plugin::Status::ERROR_UNIMPLEMENTED, AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT}, + {Plugin::Status::ERROR_INVALID_PARAMETER, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL}, + {Plugin::Status::ERROR_INVALID_DATA, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL}, + {Plugin::Status::ERROR_MISMATCHED_TYPE, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL}, + {Plugin::Status::ERROR_TIMED_OUT, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_UNSUPPORTED_FORMAT, AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT_CONTAINER_TYPE}, + {Plugin::Status::ERROR_NOT_ENOUGH_DATA, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_NOT_EXISTED, AVCodecServiceErrCode::AVCS_ERR_OPEN_FILE_FAILED}, + {Plugin::Status::ERROR_AGAIN, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_PERMISSION_DENIED, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_NULL_POINTER, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL}, + {Plugin::Status::ERROR_INVALID_OPERATION, AVCodecServiceErrCode::AVCS_ERR_INVALID_OPERATION}, + {Plugin::Status::ERROR_CLIENT, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_SERVER, AVCodecServiceErrCode::AVCS_ERR_UNKNOWN}, + {Plugin::Status::ERROR_DELAY_READY, AVCodecServiceErrCode::AVCS_ERR_OK}, + }; + auto ite = g_transTable.find(error); + if (ite == g_transTable.end()) { + return AVCS_ERR_UNKNOWN; + } + return ite->second; +} +} // Media +} // OHOS diff --git a/services/engine/muxer/muxer_engine_impl.h b/services/engine/muxer/muxer_engine_impl.h new file mode 100644 index 000000000..c36966b67 --- /dev/null +++ b/services/engine/muxer/muxer_engine_impl.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MUXER_ENGINE_IMPL_H +#define MUXER_ENGINE_IMPL_H + +#include +#include +#include +#include +#include +#include "i_muxer_engine.h" +#include "muxer.h" +#include "block_queue.h" + +namespace OHOS { +namespace Media { +class MuxerEngineImpl : public IMuxerEngine { +public: + MuxerEngineImpl(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format); + ~MuxerEngineImpl() override; + int32_t SetLocation(float latitude, float longitude) override; + int32_t SetRotation(int32_t rotation) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; + int32_t Start() override; + int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) override; + int32_t Stop() override; + int32_t DumpInfo(int32_t fd) override; + +private: + int32_t StartThread(std::string name); + int32_t StopThread() noexcept; + void ThreadProcessor(); + bool CanAddTrack(std::string &mimeType); + bool CheckKeys(std::string &mimeType, const MediaDescription &trackDesc); + std::string ConvertStateToString(int32_t state); + int32_t TranslatePluginStatus(Plugin::Status error); + +private: + enum State { + UNINITIALIZED, + INITIALIZED, + STARTED, + STOPPED + }; + struct BlockBuffer { + std::shared_ptr buffer_; + TrackSampleInfo info_; + }; + + int32_t appUid_ = -1; + int32_t appPid_ = -1; + int64_t fd_ = -1; + OutputFormat format_; + std::atomic state_ = UNINITIALIZED; + std::shared_ptr muxer_ = nullptr; + std::map tracks_; + BlockQueue> que_; + std::string threadName_; + std::mutex mutex_; + std::condition_variable cond_; + std::unique_ptr thread_ = nullptr; + bool isThreadExit_ = true; +}; +} // namespace Media +} // namespace OHOS +#endif // MUXER_ENGINE_IMPL_H \ No newline at end of file diff --git a/services/engine/plugin/BUILD.gn b/services/engine/plugin/BUILD.gn index 68e7634fe..f2010ead4 100644 --- a/services/engine/plugin/BUILD.gn +++ b/services/engine/plugin/BUILD.gn @@ -10,15 +10,35 @@ # 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. +# import("//build/ohos.gni") import("//foundation/multimedia/av_codec/config.gni") +config("plugin_presets") { + include_dirs = [ + "//foundation/multimedia/av_codec/interfaces/kits/c", + "//foundation/multimedia/av_codec/interfaces/inner_api/native", + "//foundation/multimedia/av_codec/services/dfx/include", + "//foundation/multimedia/av_codec/services/utils/include", + "//foundation/multimedia/av_codec/services/engine/plugin/core", + "//foundation/multimedia/av_codec/services/engine/plugin/interface", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] -group("av_codec_engine_plugins") { - deps = [] - if (multimedia_av_codec_support_demuxer) { - deps += [ - #"plugins/demuxer:av_codec_engine_demuxer", - ] - } + cflags = [ + "-O2", + "-fPIC", + "-Wall", + "-frtti", + "-fexceptions", + ] + cflags_cc = cflags } + +group("av_codec_plugin") { + deps = [ + "plugins:av_codec_plugin_store", + ] +} + diff --git a/services/engine/plugin/core/muxer.cpp b/services/engine/plugin/core/muxer.cpp new file mode 100644 index 000000000..da8d162eb --- /dev/null +++ b/services/engine/plugin/core/muxer.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +Muxer::Muxer (uint32_t pkgVer, uint32_t apiVer, std::shared_ptr plugin) + : pkgVersion_(pkgVer), apiVersion_(apiVer), muxer_(std::move(plugin)) {} + +Status Muxer::SetLocation(float latitude, float longitude) +{ + return muxer_->SetLocation(latitude, longitude); +} + +Status Muxer::SetRotation(int32_t rotation) +{ + return muxer_->SetRotation(rotation); +} + +Status Muxer::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + return muxer_->AddTrack(trackIndex, trackDesc); +} + +Status Muxer::Start() +{ + return muxer_->Start(); +} + +Status Muxer::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) +{ + return muxer_->WriteSampleBuffer(sampleBuffer, info); +} + +Status Muxer::Stop() +{ + return muxer_->Stop(); +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/plugin/core/muxer.h b/services/engine/plugin/core/muxer.h new file mode 100644 index 000000000..7bc7b5c65 --- /dev/null +++ b/services/engine/plugin/core/muxer.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_CORE_MUXER_H +#define PLUGIN_CORE_MUXER_H + +#include "muxer_plugin.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +class Muxer { +public: + Muxer(const Muxer &) = delete; + Muxer operator=(const Muxer &) = delete; + ~Muxer() = default; + + Status SetLocation(float latitude, float longitude); + Status SetRotation(int32_t rotation); + Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc); + Status Start(); + Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info); + Status Stop(); + +private: + friend class MuxerFactory; + + Muxer(uint32_t pkgVer, uint32_t apiVer, std::shared_ptr plugin); + +private: + const uint32_t pkgVersion_; + const uint32_t apiVersion_; + std::shared_ptr muxer_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_CORE_MUXER_H diff --git a/services/engine/plugin/core/muxer_factory.cpp b/services/engine/plugin/core/muxer_factory.cpp new file mode 100644 index 000000000..e8a8a08e8 --- /dev/null +++ b/services/engine/plugin/core/muxer_factory.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer_factory.h" +#include +#include +#include +#include "muxer_plugin.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerFactory"}; +} + +namespace OHOS { +namespace Media { +namespace Plugin { +static std::string g_libFileHead = "libav_codec_plugin_"; +static std::string g_fileSeparator = "/"; +static std::string g_fileMark = "Muxer"; +static std::string g_libFileTail = AV_CODEC_PLUGIN_FILE_TAIL; + +MuxerFactory::MuxerFactory() +{ + RegisterPlugins(); +} + +MuxerFactory::~MuxerFactory() +{ + UnregisterAllPlugins(); +} + +std::shared_ptr MuxerFactory::CreatePlugin(int32_t fd, uint32_t outputFormat) +{ + AVCODEC_LOGD("CreatePlugin: fd %{public}d, outputFormat %{public}d", fd, outputFormat); + std::string pluginName; + int32_t maxProb = 0; + for (auto& name : registerData_->registerNames) { + std::shared_ptr regInfo = registerData_->registerTable[name]; + if (regInfo->pluginDef->pluginType == PluginType::MUXER) { + auto prob = regInfo->pluginDef->sniffer(name, outputFormat); + if (prob > maxProb) { + maxProb = prob; + pluginName = name; + } + } + } + AVCODEC_LOGD("maxProb %{public}d, pluginName %{public}s", maxProb, pluginName.c_str()); + if (!pluginName.empty()) { + std::shared_ptr regInfo = registerData_->registerTable[pluginName]; + auto plugin = regInfo->pluginDef->creator(pluginName, fd); + return std::shared_ptr( + new Muxer(regInfo->packageDef->pkgVersion, regInfo->pluginDef->apiVersion, plugin)); + } else { + AVCODEC_LOGE("No plugins matching output format - %{public}d", outputFormat); + } + return nullptr; +} + +void MuxerFactory::RegisterPlugins() +{ + RegisterDynamicPlugins(AV_CODEC_PLUGIN_PATH); +} + +void MuxerFactory::RegisterDynamicPlugins(const char* libDirPath) +{ + DIR* libDir = opendir(libDirPath); + if (libDir) { + struct dirent* lib = nullptr; + std::shared_ptr loader = nullptr; + while ((lib = readdir(libDir))) { + if (lib->d_name[0] == '.') { + continue; + } + std::string libName = lib->d_name; + AVCODEC_LOGD("libName %{public}s", libName.c_str()); + if (libName.find(g_libFileHead) || + libName.find(g_fileMark) == std::string::npos || + libName.compare(libName.size() - g_libFileTail.size(), g_libFileTail.size(), g_libFileTail)) { + continue; + } + std::string pluginName = + libName.substr(g_libFileHead.size(), libName.size() - g_libFileHead.size() - g_libFileTail.size()); + std::string libPath = libDirPath + g_fileSeparator + lib->d_name; + loader = PluginLoader::Create(pluginName, libPath); + if (loader) { + loader->FetchRegisterFunction()(std::make_shared(registerData_, loader)); + registeredLoaders_.push_back(loader); + } + } + closedir(libDir); + } +} + +void MuxerFactory::UnregisterAllPlugins() +{ + for (auto& loader : registeredLoaders_) { + loader->FetchUnregisterFunction()(); + loader.reset(); + } + registeredLoaders_.clear(); + registerData_->registerNames.clear(); + registerData_->registerTable.clear(); +} + +bool MuxerFactory::RegisterData::IsExist(const std::string& name) +{ + return registerTable.find(name) != registerTable.end(); +} + +Status MuxerFactory::RegisterImpl::AddPlugin(const PluginDefBase& def) +{ + CHECK_AND_RETURN_RET_LOG(Verification(def), Status::ERROR_INVALID_DATA, + "The plugin type is not muxer, or plugin rank < 0, or plugin rank > 100"); + CHECK_AND_RETURN_RET_LOG(VersionMatched(def), Status::ERROR_UNKNOWN, + "The plugin version is not matched"); + CHECK_AND_RETURN_RET_LOG(!registerData->IsExist(def.name), + Status::ERROR_PLUGIN_ALREADY_EXISTS, "The plugin already exists"); + + auto& pluginDef = (MuxerPluginDef&)(def); + std::shared_ptr regInfo = std::make_shared(); + regInfo->packageDef = packageDef; + regInfo->pluginDef = std::make_shared(pluginDef); + regInfo->loader = std::move(pluginLoader); + + registerData->registerTable[pluginDef.name] = regInfo; + registerData->registerNames.push_back(pluginDef.name); + return Status::NO_ERROR; +} + +Status MuxerFactory::RegisterImpl::AddPackage(const PackageDef& def) +{ + return SetPackageDef(def); +} + +Status MuxerFactory::RegisterImpl::SetPackageDef(const PackageDef& def) +{ + packageDef = std::make_shared(def); + return Status::NO_ERROR; +} + +bool MuxerFactory::RegisterImpl::Verification(const PluginDefBase& def) +{ + if (def.rank < 0 || def.rank > 100) { // 100 + return false; + } + return (def.pluginType == PluginType::MUXER); +} + +bool MuxerFactory::RegisterImpl::VersionMatched(const PluginDefBase& def) +{ + int major = (def.apiVersion >> 16) & 0xFFFF; // 16 + int minor = def.apiVersion & 0xFFFF; + uint32_t version = MUXER_API_VERSION; + int coreMajor = (version >> 16) & 0xFFFF; // 16 + int coreMinor = version & 0xFFFF; + return (major == coreMajor) && (minor <= coreMinor); +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/plugin/core/muxer_factory.h b/services/engine/plugin/core/muxer_factory.h new file mode 100644 index 000000000..297b9b58b --- /dev/null +++ b/services/engine/plugin/core/muxer_factory.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MUXER_FACTORY_H +#define MUXER_FACTORY_H + +#include "muxer.h" +#include "plugin_loader.h" +#include +#include + +namespace OHOS { +namespace Media { +namespace Plugin { +class MuxerFactory { +public: + MuxerFactory(const MuxerFactory&) = delete; + MuxerFactory operator=(const MuxerFactory&) = delete; + ~MuxerFactory(); + static MuxerFactory& Instance() + { + static MuxerFactory impl; + return impl; + } + + std::shared_ptr CreatePlugin(int32_t fd, uint32_t outputFormat); + +private: + MuxerFactory(); + + void RegisterPlugins(); + void RegisterDynamicPlugins(const char* libDirPath); + void UnregisterAllPlugins(); + +private: + struct PluginRegInfo { + std::shared_ptr packageDef; + std::shared_ptr pluginDef; + std::shared_ptr loader; + }; + struct RegisterData { + std::vector registerNames; + std::map> registerTable; + bool IsExist(const std::string& name); + }; + struct RegisterImpl : PackageRegister { + explicit RegisterImpl(std::shared_ptr data, std::shared_ptr loader = nullptr) + : pluginLoader(std::move(loader)), registerData(std::move(data)) {} + + ~RegisterImpl() override = default; + + Status AddPlugin(const PluginDefBase& def) override; + Status AddPackage(const PackageDef& def) override; + Status SetPackageDef(const PackageDef& def); + bool Verification(const PluginDefBase& def); + bool VersionMatched(const PluginDefBase& def); + + std::shared_ptr pluginLoader; + std::shared_ptr registerData; + std::shared_ptr packageDef {nullptr}; + }; + + std::shared_ptr registerData_ = std::make_shared(); + std::vector> registeredLoaders_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // MUXER_FACTORY_H diff --git a/services/engine/plugin/core/plugin_loader.cpp b/services/engine/plugin/core/plugin_loader.cpp new file mode 100644 index 000000000..9c498fb0a --- /dev/null +++ b/services/engine/plugin/core/plugin_loader.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "plugin_loader.h" +#include +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "PluginLoader"}; +} + +using namespace OHOS::Media::Plugin; + +// NOLINTNEXTLINE: void* +PluginLoader::PluginLoader(void* handler, std::string name) : handler_(handler), name_(std::move(name)) +{ +} + +PluginLoader::~PluginLoader() +{ + UnLoadPluginFile(); +} + +std::shared_ptr PluginLoader::Create(const std::string& name, const std::string& path) +{ + if (name.empty() || path.empty()) { + return {}; + } + return CheckSymbol(LoadPluginFile(path), name); +} + +RegisterFunc PluginLoader::FetchRegisterFunction() +{ + return registerFunc_; +} + +UnregisterFunc PluginLoader::FetchUnregisterFunction() +{ + return unregisterFunc_; +} + +void* PluginLoader::LoadPluginFile(const std::string& path) +{ + auto pathStr = path.c_str(); + if (pathStr) { + auto ptr = ::dlopen(pathStr, RTLD_NOW | RTLD_LOCAL); + if (ptr == nullptr) { + AVCODEC_LOGE("dlopen failed due to %{public}s", ::dlerror()); + } + return ptr; + } + return nullptr; +} + +std::shared_ptr PluginLoader::CheckSymbol(void* handler, const std::string& name) +{ + if (handler) { + std::string registerFuncName = "register_" + name; + std::string unregisterFuncName = "unregister_" + name; + RegisterFunc registerFunc = nullptr; + UnregisterFunc unregisterFunc = nullptr; + AVCODEC_LOGD("CheckSymbol: registerFuncName %{public}s", registerFuncName.c_str()); + AVCODEC_LOGD("CheckSymbol: unregisterFuncName %{public}s", unregisterFuncName.c_str()); + registerFunc = (RegisterFunc)(::dlsym(handler, registerFuncName.c_str())); + unregisterFunc = (UnregisterFunc)(::dlsym(handler, unregisterFuncName.c_str())); + if (registerFunc && unregisterFunc) { + std::shared_ptr loader(new PluginLoader(handler, name)); + loader->registerFunc_ = registerFunc; + loader->unregisterFunc_ = unregisterFunc; + return loader; + } + } + return {}; +} + +void PluginLoader::UnLoadPluginFile() +{ + if (handler_) { + ::dlclose(const_cast(handler_)); // NOLINT: const_cast + } +} diff --git a/services/engine/plugin/core/plugin_loader.h b/services/engine/plugin/core/plugin_loader.h new file mode 100644 index 000000000..eb7c94a5b --- /dev/null +++ b/services/engine/plugin/core/plugin_loader.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_CORE_PLUGIN_LOADER_H +#define PLUGIN_CORE_PLUGIN_LOADER_H + +#include "plugin_base.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +class PluginLoader { +public: + PluginLoader(const PluginLoader &) = delete; + + PluginLoader operator=(const PluginLoader &) = delete; + + ~PluginLoader(); + + static std::shared_ptr Create(const std::string &name, const std::string &path); + + RegisterFunc FetchRegisterFunction(); + + UnregisterFunc FetchUnregisterFunction(); + +private: + PluginLoader(void* handler, std::string name); // NOLINT: void* + + static void* LoadPluginFile(const std::string &path); + + static std::shared_ptr CheckSymbol(void* handler, const std::string &name); // NOLINT: void* + + void UnLoadPluginFile(); + +private: + const void *handler_; + const std::string name_; + RegisterFunc registerFunc_ {nullptr}; + UnregisterFunc unregisterFunc_ {nullptr}; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_CORE_PLUGIN_LOADER_H diff --git a/services/engine/plugin/interface/muxer_plugin.h b/services/engine/plugin/interface/muxer_plugin.h new file mode 100644 index 000000000..f3d0a95e5 --- /dev/null +++ b/services/engine/plugin/interface/muxer_plugin.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_INTF_MUXER_PLUGIN_H +#define PLUGIN_INTF_MUXER_PLUGIN_H + +#include "media_description.h" +#include "av_common.h" +#include "plugin_base.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { + +struct MuxerPlugin : public PluginBase { + explicit MuxerPlugin(std::string &&name) : PluginBase(std::move(name)) {} + virtual Status SetLocation(float latitude, float longitude) = 0; + virtual Status SetRotation(int32_t rotation) = 0; + virtual Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0; + virtual Status Start() = 0; + virtual Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) = 0; + virtual Status Stop() = 0; +}; + +/// Muxer plugin api major number. +#define MUXER_API_VERSION_MAJOR (1) + +/// Muxer plugin api minor number +#define MUXER_API_VERSION_MINOR (0) + +/// Muxer plugin version +#define MUXER_API_VERSION MAKE_VERSION(MUXER_API_VERSION_MAJOR, MUXER_API_VERSION_MINOR) + +/// Muxer create function +using MuxerPluginCreatorFunc = std::shared_ptr(*)(const std::string& name, int32_t fd); +/// Muxer sniff function +using MuxerPluginSnifferFunc = int32_t (*)(const std::string& name, uint32_t outputFormat); + +struct MuxerPluginDef : public PluginDefBase { + MuxerPluginCreatorFunc creator {nullptr}; ///< Muxer plugin create function. + MuxerPluginSnifferFunc sniffer {nullptr}; ///< Muxer plugin sniff function. + MuxerPluginDef() + { + apiVersion = MUXER_API_VERSION; ///< Muxer plugin version. + pluginType = PluginType::MUXER; ///< Plugin type, MUST be MUXER. + } +}; +} // Plugin +} // Media +} // OHOS +#endif // PLUGIN_INTF_MUXER_PLUGIN_H diff --git a/services/engine/plugin/interface/plugin_base.h b/services/engine/plugin/interface/plugin_base.h new file mode 100644 index 000000000..95059a011 --- /dev/null +++ b/services/engine/plugin/interface/plugin_base.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_INTF_PLUGIN_BASE_H +#define PLUGIN_INTF_PLUGIN_BASE_H + +#include +#include + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @brief Base class of a plugin. All plugins of different types inherit this interface. + * + * @details The base class contains only common operation methods and defines basic operation processes. + * Different operations are valid only in the corresponding states. The timing of calls is guaranteed by + * the plugin framework. Some operations also change the plugin status. + * For details, see the description of each function. + * + * @since 10 + * @version 1.0 + */ +struct PluginBase { + /// Constructor + explicit PluginBase(std::string name): pluginName_(std::move(name)) {} + + /// Destructor + virtual ~PluginBase() = default; + + /** + * @brief Get plugin name + * + * @return plugin name + */ + std::string GetName() const + { + return pluginName_; + } + +protected: + const std::string pluginName_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_INTF_PLUGIN_BASE_H diff --git a/services/engine/plugin/interface/plugin_definition.h b/services/engine/plugin/interface/plugin_definition.h new file mode 100644 index 000000000..2f55397dc --- /dev/null +++ b/services/engine/plugin/interface/plugin_definition.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PLUGIN_INTF_PLUGIN_DEFINITION_H +#define PLUGIN_INTF_PLUGIN_DEFINITION_H + +#include +#include +#include // NOLINT: using int32_t in this file + + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @brief Macro definition, creating the version information. + * + * @details The versioning is the process of assigning a unique version number to a unique state + * of plugin interface. Within a given version number category (major, minor), these numbers are + * usually assigned in ascending order and correspond to new developments in the plugin. + * + * Given a version number MAJOR.MINOR: + * - MAJOR: When you make incompatible API changes. + * - MINOR: When you add features in a backwards-compatible manner or do backwards-compatible bug fixes. + */ +#define MAKE_VERSION(MAJOR, MINOR) ((((MAJOR)&0xFFFF) << 16) | ((MINOR)&0xFFFF)) + +/// Plugin interface major number +#define PLUGIN_INTERFACE_VERSION_MAJOR (1) + +/// Plugin interface minor number +#define PLUGIN_INTERFACE_VERSION_MINOR (0) + +/// Plugin interface version +#define PLUGIN_INTERFACE_VERSION MAKE_VERSION(PLUGIN_INTERFACE_VERSION_MAJOR, PLUGIN_INTERFACE_VERSION_MINOR) + +/** + * @enum License Type. + * an official permission or permit. + * + * @since 10 + * @version 1.0 + */ +enum struct LicenseType : uint8_t { + APACHE_V2, ///< The Apache License 2.0 + LGPL, ///< The GNU Lesser General Public License + GPL, ///< The GNU General Public License + CC0, ///< The Creative Commons Zero v1.0 Universal + UNKNOWN, ///< Unknown License +}; + +/** + * @brief Definition of plugin packaging information. + * + * @since 10 + * @version 1.0 + */ +struct PackageDef { + uint32_t pkgVersion; ///< Package information version, which indicates the latest plug-in interface version + ///< used by the plugin in the package. The default value is PLUGIN_INTERFACE_VERSION. + + std::string name; ///< Package name. The plugin framework registers the plugin using this name. + ///< If the plugins are packaged as a dynamic library, the name of library + ///< must be in the format of "libplugin_.so". + + LicenseType + licenseType; ///< The License information of the plugin in the package. + ///< The different plugins must be the same. + ///< The plugin framework processing in the plugin running state based on different license. +}; + +/** + * @enum Plugin Return Status. + * + * @since 10 + * @version 1.0 + */ +enum struct Status : int32_t { + END_OF_STREAM = 1, ///< Read source when end of stream + OK = 0, ///< The execution result is correct. + NO_ERROR = OK, ///< Same as Status::OK + ERROR_UNKNOWN = -1, ///< An unknown error occurred. + ERROR_PLUGIN_ALREADY_EXISTS = -2, ///< The plugin already exists, usually occurs when in plugin registered. + ERROR_INCOMPATIBLE_VERSION = -3, ///< Incompatible version, may occur during plugin registration or function calling. + ERROR_NO_MEMORY = -4, ///< The system memory is insufficient. + ERROR_WRONG_STATE = -5, ///< The function is called in an invalid state. + ERROR_UNIMPLEMENTED = -6, ///< This method or interface is not implemented. + ERROR_INVALID_PARAMETER = -7, ///< The plugin does not support this parameter. + ERROR_INVALID_DATA = -8, ///< The value is not in the valid range. + ERROR_MISMATCHED_TYPE = -9, ///< Mismatched data type + ERROR_TIMED_OUT = -10, ///< Operation timeout. + ERROR_UNSUPPORTED_FORMAT = -11, ///< The plugin not support this format/name. + ERROR_NOT_ENOUGH_DATA = -12, ///< Not enough data when read from source. + ERROR_NOT_EXISTED = -13, ///< Source is not existed. + ERROR_AGAIN = -14, ///< Operation is not available right now, should try again later. + ERROR_PERMISSION_DENIED = -15, ///< Permission denied. + ERROR_NULL_POINTER = -16, ///< Null pointer. + ERROR_INVALID_OPERATION = -17, ///< Invalid operation. + ERROR_CLIENT = -18, ///< Http client error + ERROR_SERVER = -19, ///< Http server error + ERROR_DELAY_READY = -20, ///< Delay ready event +}; + +/** + * @enum Plugin Type. + * + * @since 10 + * @version 1.0 + */ +enum struct PluginType : int32_t { + INVALID_TYPE = -1, ///< Invalid plugin + MUXER = 1, ///< reference MuxerPlugin + DEMUXER, ///< reference DemuxerPlugin +}; + +/** + * @brief Describes the basic information about the plugin. + * + * @since 10 + * @version 1.0 + */ +struct PluginDefBase { + uint32_t apiVersion; ///< Versions of different plugins. Different types of plugin have their own versions. + + PluginType pluginType = PluginType::INVALID_TYPE; ///< Describe the plugin type, e.g. 'source', 'codec'. + + std::string name; ///< Indicates the name of a plugin. The name of the same type plugins must be unique. + ///< Plugins with the same name may fail to be registered. + + std::string description; ///< Detailed description of the plugin. + + uint32_t rank; ///< Plugin score. The plugin with a high score may be preferred. You can evaluate the + ///< plugin score in terms of performance, version support, and license. Range: 0 to 100. +}; + +/** + * @brief The plugin registration interface. + * The plugin framework will provide the implementation. + * Developers only need to invoke the API to register the plugin. + * + * @since 10 + * @version 1.0 + */ +struct Register { + virtual ~Register() = default; + /** + * @brief Register the plugin. + * + * @param def Basic information about the plugin + * @return Registration status return + * @retval OK: The plugin is registered succeed. + * @retval ERROR_PLUGIN_ALREADY_EXISTS: The plugin already exists in plugin registered. + * @retval ERROR_INCOMPATIBLE_VERSION: Incompatible version during plugin registration. + */ + virtual Status AddPlugin(const PluginDefBase& def) = 0; +}; + +/** + * @brief The package registration interface. + * The plugin framework will provide the implementation and auto invoke the API to + * finish the package registration when plugin framework first time be initialized. + * + * @since 10 + * @version 1.0 + */ +struct PackageRegister : Register { + ~PackageRegister() override = default; + + /** + * @brief Register the package. + * During package registration, all plugins in the package are automatically registered. + * + * @param def plugin packaging information. + * @return Registration status return + * @retval OK: The package is registered succeed without any errors. + * @retval ERROR_PLUGIN_ALREADY_EXISTS: The package or plugins already exists. + * @retval ERROR_INCOMPATIBLE_VERSION: Incompatible plugin interface version or api version. + */ + virtual Status AddPackage(const PackageDef& def) = 0; +}; + +/// Plugin registration function, all plugins must be implemented. +using RegisterFunc = Status (*)(std::shared_ptr reg); + +/// Plugin deregister function, all plugins must be implemented. +using UnregisterFunc = void (*)(); + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#define PLUGIN_EXPORT extern "C" __declspec(dllexport) +#else +#if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) +#define PLUGIN_EXPORT extern "C" __attribute__((visibility("default"))) +#else +#define PLUGIN_EXPORT +#endif +#endif + +/// Macro definition, string concatenation +#define PLUGIN_PASTE_ARGS(str1, str2) str1##str2 + +/// Macro definition, string concatenation +#define PLUGIN_PASTE(str1, str2) PLUGIN_PASTE_ARGS(str1, str2) + +/// Macro definition, stringify +#define PLUGIN_STRINGIFY_ARG(str) #str + +/// Macro definition, stringify +#define PLUGIN_STRINGIFY(str) PLUGIN_STRINGIFY_ARG(str) + +/** + * @brief Macro definition, Defines basic plugin information. + * Which is invoked during plugin package registration. All plugin packages must be implemented. + * + * @param name Package name. For details, @see PackageDef::name + * @param license Package License, For details, @see PackageDef::licenseType + * @param registerFunc Plugin registration function, MUST NOT be NULL. + * @param unregisterFunc Plugin deregister function,MUST NOT be NULL. + */ +#define PLUGIN_DEFINITION(name, license, registerFunc, unregisterFunc) \ + PLUGIN_EXPORT OHOS::Media::Plugin::Status PLUGIN_PASTE(register_, name)( \ + const std::shared_ptr& pkgReg) \ + { \ + pkgReg->AddPackage({PLUGIN_INTERFACE_VERSION, PLUGIN_STRINGIFY(name), license}); \ + std::shared_ptr pluginReg = pkgReg; \ + return registerFunc(pluginReg); \ + } \ + PLUGIN_EXPORT void PLUGIN_PASTE(unregister_, name)() \ + { \ + unregisterFunc(); \ + } +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_INTF_PLUGIN_DEFINITION_H diff --git a/services/engine/plugin/plugins/BUILD.gn b/services/engine/plugin/plugins/BUILD.gn new file mode 100644 index 000000000..5443b5e33 --- /dev/null +++ b/services/engine/plugin/plugins/BUILD.gn @@ -0,0 +1,19 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import("//foundation/multimedia/av_codec/config.gni") +group("av_codec_plugin_store") { + deps = [] + deps += [ "muxer/ffmpeg_muxer:plugin_muxer_ffmpeg" ] +} \ No newline at end of file diff --git a/services/engine/plugin/plugins/muxer/ffmpeg_muxer/BUILD.gn b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/BUILD.gn new file mode 100644 index 000000000..1a64f28a1 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/BUILD.gn @@ -0,0 +1,47 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import("//foundation/multimedia/av_codec/config.gni") + +group("plugin_muxer_ffmpeg") { + deps = [] + deps += [ ":av_codec_plugin_FFmpegMuxer" ] +} + +# standard +import("//build/ohos.gni") +ohos_shared_library("av_codec_plugin_FFmpegMuxer") { + sources = [ + "ffmpeg_muxer_plugin.cpp", + "ffmpeg_utils.cpp", + ] + + include_dirs = [ + "//third_party/ffmpeg", + ] + + public_configs = [ + "//foundation/multimedia/av_codec/services/engine/plugin:plugin_presets", + ] + + public_deps = [ + "//third_party/bounds_checking_function:libsec_static", + "//foundation/multimedia/av_codec/services/utils:av_codec_format", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//third_party/ffmpeg:libohosffmpeg", + ] + + relative_install_dir = "media/av_codec_plugins" + subsystem_name = "multimedia" + part_name = "multimedia_av_codec" +} diff --git a/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.cpp b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.cpp new file mode 100644 index 000000000..bed654d60 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ffmpeg_muxer_plugin.h" +#include +#include +#include +#include +#include "securec.h" +#include "ffmpeg_utils.h" +#include "avcodec_log.h" +#include "avcodec_common.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "FfmpegMuxerPlugin"}; +} + +namespace { +using namespace OHOS::Media; +using namespace Plugin; +using namespace Ffmpeg; + +std::map> g_pluginOutputFmt; + +std::map g_supportedMuxer = {{"mp4", OUTPUT_FORMAT_MPEG_4}, {"ipod", OUTPUT_FORMAT_M4A}}; + +bool IsMuxerSupported(const char *name) +{ + auto it = g_supportedMuxer.find(name); + if (it != g_supportedMuxer.end()) { + return true; + } + return false; +} + +int32_t Sniff(const std::string& pluginName, uint32_t outputFormat) +{ + if (pluginName.empty()) { + return 0; + } + auto plugin = g_pluginOutputFmt[pluginName]; + int32_t confidence = 0; + auto it = g_supportedMuxer.find(plugin->name); + if (it != g_supportedMuxer.end() && it->second == outputFormat) { + confidence = 60; + } + + return confidence; +} + +Status RegisterMuxerPlugins(const std::shared_ptr& reg) +{ + const AVOutputFormat *outputFormat = nullptr; + void *ite = nullptr; + while ((outputFormat = av_muxer_iterate(&ite))) { + if (!IsMuxerSupported(outputFormat->name)) { + continue; + } + if (outputFormat->long_name != nullptr) { + if (!strncmp(outputFormat->long_name, "raw ", 4)) { // 4 + continue; + } + } + std::string pluginName = "ffmpegMux_" + std::string(outputFormat->name); + ReplaceDelimiter(".,|-<> ", '_', pluginName); + MuxerPluginDef def; + def.name = pluginName; + def.description = "ffmpeg muxer"; + def.rank = 100; // 100 + def.creator = [](const std::string& name, int32_t fd) -> std::shared_ptr { + return std::make_shared(name, fd); + }; + def.sniffer = Sniff; + if (reg->AddPlugin(def) != Status::NO_ERROR) { + continue; + } + g_pluginOutputFmt[pluginName] = std::shared_ptr( + const_cast(outputFormat), [](AVOutputFormat *ptr) {}); // do not delete + } + return Status::NO_ERROR; +} + +PLUGIN_DEFINITION(FFmpegMuxer, LicenseType::LGPL, RegisterMuxerPlugins, [] {g_pluginOutputFmt.clear();}) + +void ResetCodecParameter(AVCodecParameters *par) +{ + av_freep(&par->extradata); + (void)memset_s(par, sizeof(*par), 0, sizeof(*par)); + par->codec_type = AVMEDIA_TYPE_UNKNOWN; + par->codec_id = AV_CODEC_ID_NONE; + par->format = -1; + par->profile = FF_PROFILE_UNKNOWN; + par->level = FF_LEVEL_UNKNOWN; + par->field_order = AV_FIELD_UNKNOWN; + par->color_range = AVCOL_RANGE_UNSPECIFIED; + par->color_primaries = AVCOL_PRI_UNSPECIFIED; + par->color_trc = AVCOL_TRC_UNSPECIFIED; + par->color_space = AVCOL_SPC_UNSPECIFIED; + par->chroma_location = AVCHROMA_LOC_UNSPECIFIED; + par->sample_aspect_ratio = AVRational {0, 1}; +} +} + + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace Ffmpeg { +FFmpegMuxerPlugin::FFmpegMuxerPlugin(std::string name, int32_t fd) : MuxerPlugin(std::move(name)), fd_(dup(fd)) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + if ((fcntl(fd_, F_GETFL, 0) & O_RDWR) != O_RDWR) { + AVCODEC_LOGE("No permission to read and write fd"); + } + if (lseek(fd_, 0, SEEK_SET) < 0) { + AVCODEC_LOGE("The fd is not seekable"); + } + auto pkt = av_packet_alloc(); + cachePacket_ = std::shared_ptr (pkt, [] (AVPacket *packet) {av_packet_free(&packet);}); + outputFormat_ = g_pluginOutputFmt[pluginName_]; + auto fmt = avformat_alloc_context(); + fmt->pb = InitAvIoCtx(fd_, 1); + fmt->oformat = outputFormat_.get(); + fmt->flags = static_cast(fmt->flags) | static_cast(AVFMT_FLAG_CUSTOM_IO); + fmt->io_open = IoOpen; + fmt->io_close = IoClose; + formatContext_ = std::shared_ptr(fmt, [](AVFormatContext *ptr) { + if (ptr) { + DeInitAvIoCtx(ptr->pb); + avformat_free_context(ptr); + } + }); +} + +FFmpegMuxerPlugin::~FFmpegMuxerPlugin() +{ + AVCODEC_LOGD("Destory"); + outputFormat_.reset(); + cachePacket_.reset(); + formatContext_.reset(); + CloseFd(); + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +Status FFmpegMuxerPlugin::SetLocation(float latitude, float longitude) +{ + std::string location = std::to_string(longitude) + " "; + location += std::to_string(latitude) + " "; + location += std::to_string(0.0f); + av_dict_set(&formatContext_.get()->metadata, "location", location.c_str(), 0); + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::SetRotation(int32_t rotation) +{ + rotation_ = rotation; + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::SetCodecParameterOfTrack(AVStream *stream, const MediaDescription &trackDesc) +{ + bool ret = false; + uint8_t *extraData = nullptr; + size_t extraDataSize = 0; + std::string mimeType = {}; + AVCodecID codeID = AV_CODEC_ID_NONE; + + CHECK_AND_RETURN_RET_LOG(trackDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, mimeType), + Status::ERROR_MISMATCHED_TYPE, "get mimeType failed!"); // mime + AVCODEC_LOGD("mimeType is %{public}s", mimeType.c_str()); + CHECK_AND_RETURN_RET_LOG(Mime2CodecId(mimeType, codeID), Status::ERROR_INVALID_DATA, + "this mimeType do not support! mimeType:%{public}s", mimeType.c_str()); + + AVCodecParameters *par = stream->codecpar; + par->codec_id = codeID; + if (!mimeType.compare(0, 5, "audio")) { + par->codec_type = AVMEDIA_TYPE_AUDIO; // type + ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, par->sample_rate); // sample rate + CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get audio sample_rate failed!"); + ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, par->channels); // channels + CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get audio channels failed!"); + } else if(!mimeType.compare(0, 5, "video") || !mimeType.compare(0, 5, "image")) { + if (!mimeType.compare(0, 5, "image")) { // pic + stream->disposition = AV_DISPOSITION_ATTACHED_PIC; + } + par->codec_type = AVMEDIA_TYPE_VIDEO; // type + ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, par->width); // width + CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get video width failed!"); + ret = trackDesc.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, par->height); // height + CHECK_AND_RETURN_RET_LOG(ret, Status::ERROR_MISMATCHED_TYPE, "get video height failed!"); + } else{ + AVCODEC_LOGD("mimeType %{public}s is unsupported", mimeType.c_str()); + } + + trackDesc.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, par->bit_rate); // bit rate + if (trackDesc.GetBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, &extraData, extraDataSize)) { // codec config + par->extradata = static_cast(av_mallocz(extraDataSize + AV_INPUT_BUFFER_PADDING_SIZE)); + CHECK_AND_RETURN_RET_LOG(par->extradata != nullptr, Status::ERROR_NO_MEMORY, "codec config malloc failed!"); + par->extradata_size = static_cast(extraDataSize); + errno_t rc = memcpy_s(par->extradata, par->extradata_size, extraData, extraDataSize); + CHECK_AND_RETURN_RET_LOG(rc == EOK, Status::ERROR_UNKNOWN, "memcpy_s failed"); + } + + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + CHECK_AND_RETURN_RET_LOG(outputFormat_ != nullptr, Status::ERROR_NULL_POINTER, "AVOutputFormat is nullptr"); + auto st = avformat_new_stream(formatContext_.get(), nullptr); + CHECK_AND_RETURN_RET_LOG(st != nullptr, Status::ERROR_NO_MEMORY, "avformat_new_stream failed!"); + st->codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; + st->codecpar->codec_id = AV_CODEC_ID_NONE; + trackIndex = st->index; + + // 设置track参数 + ResetCodecParameter(st->codecpar); + Status ret = SetCodecParameterOfTrack(st, trackDesc); + CHECK_AND_RETURN_RET_LOG(ret == Status::NO_ERROR, ret, "SetCodecParameter failed!"); + formatContext_->flags |= AVFMT_TS_NONSTRICT; + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::Start() +{ + if (rotation_ != 0) { + std::string rotate = std::to_string(rotation_); + for (uint32_t i = 0; i < formatContext_->nb_streams; i++) { + if (formatContext_->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + av_dict_set(&formatContext_->streams[i]->metadata, "rotate", rotate.c_str(), 0); + } + } + } + AVDictionary *options = nullptr; + av_dict_set(&options, "movflags", "faststart", 0); + int ret = avformat_write_header(formatContext_.get(), &options); + if (ret < 0) { + AVCODEC_LOGE("write header failed, %{public}s", AVStrError(ret).c_str()); + return Status::ERROR_UNKNOWN; + } + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::Stop() +{ + int ret = av_write_frame(formatContext_.get(), nullptr); // flush out cache data + if (ret < 0) { + AVCODEC_LOGE("write trailer failed, %{public}s", AVStrError(ret).c_str()); + } + ret = av_write_trailer(formatContext_.get()); + if (ret != 0) { + AVCODEC_LOGE("write trailer failed, %{public}s", AVStrError(ret).c_str()); + } + avio_flush(formatContext_->pb); + + CloseFd(); + return Status::NO_ERROR; +} + +Status FFmpegMuxerPlugin::WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) +{ + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, Status::ERROR_NULL_POINTER, "av_write_frame sampleBuffer is null!"); + CHECK_AND_RETURN_RET_LOG(info.trackIndex < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER, "track index is invalid!"); + (void)memset_s(cachePacket_.get(), sizeof(AVPacket), 0, sizeof(AVPacket)); + cachePacket_->data = sampleBuffer; + cachePacket_->size = info.size; + cachePacket_->stream_index = static_cast(info.trackIndex); + cachePacket_->pts = ConvertTimeToFFmpeg(info.timeUs, formatContext_->streams[info.trackIndex]->time_base); + cachePacket_->dts = cachePacket_->pts; + cachePacket_->flags = 0; + if (info.flags & AVCODEC_BUFFER_FLAG_SYNC_FRAME) { + AVCODEC_LOGD("It is key frame"); + cachePacket_->flags |= AV_PKT_FLAG_KEY; + } + auto ret = av_write_frame(formatContext_.get(), cachePacket_.get()); + av_packet_unref(cachePacket_.get()); + if (ret < 0) { + AVCODEC_LOGE("write sample buffer failed, %{public}s", AVStrError(ret).c_str()); + return Status::ERROR_UNKNOWN; + } + return Status::NO_ERROR; +} + +AVIOContext *FFmpegMuxerPlugin::InitAvIoCtx(int32_t fd, int writeFlags) +{ + IOContext *ioContext = new IOContext(); + ioContext->fd_ = fd; + ioContext->pos_ = 0; + ioContext->end_ = 0; + + constexpr int bufferSize = 4 * 1024; // 4096 + auto buffer = static_cast(av_malloc(bufferSize)); + AVIOContext *avioContext = avio_alloc_context(buffer, bufferSize, writeFlags, static_cast(ioContext), + IoRead, IoWrite, IoSeek); + if (avioContext == nullptr) { + delete ioContext; + av_free(buffer); + return nullptr; + } + avioContext->seekable = AVIO_SEEKABLE_NORMAL; + return avioContext; +} + +void FFmpegMuxerPlugin::DeInitAvIoCtx(AVIOContext *ptr) +{ + if (ptr != nullptr) { + delete static_cast(ptr->opaque); + ptr->opaque = nullptr; + av_freep(&ptr->buffer); + av_opt_free(ptr); + avio_context_free(&ptr); + } +} + +void FFmpegMuxerPlugin::CloseFd() +{ + if (fd_ != -1) { + AVCODEC_LOGD("close fd"); + close(fd_); + fd_ = -1; + } +} + +int32_t FFmpegMuxerPlugin::IoRead(void *opaque, uint8_t *buf, int bufSize) +{ + auto ioCtx = static_cast(opaque); + if (ioCtx && ioCtx->fd_ != -1) { + int64_t ret = lseek(ioCtx->fd_, ioCtx->pos_, SEEK_SET); + if (ret != -1) { + ssize_t size = read(ioCtx->fd_, buf, bufSize); + if (size < 0) { + return -1; + } + ioCtx->pos_ += size; + if (ioCtx->pos_ > ioCtx->end_) { + ioCtx->end_ = ioCtx->pos_; + } + return size; + } + return 0; + } + return -1; +} + +int32_t FFmpegMuxerPlugin::IoWrite(void *opaque, uint8_t *buf, int bufSize) +{ + auto ioCtx = static_cast(opaque); + if (ioCtx && ioCtx->fd_ != -1) { + int64_t ret = lseek(ioCtx->fd_, ioCtx->pos_, SEEK_SET); + if (ret != -1) { + ssize_t size = write(ioCtx->fd_, buf, bufSize); + if (size < 0) { + return -1; + } + ioCtx->pos_ += size; + if (ioCtx->pos_ > ioCtx->end_) { + ioCtx->end_ = ioCtx->pos_; + } + return size; + } + return 0; + } + return -1; +} + +int64_t FFmpegMuxerPlugin::IoSeek(void *opaque, int64_t offset, int whence) +{ + auto ioContext = static_cast(opaque); + uint64_t newPos = 0; + switch (whence) { + case SEEK_SET: + newPos = static_cast(offset); + ioContext->pos_ = newPos; + break; + case SEEK_CUR: + newPos = ioContext->pos_ + offset; + break; + case SEEK_END: + case AVSEEK_SIZE: + newPos = ioContext->end_ + offset; + break; + default: + break; + } + if (whence != AVSEEK_SIZE) { + ioContext->pos_ = newPos; + } + return newPos; +} + +int32_t FFmpegMuxerPlugin::IoOpen(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options) +{ + AVCODEC_LOGD("IoOpen flags %{public}d", flags); + *pb = InitAvIoCtx(static_cast(s->pb->opaque)->fd_, 0); + return 0; +} + +void FFmpegMuxerPlugin::IoClose(AVFormatContext *s, AVIOContext *pb) +{ + avio_flush(pb); + DeInitAvIoCtx(pb); +} +} // Ffmpeg +} // Plugin +} // Media +} // OHOS diff --git a/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.h b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.h new file mode 100644 index 000000000..2c53a2038 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FFMPEG_MUXER_PLUGIN_H +#define FFMPEG_MUXER_PLUGIN_H + +#include "muxer_plugin.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavformat/avformat.h" +#include "libavutil/opt.h" +#ifdef __cplusplus +} +#endif + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace Ffmpeg { +class FFmpegMuxerPlugin : public MuxerPlugin { +public: + explicit FFmpegMuxerPlugin(std::string name, int32_t fd); + ~FFmpegMuxerPlugin() override; + + Status SetLocation(float latitude, float longitude) override; + Status SetRotation(int32_t rotation) override; + Status AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; + Status Start() override; + Status WriteSampleBuffer(uint8_t *sampleBuffer, const TrackSampleInfo &info) override; + Status Stop() override; + +private: + Status SetCodecParameterOfTrack(AVStream *stream, const MediaDescription &trackDesc); + static int32_t IoRead(void *opaque, uint8_t *buf, int bufSize); + static int32_t IoWrite(void *opaque, uint8_t *buf, int bufSize); + static int64_t IoSeek(void *opaque, int64_t offset, int whence); + static AVIOContext *InitAvIoCtx(int32_t fd, int writeFlags); + static void DeInitAvIoCtx(AVIOContext *ptr); + static int32_t IoOpen(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options); + static void IoClose(AVFormatContext *s, AVIOContext *pb); + void CloseFd(); + +private: + struct IOContext { + int32_t fd_ {-1}; + int64_t pos_ {0}; + int64_t end_ {0}; + }; + int32_t fd_ {-1}; + std::shared_ptr cachePacket_ {}; + std::shared_ptr outputFormat_ {}; + std::shared_ptr formatContext_ {}; + int32_t rotation_ { 0 }; +}; +} // Ffmpeg +} // Plugin +} // Media +} // OHOS +#endif // FFMPEG_MUXER_PLUGIN_H diff --git a/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.cpp b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.cpp new file mode 100644 index 000000000..2d03a0259 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ffmpeg_utils.h" +#include +#include +#include +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace Ffmpeg { +// Internal definitions +namespace { +/* time scale microsecond */ +constexpr int32_t TIME_SCALE_US = 1000000; + +/* MIME to AVCodecID */ +std::unordered_map g_mimeToCodecId = { + {CodecMimeType::AUDIO_MPEG, AV_CODEC_ID_MP3}, + {CodecMimeType::AUDIO_FLAC, AV_CODEC_ID_FLAC}, + {CodecMimeType::AUDIO_RAW, AV_CODEC_ID_PCM_S16LE}, + {CodecMimeType::AUDIO_AAC, AV_CODEC_ID_AAC}, + {CodecMimeType::AUDIO_VORBIS, AV_CODEC_ID_VORBIS}, + {CodecMimeType::AUDIO_OPUS, AV_CODEC_ID_OPUS}, + {CodecMimeType::AUDIO_AMR_NB, AV_CODEC_ID_AMR_NB}, + {CodecMimeType::AUDIO_AMR_WB, AV_CODEC_ID_AMR_WB}, + {CodecMimeType::VIDEO_AVC, AV_CODEC_ID_H264}, + {CodecMimeType::VIDEO_MPEG4, AV_CODEC_ID_MPEG4}, + {CodecMimeType::IMAGE_JPG, AV_CODEC_ID_MJPEG}, + {CodecMimeType::IMAGE_PNG, AV_CODEC_ID_PNG}, + {CodecMimeType::IMAGE_BMP, AV_CODEC_ID_BMP}, +}; +} // namespace + +bool Mime2CodecId(const std::string_view &mime, AVCodecID &codecId) +{ + auto it = g_mimeToCodecId.find(mime); + if (it != g_mimeToCodecId.end()) { + codecId = it->second; + return true; + } + return false; +} + +void ReplaceDelimiter(const std::string &delmiters, char newDelimiter, std::string &str) +{ + for (auto it = str.begin(); it != str.end(); ++it) { + if (delmiters.find(newDelimiter) != std::string::npos) { + *it = newDelimiter; + } + } +} + +std::vector SplitString(const char* str, char delimiter) +{ + std::vector rtv; + if (str) { + SplitString(std::string(str), delimiter).swap(rtv); + } + return rtv; +} + +std::vector SplitString(const std::string &str, char delimiter) +{ + if (str.empty()) { + return {}; + } + std::vector rtv; + std::string::size_type startPos = 0; + std::string::size_type endPos = str.find_first_of(delimiter, startPos); + while (startPos != endPos) { + rtv.emplace_back(str.substr(startPos, endPos - startPos)); + if (endPos == std::string::npos) { + break; + } + startPos = endPos + 1; + endPos = str.find_first_of(delimiter, startPos); + } + return rtv; +} + +std::string AVStrError(int errnum) +{ + char errbuf[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE); + return std::string(errbuf); +} + +int64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base) +{ + int64_t out; + if (pts == AV_NOPTS_VALUE) { + out = -1; + } else { + AVRational bq = {1, TIME_SCALE_US}; + out = av_rescale_q(pts, base, bq); + } + return out; +} + +int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base) +{ + int64_t result; + if (base.num == 0) { + result = AV_NOPTS_VALUE; + } else { + AVRational bq = {1, TIME_SCALE_US}; + result = av_rescale_q(timestampUs, bq, base); + } + return result; +} +} // namespace Ffmpeg +} // namespace Plugin +} // namespace Media +} // namespace OHOS diff --git a/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.h b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.h new file mode 100644 index 000000000..0bcdc9ab0 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FFMPEG_UTILS_H +#define FFMPEG_UTILS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavcodec/avcodec.h" +#include "libavutil/channel_layout.h" +#include "libavutil/error.h" +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/pixdesc.h" +#include "libavutil/pixfmt.h" +#include "libswresample/swresample.h" +#include "libswscale/swscale.h" +#ifdef __cplusplus +}; +#endif + + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace Ffmpeg { +bool Mime2CodecId(const std::string_view &mime, AVCodecID &codecId); + +void ReplaceDelimiter(const std::string &delmiters, char newDelimiter, std::string &str); +std::vector SplitString(const char* str, char delimiter); +std::vector SplitString(const std::string &str, char delimiter); + +std::string AVStrError(int errnum); + +/** + * Convert time from ffmpeg to time in HST_TIME_BASE. + * @param pts ffmpeg time + * @param base ffmpeg time_base + * @return time in HST_TIME_BASE + */ +int64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base); + +/** + * Convert time in TIME_BASE to ffmpeg time. + * @param time time in HST_TIME_BASE + * @param base ffmpeg time_base + * @return time in ffmpeg. + */ +int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base); +} // namespace Ffmpeg +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // FFMPEG_UTILS_H diff --git a/services/etc/av_codec_service.cfg b/services/etc/av_codec_service.cfg index 82ca554e2..2abd2ba0a 100644 --- a/services/etc/av_codec_service.cfg +++ b/services/etc/av_codec_service.cfg @@ -7,4 +7,4 @@ "secon" : "u:r:media_service:s0" } ] -} \ No newline at end of file +} diff --git a/services/include/i_avcodec_service.h b/services/include/i_avcodec_service.h index d1939f425..b78984e6d 100644 --- a/services/include/i_avcodec_service.h +++ b/services/include/i_avcodec_service.h @@ -31,7 +31,7 @@ #endif #ifdef SUPPORT_MUXER -#include "i_avmuxer.h" +#include "i_muxer_service.h" #endif #ifdef SUPPORT_SOURCE @@ -99,8 +99,28 @@ public: #endif #ifdef SUPPORT_MUXER - virtual std::shared_ptr CreateMuxerService() = 0; - virtual int32_t DestroyMuxerService(std::shared_ptr muxer) = 0; + /** + * @brief Create an muxer service. + * + * All muxer functions must be created and obtained first. + * + * @return Returns a valid pointer if the setting is successful; + * @since 10 + * @version 4.0 + */ + virtual std::shared_ptr CreateMuxerService() = 0; + + /** + * @brief Destroy a muxer service. + * + * call the API to destroy the muxer service. + * + * @param pointer to the muxer service. + * @return Returns a valid pointer if the setting is successful; + * @since 10 + * @version 4.0 + */ + virtual int32_t DestroyMuxerService(std::shared_ptr muxer) = 0; #endif #ifdef SUPPORT_SOURCE @@ -114,7 +134,7 @@ public: /** * @brief IAVCodecService singleton * - * Create Recorder Service and Player Service Through the Avcodec Service. + * Create Muxer and Demuxer Service Through the AVCodec Service. * * @return Returns IAVCodecService singleton; * @since 4.0 diff --git a/services/include/i_avmuxer.h b/services/include/i_avmuxer.h deleted file mode 100644 index 85cb2e7b4..000000000 --- a/services/include/i_avmuxer.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef I_MUXER_SERVICE_H -#define I_MUXER_SERVICE_H - -#include -#include -#include "format.h" -#include "avcodec_common.h" - -namespace OHOS { -namespace Media { -class IAVMuxer { -public: - virtual ~IAVMuxer() = default; - - // 业务 - virtual int32_t Init() = 0; - virtual int32_t SetLocation(float latitude, float longitude) = 0; - virtual int32_t SetRotation(int32_t rotation) = 0; - virtual int32_t SetParameter(const Format &generalFormat) = 0; - virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0; - virtual int32_t Start() = 0; - virtual int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, - AVCodecBufferInfo info) = 0; - virtual int32_t Stop() = 0; -}; -} // namespace Media -} // namespace OHOS -#endif // I_MUXER_SERVICE_H \ No newline at end of file diff --git a/services/include/i_muxer_service.h b/services/include/i_muxer_service.h new file mode 100644 index 000000000..ec1efd54b --- /dev/null +++ b/services/include/i_muxer_service.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef I_MUXER_SERVICE_H +#define I_MUXER_SERVICE_H + +#include +#include +#include "avsharedmemory.h" +#include "media_description.h" +#include "av_common.h" + +namespace OHOS { +namespace Media { +class IMuxerService { +public: + virtual ~IMuxerService() = default; + + virtual int32_t InitParameter(int32_t fd, OutputFormat format) = 0; + virtual int32_t SetLocation(float latitude, float longitude) = 0; + virtual int32_t SetRotation(int32_t rotation) = 0; + virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0; + virtual int32_t Start() = 0; + virtual int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) = 0; + virtual int32_t Stop() = 0; + virtual void Release() = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // I_MUXER_SERVICE_H \ No newline at end of file diff --git a/services/services/BUILD.gn b/services/services/BUILD.gn index eacce9398..161029743 100644 --- a/services/services/BUILD.gn +++ b/services/services/BUILD.gn @@ -81,12 +81,16 @@ config("av_codec_service_config") { "//foundation/multimedia/av_codec/services/dfx/include/", "//foundation/multimedia/av_codec/services/engine/", "//foundation/multimedia/av_codec/services/engine/avcodeclist", + "//foundation/multimedia/av_codec/services/engine/muxer", + "//foundation/multimedia/av_codec/services/engine/plugin/core", + "//foundation/multimedia/av_codec/services/engine/plugin/interface", "//foundation/multimedia/av_codec/services/engine/plugin/", "//foundation/multimedia/av_codec/services/engine/plugin/plugins/", "//foundation/multimedia/av_codec/services/engine/plugin/plugins/demuxer/", "//foundation/multimedia/av_codec/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/", "//foundation/multimedia/av_codec/services/include/", "//foundation/multimedia/av_codec/services/services/", + "//foundation/multimedia/av_codec/services/services/factory", "//foundation/multimedia/av_codec/services/services/avcodeclist/", "//foundation/multimedia/av_codec/services/services/avcodeclist/client", "//foundation/multimedia/av_codec/services/services/avcodeclist/ipc", @@ -106,9 +110,9 @@ config("av_codec_service_config") { "//foundation/multimedia/av_codec/services/services/demuxer/ipc/", "//foundation/multimedia/av_codec/services/services/demuxer/server/", "//foundation/multimedia/av_codec/services/services/muxer/", - "//foundation/multimedia/av_codec/services/services/muxer/client/include", - "//foundation/multimedia/av_codec/services/services/muxer/ipc/include", - "//foundation/multimedia/av_codec/services/services/muxer/server/include", + "//foundation/multimedia/av_codec/services/services/muxer/client", + "//foundation/multimedia/av_codec/services/services/muxer/ipc", + "//foundation/multimedia/av_codec/services/services/muxer/server", "//foundation/multimedia/av_codec/services/services/sa_avcodec/", "//foundation/multimedia/av_codec/services/services/sa_avcodec/client/", "//foundation/multimedia/av_codec/services/services/sa_avcodec/ipc/", @@ -131,6 +135,17 @@ config("av_codec_service_config") { if (target_cpu == "arm") { cflags += [ "-DBINDER_IPC_32BIT" ] } + + if (target_cpu == "arm64") { + av_codec_plugin_path = "\"/system/lib64/media/av_codec_plugins\"" + } else { + av_codec_plugin_path = "\"/system/lib/media/av_codec_plugins\"" + } + + defines += [ + "AV_CODEC_PLUGIN_PATH=${av_codec_plugin_path}", + "AV_CODEC_PLUGIN_FILE_TAIL=\".z.so\"", + ] } ohos_shared_library("av_codec_service") { @@ -155,6 +170,10 @@ ohos_shared_library("av_codec_service") { "sa_avcodec/ipc/avcodec_service_stub.cpp", "sa_avcodec/server/avcodec_server.cpp", "sa_avcodec/server/avcodec_server_manager.cpp", + "//foundation/multimedia/av_codec/services/engine/muxer/muxer_engine_impl.cpp", + "//foundation/multimedia/av_codec/services/engine/plugin/core/muxer_factory.cpp", + "//foundation/multimedia/av_codec/services/engine/plugin/core/muxer.cpp", + "//foundation/multimedia/av_codec/services/engine/plugin/core/plugin_loader.cpp", ] @@ -174,8 +193,8 @@ ohos_shared_library("av_codec_service") { } if (multimedia_av_codec_support_muxer) { sources += [ - "muxer/ipc/avmuxer_stub.cpp", - "muxer/server/avmuxer_server.cpp", + "muxer/ipc/muxer_service_stub.cpp", + "muxer/server/muxer_server.cpp", ] } @@ -184,6 +203,7 @@ ohos_shared_library("av_codec_service") { "$AV_CODEC_ROOT_DIR/services/dfx:av_codec_service_dfx", "$AV_CODEC_ROOT_DIR/services/utils:av_codec_format", "$AV_CODEC_ROOT_DIR/services/utils:av_codec_service_utils", + "$AV_CODEC_ROOT_DIR/services/engine:av_codec_engine_package", ] external_deps = [ diff --git a/services/services/factory/i_muxer_engine.h b/services/services/factory/i_muxer_engine.h new file mode 100644 index 000000000..b75fbc5fa --- /dev/null +++ b/services/services/factory/i_muxer_engine.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMUXER_ENGINE_H +#define IMUXER_ENGINE_H + +#include +#include "avsharedmemory.h" +#include "media_description.h" +#include "av_common.h" + +namespace OHOS { +namespace Media { +class IMuxerEngine { +public: + virtual ~IMuxerEngine() = default; + virtual int32_t SetLocation(float latitude, float longitude) = 0; + virtual int32_t SetRotation(int32_t rotation) = 0; + virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0; + virtual int32_t Start() = 0; + virtual int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) = 0; + virtual int32_t Stop() = 0; + virtual int32_t DumpInfo(int32_t fd) = 0; +}; + +class __attribute__((visibility("default"))) IMuxerEngineFactory { +public: + static std::shared_ptr CreateMuxerEngine(int32_t appUid, int32_t appPid, int32_t fd, OutputFormat format); +private: + IMuxerEngineFactory() = default; + ~IMuxerEngineFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // IMUXER_ENGINE_H \ No newline at end of file diff --git a/services/services/muxer/client/avmuxer_client.cpp b/services/services/muxer/client/muxer_client.cpp similarity index 65% rename from services/services/muxer/client/avmuxer_client.cpp rename to services/services/muxer/client/muxer_client.cpp index 7e7a79028..6ac0760f0 100644 --- a/services/services/muxer/client/avmuxer_client.cpp +++ b/services/services/muxer/client/muxer_client.cpp @@ -13,31 +13,30 @@ * limitations under the License. */ -#include -#include "avmuxer_client.h" +#include "muxer_client.h" #include "avcodec_errors.h" #include "avcodec_log.h" namespace { - constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerClient"}; + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerClient"}; } namespace OHOS { namespace Media { -std::shared_ptr AVMuxerClient::Create(const sptr &ipcProxy) +std::shared_ptr MuxerClient::Create(const sptr &ipcProxy) { - std::shared_ptr muxerClient = std::make_shared(ipcProxy); - CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Failed to create muxer client"); + std::shared_ptr muxerClient = std::make_shared(ipcProxy); + CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Create muxer client failed"); return muxerClient; } -AVMuxerClient::AVMuxerClient(const sptr &ipcProxy) +MuxerClient::MuxerClient(const sptr &ipcProxy) : muxerProxy_(ipcProxy) { AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); } -AVMuxerClient::~AVMuxerClient() +MuxerClient::~MuxerClient() { std::lock_guard lock(mutex_); if (muxerProxy_ != nullptr) { @@ -47,67 +46,67 @@ AVMuxerClient::~AVMuxerClient() AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); } -void AVMuxerClient::AVCodecServerDied() +void MuxerClient::AVCodecServerDied() { std::lock_guard lock(mutex_); muxerProxy_ = nullptr; } -int32_t AVMuxerClient::Init() +int32_t MuxerClient::InitParameter(int32_t fd, OutputFormat format) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); - return muxerProxy_->Init(); + return muxerProxy_->InitParameter(fd, format); } -int32_t AVMuxerClient::SetLocation(float latitude, float longitude) +int32_t MuxerClient::SetLocation(float latitude, float longitude) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); return muxerProxy_->SetLocation(latitude, longitude); } -int32_t AVMuxerClient::SetRotation(int32_t rotation) +int32_t MuxerClient::SetRotation(int32_t rotation) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); return muxerProxy_->SetRotation(rotation); } -int32_t AVMuxerClient::SetParameter(const Format &generalFormat) -{ - std::lock_guard lock(mutex_); - CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "codec service does not exist."); - return muxerProxy_->SetParameter(generalFormat); -} - -int32_t AVMuxerClient::AddTrack(uint32_t &trackIndex, const Format &trackFormat) +int32_t MuxerClient::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); - return muxerProxy_->AddTrack(trackIndex, trackFormat); + return muxerProxy_->AddTrack(trackIndex, trackDesc); } -int32_t AVMuxerClient::Start() +int32_t MuxerClient::Start() { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); return muxerProxy_->Start(); } -int32_t AVMuxerClient::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) +int32_t MuxerClient::WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) { std::lock_guard lock(mutex_); - CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "SampleBuffer is nullptr"); + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleBuffer is nullptr"); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); - return muxerProxy_->WriteSampleBuffer(trackIndex, sampleBuffer, info); + return muxerProxy_->WriteSampleBuffer(sampleBuffer, info); } -int32_t AVMuxerClient::Stop() +int32_t MuxerClient::Stop() { std::lock_guard lock(mutex_); CHECK_AND_RETURN_RET_LOG(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); return muxerProxy_->Stop(); } + +void MuxerClient::Release() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_LOG(muxerProxy_ != nullptr, "Muxer Service does not exist"); + muxerProxy_->Release(); +} } // namespace Media } // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/client/include/avmuxer_client.h b/services/services/muxer/client/muxer_client.h similarity index 58% rename from services/services/muxer/client/include/avmuxer_client.h rename to services/services/muxer/client/muxer_client.h index 9d2c49914..57f24a2dd 100644 --- a/services/services/muxer/client/include/avmuxer_client.h +++ b/services/services/muxer/client/muxer_client.h @@ -16,30 +16,31 @@ #ifndef MUXER_CLIENT_H #define MUXER_CLIENT_H -#include "i_avmuxer.h" -#include "i_avmuxer_service.h" +#include +#include "i_muxer_service.h" +#include "i_standard_muxer_service.h" namespace OHOS { namespace Media { -class AVMuxerClient : public IAVMuxer, public NoCopyable { +class MuxerClient : public IMuxerService, public NoCopyable { public: - static std::shared_ptr Create(const sptr &ipcProxy); - explicit AVMuxerClient(const sptr &ipcProxy); - ~AVMuxerClient(); + static std::shared_ptr Create(const sptr &ipcProxy); + explicit MuxerClient(const sptr &ipcProxy); + ~MuxerClient(); - int32_t Init() override; + int32_t InitParameter(int32_t fd, OutputFormat format) override; int32_t SetLocation(float latitude, float longitude) override; int32_t SetRotation(int32_t rotation) override; - int32_t SetParameter(const Format &generalFormat) override; - int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; int32_t Start() override; - int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) override; + int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) override; int32_t Stop() override; + void Release() override; void AVCodecServerDied(); private: std::mutex mutex_; - sptr muxerProxy_ = nullptr; + sptr muxerProxy_ = nullptr; }; } // namespace Media } // namespace OHOS diff --git a/services/services/muxer/ipc/avmuxer_proxy.cpp b/services/services/muxer/ipc/avmuxer_proxy.cpp deleted file mode 100644 index 797f958fa..000000000 --- a/services/services/muxer/ipc/avmuxer_proxy.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "avmuxer_proxy.h" -#include "avcodec_log.h" -#include "avcodec_errors.h" -#include "avsharedmemory_ipc.h" -#include "avcodec_parcel.h" - -namespace { - constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerProxy"}; -} - -namespace OHOS { -namespace Media { -AVMuxerProxy::AVMuxerProxy(const sptr &impl) - : IRemoteProxy(impl) -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); -} - -AVMuxerProxy::~AVMuxerProxy() -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); -} - -int32_t AVMuxerProxy::DestroyStub() -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - int32_t ret = Remote()->SendRequest(DESTROY_STUB, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call DestroyStub"); - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::Init() -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - int32_t ret = Remote()->SendRequest(INIT, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Init"); - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::SetLocation(float latitude, float longitude) -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - data.WriteFloat(latitude); - data.WriteFloat(longitude); - int32_t ret = Remote()->SendRequest(SET_LOCATION, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetLocation"); - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::SetRotation(int32_t rotation) -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - data.WriteInt32(rotation); - int32_t ret = Remote()->SendRequest(SET_ROTATION, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); - return reply.ReadInt32(); -} - - -int32_t AVMuxerProxy::SetParameter(const Format &generalFormat) -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - AVCodecParcel::Marshalling(data, generalFormat); - int32_t ret = Remote()->SendRequest(SET_PARAMETER, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, "SetParameter failed"); - - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::AddTrack(uint32_t &trackIndex, const Format &trackFormat) -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - data.WriteInt32(trackIndex); - AVCodecParcel::Marshalling(data, trackFormat); - int32_t ret = Remote()->SendRequest(ADD_TRACK, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call AddTrack"); - - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::Start() -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor"); - - int32_t ret = Remote()->SendRequest(START, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Start"); - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) -{ - CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleBuffer is nullptr"); - MessageParcel data; - MessageParcel reply; - MessageOption option; - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); - data.WriteInt32(trackIndex); - WriteAVSharedMemoryToParcel(sampleBuffer, data); - data.WriteInt64(info.presentationTimeUs); - data.WriteInt32(info.size); - data.WriteInt32(info.offset); - // data.WriteInt32(info.flag); - - int32_t ret = Remote()->SendRequest(WRITE_SAMPLE_BUFFER, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call WriteTrackSample"); - return reply.ReadInt32(); -} - -int32_t AVMuxerProxy::Stop() -{ - MessageParcel data; - MessageParcel reply; - MessageOption option; - - bool token = data.WriteInterfaceToken(AVMuxerProxy::GetDescriptor()); - CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); - - int ret = Remote()->SendRequest(STOP, data, reply, option); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Stop"); - return reply.ReadInt32(); -} -} // namespace Media -} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/ipc/avmuxer_stub.cpp b/services/services/muxer/ipc/avmuxer_stub.cpp deleted file mode 100644 index ed5c8fb13..000000000 --- a/services/services/muxer/ipc/avmuxer_stub.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "avmuxer_stub.h" -#include "unistd.h" -#include "avcodec_server_manager.h" -#include "avcodec_errors.h" -#include "avcodec_log.h" -#include "avsharedmemory_ipc.h" -#include "avcodec_parcel.h" -#include "avcodec_xcollie.h" - -namespace { - constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerStub"}; -} - -namespace OHOS { -namespace Media { -sptr AVMuxerStub::Create() -{ - sptr muxerStub = new(std::nothrow) AVMuxerStub(); - CHECK_AND_RETURN_RET_LOG(muxerStub != nullptr, nullptr, "Failed to create muxer service stub"); - - int32_t ret = muxerStub->InitStub(); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init AVMuxerStub"); - return muxerStub; -} - -AVMuxerStub::AVMuxerStub() -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); -} - -AVMuxerStub::~AVMuxerStub() -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); -} - -int32_t AVMuxerStub::InitStub() -{ - muxerServer_ = AVMuxerServer::Create(); - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Failed to create muxer server"); - - muxerFuncs_[INIT] = &AVMuxerStub::Init; - muxerFuncs_[SET_LOCATION] = &AVMuxerStub::SetLocation; - muxerFuncs_[SET_ROTATION] = &AVMuxerStub::SetRotation; - muxerFuncs_[SET_PARAMETER] = &AVMuxerStub::SetParameter; - muxerFuncs_[ADD_TRACK] = &AVMuxerStub::AddTrack; - muxerFuncs_[START] = &AVMuxerStub::Start; - muxerFuncs_[WRITE_SAMPLE_BUFFER] = &AVMuxerStub::WriteSampleBuffer; - muxerFuncs_[STOP] = &AVMuxerStub::Stop; - muxerFuncs_[DESTROY_STUB] = &AVMuxerStub::DestroyStub; - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::DestroyStub() -{ - muxerServer_ = nullptr; - AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::MUXER, AsObject()); - return AVCS_ERR_OK; -} - -int AVMuxerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) -{ - AVCODEC_LOGI("Stub: OnRemoteRequest of code: %{public}u is received", code); - - auto remoteDescriptor = data.ReadInterfaceToken(); - if (AVMuxerStub::GetDescriptor() != remoteDescriptor) { - AVCODEC_LOGE("Invalid descriptor"); - return AVCS_ERR_INVALID_OPERATION; - } - - auto itFunc = muxerFuncs_.find(code); - if (itFunc != muxerFuncs_.end()) { - auto memberFunc = itFunc->second; - if (memberFunc != nullptr) { - int32_t ret = -1; - COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), - "AVMuxerStub::OnRemoteRequest"); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call memberFunc"); - return AVCS_ERR_OK; - } - } - AVCODEC_LOGW("Failed to find corresponding function"); - return IPCObjectStub::OnRemoteRequest(code, data, reply, option); -} - -int32_t AVMuxerStub::Init() -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->Init(); -} - - -int32_t AVMuxerStub::SetLocation(float latitude, float longitude) -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->SetLocation(latitude, longitude); -} - -int32_t AVMuxerStub::SetRotation(int32_t rotation) -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->SetRotation(rotation); -} - -int32_t AVMuxerStub::SetParameter(const Format &generalFormat) -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->SetParameter(generalFormat); -} - -int32_t AVMuxerStub::AddTrack(uint32_t &trackIndex, const Format &trackFormat) -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->AddTrack(trackIndex, trackFormat); -} - -int32_t AVMuxerStub::Start() -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->Start(); -} - -int32_t AVMuxerStub::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->WriteSampleBuffer(trackIndex, sampleBuffer, info); -} - -int32_t AVMuxerStub::Stop() -{ - CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "muxer service is nullptr"); - return muxerServer_->Stop(); -} - -int32_t AVMuxerStub::DumpInfo(int32_t fd) -{ - std::string dumpInfo; - dumpInfo += "# AVMuxerStub"; - GetDumpInfo(dumpInfo); - - CHECK_AND_RETURN_RET_LOG(fd != -1, AVCS_ERR_INVALID_VAL, "Attempt to write to a invalid fd: %{public}d", fd); - write(fd, dumpInfo.c_str(), dumpInfo.size()); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::Init(MessageParcel &data, MessageParcel &reply) -{ - // TODO: 补充LOG说明 - (void)data; - (void)reply; - bool ret = reply.WriteInt32(Init()); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::DestroyStub(MessageParcel &data, MessageParcel &reply) -{ - (void)data; - bool ret = reply.WriteInt32(DestroyStub()); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::SetLocation(MessageParcel &data, MessageParcel &reply) -{ - float latitude = data.ReadFloat(); - float longitude = data.ReadFloat(); - bool ret = reply.WriteInt32(SetLocation(latitude, longitude)); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::SetRotation(MessageParcel &data, MessageParcel &reply) -{ - int32_t rotation = data.ReadInt32(); - bool ret = reply.WriteInt32(SetRotation(rotation)); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::SetParameter(MessageParcel &data, MessageParcel &reply) -{ - Format format; - AVCodecParcel::Unmarshalling(data, format); - bool ret = reply.WriteInt32(SetParameter(format)); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::AddTrack(MessageParcel &data, MessageParcel &reply) -{ - Format generalFormat; - uint32_t trackIndex = data.ReadInt32(); - (void)AVCodecParcel::Unmarshalling(data, generalFormat); - bool ret = reply.WriteInt32(AddTrack(trackIndex, generalFormat)); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::Start(MessageParcel &data, MessageParcel &reply) -{ - (void)data; - bool ret = reply.WriteInt32(Start()); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::WriteSampleBuffer(MessageParcel &data, MessageParcel &reply) -{ - (void)data; - (void)reply; - uint32_t trackIndex = data.ReadInt32(); - std::shared_ptr sampleBuffer = ReadAVSharedMemoryFromParcel(data); - AVCodecBufferInfo bufferInfo; - bufferInfo.presentationTimeUs = data.ReadInt64(); - bufferInfo.size = data.ReadInt32(); - bufferInfo.offset = data.ReadInt32(); - bool ret = reply.WriteInt32(WriteSampleBuffer(trackIndex, sampleBuffer, bufferInfo)); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::Stop(MessageParcel &data, MessageParcel &reply) -{ - (void)data; - bool ret = reply.WriteInt32(Stop()); - CHECK_AND_RETURN_RET_LOG(ret, AVCS_ERR_INVALID_OPERATION, "MessageParcel write failed"); - return AVCS_ERR_OK; -} - -int32_t AVMuxerStub::GetDumpInfo(std::string& dumpInfo) -{ - dumpInfo += "## pid: " + std::to_string(getpid()); - dumpInfo += "## uid: " + std::to_string(getuid()); - return AVCS_ERR_OK; -} -} // namespace Media -} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/ipc/include/i_avmuxer_service.h b/services/services/muxer/ipc/i_standard_muxer_service.h similarity index 63% rename from services/services/muxer/ipc/include/i_avmuxer_service.h rename to services/services/muxer/ipc/i_standard_muxer_service.h index 91da33755..c43ed1603 100644 --- a/services/services/muxer/ipc/include/i_avmuxer_service.h +++ b/services/services/muxer/ipc/i_standard_muxer_service.h @@ -16,39 +16,37 @@ #ifndef I_STANDARD_MUXER_SERVICE_H #define I_STANDARD_MUXER_SERVICE_H -#include "avcodec_info.h" -#include "avcodec_common.h" +#include "i_muxer_service.h" #include "iremote_proxy.h" namespace OHOS { namespace Media { -class IAVMuxerService : public IRemoteBroker { +class IStandardMuxerService : public IRemoteBroker { public: - virtual ~IAVMuxerService() = default; - - virtual int32_t Init() = 0; + virtual ~IStandardMuxerService() = default; + virtual int32_t InitParameter(int32_t fd, OutputFormat format) = 0; virtual int32_t SetLocation(float latitude, float longitude) = 0; virtual int32_t SetRotation(int32_t rotation) = 0; - virtual int32_t SetParameter(const Format &generalFormat) = 0; - virtual int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) = 0; + virtual int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) = 0; virtual int32_t Start() = 0; - virtual int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) = 0; + virtual int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) = 0; virtual int32_t Stop() = 0; + virtual void Release() = 0; + virtual int32_t DestroyStub() = 0; - virtual int32_t DestroyStub() = 0; enum MuxerServiceMsg { - INIT, + INIT_PARAMETER = 0, SET_LOCATION, SET_ROTATION, - SET_PARAMETER, ADD_TRACK, START, WRITE_SAMPLE_BUFFER, STOP, - DESTROY_STUB, + RELEASE, + DESTROY, }; - - DECLARE_INTERFACE_DESCRIPTOR(u"IAVMuxerService"); + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardMuxerServiceq1a"); }; } // namespace Media } // namespace OHOS diff --git a/services/services/muxer/ipc/muxer_service_proxy.cpp b/services/services/muxer/ipc/muxer_service_proxy.cpp new file mode 100644 index 000000000..e386b9de1 --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_proxy.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer_service_proxy.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avsharedmemory_ipc.h" +#include "avcodec_parcel.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServiceProxy"}; +} + +namespace OHOS { +namespace Media { +MuxerServiceProxy::MuxerServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +MuxerServiceProxy::~MuxerServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t MuxerServiceProxy::InitParameter(int32_t fd, OutputFormat format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + CHECK_AND_RETURN_RET_LOG(data.WriteFileDescriptor(fd), AVCS_ERR_UNKNOWN, "WriteFileDescriptor failed!"); + CHECK_AND_RETURN_RET_LOG(data.WriteInt32(format), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); + + int error = Remote()->SendRequest(INIT_PARAMETER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Call InitParameter failed, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::SetLocation(float latitude, float longitude) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + CHECK_AND_RETURN_RET_LOG(data.WriteFloat(latitude), AVCS_ERR_UNKNOWN, "WriteFloat failed!"); + CHECK_AND_RETURN_RET_LOG(data.WriteFloat(longitude), AVCS_ERR_UNKNOWN, "WriteFloat failed!"); + + int32_t ret = Remote()->SendRequest(SET_LOCATION, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "SetLocation failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::SetRotation(int32_t rotation) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + CHECK_AND_RETURN_RET_LOG(data.WriteInt32(rotation), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); + + int32_t ret = Remote()->SendRequest(SET_ROTATION, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "SetRotation failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + AVCodecParcel::Marshalling(data, trackDesc); + + int32_t ret = Remote()->SendRequest(ADD_TRACK, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "AddTrack failed, error: %{public}d", ret); + trackIndex = reply.ReadInt32(); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::Start() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + int32_t ret = Remote()->SendRequest(START, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Start failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + WriteAVSharedMemoryToParcel(sampleBuffer, data); + CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.trackIndex), AVCS_ERR_UNKNOWN, "Write track index failed!"); + CHECK_AND_RETURN_RET_LOG(data.WriteInt64(info.timeUs), AVCS_ERR_UNKNOWN, "Write timeUs failed!"); + CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.size), AVCS_ERR_UNKNOWN, "Write size failed!"); + CHECK_AND_RETURN_RET_LOG(data.WriteUint32(info.flags), AVCS_ERR_UNKNOWN, "Write flags failed!"); + + int32_t ret = Remote()->SendRequest(WRITE_SAMPLE_BUFFER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "WriteSampleBuffer failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::Stop() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + int32_t ret = Remote()->SendRequest(STOP, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Stop failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +int32_t MuxerServiceProxy::DestroyStub() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!!"); + + int ret = Remote()->SendRequest(DESTROY, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Call DestroyStub failed, error: %{public}d", ret); + return reply.ReadInt32(); +} + +void MuxerServiceProxy::Release() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(MuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_LOG(token, "Write descriptor failed!"); + + int ret = Remote()->SendRequest(RELEASE, data, reply, option); + CHECK_AND_RETURN_LOG(ret == AVCS_ERR_OK, " Call Release failed, error: %{public}d", ret); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/ipc/include/avmuxer_proxy.h b/services/services/muxer/ipc/muxer_service_proxy.h similarity index 61% rename from services/services/muxer/ipc/include/avmuxer_proxy.h rename to services/services/muxer/ipc/muxer_service_proxy.h index 12abdbfc7..b75ad2fb7 100644 --- a/services/services/muxer/ipc/include/avmuxer_proxy.h +++ b/services/services/muxer/ipc/muxer_service_proxy.h @@ -16,27 +16,26 @@ #ifndef MUXER_SERVICE_PROXY_H #define MUXER_SERVICE_PROXY_H -#include "i_avmuxer_service.h" +#include "i_standard_muxer_service.h" namespace OHOS { namespace Media { -class AVMuxerProxy : public IRemoteProxy, public NoCopyable { +class MuxerServiceProxy : public IRemoteProxy, public NoCopyable { public: - explicit AVMuxerProxy(const sptr &impl); - virtual ~AVMuxerProxy(); + explicit MuxerServiceProxy(const sptr &impl); + virtual ~MuxerServiceProxy(); - int32_t Init() override; + int32_t InitParameter(int32_t fd, OutputFormat format) override; int32_t SetLocation(float latitude, float longitude) override; int32_t SetRotation(int32_t rotation) override; - int32_t SetParameter(const Format &generalFormat) override; - int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; int32_t Start() override; - int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) override; + int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) override; int32_t Stop() override; - + void Release() override; int32_t DestroyStub() override; private: - static inline BrokerDelegator delegator_; + static inline BrokerDelegator delegator_; }; } // namespace Media } // namespace OHOS diff --git a/services/services/muxer/ipc/muxer_service_stub.cpp b/services/services/muxer/ipc/muxer_service_stub.cpp new file mode 100644 index 000000000..2f5439848 --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_stub.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer_service_stub.h" +#include "avcodec_server_manager.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avsharedmemory_ipc.h" +#include "avcodec_parcel.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServiceStub"}; +} + +namespace OHOS { +namespace Media { +sptr MuxerServiceStub::Create() +{ + sptr muxerStub = new(std::nothrow) MuxerServiceStub(); + CHECK_AND_RETURN_RET_LOG(muxerStub != nullptr, nullptr, "Create muxer service stub failed"); + + int32_t ret = muxerStub->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init MuxerServiceStub failed to "); + return muxerStub; +} + +MuxerServiceStub::MuxerServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +MuxerServiceStub::~MuxerServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t MuxerServiceStub::Init() +{ + muxerServer_ = MuxerServer::Create(); + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Create muxer server failed"); + + muxerFuncs_[INIT_PARAMETER] = &MuxerServiceStub::InitParameter; + muxerFuncs_[SET_LOCATION] = &MuxerServiceStub::SetLocation; + muxerFuncs_[SET_ROTATION] = &MuxerServiceStub::SetRotation; + muxerFuncs_[ADD_TRACK] = &MuxerServiceStub::AddTrack; + muxerFuncs_[START] = &MuxerServiceStub::Start; + muxerFuncs_[WRITE_SAMPLE_BUFFER] = &MuxerServiceStub::WriteSampleBuffer; + muxerFuncs_[STOP] = &MuxerServiceStub::Stop; + muxerFuncs_[RELEASE] = &MuxerServiceStub::Release; + muxerFuncs_[DESTROY] = &MuxerServiceStub::DestroyStub; + return AVCS_ERR_OK; +} + +int MuxerServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + auto remoteDescriptor = data.ReadInterfaceToken(); + if (MuxerServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = muxerFuncs_.find(code); + if (itFunc != muxerFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = (this->*memberFunc)(data, reply); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call memberFunc"); + return AVCS_ERR_OK; + } + } + AVCODEC_LOGW("Failed to find corresponding function"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t MuxerServiceStub::InitParameter(int32_t fd, OutputFormat format) +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->InitParameter(fd, format); +} + +int32_t MuxerServiceStub::SetLocation(float latitude, float longitude) +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->SetLocation(latitude, longitude); +} + +int32_t MuxerServiceStub::SetRotation(int32_t rotation) +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->SetRotation(rotation); +} + +int32_t MuxerServiceStub::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->AddTrack(trackIndex, trackDesc); +} + +int32_t MuxerServiceStub::Start() +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->Start(); +} + +int32_t MuxerServiceStub::WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) +{ + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleData is nullptr"); + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->WriteSampleBuffer(sampleBuffer, info); +} + +int32_t MuxerServiceStub::Stop() +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerServer_->Stop(); +} + +void MuxerServiceStub::Release() +{ + CHECK_AND_RETURN_LOG(muxerServer_ != nullptr, "Muxer Service does not exist"); + muxerServer_->Release(); +} + +int32_t MuxerServiceStub::DestroyStub() +{ + muxerServer_ = nullptr; + AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::MUXER, AsObject()); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::DumpInfo(int32_t fd) +{ + CHECK_AND_RETURN_RET_LOG(muxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return std::static_pointer_cast(muxerServer_)->DumpInfo(fd); +} + +int32_t MuxerServiceStub::InitParameter(MessageParcel &data, MessageParcel &reply) +{ + int32_t fd = data.ReadFileDescriptor(); + OutputFormat format = static_cast(data.ReadInt32()); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(InitParameter(fd, format)), AVCS_ERR_UNKNOWN, "Reply InitParameter failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::SetLocation(MessageParcel &data, MessageParcel &reply) +{ + float latitude = data.ReadFloat(); + float longitude = data.ReadFloat(); + int32_t ret = SetLocation(latitude, longitude); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply SetLocation failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::SetRotation(MessageParcel &data, MessageParcel &reply) +{ + int32_t rotation = data.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SetRotation(rotation)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::AddTrack(MessageParcel &data, MessageParcel &reply) +{ + MediaDescription trackDesc; + (void)AVCodecParcel::Unmarshalling(data, trackDesc); + int32_t trackIndex = -1; + int32_t ret = AddTrack(trackIndex, trackDesc); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(trackIndex), AVCS_ERR_UNKNOWN, "Reply AddTrack failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply AddTrack failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::Start(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Start()), AVCS_ERR_UNKNOWN, "Reply Start failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::WriteSampleBuffer(MessageParcel &data, MessageParcel &reply) +{ + std::shared_ptr sampleBuffer = ReadAVSharedMemoryFromParcel(data); + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_UNKNOWN, "Read sampleBuffer from parcel failed!"); + TrackSampleInfo info; + info.trackIndex = data.ReadUint32(); + info.timeUs = data.ReadInt64(); + info.size = data.ReadUint32(); + info.flags = data.ReadUint32(); + int32_t ret = WriteSampleBuffer(sampleBuffer, info); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply WriteSampleBuffer failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::Stop(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Stop()), AVCS_ERR_UNKNOWN, "Reply Stop failed!"); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::Release(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + (void)reply; + Release(); + return AVCS_ERR_OK; +} + +int32_t MuxerServiceStub::DestroyStub(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN, "Reply DestroyStub failed!"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/ipc/include/avmuxer_stub.h b/services/services/muxer/ipc/muxer_service_stub.h similarity index 64% rename from services/services/muxer/ipc/include/avmuxer_stub.h rename to services/services/muxer/ipc/muxer_service_stub.h index f807a2ccf..0ea5dd2dc 100644 --- a/services/services/muxer/ipc/include/avmuxer_stub.h +++ b/services/services/muxer/ipc/muxer_service_stub.h @@ -16,50 +16,46 @@ #ifndef MUXER_SERVICE_STUB_H #define MUXER_SERVICE_STUB_H -#include -#include "i_avmuxer_service.h" -#include "avmuxer_server.h" +#include "i_standard_muxer_service.h" +#include "muxer_server.h" #include "iremote_stub.h" namespace OHOS { namespace Media { -class AVMuxerStub : public IRemoteStub, public NoCopyable { +class MuxerServiceStub : public IRemoteStub, public NoCopyable { public: - static sptr Create(); - virtual ~AVMuxerStub(); + static sptr Create(); + virtual ~MuxerServiceStub(); int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; - using MuxerStubFunc = int32_t(AVMuxerStub::*)(MessageParcel &data, MessageParcel &reply); + using MuxerStubFunc = int32_t(MuxerServiceStub::*)(MessageParcel &data, MessageParcel &reply); - int32_t Init() override; + int32_t InitParameter(int32_t fd, OutputFormat format) override; int32_t SetLocation(float latitude, float longitude) override; int32_t SetRotation(int32_t rotation) override; - int32_t SetParameter(const Format &generalFormat) override; - int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; int32_t Start() override; - int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) override; + int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) override; int32_t Stop() override; - - int32_t DumpInfo(int32_t fd); + void Release() override; int32_t DestroyStub() override; + int32_t DumpInfo(int32_t fd); + private: - AVMuxerStub(); - int32_t InitStub(); - int32_t Init(MessageParcel &data, MessageParcel &reply); + MuxerServiceStub(); + int32_t Init(); + int32_t InitParameter(MessageParcel &data, MessageParcel &reply); int32_t SetLocation(MessageParcel &data, MessageParcel &reply); int32_t SetRotation(MessageParcel &data, MessageParcel &reply); - int32_t SetParameter(MessageParcel &data, MessageParcel &reply); int32_t AddTrack(MessageParcel &data, MessageParcel &reply); int32_t Start(MessageParcel &data, MessageParcel &reply); int32_t WriteSampleBuffer(MessageParcel &data, MessageParcel &reply); int32_t Stop(MessageParcel &data, MessageParcel &reply); - - int32_t GetDumpInfo(std::string& dumpInfo); + int32_t Release(MessageParcel &data, MessageParcel &reply); int32_t DestroyStub(MessageParcel &data, MessageParcel &reply); - std::mutex mutex_; - std::shared_ptr muxerServer_ = nullptr; + std::shared_ptr muxerServer_ {nullptr}; std::map muxerFuncs_; }; } // namespace Media } // namespace OHOS -#endif \ No newline at end of file +#endif // MUXER_SERVICE_STUB_H \ No newline at end of file diff --git a/services/services/muxer/server/avmuxer_server.cpp b/services/services/muxer/server/avmuxer_server.cpp deleted file mode 100644 index 9b0d02c6f..000000000 --- a/services/services/muxer/server/avmuxer_server.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "avmuxer_server.h" -#include "avcodec_errors.h" -#include "avcodec_log.h" - -namespace { - constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerServer"}; -} - -namespace OHOS { -namespace Media { -std::shared_ptr AVMuxerServer::Create() -{ - std::shared_ptr muxerServer = std::make_shared(); - CHECK_AND_RETURN_RET_LOG(muxerServer != nullptr, nullptr, "Muxer Service does not exist"); - int32_t ret = muxerServer->InitServer(); - CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init muxer server"); - return muxerServer; -} - -AVMuxerServer::AVMuxerServer() -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); -} - -AVMuxerServer::~AVMuxerServer() -{ - AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); -} - -int32_t AVMuxerServer::InitServer() -{ - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::Init() -{ - std::lock_guard lock(mutex_); - - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::SetLocation(float latitude, float longitude) -{ - // TODO:achieve it - (void)latitude; - (void)longitude; - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::SetRotation(int32_t rotation) -{ - // TODO:achieve it - (void)rotation; - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::SetParameter(const Format &generalFormat) -{ - // TODO:achieve it - (void)generalFormat; - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::AddTrack(uint32_t &trackIndex, const Format &trackFormat) -{ - // TODO:achieve it - (void)trackIndex; - (void)trackFormat; - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::Start() -{ - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) -{ - // TODO:achieve it - (void)trackIndex; - (void)sampleBuffer; - (void)info; - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} - -int32_t AVMuxerServer::Stop() -{ - std::lock_guard lock(mutex_); - - return AVCS_ERR_OK; -} -} // namespace Media -} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/server/muxer_server.cpp b/services/services/muxer/server/muxer_server.cpp new file mode 100644 index 000000000..42a107672 --- /dev/null +++ b/services/services/muxer/server/muxer_server.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "muxer_server.h" +#include +#include +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "ipc_skeleton.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerServer"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr MuxerServer::Create() +{ + std::shared_ptr muxerServer = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(muxerServer != nullptr, nullptr, "Muxer Service does not exist"); + return muxerServer; +} + +MuxerServer::MuxerServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + appUid_ = IPCSkeleton::GetCallingUid(); + appPid_ = IPCSkeleton::GetCallingPid(); +} + +MuxerServer::~MuxerServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); + muxerEngine_ = nullptr; +} + +int32_t MuxerServer::InitParameter(int32_t fd, OutputFormat format) +{ + muxerEngine_ = IMuxerEngineFactory::CreateMuxerEngine(appUid_, appPid_, fd, format); + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Create muxer engine failed"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::SetLocation(float latitude, float longitude) +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->SetLocation(latitude, longitude); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetLocation"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::SetRotation(int32_t rotation) +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->SetRotation(rotation); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->AddTrack(trackIndex, trackDesc); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call AddTrack"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::Start() +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Start"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) +{ + CHECK_AND_RETURN_RET_LOG(sampleBuffer != nullptr, AVCS_ERR_INVALID_VAL, "sampleData is nullptr"); + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->WriteSampleBuffer(sampleBuffer, info); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call WriteSampleBuffer"); + return AVCS_ERR_OK; +} + +int32_t MuxerServer::Stop() +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + int32_t ret = muxerEngine_->Stop(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call Stop"); + return AVCS_ERR_OK; +} + +void MuxerServer::Release() +{ + CHECK_AND_RETURN_LOG(muxerEngine_ != nullptr, "muxer engine does not exist"); + (void)muxerEngine_->Stop(); + muxerEngine_ = nullptr; +} + +int32_t MuxerServer::DumpInfo(int32_t fd) +{ + CHECK_AND_RETURN_RET_LOG(muxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "muxer engine does not exist"); + return muxerEngine_->DumpInfo(fd); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/muxer/server/include/avmuxer_server.h b/services/services/muxer/server/muxer_server.h similarity index 58% rename from services/services/muxer/server/include/avmuxer_server.h rename to services/services/muxer/server/muxer_server.h index 1764ab79b..df6438f31 100644 --- a/services/services/muxer/server/include/avmuxer_server.h +++ b/services/services/muxer/server/muxer_server.h @@ -17,31 +17,32 @@ #define MUXER_SERVER_H #include -#include "i_avmuxer.h" +#include "i_muxer_service.h" +#include "i_muxer_engine.h" #include "nocopyable.h" namespace OHOS { -namespace Media { -class AVMuxerServer : public IAVMuxer, public NoCopyable { +namespace Media { +class MuxerServer : public IMuxerService, public NoCopyable { public: - static std::shared_ptr Create(); - AVMuxerServer(); - ~AVMuxerServer(); + static std::shared_ptr Create(); + MuxerServer(); + ~MuxerServer(); - int32_t Init() override; + int32_t InitParameter(int32_t fd, OutputFormat format) override; int32_t SetLocation(float latitude, float longitude) override; int32_t SetRotation(int32_t rotation) override; - int32_t SetParameter(const Format &generalFormat) override; - int32_t AddTrack(uint32_t &trackIndex, const Format &trackFormat) override; + int32_t AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) override; int32_t Start() override; - int32_t WriteSampleBuffer(uint32_t trackIndex, const std::shared_ptr &sampleBuffer, AVCodecBufferInfo info) override; + int32_t WriteSampleBuffer(std::shared_ptr sampleBuffer, const TrackSampleInfo &info) override; int32_t Stop() override; + void Release() override; + int32_t DumpInfo(int32_t fd); private: - int32_t InitServer(); - std::mutex mutex_; - // std::shared_ptr avmuxerEngine_ = nullptr; - // uint32_t trackNum_ = 0; + std::shared_ptr muxerEngine_ = nullptr; + int32_t appUid_ = 0; + int32_t appPid_ = 0; }; } // namespace Media } // namespace OHOS diff --git a/services/services/sa_avcodec/client/avcodec_client.cpp b/services/services/sa_avcodec/client/avcodec_client.cpp index a6d61eb57..e8e741bac 100644 --- a/services/services/sa_avcodec/client/avcodec_client.cpp +++ b/services/services/sa_avcodec/client/avcodec_client.cpp @@ -21,9 +21,6 @@ #ifdef SUPPORT_DEMUXER #include "i_avdemuxer_service.h" #endif -#ifdef SUPPORT_MUXER -#include "i_avmuxer_service.h" -#endif #ifdef SUPPORT_CODEC #include "i_standard_codec_service.h" #endif @@ -165,33 +162,33 @@ int32_t AVCodecClient::DestroyDemuxerService(std::shared_ptr demuxer #endif #ifdef SUPPORT_MUXER -std::shared_ptr AVCodecClient::CreateMuxerService() +std::shared_ptr AVCodecClient::CreateMuxerService() { std::lock_guard lock(mutex_); if (!IsAlived()) { - AVCODEC_LOGE("av_codec service does not exist."); + AVCODEC_LOGE("avcodec service does not exist."); return nullptr; } sptr object = avCodecProxy_->GetSubSystemAbility( IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_MUXER, listenerStub_->AsObject()); - CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Muxer proxy object is nullptr."); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "muxer proxy object is nullptr."); - sptr muxerProxy = iface_cast(object); - CHECK_AND_RETURN_RET_LOG(muxerProxy != nullptr, nullptr, "Muxer proxy is nullptr."); + sptr muxerProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(muxerProxy != nullptr, nullptr, "muxer proxy is nullptr."); - std::shared_ptr muxerClient = AVMuxerClient::Create(muxerProxy); - CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, nullptr, "Failed to create muxer client."); + std::shared_ptr muxer = MuxerClient::Create(muxerProxy); + CHECK_AND_RETURN_RET_LOG(muxer != nullptr, nullptr, "failed to create muxer client."); - muxerClientList_.push_back(muxerClient); - return muxerClient; + muxerClientList_.push_back(muxer); + return muxer; } -int32_t AVCodecClient::DestroyMuxerService(std::shared_ptr muxerClient) +int32_t AVCodecClient::DestroyMuxerService(std::shared_ptr muxer) { std::lock_guard lock(mutex_); - CHECK_AND_RETURN_RET_LOG(muxerClient != nullptr, AVCS_ERR_NO_MEMORY, "muxer client is nullptr."); - muxerClientList_.remove(muxerClient); + CHECK_AND_RETURN_RET_LOG(muxer != nullptr, AVCS_ERR_NO_MEMORY, "input muxer is nullptr."); + muxerClientList_.remove(muxer); return AVCS_ERR_OK; } #endif @@ -237,7 +234,7 @@ sptr AVCodecClient::GetAVCodecProxy() CHECK_AND_RETURN_RET_LOG(samgr != nullptr, nullptr, "system ability manager is nullptr."); sptr object = nullptr; - COLLIE_LISTEN(object = samgr->GetSystemAbility(OHOS::AVCODEC_SERVICE_ID), + COLLIE_LISTEN(object = samgr->GetSystemAbility(OHOS::AV_CODEC_SERVICE_ID), "AVCodecClient::GetAVCodecProxy"); CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "avcodec object is nullptr."); @@ -295,9 +292,9 @@ void AVCodecClient::DoAVCodecServerDied() #endif #ifdef SUPPORT_MUXER for (auto &it : muxerClientList_) { - auto muxerClient = std::static_pointer_cast(it); - if (muxerClient != nullptr) { - muxerClient->AVCodecServerDied(); + auto muxer = std::static_pointer_cast(it); + if (muxer != nullptr) { + muxer->AVCodecServerDied(); } } #endif diff --git a/services/services/sa_avcodec/client/avcodec_client.h b/services/services/sa_avcodec/client/avcodec_client.h index e3f9a6a2c..977f3362e 100644 --- a/services/services/sa_avcodec/client/avcodec_client.h +++ b/services/services/sa_avcodec/client/avcodec_client.h @@ -25,7 +25,7 @@ #endif #ifdef SUPPORT_MUXER -#include "avmuxer_client.h" +#include "muxer_client.h" #endif #ifdef SUPPORT_CODEC @@ -51,8 +51,8 @@ public: #endif #ifdef SUPPORT_MUXER - std::shared_ptr CreateMuxerService() override; - int32_t DestroyMuxerService(std::shared_ptr muxerClient) override; + std::shared_ptr CreateMuxerService() override; + int32_t DestroyMuxerService(std::shared_ptr muxer) override; #endif #ifdef SUPPORT_CODEC @@ -80,7 +80,7 @@ private: std::list> demuxerClientList_; #endif #ifdef SUPPORT_MUXER - std::list> muxerClientList_; + std::list> muxerClientList_; #endif #ifdef SUPPORT_CODEC std::list> codecClientList_; diff --git a/services/services/sa_avcodec/ipc/avcodec_parcel.cpp b/services/services/sa_avcodec/ipc/avcodec_parcel.cpp index 68eab8962..07270ae76 100644 --- a/services/services/sa_avcodec/ipc/avcodec_parcel.cpp +++ b/services/services/sa_avcodec/ipc/avcodec_parcel.cpp @@ -47,7 +47,7 @@ bool AVCodecParcel::Marshalling(MessageParcel &parcel, const Format &format) break; case FORMAT_TYPE_ADDR: (void)parcel.WriteInt32(static_cast(it->second.size)); - (void)parcel.WriteBuffer(reinterpret_cast(it->second.addr), it->second.size); + (void)parcel.WriteUnpadBuffer(reinterpret_cast(it->second.addr), it->second.size); break; default: AVCODEC_LOGE("fail to Marshalling Key: %{public}s", it->first.c_str()); @@ -55,6 +55,7 @@ bool AVCodecParcel::Marshalling(MessageParcel &parcel, const Format &format) } AVCODEC_LOGD("success to Marshalling Key: %{public}s", it->first.c_str()); } + return true; } @@ -82,7 +83,7 @@ bool AVCodecParcel::Unmarshalling(MessageParcel &parcel, Format &format) break; case FORMAT_TYPE_ADDR: { auto addrSize = parcel.ReadInt32(); - auto addr = parcel.ReadBuffer(static_cast(addrSize)); + auto addr = parcel.ReadUnpadBuffer(static_cast(addrSize)); if (addr == nullptr) { AVCODEC_LOGE("fail to ReadBuffer Key: %{public}s", key.c_str()); return false; diff --git a/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h b/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h index 7f49d1eab..4368b6404 100644 --- a/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h +++ b/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef I_STANDARD_AVCODEC_LISTENER_H #define I_STANDARD_AVCODEC_LISTENER_H diff --git a/services/services/sa_avcodec/server/avcodec_server.cpp b/services/services/sa_avcodec/server/avcodec_server.cpp index 503621dff..28d4ceec4 100644 --- a/services/services/sa_avcodec/server/avcodec_server.cpp +++ b/services/services/sa_avcodec/server/avcodec_server.cpp @@ -26,7 +26,7 @@ constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecSer namespace OHOS { namespace Media { -REGISTER_SYSTEM_ABILITY_BY_ID(AVCodecServer, AVCODEC_SERVICE_ID, true) +REGISTER_SYSTEM_ABILITY_BY_ID(AVCodecServer, AV_CODEC_SERVICE_ID, true) AVCodecServer::AVCodecServer(int32_t systemAbilityId, bool runOnCreate) : SystemAbility(systemAbilityId, runOnCreate) { AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); diff --git a/services/services/sa_avcodec/server/avcodec_server_manager.cpp b/services/services/sa_avcodec/server/avcodec_server_manager.cpp index 0450ac464..47693d0c3 100644 --- a/services/services/sa_avcodec/server/avcodec_server_manager.cpp +++ b/services/services/sa_avcodec/server/avcodec_server_manager.cpp @@ -33,7 +33,7 @@ #include "avdemuxer_stub.h" #endif #ifdef SUPPORT_MUXER -#include "avmuxer_stub.h" +#include "muxer_service_stub.h" #endif #ifdef SUPPORT_SOURCE #include "source_service_stub.h" @@ -100,10 +100,10 @@ int32_t AVCodecServerManager::Dump(int32_t fd, const std::vector #endif #ifdef SUPPORT_MUXER - dumpString += "------------------AVMuxerServer------------------\n"; + dumpString += "------------------MuxerServer------------------\n"; if (WriteInfo(fd, dumpString, dumperTbl_[StubType::MUXER], argSets.find(u"muxer") != argSets.end()) != OHOS::NO_ERROR) { - AVCODEC_LOGW("Failed to write AVMuxerServer information"); + AVCODEC_LOGW("Failed to write MuxerServer information"); return OHOS::INVALID_OPERATION; } #endif @@ -285,19 +285,19 @@ sptr AVCodecServerManager::CreateMuxerStubObject() "Please release the applied resources.", muxerStubMap_.size()); return nullptr; } - sptr stub = AVMuxerStub::Create(); - if (stub == nullptr) { - AVCODEC_LOGE("Failed to create AVMuxerStub"); + sptr muxerStub = MuxerServiceStub::Create(); + if (muxerStub == nullptr) { + AVCODEC_LOGE("Create MuxerServiceStub failed"); return nullptr; } - sptr object = stub->AsObject(); + sptr object = muxerStub->AsObject(); if (object != nullptr) { pid_t pid = IPCSkeleton::GetCallingPid(); muxerStubMap_[object] = pid; Dumper dumper; - dumper.entry_ = [stub](int32_t fd) -> int32_t { - return stub->DumpInfo(fd); + dumper.entry_ = [muxer = muxerStub](int32_t fd) -> int32_t { + return muxer->DumpInfo(fd); }; dumper.pid_ = pid; dumper.uid_ = IPCSkeleton::GetCallingUid(); @@ -379,7 +379,8 @@ void AVCodecServerManager::DestroyStubObject(StubType type, sptr case MUXER: { auto it = find_if(muxerStubMap_.begin(), muxerStubMap_.end(), compare_func); if (it != muxerStubMap_.end()) { - AVCODEC_LOGD("destroy muxer stub services(%{public}zu) pid(%{public}d).", muxerStubMap_.size(), pid); + AVCODEC_LOGD("destroy muxer stub services(%{public}zu) pid(%{public}d).", + muxerStubMap_.size(), pid); (void)muxerStubMap_.erase(it); return; } diff --git a/services/services/source/ipc/source_service_stub.cpp b/services/services/source/ipc/source_service_stub.cpp index 431f0e7b0..6bd047baf 100644 --- a/services/services/source/ipc/source_service_stub.cpp +++ b/services/services/source/ipc/source_service_stub.cpp @@ -146,19 +146,19 @@ int32_t SourceServiceStub::DumpInfo(int32_t fd) int32_t SourceServiceStub::Init(MessageParcel &data, MessageParcel &reply) { std::string uri = data.ReadString(); - CHECK_AND_RETURN_RET(reply.WriteInt32(Init(uri)), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Init(uri)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); return AVCS_ERR_OK; } int32_t SourceServiceStub::GetTrackCount(MessageParcel &data, MessageParcel &reply) { - CHECK_AND_RETURN_RET(reply.WriteInt32(GetTrackCount()), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(GetTrackCount()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); return AVCS_ERR_OK; } int32_t SourceServiceStub::Destroy(MessageParcel &data, MessageParcel &reply) { - CHECK_AND_RETURN_RET(reply.WriteInt32(Destroy()), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Destroy()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); return AVCS_ERR_OK; } @@ -167,7 +167,7 @@ int32_t SourceServiceStub::SetParameter(MessageParcel &data, MessageParcel &repl Format param; (void)AVCodecParcel::Unmarshalling(data, param); uint32_t trackId = data.ReadUint32(); - CHECK_AND_RETURN_RET(reply.WriteInt32(SetParameter(param, trackId)), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SetParameter(param, trackId)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); return AVCS_ERR_OK; } @@ -175,20 +175,20 @@ int32_t SourceServiceStub::GetTrackFormat(MessageParcel &data, MessageParcel &re { uint32_t trackId = data.ReadUint32(); Format format; - CHECK_AND_RETURN_RET(reply.WriteInt32(GetTrackFormat(format, trackId)), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(GetTrackFormat(format, trackId)), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); AVCodecParcel::Marshalling(reply, format); return AVCS_ERR_OK; } int32_t SourceServiceStub::GetSourceAttr(MessageParcel &data, MessageParcel &reply) { - CHECK_AND_RETURN_RET(reply.WriteUint64(GetSourceAttr()), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteUint64(GetSourceAttr()), AVCS_ERR_UNKNOWN, "WriteUint64 failed!"); return AVCS_ERR_OK; } int32_t SourceServiceStub::DestroyStub(MessageParcel &data, MessageParcel &reply) { - CHECK_AND_RETURN_RET(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(DestroyStub()), AVCS_ERR_UNKNOWN, "WriteInt32 failed!"); return AVCS_ERR_OK; } diff --git a/services/utils/include/block_queue.h b/services/utils/include/block_queue.h new file mode 100644 index 000000000..b226b3a0a --- /dev/null +++ b/services/utils/include/block_queue.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UTILS_BLOCK_QUEUE_H +#define UTILS_BLOCK_QUEUE_H +#include +#include +#include +#include +#include "avcodec_log.h" + +namespace OHOS { +namespace Media { +namespace { +constexpr size_t DEFAULT_QUEUE_SIZE = 10; +} + +template +class BlockQueue { +public: + explicit BlockQueue(std::string name, size_t capacity = DEFAULT_QUEUE_SIZE) + : name_(std::move(name)), capacity_(capacity), isActive_(true) + { + } + + ~BlockQueue() = default; + + size_t Size() + { + std::unique_lock lock(mutex_); + return que_.size(); + } + + size_t Capacity() + { + return capacity_; + } + + size_t Empty() + { + std::unique_lock lock(mutex_); + return que_.empty(); + } + + bool Push(const T& block) + { + AVCODEC_LOGD("block queue %{public}s Push enter.", name_.c_str()); + std::unique_lock lock(mutex_); + if (!isActive_) { + AVCODEC_LOGD("block queue %{public}s is inactive for Push.", name_.c_str()); + return false; + } + if (que_.size() >= capacity_) { + AVCODEC_LOGD("block queue %{public}s is full, please waiting for Pop.", name_.c_str()); + condFull_.wait(lock, [this] { return !isActive_ || que_.size() < capacity_; }); + } + if (!isActive_) { + AVCODEC_LOGD("block queue %{public}s: inactive: %{public}d, isFull: %{public}d.", + name_.c_str(), isActive_.load(), que_.size() < capacity_); + return false; + } + que_.push(block); + condEmpty_.notify_one(); + AVCODEC_LOGD("block queue %{public}s Push ok.", name_.c_str()); + return true; + } + + T Pop() + { + AVCODEC_LOGD("block queue %{public}s Pop enter.", name_.c_str()); + std::unique_lock lock(mutex_); + if (que_.empty() && !isActive_) { + AVCODEC_LOGD("block queue %{public}s is inactive for Pop.", name_.c_str()); + return {}; + } else if (que_.empty() && isActive_) { + AVCODEC_LOGD("block queue %{public}s is empty, please waiting for Push.", name_.c_str()); + condEmpty_.wait(lock, [this] { return !isActive_ || !que_.empty(); }); + } + if (que_.empty()) { + AVCODEC_LOGD("block queue %{public}s: inactive: %{public}d, size: %{public}d.", + name_.c_str(), isActive_.load(), que_.size()); + return {}; + } + T element = que_.front(); + que_.pop(); + condFull_.notify_one(); + AVCODEC_LOGD("block queue %{public}s Pop ok.", name_.c_str()); + return element; + } + + void Clear() + { + std::unique_lock lock(mutex_); + ClearUnprotected(); + } + + void SetActive(bool active, bool cleanData = true) + { + std::unique_lock lock(mutex_); + AVCODEC_LOGD("SetActive %{public}s: %{public}d.", name_.c_str(), isActive_.load()); + isActive_ = active; + if (!active) { + if (cleanData) { + ClearUnprotected(); + } + condEmpty_.notify_one(); + } + } + +private: + void ClearUnprotected() + { + if (que_.empty()) { + return; + } + bool needNotify = que_.size() == capacity_; + std::queue().swap(que_); + if (needNotify) { + condFull_.notify_one(); + } + } + + std::mutex mutex_; + std::condition_variable condFull_; + std::condition_variable condEmpty_; + std::queue que_; + std::string name_; + const size_t capacity_; + std::atomic isActive_; + const OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "BlockQueue"}; +}; +} // namespace Media +} // namespace OHOS +#endif // !UTILS_BLOCK_QUEUE_H diff --git a/test/BUILD.gn b/test/BUILD.gn index 954d439c3..f11818169 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -14,17 +14,21 @@ import("//build/ohos.gni") import("//foundation/multimedia/av_codec/config.gni") +group("av_codec_demo_test") { + testonly = true + deps = [] + if (multimedia_av_codec_support_test) { + deps += [ "nativedemo:av_codec_demo" ] + } +} + group("av_codec_unit_test") { testonly = true deps = [] -} - -group("av_codec_fuzz_test") { - testonly = true - deps = [] -} - -group("av_codec_demo_test") { - testonly = true - deps = [ "//foundation/multimedia/av_codec/test/nativedemo:av_codec_demo" ] + if (multimedia_av_codec_support_test) { + deps += [ + "unittest:av_muxer_unit_test", + "unittest:format_unit_test", + ] + } } diff --git a/test/nativedemo/BUILD.gn b/test/nativedemo/BUILD.gn index 34e0ae8c5..0b711c20b 100644 --- a/test/nativedemo/BUILD.gn +++ b/test/nativedemo/BUILD.gn @@ -16,18 +16,21 @@ import("//foundation/multimedia/av_codec/config.gni") ohos_executable("av_codec_demo") { include_dirs = [ + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer", + "//foundation/multimedia/av_codec/interfaces/kits/c", + "//foundation/multimedia/av_codec/interfaces/inner_api/native", + "//foundation/multimedia/av_codec/services/services/factory", + "//foundation/multimedia/av_codec/services/engine/plugin/core", + "//foundation/multimedia/av_codec/services/engine/plugin/interface", + "//foundation/multimedia/av_codec/services/dfx/include", + "//foundation/multimedia/av_codec/services/utils/include", "./av_codec_audio", "./audio_demo", "./include", - "//foundation/multimedia/av_codec/interfaces/inner_api/native", - "//foundation/multimedia/av_codec/interfaces/kits/c", - "//foundation/multimedia/av_codec/services/utils/include", - "//foundation/multimedia/av_codec/services/dfx/include", ] cflags = [ "-Wall", - "-std=c++17", "-fno-rtti", "-fno-exceptions", "-fno-common", @@ -48,15 +51,27 @@ ohos_executable("av_codec_demo") { "-Wno-deprecated-declarations", ] + cflags_cc = cflags + cflags_cc += ["-std=c++17"] + sources = [ - "./av_codec_demo.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/av_codec_demo.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo_base.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/avmuxer_demo_common.c", + "//foundation/multimedia/av_codec/test/nativedemo/avmuxer/native_avmuxer_demo.c", "./audio_demo/avcodec_audio_encoder_inner_demo.cpp", "./audio_demo/avcodec_audio_decoder_demo.cpp", "./audio_demo/avcodec_audio_encoder_demo.cpp" ] deps = [ + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_avmuxer", "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "//foundation/multimedia/av_codec/services/services:av_codec_service", + "//foundation/multimedia/av_codec/services/utils:av_codec_format", "//foundation/multimedia/av_codec/interfaces/kits/c:capi_packages" ] diff --git a/test/nativedemo/avmuxer/avmuxer_demo.cpp b/test/nativedemo/avmuxer/avmuxer_demo.cpp new file mode 100644 index 000000000..e9d5f9cfa --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "avmuxer_demo.h" +#include +#include +#include +#include +#include +#include +#include +#include "avcodec_errors.h" + +namespace { + extern "C" { + extern char *RUN_NORMAL; + extern char *RUN_MUL_THREAD; + } +} + +namespace OHOS { +namespace Media { + +int AVMuxerDemo::DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) +{ + if (avmuxer_ != nullptr && + avmuxer_->WriteSampleBuffer(sampleBuffer, info) == AVCS_ERR_OK) { + return 0; + } + return -1; +} + +int AVMuxerDemo::DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) +{ + int ret; + if ((ret = avmuxer_->AddTrack(trackIndex, trackDesc)) != AVCS_ERR_OK) { + std::cout<<"AVMuxerDemo::DoAddTrack failed! ret:"<SetLocation(10, 10) != AVCS_ERR_OK + || avmuxer_->SetRotation(0) != AVCS_ERR_OK) { + std::cout<<"set failed!"<Start() != AVCS_ERR_OK) { + return; + } + + std::cout << "start muxer success" << std::endl; + + if (coverParams_ != nullptr) { + WriteCoverSample(); + } + + std::cout<<"AVMuxerDemo::DoRunMuxer runMode is : "< vecThread; + vecThread.emplace_back(MulThdWriteTrackSample, this, audioTrackId_, audioFile_); + vecThread.emplace_back(MulThdWriteTrackSample, this, videoTrackId_, videoFile_); + for (uint32_t i = 0; i < vecThread.size(); ++i) { + vecThread[i].join(); + } + } + + std::cout << "write muxer success" << std::endl; + + if (avmuxer_->Stop() != AVCS_ERR_OK) { + return; + } + std::cout << "stop muxer success" << std::endl; +} + +void AVMuxerDemo::DoRunMuxer() +{ + DoRunMuxer(std::string(RUN_NORMAL)); +} + +void AVMuxerDemo::DoRunMultiThreadCase() +{ + DoRunMuxer(std::string(RUN_MUL_THREAD)); +} + +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo.h b/test/nativedemo/avmuxer/avmuxer_demo.h new file mode 100644 index 000000000..44f82771e --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVMUXER_DEMO_H +#define AVMUXER_DEMO_H + +#include "avmuxer.h" +#include "avmuxer_demo_base.h" + +namespace OHOS { +namespace Media { +class AVMuxerDemo /*: public NoCopyable*/ : public AVMuxerDemoBase { +public: + AVMuxerDemo() = default; + ~AVMuxerDemo() = default; +private: + void DoRunMuxer() override; + int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override; + int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override; + void DoRunMultiThreadCase() override; + void DoRunMuxer(const std::string &runMode); + std::shared_ptr avmuxer_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_DEMO_H \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_base.cpp b/test/nativedemo/avmuxer/avmuxer_demo_base.cpp new file mode 100644 index 000000000..23e2b5bfe --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_base.cpp @@ -0,0 +1,501 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "avmuxer_demo_base.h" +#include +#include +#include +#include "avcodec_errors.h" +#include "avcodec_common.h" + +namespace { + // constexpr uint32_t DATA_AUDIO_ID = 0; + // constexpr uint32_t DATA_VIDEO_ID = 1; + extern "C" { + extern AudioTrackParam g_audioMpegPar; + extern AudioTrackParam g_audioAacPar; + extern VideoTrackParam g_videoH264Par; + extern VideoTrackParam g_videoMpeg4Par; + extern VideoTrackParam g_jpegCoverPar; + extern VideoTrackParam g_pngCoverPar; + extern VideoTrackParam g_bmpCoverPar; + } +} + +namespace OHOS { +namespace Media { +AVMuxerDemoBase::AVMuxerDemoBase() +{ +} + +std::shared_ptr OpenFile(const std::string &filePath) +{ + auto file = std::make_shared(); + file->open(filePath, std::ios::in | std::ios::binary); + if (file->is_open()) { + return file; + } + + return nullptr; +} + +int AVMuxerDemoBase::SelectMode() +{ + // TODO:add muxer mode select + int num; + + std::cout<<"\nplease select muxer type: 0.mp4 1.m4a"<>num; + switch (num) + { + case 0: + format_ = "mp4"; + outputFormat_ = OUTPUT_FORMAT_MPEG_4; + break; + case 1: + format_ = "m4a"; + outputFormat_ = OUTPUT_FORMAT_M4A; + break; + default: + format_ = "mp4"; + outputFormat_ = OUTPUT_FORMAT_MPEG_4; + break; + } + + std::cout<<"\nplease select audio file: 0.noAudio 1.aac 2.mpeg"<>num; + switch (num) + { + case 0: + audioType_ = "noAudio"; + audioParams_ = nullptr; + break; + case 1: + audioType_ = "aac"; + audioParams_ = &g_audioAacPar; + break; + case 2: + audioType_ = "mpeg"; + audioParams_ = &g_audioMpegPar; + break; + default: + videoType_ = "noAudio"; + audioParams_ = nullptr; + std::cout<<"do not support audio type index: "<>num; + switch (num) + { + case 0: + videoType_ = "noVideo"; + videoParams_ = nullptr; + break; + case 1: + videoType_ = "h264"; + videoParams_ = &g_videoH264Par; + break; + case 2: + videoType_ = "mpeg4"; + videoParams_ = &g_videoMpeg4Par; + break; + default: + videoType_ = "noVideo"; + videoParams_ = nullptr; + std::cout<<"do not support video type index: "<<", set to noVideo"<>num; + switch (num) + { + case 0: + coverType_ = "noCover"; + coverParams_ = nullptr; + break; + case 1: + coverType_ = "jpg"; + coverParams_ = &g_jpegCoverPar; + break; + case 2: + coverType_ = "png"; + coverParams_ = &g_pngCoverPar; + break; + case 3: + coverType_ = "bmp"; + coverParams_ = &g_bmpCoverPar; + break; + default: + coverType_ = "noCover"; + coverParams_ = nullptr; + std::cout<<"do not support cover type index: "<<", set to noCover"<fileName); + if (audioFile_ == nullptr) { + std::cout<<"open audio file failed! file name:"<fileName<fileName<fileName); + if (videoFile_ == nullptr) { + std::cout<<"open video file failed! file name:"<fileName<fileName<fileName); + if (coverFile_ == nullptr) { + std::cout<<"open cover file failed! file name:"<fileName<fileName< 0) { + close(outFd_); + outFd_ = -1; + } + if (audioFile_ != nullptr) { + audioFile_->close(); + audioFile_ = nullptr; + } + if (videoFile_ != nullptr) { + videoFile_->close(); + videoFile_ = nullptr; + } + if (coverFile_ != nullptr) { + coverFile_->close(); + coverFile_ = nullptr; + } +} + +void AVMuxerDemoBase::RunCase() +{ + if (SelectModeAndOpenFile() != 0) { + return; + } + + DoRunMuxer(); + + Reset(); +} + +void AVMuxerDemoBase::RunMultiThreadCase() +{ + std::cout<<"==== start AVMuxerDemoBase::RunMultiThreadCase ==="< file) +{ + if (file == nullptr) { + std::cout<<"AVMuxerDemoBase::WriteTrackSample file si nullptr"<read((char *)&info.timeUs, sizeof(info.timeUs)); + if (file->eof()) { + break; + } + + file->read((char *)&flags, sizeof(flags)); + if (file->eof()) { + break; + } + + file->read((char *)&dataSize, sizeof(dataSize)); + if (file->eof()) { + break; + } + + if (avMuxerDemoBuffer != nullptr && dataSize > avMuxerDemoBufferSize) { + delete [] avMuxerDemoBuffer; + avMuxerDemoBuffer = nullptr; + avMuxerDemoBufferSize = 0; + } + if (avMuxerDemoBuffer == nullptr) { + avMuxerDemoBuffer = new unsigned char[dataSize]; + avMuxerDemoBufferSize = dataSize; + } + + file->read((char *)avMuxerDemoBuffer, dataSize); + if(file->eof()) { + break; + } + info.size = dataSize; + + info.flags = 0; + if (flags != 0) { + info.flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME; + } + + // std::cout<<"tracker id:"< curFile = nullptr; + unsigned char *avMuxerDemoBuffer = nullptr; + uint32_t avMuxerDemoBufferSize = 0; + audioFile_->read((char *)&audioPts, sizeof(audioPts)); + if (audioFile_->eof()) { + return; + } + videoFile_->read((char *)&videoPts, sizeof(videoPts)); + if (videoFile_->eof()) { + return; + } + while (1) { + if (audioPts > videoPts) { + curFile = videoFile_; + info.trackIndex = videoTrackId_; + info.timeUs = videoPts; + } else { + curFile = audioFile_; + info.trackIndex = audioTrackId_; + info.timeUs = audioPts; + } + + curFile->read((char *)&flags, sizeof(flags)); + if (curFile->eof()) { + break; + } + + curFile->read((char *)&dataSize, sizeof(dataSize)); + if (curFile->eof()) { + break; + } + + if (avMuxerDemoBuffer != nullptr && dataSize > avMuxerDemoBufferSize) { + delete [] avMuxerDemoBuffer; + avMuxerDemoBuffer = nullptr; + avMuxerDemoBufferSize = 0; + } + if (avMuxerDemoBuffer == nullptr) { + avMuxerDemoBuffer = new unsigned char[dataSize]; + avMuxerDemoBufferSize = dataSize; + } + curFile->read((char *)avMuxerDemoBuffer, dataSize); + if(curFile->eof()) { + break; + } + info.size = dataSize; + + info.flags = 0; + if (flags != 0) { + info.flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME; + } + + if (DoWriteSampleBuffer((uint8_t*)avMuxerDemoBuffer, info) != 0) { + std::cout<<"DoWriteSampleBuffer failed!"<read((char *)&audioPts, sizeof(audioPts)); + if (audioFile_->eof()) { + break; + } + } else { + videoFile_->read((char *)&videoPts, sizeof(videoPts)); + if (videoFile_->eof()) { + break; + } + } + } + + if (avMuxerDemoBuffer != nullptr) { + delete [] avMuxerDemoBuffer; + avMuxerDemoBuffer = nullptr; + } +} + +void AVMuxerDemoBase::WriteTrackSample() +{ + if (audioFile_ != nullptr && videoFile_ != nullptr && audioTrackId_ >= 0 && videoTrackId_ >= 0) { + std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO and VIDEO sample"<= 0) { + std::cout<<"AVMuxerDemoBase::WriteTrackSample write AUDIO sample"<= 0) { + std::cout<<"AVMuxerDemoBase::WriteTrackSample write VIDEO sample"< file) +{ + muxerBase->WriteSingleTrackSample(trackId, file); +} + +void AVMuxerDemoBase::WriteCoverSample() +{ + std::cout<<"AVMuxerDemoBase::WriteCoverSample"<seekg(0, std::ios::end); + info.size = coverFile_->tellg(); + coverFile_->seekg(0, std::ios::beg); + if (info.size <= 0) { + std::cout<<"AVMuxerDemoBase::WriteCoverSample coverFile_ size is 0!"<read((char *)avMuxerDemoBuffer, info.size); + if (DoWriteSampleBuffer((uint8_t*)avMuxerDemoBuffer, info) != AVCS_ERR_OK) { + delete [] avMuxerDemoBuffer; + std::cout<<"WriteCoverSample error"<mimeType); + videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width); + videoParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height); + + int extSize = 0; + char buffer[100] {0}; + // fread(&extSize, sizeof(extSize), 1, g_avBinStrNewFd); + videoFile_->read((char*)&extSize, sizeof(extSize)); + if (extSize > 0 && extSize < 100) { + // fread(buffer, extSize, 1, g_avBinStrNewFd); + videoFile_->read((char*)buffer, extSize); + videoParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, (uint8_t *)buffer, extSize); + } else { + std::cout<<"AVMuxerDemoBase::AddVideoTrack DoAddTrack failed!"<mimeType); + audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, param->sampleRate); + audioParams.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, param->channels); + + int extSize = 0; + char buffer[100] {0}; + audioFile_->read((char*)&extSize, sizeof(extSize)); + if (extSize > 0 && extSize < 100) { + audioFile_->read((char*)buffer, extSize); + audioParams.PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, (uint8_t *)buffer, extSize); + } else { + std::cout<<"AVMuxerDemoBase::AddAudioTrack error extSize:"<mimeType); + coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, param->width); + coverParams.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, param->height); + + if (DoAddTrack(coverTrackId_, coverParams) != AVCS_ERR_OK) { + return -1; + } + std::cout << "AVMuxerDemoBase::AddCoverTrack video trackId is: " << coverTrackId_ << std::endl; + return 0; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_base.h b/test/nativedemo/avmuxer/avmuxer_demo_base.h new file mode 100644 index 000000000..9dea8914c --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_base.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AVMUXER_DEMO_BASE +#define AVMUXER_DEMO_BASE + +#include +#include "av_common.h" +#include "media_description.h" +#include "avmuxer_demo_common.h" +namespace OHOS { +namespace Media { +class AVMuxerDemoBase { +public: + AVMuxerDemoBase(); + virtual ~AVMuxerDemoBase() = default; + void RunCase(); + void RunMultiThreadCase(); +protected: + virtual void DoRunMuxer() = 0; + virtual void DoRunMultiThreadCase()= 0; + virtual int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) = 0; + virtual int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) = 0; + int AddVideoTrack(VideoTrackParam *param); + int AddAudioTrack(AudioTrackParam *param); + int AddCoverTrack(VideoTrackParam *param); + void WriteTrackSample(); + void WriteAvTrackSample(); + void WriteSingleTrackSample(uint32_t trackId, std::shared_ptr file); + void WriteCoverSample(); + int SelectMode(); + int SelectModeAndOpenFile(); + void Reset(); + static void MulThdWriteTrackSample(AVMuxerDemoBase *muxerBase, uint32_t trackId, std::shared_ptr file); + + int32_t videoTrackId_ {-1}; + int32_t audioTrackId_ {-1}; + int32_t coverTrackId_ {-1}; + std::shared_ptr audioFile_ {nullptr}; + std::shared_ptr videoFile_ {nullptr}; + std::shared_ptr coverFile_ {nullptr}; + AudioTrackParam *audioParams_ {nullptr}; + VideoTrackParam *videoParams_ {nullptr}; + VideoTrackParam *coverParams_ {nullptr}; + std::string videoType_ = std::string(""); + std::string audioType_ = std::string(""); + std::string coverType_ = std::string(""); + std::string format_ = std::string(""); + int32_t outFd_ {-1}; + OutputFormat outputFormat_ {OUTPUT_FORMAT_MPEG_4}; +}; +} // Media +} // OHOS +#endif \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_common.c b/test/nativedemo/avmuxer/avmuxer_demo_common.c new file mode 100644 index 000000000..f33bf7321 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_common.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "avmuxer_demo_common.h" + +struct AudioTrackParam g_audioMpegPar = { + .fileName = "mpeg_44100_2.bin", + .mimeType = "audio/mpeg", + .sampleRate = 44100, + .channels = 2, +}; + +struct AudioTrackParam g_audioAacPar = { + .fileName = "aac_44100_2.bin", + .mimeType = "audio/mp4a-latm", + .sampleRate = 44100, + .channels = 2, +}; + +struct VideoTrackParam g_videoH264Par = { + .fileName = "h264_640_360.bin", + .mimeType = "video/avc", + .width = 640, + .height = 360, +}; + +struct VideoTrackParam g_videoMpeg4Par = { + .fileName = "mpeg4_720_480.bin", + .mimeType = "video/mp4v-es", + .width = 720, + .height = 480, +}; + +struct VideoTrackParam g_jpegCoverPar = { + .fileName = "greatwall.jpg", + .mimeType = "image/jpeg", + .width = 352, + .height = 288, +}; + +struct VideoTrackParam g_pngCoverPar = { + .fileName = "greatwall.png", + .mimeType = "image/png", + .width = 352, + .height = 288, +}; + +struct VideoTrackParam g_bmpCoverPar = { + .fileName = "greatwall.bmp", + .mimeType = "image/bmp", + .width = 352, + .height = 288, +}; + +const char *RUN_NORMAL = "normal"; +const char *RUN_MUL_THREAD = "multhrd"; diff --git a/test/nativedemo/avmuxer/avmuxer_demo_common.h b/test/nativedemo/avmuxer/avmuxer_demo_common.h new file mode 100644 index 000000000..0217ce78f --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_common.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef AVMUXER_DEMO_COMMON_H +#define AVMUXER_DEMO_COMMON_H + +// only for demo +typedef struct AudioTrackParam { + const char *fileName; + const char *mimeType; + int sampleRate; + int channels; +} AudioTrackParam; + +typedef struct VideoTrackParam { + const char *fileName; + const char *mimeType; + int width; + int height; +} VideoTrackParam; + +typedef struct FdListStr { + int start[0]; + int outputFd; + int inAudioFd; + int inVideoFd; + int inCoverFd; +} FdListStr; + +#endif \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp b/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp new file mode 100644 index 000000000..7a6ace592 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "avmuxer_engine_demo.h" +#include +#include +#include +#include +#include +#include +#include +#include "securec.h" +#include "avcodec_errors.h" +#include "avsharedmemorybase.h" + +namespace OHOS { +namespace Media { + +namespace { + extern "C" { + extern char *RUN_NORMAL; + extern char *RUN_MUL_THREAD; + } +} + +int AVMuxerEngineDemo::DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) +{ + std::shared_ptr sharedSampleBuffer = + std::make_shared(info.size, AVSharedMemory::FLAGS_READ_ONLY, "sampleBuffer"); + int32_t ret = sharedSampleBuffer->Init(); + if (ret != AVCS_ERR_OK) { + std::cout<<"AVMuxerEngineDemo::DoWriteSampleBuffer shared memory Init failed!"<GetBase(), sharedSampleBuffer->GetSize(), sampleBuffer, info.size); + if (rc != EOK) { + std::cout<<"AVMuxerEngineDemo::DoWriteSampleBuffer memcpy_s failed!"<WriteSampleBuffer(sharedSampleBuffer, info) == AVCS_ERR_OK) { + return 0; + } + return -1; +} + +int AVMuxerEngineDemo::DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) +{ + int ret; + if ((ret = avmuxer_->AddTrack(trackIndex, trackDesc)) != AVCS_ERR_OK) { + std::cout<<"AVMuxerDemo::DoAddTrack failed! ret:"<SetLocation(10, 10) != AVCS_ERR_OK + || avmuxer_->SetRotation(0) != AVCS_ERR_OK) { + std::cout<<"set failed!"<Start() != AVCS_ERR_OK) { + return; + } + + std::cout << "start muxer success" << std::endl; + + if (coverParams_ != nullptr) { + WriteCoverSample(); + } + + std::cout<<"AVMuxerDemo::DoRunMuxer runMode is : "< vecThread; + vecThread.emplace_back(MulThdWriteTrackSample, this, audioTrackId_, audioFile_); + vecThread.emplace_back(MulThdWriteTrackSample, this, videoTrackId_, videoFile_); + for (uint32_t i = 0; i < vecThread.size(); ++i) { + vecThread[i].join(); + } + } + + std::cout << "write muxer success" << std::endl; + + if (avmuxer_->Stop() != AVCS_ERR_OK) { + return; + } + std::cout << "stop muxer success" << std::endl; +} + +void AVMuxerEngineDemo::DoRunMuxer() +{ + DoRunMuxer(std::string(RUN_NORMAL)); +} + +void AVMuxerEngineDemo::DoRunMultiThreadCase() +{ + DoRunMuxer(std::string(RUN_MUL_THREAD)); +} + +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_engine_demo.h b/test/nativedemo/avmuxer/avmuxer_engine_demo.h new file mode 100644 index 000000000..238471ad1 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_engine_demo.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef AVMUXER_ENGINE_DEMO_H +#define AVMUXER_ENGINE_DEMO_H + +#include "avmuxer_demo_base.h" +#include "i_muxer_engine.h" + +namespace OHOS { +namespace Media { +class AVMuxerEngineDemo /*: public NoCopyable*/ : public AVMuxerDemoBase { +public: + AVMuxerEngineDemo() = default; + ~AVMuxerEngineDemo() = default; +private: + void DoRunMuxer() override; + int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override; + int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override; + void DoRunMultiThreadCase() override; + void DoRunMuxer(const std::string &runMode); + std::shared_ptr avmuxer_; +}; + +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_DEMO_H \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp b/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp new file mode 100644 index 000000000..188dc48d9 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "avmuxer_ffmpeg_demo.h" +#include +#include +#include +#include +#include +#include + +namespace { + const char *FFMPEG_REGISTER_FUNC_NAME = "register_FFmpegMuxer"; + const char *FFMPEG_UNREGISTER_FUNC_NAME = "unregister_FFmpegMuxer"; + const char *FFMPEG_LIB_PATH = "/system/lib/media/av_codec_plugins/libav_codec_plugin_FFmpegMuxer.z.so"; +} + +namespace OHOS { +namespace Media { +namespace Plugin { +Status AVMuxerFFmpegDemo::FfmpegRegister::AddPlugin(const PluginDefBase& def) +{ + auto& tempDef = (MuxerPluginDef&)def; + std::cout<<"find plugin apiVersion:"<(); +} + +int AVMuxerFFmpegDemo::DoAddTrack(int32_t &trackIndex, MediaDescription ¶m) +{ + int32_t tempTrackId = 0; + ffmpegMuxer_->AddTrack(tempTrackId, param); + if (tempTrackId < 0) { + std::cout<<"AVMuxerFFmpegDemo::DoAddTrack failed! trackId:"<plugins.size() <= 0) { + std::cout<<"regist muxers failed!"<plugins) { + if (plugin.pluginType == PluginType::MUXER) { + auto prob = plugin.sniffer(plugin.name, outputFormat_); + if (prob > maxProb) { + maxProb = prob; + pluginDef = plugin; + } + } + } + + if (pluginDef.creator == nullptr) { + std::cout<<"no plugins matching output format - "<< outputFormat_ <SetLocation(10, 10); + ffmpegMuxer_->SetRotation(90); + + AddAudioTrack(audioParams_); + AddVideoTrack(videoParams_); + + ffmpegMuxer_->Start(); + WriteTrackSample(); + ffmpegMuxer_->Stop(); +} + +void AVMuxerFFmpegDemo::DoRunMultiThreadCase() +{ + std::cout<<"ffmpeg plugin demo is not support multi-thread write!"<WriteSampleBuffer(sampleBuffer, info) == Status::NO_ERROR) { + return 0; + } + return -1; +} + +int AVMuxerFFmpegDemo::GetFfmpegRegister() +{ + dlHandle_ = ::dlopen(FFMPEG_LIB_PATH, RTLD_NOW | RTLD_LOCAL); + if (dlHandle_ == nullptr) { + std::cout<<"AVMuxerFFmpegDemo::GetFfmpegRegister dlHandle_ is nullptr!"< +#include "avmuxer.h" +#include "muxer_plugin.h" +#include "avmuxer_demo_base.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { + +class AVMuxerFFmpegDemo /*: public NoCopyable*/ : public AVMuxerDemoBase { +public: + AVMuxerFFmpegDemo(); + ~AVMuxerFFmpegDemo() = default; +private: + struct FfmpegRegister : PackageRegister { + Status AddPlugin(const PluginDefBase& def) override; + Status AddPackage(const PackageDef& def) override { + (void)def; + return Status::NO_ERROR; + } + std::vector plugins; + }; + + void DoRunMuxer() override; + int GetFfmpegRegister(); + int DoWriteSampleBuffer(uint8_t *sampleBuffer, TrackSampleInfo &info) override; + int DoAddTrack(int32_t &trackIndex, MediaDescription &trackDesc) override; + void DoRunMultiThreadCase() override; + + std::shared_ptr ffmpegMuxer_ {nullptr}; + std::shared_ptr register_ {nullptr}; + void *dlHandle_ {nullptr}; + RegisterFunc registerFunc_ {nullptr}; + UnregisterFunc unregisterFunc_ {nullptr}; +}; +} // Plugin +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_FFMPEG_DEMO_H \ No newline at end of file diff --git a/test/nativedemo/avmuxer/native_avmuxer_demo.c b/test/nativedemo/avmuxer/native_avmuxer_demo.c new file mode 100644 index 000000000..cfd0be150 --- /dev/null +++ b/test/nativedemo/avmuxer/native_avmuxer_demo.c @@ -0,0 +1,665 @@ +/* + * Copyright (C) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "securec.h" +#include "native_avcodec_base.h" +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmuxer.h" +#include "avmuxer_demo_common.h" + + +#define NORMAL 0 +#define THREAD 1 + +struct WriteTrackSampleParam { + OH_AVMuxer *muxer; + int trackId; + int fd; +}; + +struct MuxerParam { + int outputFormat; + char outputFormatType[20]; + int runMode; + char runModeType[20]; + AudioTrackParam *audioParams; + char audioType[20]; + VideoTrackParam *videoParams; + char videoType[20]; + VideoTrackParam *coverParams; + char coverType[20]; +}; + +extern char *RUN_NORMAL; +extern char *RUN_MUL_THREAD; +extern AudioTrackParam g_audioMpegPar; +extern AudioTrackParam g_audioAacPar; +extern VideoTrackParam g_videoH264Par; +extern VideoTrackParam g_videoMpeg4Par; +extern VideoTrackParam g_jpegCoverPar; +extern VideoTrackParam g_pngCoverPar; +extern VideoTrackParam g_bmpCoverPar; + +static struct MuxerParam g_muxerParam = { + .outputFormat = AV_OUTPUT_FORMAT_UNKNOWN, + .outputFormatType = "", + .runMode = NORMAL, + .runModeType = "", + .audioParams = NULL, + .audioType = "", + .videoParams = NULL, + .videoType = "", + .coverParams = NULL, + .coverType = "", +}; + +int AddTrackAudio(OH_AVMuxer *muxer, const AudioTrackParam *param, int fdInput) +{ + if (fdInput < 0) { + printf("unselect audio, fd is %d\n", fdInput); + return -1; + } + OH_AVFormat *formatAudio = OH_AVFormat_Create(); + if (formatAudio == NULL) { + printf("audio format failed!\n"); + return AV_ERR_NO_MEMORY; + } + int extraSize = 0; + unsigned char buffer[100] = {0}; + read(fdInput, (void*)&extraSize, sizeof(extraSize)); + if (extraSize <= 100 && extraSize > 0) { + read(fdInput, buffer, extraSize); + OH_AVFormat_SetBuffer(formatAudio, OH_MD_KEY_CODEC_CONFIG, buffer, extraSize); + } + printf("AddTrackAudio audio metadata size: %d\n", extraSize); + OH_AVFormat_SetStringValue(formatAudio, OH_MD_KEY_CODEC_MIME, param->mimeType); + OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_AUD_SAMPLE_RATE, param->sampleRate); + OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_AUD_CHANNEL_COUNT, param->channels); + int trackIndex = -1; + int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatAudio); + OH_AVFormat_Destroy(formatAudio); + if (ret != AV_ERR_OK) { + printf("AddTrackAudio failed! mime: %s\n", param->mimeType); + return -1; + } + printf("AddTrackAudio success! trackIndex: %d\n", trackIndex); + return trackIndex; +} + +int AddTrackVideo(OH_AVMuxer *muxer, const VideoTrackParam *param, int fdInput) +{ + if (fdInput < 0) { + printf("unselect video, fd is %d\n", fdInput); + return -1; + } + OH_AVFormat *formatVideo = OH_AVFormat_Create(); + if (formatVideo == NULL) { + printf("video format failed!\n"); + return AV_ERR_NO_MEMORY; + } + int extraSize = 0; + unsigned char buffer[100] = {0}; + read(fdInput, (void*)&extraSize, sizeof(extraSize)); + if (extraSize <= 100 && extraSize > 0) { + read(fdInput, buffer, extraSize); + OH_AVFormat_SetBuffer(formatVideo, OH_MD_KEY_CODEC_CONFIG, buffer, extraSize); + } + printf("AddTrackVideo video metadata size: %d\n", extraSize); + OH_AVFormat_SetStringValue(formatVideo, OH_MD_KEY_CODEC_MIME, param->mimeType); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_WIDTH, param->width); + OH_AVFormat_SetIntValue(formatVideo, OH_MD_KEY_HEIGHT, param->height); + int trackIndex = -1; + int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatVideo); + OH_AVFormat_Destroy(formatVideo); + if (ret != AV_ERR_OK) { + printf("AddTrackVideo failed! mime: %s\n", param->mimeType); + return -1; + } + printf("AddTrackVideo success! trackIndex: %d\n", trackIndex); + return trackIndex; +} + +int AddTrackCover(OH_AVMuxer *muxer, const VideoTrackParam *param, int fdInput) +{ + if (fdInput < 0) { + printf("unselect cover, fd is %d\n", fdInput); + return -1; + } + + OH_AVFormat *formatCover = OH_AVFormat_Create(); + if (formatCover == NULL) { + printf("cover format failed!\n"); + return AV_ERR_NO_MEMORY; + } + OH_AVFormat_SetStringValue(formatCover, OH_MD_KEY_CODEC_MIME, param->mimeType); + OH_AVFormat_SetIntValue(formatCover, OH_MD_KEY_WIDTH, param->width); + OH_AVFormat_SetIntValue(formatCover, OH_MD_KEY_HEIGHT, param->height); + int trackIndex = -1; + int ret = OH_AVMuxer_AddTrack(muxer, &trackIndex, formatCover); + OH_AVFormat_Destroy(formatCover); + if (ret != AV_ERR_OK) { + printf("AddTrackCover failed! mime: %s\n", param->mimeType); + return -1; + } + printf("AddTrackCover success! trackIndex: %d\n", trackIndex); + return trackIndex; +} + +void WriteSingleTrackSample(OH_AVMuxer *muxer, int trackId, int fd) +{ + if (muxer == NULL || fd < 0 || trackId < 0) { + printf("WriteSingleTrackSample muxer is null or fd < 0, fd:%d\n", fd); + return; + } + int ret = 0; + int dataSize = 0; + int flags = 0; + unsigned char *avMuxerDemoBuffer = NULL; + int avMuxerDemoBufferSize = 0; + OH_AVCodecBufferAttr info; + memset_s(&info, sizeof(info), 0, sizeof(info)); + while (1) { + ret = read(fd, (void*)&info.pts, sizeof(info.pts)); + if (ret <= 0) { + break; + } + + ret = read(fd, (void*)&flags, sizeof(flags)); + if (ret <= 0) { + break; + } + + // read frame buffer + ret = read(fd, (void*)&dataSize, sizeof(dataSize)); + if (ret <= 0 || dataSize < 0) { + break; + } + + if (avMuxerDemoBuffer != NULL && dataSize > avMuxerDemoBufferSize) { + free(avMuxerDemoBuffer); + avMuxerDemoBufferSize = 0; + avMuxerDemoBuffer = NULL; + } + if (avMuxerDemoBuffer == NULL) { + avMuxerDemoBuffer = malloc(dataSize); + avMuxerDemoBufferSize = dataSize; + if (avMuxerDemoBuffer == NULL) { + printf("error malloc memory! %d\n", dataSize); + break; + } + } + ret = read(fd, (void*)avMuxerDemoBuffer, dataSize); + if (ret <= 0) { + break; + } + info.size = dataSize; + + info.flags = 0; + if (flags != 0) { + info.flags |= AVCODEC_BUFFER_FLAGS_SYNC_FRAME; + } + + if (OH_AVMuxer_WriteSampleBuffer(muxer, trackId, avMuxerDemoBuffer, info) != AV_ERR_OK) { + printf("OH_AVMuxer_WriteSampleBuffer error!\n"); + break; + } + } + + if (avMuxerDemoBuffer != NULL) { + free(avMuxerDemoBuffer); + } +} + +void *ThreadWriteTrackSample(void *param) +{ + struct WriteTrackSampleParam *wrTrackParam = (struct WriteTrackSampleParam *)param; + WriteSingleTrackSample(wrTrackParam->muxer, wrTrackParam->trackId, wrTrackParam->fd); + return NULL; +} + +void WriteTrackSample(OH_AVMuxer *muxer, int audioTrackIndex, int videoTrackIndex, FdListStr *fdStr) +{ + if (fdStr == NULL || fdStr->inAudioFd < 0 || fdStr->inVideoFd < 0) { + printf("WriteTrackSample start failed!\n"); + return; + } + printf("WriteTrackSample\n"); + int dataSize = 0; + int ret = 0; + int trackId = 0; + int curFd = 0; + int flags = 0; + int64_t audioPts = 0; + int64_t videoPts = 0; + OH_AVCodecBufferAttr info; + memset_s(&info, sizeof(info), 0, sizeof(info)); + unsigned char *avMuxerDemoBuffer = NULL; + int avMuxerDemoBufferSize = 0; + + ret = read(fdStr->inAudioFd, (void*)&audioPts, sizeof(audioPts)); + if (ret <= 0) { + return; + } + ret = read(fdStr->inVideoFd, (void*)&videoPts, sizeof(videoPts)); + if (ret <= 0) { + return; + } + while (1) { + if (audioPts > videoPts) { // write video + info.pts = videoPts; + trackId = videoTrackIndex; + curFd = fdStr->inVideoFd; + } else { // write audio + info.pts = audioPts; + trackId = audioTrackIndex; + curFd = fdStr->inAudioFd; + } + + // read flags + ret = read(curFd, (void*)&flags, sizeof(flags)); + if (ret <= 0) { + break; + } + info.flags = 0; + if (flags != 0) { + info.flags |= AVCODEC_BUFFER_FLAGS_SYNC_FRAME; + } + + // read frame buffer + ret = read(curFd, (void*)&dataSize, sizeof(dataSize)); + if (ret <= 0 || dataSize < 0) { + break; + } + + if (avMuxerDemoBuffer != NULL && dataSize > avMuxerDemoBufferSize) { + free(avMuxerDemoBuffer); + avMuxerDemoBufferSize = 0; + avMuxerDemoBuffer = NULL; + } + if (avMuxerDemoBuffer == NULL) { + avMuxerDemoBuffer = malloc(dataSize); + avMuxerDemoBufferSize = dataSize; + if (avMuxerDemoBuffer == NULL) { + printf("error malloc memory! %d\n", dataSize); + break; + } + } + ret = read(curFd, (void*)avMuxerDemoBuffer, dataSize); + if (ret <= 0) { + break; + } + info.size = dataSize; + + if (OH_AVMuxer_WriteSampleBuffer(muxer, trackId, avMuxerDemoBuffer, info) != AV_ERR_OK) { + printf("OH_AVMuxer_WriteSampleBuffer error!\n"); + break; + } + + if (curFd == fdStr->inVideoFd) { + ret = read(fdStr->inVideoFd, (void*)&videoPts, sizeof(videoPts)); + if (ret <= 0) { + break; + } + } else { + ret = read(fdStr->inAudioFd, (void*)&audioPts, sizeof(audioPts)); + if (ret <= 0) { + break; + } + } + } + + if (avMuxerDemoBuffer != NULL) { + free(avMuxerDemoBuffer); + } +} + +void WriteTrackCover(OH_AVMuxer *muxer, int coverTrackIndex, int fdInput) +{ + printf("WriteTrackCover\n"); + OH_AVCodecBufferAttr info; + memset_s(&info, sizeof(info), 0, sizeof(info)); + struct stat fileStat; + fstat(fdInput, &fileStat); + info.size = fileStat.st_size; + unsigned char *avMuxerDemoBuffer = malloc(info.size); + if (avMuxerDemoBuffer == NULL) { + printf("malloc memory error! size: %d \n", info.size); + return; + } + + int ret = read(fdInput, avMuxerDemoBuffer, info.size); + if (ret <= 0) { + free(avMuxerDemoBuffer); + return; + } + + if (OH_AVMuxer_WriteSampleBuffer(muxer, coverTrackIndex, avMuxerDemoBuffer, info) != AV_ERR_OK) { + free(avMuxerDemoBuffer); + printf("OH_AVMuxer_WriteSampleBuffer error!\n"); + return; + } + free(avMuxerDemoBuffer); +} + +int GetInputNum(int defaultNum) +{ + int num = defaultNum; + num = getchar(); + if (num == '\n') { // default + num = defaultNum; + } else { + ungetc(num, stdin); + scanf("%d", &num); + fflush(stdin); + } + return num; +} + + +void NativeSelectMuxerType() +{ + int num; + + printf("\nplese select muxer type : 0.mp4 1.m4a\n"); + num = GetInputNum(0); + switch (num) + { + case 0: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4; + snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "mp4"); + break; + case 1: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_M4A; + snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "m4a"); + break; + default: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4; + snprintf(g_muxerParam.outputFormatType, sizeof(g_muxerParam.outputFormatType), "%s", "mp4"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectRunMode() +{ + int num; + + printf("\nplese select audio vide wrtie mode:\n"); + printf("0. audio video write in sample thread\n"); + printf("1. audio video write in different thread\n"); + num = GetInputNum(0); + switch (num) + { + case 0: + g_muxerParam.runMode = NORMAL; + snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_NORMAL); + break; + case 1: + g_muxerParam.runMode = THREAD; + snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_MUL_THREAD); + break; + default: + g_muxerParam.runMode = NORMAL; + snprintf(g_muxerParam.runModeType, sizeof(g_muxerParam.runModeType), "%s", RUN_NORMAL); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectAudio() +{ + int num; + + printf("\nplese select audio mode: 0.noAudio 1.aac 2.mpeg\n"); + num = GetInputNum(1); + switch (num) + { + case 1: + g_muxerParam.audioParams = &g_audioAacPar; + snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "aac"); + break; + case 2: + g_muxerParam.audioParams = &g_audioMpegPar; + snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "mpeg"); + break; + default: + g_muxerParam.audioParams = NULL; + snprintf(g_muxerParam.audioType, sizeof(g_muxerParam.audioType), "%s", "noAudio"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectVideo() +{ + int num; + + printf("\nplese select video mode: 0.noVideo 1.h264 2.mpeg4\n"); + num = GetInputNum(1); + switch (num) + { + case 1: + g_muxerParam.videoParams = &g_videoH264Par; + snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "h264"); + break; + case 2: + g_muxerParam.videoParams = &g_videoMpeg4Par; + snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "mpeg4"); + break; + default: + g_muxerParam.videoParams = NULL; + snprintf(g_muxerParam.videoType, sizeof(g_muxerParam.videoType), "%s", "noVideo"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectCover() +{ + int num; + + printf("\nplese select cover mode: 0.noCover 1.jpg 2.png 3.bmp\n"); + num = GetInputNum(1); + switch (num) + { + case 1: + g_muxerParam.coverParams = &g_jpegCoverPar; + snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "jpg"); + break; + case 2: + g_muxerParam.coverParams = &g_pngCoverPar; + snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "png"); + break; + case 3: + g_muxerParam.coverParams = &g_bmpCoverPar; + snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "bmp"); + break; + default: + g_muxerParam.coverParams = NULL; + snprintf(g_muxerParam.coverType, sizeof(g_muxerParam.coverType), "%s", "noCover"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectMode() +{ + if (g_muxerParam.outputFormat != AV_OUTPUT_FORMAT_UNKNOWN) { + return; + } + + NativeSelectMuxerType(); + NativeSelectRunMode(); + NativeSelectAudio(); + NativeSelectVideo(); + NativeSelectCover(); +} + +int OpenAllInputFile(FdListStr *fdStr) +{ + if (!fdStr) { + printf("fdStr is null!\n"); + return -1; + } + + if (g_muxerParam.audioParams) { + fdStr->inAudioFd = open(g_muxerParam.audioParams->fileName, O_RDONLY); + if (fdStr->inAudioFd < 0) { + printf("open %s failed!!\n", g_muxerParam.audioParams->fileName); + } else { + printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.audioParams->fileName, + fdStr->inAudioFd, fcntl(fdStr->inAudioFd, F_GETFL, 0)); + } + } + + if (g_muxerParam.videoParams) { + fdStr->inVideoFd = open(g_muxerParam.videoParams->fileName, O_RDONLY); + if (fdStr->inVideoFd < 0) { + printf("open %s failed!!\n", g_muxerParam.videoParams->fileName); + } else { + printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.videoParams->fileName, + fdStr->inVideoFd, fcntl(fdStr->inVideoFd, F_GETFL, 0)); + } + } + + if (g_muxerParam.coverParams) { + fdStr->inCoverFd = open(g_muxerParam.coverParams->fileName, O_RDONLY); + if (fdStr->inCoverFd < 0) { + printf("open %s failed!!\n", g_muxerParam.coverParams->fileName); + } else { + printf("open file %s success, -fd:%d, -flags %x\n", g_muxerParam.coverParams->fileName, + fdStr->inCoverFd, fcntl(fdStr->inCoverFd, F_GETFL, 0)); + } + } + return 0; +} + +int DoRunMuxer(FdListStr *fdStr, OH_AVMuxer *muxer) +{ + if (fdStr == NULL || muxer == NULL) { + printf("fdStr or muxer is null!\n"); + return -1; + } + + if (OH_AVMuxer_SetLocation(muxer, 10, 10) != AV_ERR_OK + || OH_AVMuxer_SetRotation(muxer, 0) != AV_ERR_OK ) { + printf("set failed!\n"); + return -1; + } + int audioTrackIndex = AddTrackAudio(muxer, g_muxerParam.audioParams, fdStr->inAudioFd); + int videoTrackIndex = AddTrackVideo(muxer, g_muxerParam.videoParams, fdStr->inVideoFd); + int coverTrackIndex = AddTrackCover(muxer, g_muxerParam.coverParams, fdStr->inCoverFd); + + if (OH_AVMuxer_Start(muxer) != AV_ERR_OK) { + printf("start muxer failed!\n"); + return -1; + } + + if (coverTrackIndex >= 0) { + WriteTrackCover(muxer, coverTrackIndex, fdStr->inCoverFd); + } + + if (g_muxerParam.runMode == NORMAL) { + printf("== write audio video sample in same thread\n"); + if (audioTrackIndex >= 0 && videoTrackIndex >= 0) { + WriteTrackSample(muxer, audioTrackIndex, videoTrackIndex, fdStr); + } else if (audioTrackIndex >= 0) { + WriteSingleTrackSample(muxer, audioTrackIndex, fdStr->inAudioFd); + } else if (videoTrackIndex >= 0) { + WriteSingleTrackSample(muxer, videoTrackIndex, fdStr->inVideoFd); + } + } else if (g_muxerParam.runMode == THREAD) { + printf("== write audio video sample in different thread\n"); + pthread_t auThread; + pthread_t viThread; + + struct WriteTrackSampleParam audioThParam = {muxer, audioTrackIndex, fdStr->inAudioFd}; + struct WriteTrackSampleParam videoThparam = {muxer, videoTrackIndex, fdStr->inVideoFd}; + pthread_create(&auThread, NULL, ThreadWriteTrackSample, &audioThParam); + pthread_create(&viThread, NULL, ThreadWriteTrackSample, &videoThparam); + + pthread_join(viThread, NULL); + pthread_join(auThread, NULL); + } + + if (OH_AVMuxer_Stop(muxer) != AV_ERR_OK) { + printf("stop muxer failed!\n"); + return -1; + } + printf("native avmuxer finish! fd:out:%d, audio:%d, video:%d, cover:%d\n", + fdStr->outputFd, fdStr->inAudioFd, fdStr->inVideoFd, fdStr->inCoverFd); + return 0; +} + +void CloseAllFd(FdListStr *fdStr) +{ + printf("close fd : ["); + int fdTotalCount = sizeof(*fdStr) /sizeof(fdStr->start[0]); + for (int i = 0; i < fdTotalCount; i++) { + printf("%d, ", fdStr->start[i]); + if (fdStr->start[i] > 0) { + close(fdStr->start[i]); + fdStr->start[i] = -1; + } + } + printf("\b\b]\n"); +} + +int RunNativeMuxer(const char *out) +{ + FdListStr fdStr; + int fdTotalCount = sizeof(fdStr) /sizeof(fdStr.start[0]); + printf("fd list total size is %d\n", fdTotalCount); + for (int i = 0; i < fdTotalCount; i++) { + fdStr.start[i] = -1; + } + + if (OpenAllInputFile(&fdStr) < 0) { + CloseAllFd(&fdStr); + return -1; + } + + char outFileName[100] = {0}; + snprintf(outFileName, sizeof(outFileName), "%s_%s_%s_%s_%s.%s", + out, g_muxerParam.runModeType, g_muxerParam.audioType, g_muxerParam.videoType, + g_muxerParam.coverType, g_muxerParam.outputFormatType); + + fdStr.outputFd = open(outFileName, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + if (fdStr.outputFd < 0) { + printf("open file failed! filePath is: %s %d\n", outFileName, fdStr.outputFd); + CloseAllFd(&fdStr); + return -1; + } + printf("open file %s success, -fd:%d, -flags %x\n", outFileName, fdStr.outputFd, fcntl(fdStr.outputFd, F_GETFL, 0)); + + OH_AVMuxer *muxer = OH_AVMuxer_Create(fdStr.outputFd, g_muxerParam.outputFormat); + DoRunMuxer(&fdStr, muxer); + + if (muxer != NULL) { + OH_AVMuxer_Destroy(muxer); + muxer = NULL; + } + + CloseAllFd(&fdStr); + + return 0; +} diff --git a/test/nativedemo/resources/aac_44100_2.bin b/test/nativedemo/resources/aac_44100_2.bin new file mode 100644 index 000000000..9b9c74749 Binary files /dev/null and b/test/nativedemo/resources/aac_44100_2.bin differ diff --git a/test/nativedemo/resources/greatwall.jpg b/test/nativedemo/resources/greatwall.jpg new file mode 100644 index 000000000..0bba921e5 Binary files /dev/null and b/test/nativedemo/resources/greatwall.jpg differ diff --git a/test/nativedemo/resources/h264_640_360.bin b/test/nativedemo/resources/h264_640_360.bin new file mode 100644 index 000000000..f9da44b1e Binary files /dev/null and b/test/nativedemo/resources/h264_640_360.bin differ diff --git a/test/nativedemo/resources/mpeg4_720_480.bin b/test/nativedemo/resources/mpeg4_720_480.bin new file mode 100644 index 000000000..024c46a73 Binary files /dev/null and b/test/nativedemo/resources/mpeg4_720_480.bin differ diff --git a/test/nativedemo/resources/mpeg_44100_2.bin b/test/nativedemo/resources/mpeg_44100_2.bin new file mode 100644 index 000000000..b7d214572 Binary files /dev/null and b/test/nativedemo/resources/mpeg_44100_2.bin differ diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn new file mode 100644 index 000000000..838b0ee20 --- /dev/null +++ b/test/unittest/BUILD.gn @@ -0,0 +1,89 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//foundation/multimedia/av_codec/config.gni") + +AV_CODE_ROOT_DIR = "//foundation/multimedia/av_codec" +module_output_path = "av_codec" + +av_codec_unittest_include_dirs = [ + "$AV_CODE_ROOT_DIR/interfaces/inner_api/native", + "$AV_CODE_ROOT_DIR/interfaces/interfaces/inner_api/native", +] + +av_codec_unittest_cflags = [ + "-std=c++17", + "-fno-rtti", + "-fno-exceptions", + "-Wall", + "-fno-common", + "-fstack-protector-strong", + "-Wshadow", + "-FPIC", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-fvisibility=hidden", + "-Wformat=2", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", +] + +################################################################################################################## +ohos_unittest("av_muxer_unit_test") { + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + ] + cflags = av_codec_unittest_cflags + + if (multimedia_av_codec_support_muxer) { + sources = [ + "./avmuxer_test/avmuxer_unittest.cpp", + ] + } + + external_deps = [ + "multimedia_av_codec:av_codec_client", + ] + + resource_config_file = "$AV_CODE_ROOT_DIR/test/unittest/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("format_unit_test") { + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + ] + cflags = av_codec_unittest_cflags + + if (multimedia_av_codec_support_muxer) { + sources = [ + "./format_unit_test.cpp", + ] + } + + public_deps = [ + "$AV_CODE_ROOT_DIR/services/utils:av_codec_format", + ] + + resource_config_file = "$AV_CODE_ROOT_DIR/test/unittest/ohos_test.xml" +} \ No newline at end of file diff --git a/test/unittest/avmuxer_test/avmuxer_unittest.cpp b/test/unittest/avmuxer_test/avmuxer_unittest.cpp new file mode 100644 index 000000000..77386d3b1 --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_unittest.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include "avmuxer.h" +#include "avcodec_info.h" + +using namespace testing::ext; +using namespace OHOS::Media; + +static const std::string TEST_FILE_PATH = "./"; + +class AvmuxerUnitTest : public testing::Test { + public: + // SetUpTestCase: Called before all test cases + static void SetUpTestCase(void); + // TearDownTestCase: Called after all test case + static void TearDownTestCase(void); + // SetUp: Called before each test cases + void SetUp(void); + // TearDown: Called after each test cases + void TearDown(void); +protected: + int32_t fd_ {-1}; + std::shared_ptr avDataFile_ {nullptr}; + std::shared_ptr avmuxer_ {nullptr}; + uint8_t buffer_[3] = {'a', 'a', 'a'}; +}; + +void AvmuxerUnitTest::SetUpTestCase() {} + +void AvmuxerUnitTest::TearDownTestCase() {} + +void AvmuxerUnitTest::SetUp() +{ + avDataFile_ = std::make_shared(); + avDataFile_->open("avDataMpegMpeg4.bin", std::ios::in | std::ios::binary); + if (avDataFile_ == nullptr) { + std::cout<<"open avDataMpegMpeg4.bin failed!"<close(); + avDataFile_ = nullptr; + } + + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } +} + +/** + * @tc.name: Muxer_AddTrack_001 + * @tc.desc: Muxer AddTrack add audio track + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_Create_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_001.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_EQ(avmuxer, nullptr); + + close(fd_); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + outputFormat = OUTPUT_FORMAT_MPEG_4; + avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_EQ(avmuxer, nullptr); + + close(fd_); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + outputFormat = OUTPUT_FORMAT_MPEG_4; + avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); +} + +/** + * @tc.name: Muxer_AddTrack_001 + * @tc.desc: Muxer AddTrack add audio track + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_001, TestSize.Level0) +{ + int audioTrackId = -1; + int ret = 0; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_001.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); + + std::shared_ptr audioParams = std::make_shared(); + audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + ret = avmuxer->AddTrack(audioTrackId, *audioParams); + EXPECT_EQ(ret, 0); + EXPECT_GE(audioTrackId, 0); + + audioParams = std::make_shared(); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + ret = avmuxer->AddTrack(audioTrackId, *audioParams); + EXPECT_NE(ret, 0); + + audioParams = std::make_shared(); + audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + ret = avmuxer->AddTrack(audioTrackId, *audioParams); + EXPECT_NE(ret, 0); + + audioParams = std::make_shared(); + audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + ret = avmuxer->AddTrack(audioTrackId, *audioParams); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_AddTrack_002 + * @tc.desc: Muxer AddTrack add video track + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_002, TestSize.Level0) +{ + int videoTrackId = -1; + int ret = 0; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_002.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); + + std::shared_ptr videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + ret = avmuxer->AddTrack(videoTrackId, *videoParams); + EXPECT_EQ(ret, 0); + EXPECT_GE(videoTrackId, 0); + + videoParams = std::make_shared(); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + ret = avmuxer->AddTrack(videoTrackId, *videoParams); + EXPECT_NE(ret, 0); + + videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + ret = avmuxer->AddTrack(videoTrackId, *videoParams); + EXPECT_NE(ret, 0); + + videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + ret = avmuxer->AddTrack(videoTrackId, *videoParams); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_AddTrack_003 + * @tc.desc: Muxer AddTrack after Start() + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_AddTrack_003, TestSize.Level0) +{ + int audioTrackId = -1; + int videoTrackId = -1; + int ret = 0; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); + + std::shared_ptr videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3); + ret = avmuxer->AddTrack(videoTrackId, *videoParams); + EXPECT_EQ(ret, 0); + EXPECT_GE(videoTrackId, 0); + + avmuxer->Start(); + std::shared_ptr audioParams = std::make_shared(); + audioParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + ret = avmuxer->AddTrack(audioTrackId, *audioParams); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_Start_001 + * @tc.desc: Muxer Start after Stop() + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_Start_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); + + std::shared_ptr videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3); + + EXPECT_NE(avmuxer->Start(), 0); + int32_t videoTrackId = -1; + int ret = avmuxer->AddTrack(videoTrackId, *videoParams); + ASSERT_EQ(ret, 0); + EXPECT_GE(videoTrackId, 0); + EXPECT_EQ(avmuxer->Start(), 0); + EXPECT_NE(avmuxer->Start(), 0); + EXPECT_EQ(avmuxer->Stop(), 0); + EXPECT_NE(avmuxer->Start(), 0); +} + +/** + * @tc.name: Muxer_Stop_001 + * @tc.desc: Muxer Stop() before Start + * @tc.type: FUNC + */ +HWTEST_F(AvmuxerUnitTest, Muxer_Stop_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack_003.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + std::shared_ptr avmuxer = AVMuxerFactory::CreateAVMuxer(fd_, outputFormat); + ASSERT_NE(avmuxer, nullptr); + + std::shared_ptr videoParams = std::make_shared(); + videoParams->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + videoParams->PutBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, buffer_, 3); + int32_t videoTrackId = -1; + int ret = avmuxer->AddTrack(videoTrackId, *videoParams); + ASSERT_EQ(ret, 0); + EXPECT_GE(videoTrackId, 0); + EXPECT_NE(avmuxer->Stop(), 0); + EXPECT_EQ(avmuxer->Start(), 0); + EXPECT_EQ(avmuxer->Stop(), 0); + EXPECT_NE(avmuxer->Stop(), 0); +} \ No newline at end of file diff --git a/test/unittest/format_unit_test.cpp b/test/unittest/format_unit_test.cpp new file mode 100644 index 000000000..bfc0da41b --- /dev/null +++ b/test/unittest/format_unit_test.cpp @@ -0,0 +1,117 @@ +#include +#include +#include +#include "format.h" + +using namespace testing::ext; +using namespace OHOS::Media; + +namespace { + constexpr float EPSINON_FLOAT = 0.0001; + constexpr double EPSINON_DOUBLE = 0.0001; +} // namespace FormatTestParam + +class FormatUnitTest : public testing::Test { + public: + // SetUpTestCase: Called before all test cases + static void SetUpTestCase(void); + // TearDownTestCase: Called after all test case + static void TearDownTestCase(void); + // SetUp: Called before each test cases + void SetUp(void); + // TearDown: Called after each test cases + void TearDown(void); + + std::unique_ptr format_ {nullptr}; +}; + +void FormatUnitTest::SetUpTestCase() {} + +void FormatUnitTest::TearDownTestCase() {} + +void FormatUnitTest::SetUp() +{ + format_ = std::make_unique(); +} + +void FormatUnitTest::TearDown() +{ + format_ = nullptr; +} + +/** + * @tc.name: Format_Value_0100 + * @tc.desc: format put and get value + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(FormatUnitTest, Format_Value_0100, TestSize.Level0) +{ + const std::string_view intKey = "IntKey"; + const std::string_view longKey = "LongKey"; + const std::string_view floatKey = "FloatKey"; + const std::string_view doubleKey = "DoubleKey"; + const std::string_view stringKey = "StringKey"; + + int32_t intValue = 1; + int64_t longValue = 1; + float floatValue = 1.0; + double doubleValue = 1.0; + const std::string stringValue = "StringValue"; + + int32_t getIntValue = 0; + int64_t getLongValue = 0; + float getFloatValue = 0.0; + double getDoubleValue = 0.0; + std::string getStringValue = ""; + + ASSERT_TRUE(format_ != nullptr); + ASSERT_TRUE(format_->PutIntValue(intKey, intValue)); + ASSERT_TRUE(format_->GetIntValue(intKey, getIntValue)); + ASSERT_TRUE(intValue == getIntValue); + ASSERT_FALSE(format_->GetLongValue(intKey, getLongValue)); + + ASSERT_TRUE(format_->PutLongValue(longKey, intValue)); + ASSERT_TRUE(format_->GetLongValue(longKey, getLongValue)); + ASSERT_TRUE(longValue == getLongValue); + ASSERT_FALSE(format_->GetIntValue(longKey, getIntValue)); + + ASSERT_TRUE(format_->PutFloatValue(floatKey, floatValue)); + ASSERT_TRUE(format_->GetFloatValue(floatKey, getFloatValue)); + ASSERT_TRUE(fabs(floatValue - getFloatValue) < EPSINON_FLOAT); + ASSERT_FALSE(format_->GetDoubleValue(floatKey, getDoubleValue)); + + ASSERT_TRUE(format_->PutDoubleValue(doubleKey, doubleValue)); + ASSERT_TRUE(format_->GetDoubleValue(doubleKey, getDoubleValue)); + ASSERT_TRUE(fabs(doubleValue - getDoubleValue) < EPSINON_DOUBLE); + ASSERT_FALSE(format_->GetFloatValue(doubleKey, getFloatValue)); + + ASSERT_TRUE(format_->PutStringValue(stringKey, stringValue.c_str())); + ASSERT_TRUE(format_->GetStringValue(stringKey, getStringValue)); + ASSERT_TRUE(stringValue == getStringValue); +} + +/** + * @tc.name: Format_Buffer_0100 + * @tc.desc: format put and get buffer + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(FormatUnitTest, Format_Buffer_0100, TestSize.Level0) +{ + constexpr size_t size = 3; + const std::string_view key = "BufferKey"; + uint8_t buffer[size] = {'a', 'b', 'b'}; + + ASSERT_TRUE(format_->PutBuffer(key, buffer, size)); + uint8_t *getBuffer; + size_t getSize; + ASSERT_TRUE(format_->GetBuffer(key, &getBuffer, getSize)); + ASSERT_TRUE(size == getSize); + for (int32_t i = 0; i < size; i++) { + ASSERT_TRUE(buffer[i] == getBuffer[i]); + } + + std::string getString; + ASSERT_FALSE(format_->GetStringValue(key, getString)); +} \ No newline at end of file diff --git a/test/unittest/ohos_test.xml b/test/unittest/ohos_test.xml new file mode 100644 index 000000000..1333e174c --- /dev/null +++ b/test/unittest/ohos_test.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file