diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..cf007af3df1352a594c13700cac7b4106c12efc0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,152 @@ +## c/c++ +# Prerequisites +*.d + +# Compiled Object files +*.ko +*.slo +*.lo +*.o +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.so.* +*.dylib +*.dll + +# module files +*.mod +*.smod +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib +*.lo + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +## cmake +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +## ninja +.ninja_deps +.ninja_log + +## vscode +.vscode +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +## jetbrains +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser +.clang-format diff --git a/BUILD.gn b/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..5e2e783b8de031832775c3488944df6dd7135505 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,22 @@ +# 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/config/ohos/config.gni") +import("//build/ohos.gni") + +group("av_codec_packages") { + public_deps = [ + "interfaces/inner_api/native:av_codec_client", + "services/services:av_codec_service", + ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000000000000000000000000000000000000..8acf17eec02762d69f84f852d0e772697505aaf5 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e1086acb12d9843f2dd4aa51444fa9a9bef4ee24..d034c7583bcb826412c90694e3d78f5ef4d612d4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# multimedia_av_codec +# av_codec #### Description {**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} diff --git a/bundle.json b/bundle.json new file mode 100644 index 0000000000000000000000000000000000000000..4eb11d490b180eebec5c573c855e825c998d3066 --- /dev/null +++ b/bundle.json @@ -0,0 +1,84 @@ +{ + "name": "@ohos/av_codec", + "description": "Media standard provides atomic capabilities", + "version": "3.1", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "foundation/multimedia/av_codec" + }, + "dirs": {}, + "scripts": {}, + "component": { + "name": "av_codec", + "subsystem": "multimedia", + "syscap": [ + "SystemCapability.Multimedia.Media.Muxer", + "SystemCapability.Multimedia.Media.Spliter", + "SystemCapability.Multimedia.Media.Core", + "SystemCapability.Multimedia.Media.AudioDecoder", + "SystemCapability.Multimedia.Media.AudioEncoder", + "SystemCapability.Multimedia.Media.VideoDecoder", + "SystemCapability.Multimedia.Media.VideoEncoder", + "SystemCapability.Multimedia.Media.CodecBase" + ], + "features": [], + "adapted_system_type": [ "standard" ], + "rom": "10000KB", + "ram": "10000KB", + "hisysevent_config": [ + "//foundation/multimedia/av_codec/hisysevent.yaml" + ], + "deps": { + "components": [ + "hiviewdfx_hilog_native", + "ipc", + "hisysevent_native", + "c_utils", + "hilog_native", + "hitrace_native" + ], + "third_party": [ + "glib", + "gstreamer", + "libffi", + "ffmpeg", + "common" + ] + }, + "build": { + "group_type": { + "base_group": [], + "fwk_group": [ + "//foundation/multimedia/av_codec/interfaces/kits/c:capi_packages", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client" + ], + "service_group": [ + "//foundation/multimedia/av_codec/services:av_codec_services_package", + "//foundation/multimedia/av_codec/sa_profile:av_codec_service_profile" + ] + }, + "inner_kits": [ + { + "type": "so", + "name": "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "header": { + "header_files": [ + "avcodec_audio_decoder.h", + "avcodec_audio_encoder.h", + "avcodec_video_decoder.h", + "avcodec_video_encoder.h", + "avdemuxer.h", + "avmuxer.h" + ], + "header_base": "//foundation/multimedia/av_codec/interfaces/inner_api/native" + } + } + ], + "test": [ + "//foundation/multimedia/av_codec/test:av_codec_demo_test", + "//foundation/multimedia/av_codec/test:av_codec_unit_test" + ] + } + } + } diff --git a/cfi_blocklist.txt b/cfi_blocklist.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f96933517c0cd3e2553a169859058b0fa692e11 --- /dev/null +++ b/cfi_blocklist.txt @@ -0,0 +1,2 @@ +src:*services/engine/* +src:*frameworks/native/capi/* \ No newline at end of file diff --git a/config.gni b/config.gni new file mode 100644 index 0000000000000000000000000000000000000000..f8b9413fc67601585414155a706e6e9872fccae5 --- /dev/null +++ b/config.gni @@ -0,0 +1,66 @@ +# Copyright (C) 2023-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. + +declare_args() { + multimedia_av_codec_support_capi = true + multimedia_av_codec_support_codec = true + multimedia_av_codec_support_codeclist = true + multimedia_av_codec_support_demuxer = true + multimedia_av_codec_support_source = true + multimedia_av_codec_support_muxer = true + multimedia_av_codec_support_ffmpeg_demuxer = true + multimedia_av_codec_support_test = true +} + +av_codec_root_dir = "//foundation/multimedia/av_codec" +av_codec_defines = [] + +if (multimedia_av_codec_support_capi) { + av_codec_defines += [ "SUPPORT_CAPI" ] +} else { + av_codec_defines += [ "UNSUPPORT_CAPI" ] +} + +if (multimedia_av_codec_support_codec) { + av_codec_defines += [ "SUPPORT_CODEC" ] +} else { + av_codec_defines += [ "UNSUPPORT_CODEC" ] +} + +if (multimedia_av_codec_support_codeclist) { + av_codec_defines += [ "SUPPORT_CODECLIST" ] +} else { + av_codec_defines += [ "UNSUPPORT_CODECLIST" ] +} + +if (multimedia_av_codec_support_demuxer) { + av_codec_defines += [ "SUPPORT_DEMUXER" ] +} else { + av_codec_defines += [ "UNSUPPORT_DEMUXER" ] +} + +if (multimedia_av_codec_support_muxer) { + av_codec_defines += [ "SUPPORT_MUXER" ] +} else { + av_codec_defines += [ "UNSUPPORT_MUXER" ] +} + +if (multimedia_av_codec_support_source) { + av_codec_defines += [ "SUPPORT_SOURCE" ] +} else { + av_codec_defines += [ "UNSUPPORT_SOURCE" ] +} + +if (multimedia_av_codec_support_ffmpeg_demuxer) { + av_codec_defines += [ "FFMPEG_DEMUXER_ENABLE" ] +} diff --git a/frameworks/native/avcodec/avcodec_audio_decoder_impl.cpp b/frameworks/native/avcodec/avcodec_audio_decoder_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..817efc533285fc65cc040014edc481f7d165abd8 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_audio_decoder_impl.cpp @@ -0,0 +1,154 @@ +/* + * 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 "avcodec_audio_decoder_impl.h" +#include "i_avcodec_service.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecAudioDecoderImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr AudioDecoderFactory::CreateByMime(const std::string &mime) +{ + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_AUDIO_DECODER, true, mime); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to init AVCodecAudioDecoderImpl"); + + return impl; +} + +std::shared_ptr AudioDecoderFactory::CreateByName(const std::string &name) +{ + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_AUDIO_DECODER, false, name); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to init AVCodecAudioDecoderImpl"); + + return impl; +} + +int32_t AVCodecAudioDecoderImpl::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + codecService_ = AVCodecServiceFactory::GetInstance().CreateCodecService(); + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_UNKNOWN, "failed to create codec service"); + + return codecService_->Init(type, isMimeType, name); +} + +AVCodecAudioDecoderImpl::AVCodecAudioDecoderImpl() +{ + AVCODEC_LOGD("AVCodecAudioDecoderImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecAudioDecoderImpl::~AVCodecAudioDecoderImpl() +{ + if (codecService_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyCodecService(codecService_); + codecService_ = nullptr; + } + AVCODEC_LOGD("AVCodecAudioDecoderImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVCodecAudioDecoderImpl::Configure(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Configure(format); +} + +int32_t AVCodecAudioDecoderImpl::Prepare() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return AVCS_ERR_OK; +} + +int32_t AVCodecAudioDecoderImpl::Start() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Start(); +} + +int32_t AVCodecAudioDecoderImpl::Stop() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Stop(); +} + +int32_t AVCodecAudioDecoderImpl::Flush() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Flush(); +} + +int32_t AVCodecAudioDecoderImpl::Reset() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Reset(); +} + +int32_t AVCodecAudioDecoderImpl::Release() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Release(); +} + +std::shared_ptr AVCodecAudioDecoderImpl::GetInputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, nullptr, "service died"); + return codecService_->GetInputBuffer(index); +} + +int32_t AVCodecAudioDecoderImpl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr AVCodecAudioDecoderImpl::GetOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, nullptr, "service died"); + return codecService_->GetOutputBuffer(index); +} + +int32_t AVCodecAudioDecoderImpl::GetOutputFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->GetOutputFormat(format); +} + +int32_t AVCodecAudioDecoderImpl::ReleaseOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->ReleaseOutputBuffer(index); +} + +int32_t AVCodecAudioDecoderImpl::SetParameter(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->SetParameter(format); +} + +int32_t AVCodecAudioDecoderImpl::SetCallback(const std::shared_ptr &callback) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_INVALID_VAL, "callback is nullptr"); + return codecService_->SetCallback(callback); +} +} // nmamespace Media +} // namespace OHOS diff --git a/frameworks/native/avcodec/avcodec_audio_decoder_impl.h b/frameworks/native/avcodec/avcodec_audio_decoder_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..6c7fba69e0b4b6c3750a585a22ce1e8b6eaec190 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_audio_decoder_impl.h @@ -0,0 +1,50 @@ +/* + * 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 AVCODEC_AUDIO_DECODER_IMPL_H +#define AVCODEC_AUDIO_DECODER_IMPL_H + +#include "avcodec_audio_decoder.h" +#include "nocopyable.h" +#include "i_avcodec_service.h" + +namespace OHOS { +namespace Media { +class AVCodecAudioDecoderImpl : public AVCodecAudioDecoder, public NoCopyable { +public: + AVCodecAudioDecoderImpl(); + ~AVCodecAudioDecoderImpl(); + + int32_t Configure(const Format &format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name); + +private: + std::shared_ptr codecService_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avcodec/avcodec_audio_encoder_impl.cpp b/frameworks/native/avcodec/avcodec_audio_encoder_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14dde42aab897f14217e1246c8e48c540a28e343 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_audio_encoder_impl.cpp @@ -0,0 +1,154 @@ +/* + * 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 "avcodec_audio_encoder_impl.h" +#include "i_avcodec_service.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecAudioEncoderImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr AudioEncoderFactory::CreateByMime(const std::string &mime) +{ + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_AUDIO_ENCODER, true, mime); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to init AVCodecAudioEncoderImpl"); + + return impl; +} + +std::shared_ptr AudioEncoderFactory::CreateByName(const std::string &name) +{ + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_AUDIO_ENCODER, false, name); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to init AVCodecAudioEncoderImpl"); + + return impl; +} + +int32_t AVCodecAudioEncoderImpl::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + codecService_ = AVCodecServiceFactory::GetInstance().CreateCodecService(); + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_UNKNOWN, "failed to create codec service"); + + return codecService_->Init(type, isMimeType, name); +} + +AVCodecAudioEncoderImpl::AVCodecAudioEncoderImpl() +{ + AVCODEC_LOGD("AVCodecAudioEncoderImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecAudioEncoderImpl::~AVCodecAudioEncoderImpl() +{ + if (codecService_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyCodecService(codecService_); + codecService_ = nullptr; + } + AVCODEC_LOGD("AVCodecAudioEncoderImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVCodecAudioEncoderImpl::Configure(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Configure(format); +} + +int32_t AVCodecAudioEncoderImpl::Prepare() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return AVCS_ERR_OK; +} + +int32_t AVCodecAudioEncoderImpl::Start() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Start(); +} + +int32_t AVCodecAudioEncoderImpl::Stop() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Stop(); +} + +int32_t AVCodecAudioEncoderImpl::Flush() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Flush(); +} + +int32_t AVCodecAudioEncoderImpl::Reset() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Reset(); +} + +int32_t AVCodecAudioEncoderImpl::Release() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->Release(); +} + +std::shared_ptr AVCodecAudioEncoderImpl::GetInputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, nullptr, "service died"); + return codecService_->GetInputBuffer(index); +} + +int32_t AVCodecAudioEncoderImpl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr AVCodecAudioEncoderImpl::GetOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, nullptr, "service died"); + return codecService_->GetOutputBuffer(index); +} + +int32_t AVCodecAudioEncoderImpl::GetOutputFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->GetOutputFormat(format); +} + +int32_t AVCodecAudioEncoderImpl::ReleaseOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->ReleaseOutputBuffer(index); +} + +int32_t AVCodecAudioEncoderImpl::SetParameter(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + return codecService_->SetParameter(format); +} + +int32_t AVCodecAudioEncoderImpl::SetCallback(const std::shared_ptr &callback) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, AVCS_ERR_INVALID_OPERATION, "service died"); + CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_INVALID_VAL, "callback is nullptr"); + return codecService_->SetCallback(callback); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/native/avcodec/avcodec_audio_encoder_impl.h b/frameworks/native/avcodec/avcodec_audio_encoder_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..647767050eeb546363cd9db822702cdb2289ffd3 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_audio_encoder_impl.h @@ -0,0 +1,51 @@ +/* + * 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 AVCODEC_AUDIO_ENCODER_IMPL_H +#define AVCODEC_AUDIO_ENCODER_IMPL_H + +#include "avcodec_audio_encoder.h" +#include "nocopyable.h" +#include "i_avcodec_service.h" + +namespace OHOS { +namespace Media { +class AVCodecAudioEncoderImpl : public AVCodecAudioEncoder, public NoCopyable { +public: + AVCodecAudioEncoderImpl(); + ~AVCodecAudioEncoderImpl(); + + int32_t Configure(const Format &format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name); + +private: + std::shared_ptr codecService_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_ENCODER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avcodec/avcodec_video_decoder_impl.cpp b/frameworks/native/avcodec/avcodec_video_decoder_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..631b6bc3ffcde26eb18d248733909a2d762b3355 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_video_decoder_impl.cpp @@ -0,0 +1,211 @@ +/* + * 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 "avcodec_video_decoder_impl.h" +#include "i_avcodec_service.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "avcodec_dfx.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecVideoDecoderImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr VideoDecoderFactory::CreateByMime(const std::string &mime) +{ + AVCODEC_SYNC_TRACE; + + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_VIDEO_DECODER, true, mime); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + nullptr, "AVCodec video decoder impl init failed"); + + return impl; +} + +std::shared_ptr VideoDecoderFactory::CreateByName(const std::string &name) +{ + AVCODEC_SYNC_TRACE; + + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_VIDEO_DECODER, false, name); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + nullptr, "AVCodec video decoder impl init failed"); + + return impl; +} + +int32_t AVCodecVideoDecoderImpl::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + AVCODEC_SYNC_TRACE; + codecService_ = AVCodecServiceFactory::GetInstance().CreateCodecService(); + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service create failed"); + + return codecService_->Init(type, isMimeType, name); +} + +AVCodecVideoDecoderImpl::AVCodecVideoDecoderImpl() +{ + AVCODEC_LOGD("AVCodecVideoDecoderImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecVideoDecoderImpl::~AVCodecVideoDecoderImpl() +{ + if (codecService_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyCodecService(codecService_); + codecService_ = nullptr; + } + AVCODEC_LOGD("AVCodecVideoDecoderImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVCodecVideoDecoderImpl::Configure(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Configure(format); +} + +int32_t AVCodecVideoDecoderImpl::Prepare() +{ + return AVCS_ERR_OK; +} + +int32_t AVCodecVideoDecoderImpl::Start() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Start(); +} + +int32_t AVCodecVideoDecoderImpl::Stop() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Stop(); +} + +int32_t AVCodecVideoDecoderImpl::Flush() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Flush(); +} + +int32_t AVCodecVideoDecoderImpl::Reset() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Reset(); +} + +int32_t AVCodecVideoDecoderImpl::Release() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Release(); +} + +int32_t AVCodecVideoDecoderImpl::SetOutputSurface(sptr surface) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->SetOutputSurface(surface); +} + +std::shared_ptr AVCodecVideoDecoderImpl::GetInputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + nullptr, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetInputBuffer(index); +} + +int32_t AVCodecVideoDecoderImpl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr AVCodecVideoDecoderImpl::GetOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + nullptr, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetOutputBuffer(index); +} + +int32_t AVCodecVideoDecoderImpl::GetOutputFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetOutputFormat(format); +} + +int32_t AVCodecVideoDecoderImpl::ReleaseOutputBuffer(uint32_t index, bool render) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->ReleaseOutputBuffer(index, render); +} + +int32_t AVCodecVideoDecoderImpl::SetParameter(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->SetParameter(format); +} + +int32_t AVCodecVideoDecoderImpl::SetCallback(const std::shared_ptr &callback) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + CHECK_AND_RETURN_RET_LOG(callback != nullptr, + AVCS_ERR_INVALID_VAL, "Callback is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->SetCallback(callback); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/native/avcodec/avcodec_video_decoder_impl.h b/frameworks/native/avcodec/avcodec_video_decoder_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..9cb3541e636cf700e996e5f1afd0112493e6a264 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_video_decoder_impl.h @@ -0,0 +1,51 @@ +/* + * 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 AVCODEC_VIDEO_DECODER_IMPL_H +#define AVCODEC_VIDEO_DECODER_IMPL_H + +#include "avcodec_video_decoder.h" +#include "nocopyable.h" +#include "i_avcodec_service.h" + +namespace OHOS { +namespace Media { +class AVCodecVideoDecoderImpl : public AVCodecVideoDecoder, public NoCopyable { +public: + AVCodecVideoDecoderImpl(); + ~AVCodecVideoDecoderImpl(); + + int32_t Configure(const Format &format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t SetOutputSurface(sptr surface) override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index, bool render) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name); + +private: + std::shared_ptr codecService_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_VIDEO_DECODER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avcodec/avcodec_video_encoder_impl.cpp b/frameworks/native/avcodec/avcodec_video_encoder_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..526be80ff2e517448c82dbc851403835d2326a30 --- /dev/null +++ b/frameworks/native/avcodec/avcodec_video_encoder_impl.cpp @@ -0,0 +1,225 @@ +/* + * 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 "avcodec_video_encoder_impl.h" +#include "i_avcodec_service.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "avcodec_dfx.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecVideoEncoderImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr VideoEncoderFactory::CreateByMime(const std::string &mime) +{ + AVCODEC_SYNC_TRACE; + + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_VIDEO_ENCODER, true, mime); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, + "AVCodec video encoder impl init failed"); + + return impl; +} + +std::shared_ptr VideoEncoderFactory::CreateByName(const std::string &name) +{ + AVCODEC_SYNC_TRACE; + + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(AVCODEC_TYPE_VIDEO_ENCODER, false, name); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, + "AVCodec video encoder impl init failed"); + + return impl; +} + +int32_t AVCodecVideoEncoderImpl::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + AVCODEC_SYNC_TRACE; + codecService_ = AVCodecServiceFactory::GetInstance().CreateCodecService(); + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_UNKNOWN, "Codec service create failed"); + + return codecService_->Init(type, isMimeType, name); +} + +AVCodecVideoEncoderImpl::AVCodecVideoEncoderImpl() +{ + AVCODEC_LOGD("AVCodecVideoEncoderImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecVideoEncoderImpl::~AVCodecVideoEncoderImpl() +{ + if (codecService_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyCodecService(codecService_); + codecService_ = nullptr; + } + AVCODEC_LOGD("AVCodecVideoEncoderImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVCodecVideoEncoderImpl::Configure(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Configure(format); +} + +int32_t AVCodecVideoEncoderImpl::Prepare() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return AVCS_ERR_OK; +} + +int32_t AVCodecVideoEncoderImpl::Start() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Start(); +} + +int32_t AVCodecVideoEncoderImpl::Stop() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Stop(); +} + +int32_t AVCodecVideoEncoderImpl::Flush() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Flush(); +} + +int32_t AVCodecVideoEncoderImpl::NotifyEos() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->NotifyEos(); +} + +int32_t AVCodecVideoEncoderImpl::Reset() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Reset(); +} + +int32_t AVCodecVideoEncoderImpl::Release() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->Release(); +} + +sptr AVCodecVideoEncoderImpl::CreateInputSurface() +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + nullptr, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + surface_ = codecService_->CreateInputSurface(); + return surface_; +} + +std::shared_ptr AVCodecVideoEncoderImpl::GetInputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + nullptr, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetInputBuffer(index); +} + +int32_t AVCodecVideoEncoderImpl::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr AVCodecVideoEncoderImpl::GetOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + nullptr, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetOutputBuffer(index); +} + +int32_t AVCodecVideoEncoderImpl::GetOutputFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->GetOutputFormat(format); +} + +int32_t AVCodecVideoEncoderImpl::ReleaseOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->ReleaseOutputBuffer(index); +} + +int32_t AVCodecVideoEncoderImpl::SetParameter(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->SetParameter(format); +} + +int32_t AVCodecVideoEncoderImpl::SetCallback(const std::shared_ptr &callback) +{ + CHECK_AND_RETURN_RET_LOG(codecService_ != nullptr, + AVCS_ERR_INVALID_OPERATION, "Codec service is nullptr"); + CHECK_AND_RETURN_RET_LOG(callback != nullptr, + AVCS_ERR_INVALID_VAL, "Callback is nullptr"); + + AVCODEC_SYNC_TRACE; + return codecService_->SetCallback(callback); +} +} // namespace Media +} // namespace OHOS diff --git a/frameworks/native/avcodec/avcodec_video_encoder_impl.h b/frameworks/native/avcodec/avcodec_video_encoder_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..bbc36d0a0f73e4139f2d2c6858b936752609d0db --- /dev/null +++ b/frameworks/native/avcodec/avcodec_video_encoder_impl.h @@ -0,0 +1,53 @@ +/* + * 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 AVCODEC_VIDEO_ENCODER_IMPL_H +#define AVCODEC_VIDEO_ENCODER_IMPL_H + +#include "avcodec_video_encoder.h" +#include "nocopyable.h" +#include "i_avcodec_service.h" + +namespace OHOS { +namespace Media { +class AVCodecVideoEncoderImpl : public AVCodecVideoEncoder, public NoCopyable { +public: + AVCodecVideoEncoderImpl(); + ~AVCodecVideoEncoderImpl(); + + int32_t Configure(const Format &format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + sptr CreateInputSurface() override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name); + +private: + std::shared_ptr codecService_ = nullptr; + sptr surface_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_VIDEO_ENCODER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avcodeclist/avcodeclist_impl.cpp b/frameworks/native/avcodeclist/avcodeclist_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5735787740257e20fa4f13957d0790bc5b9f685f --- /dev/null +++ b/frameworks/native/avcodeclist/avcodeclist_impl.cpp @@ -0,0 +1,72 @@ +/* + * 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 "avcodec_log.h" +#include "avcodec_errors.h" +#include "i_avcodec_service.h" +#include "avcodeclist_impl.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecListImpl"}; +} +namespace OHOS { +namespace Media { +std::shared_ptr AVCodecListFactory::CreateAVCodecList() +{ + std::shared_ptr impl = std::make_shared(); + + int32_t ret = impl->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to init AVCodecListImpl"); + + return impl; +} + +int32_t AVCodecListImpl::Init() +{ + codecListService_ = AVCodecServiceFactory::GetInstance().CreateCodecListService(); + CHECK_AND_RETURN_RET_LOG(codecListService_ != nullptr, AVCS_ERR_UNKNOWN, "failed to create AVCodecList service"); + return AVCS_ERR_OK; +} + +AVCodecListImpl::AVCodecListImpl() +{ + AVCODEC_LOGD("AVCodecListImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecListImpl::~AVCodecListImpl() +{ + if (codecListService_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyCodecListService(codecListService_); + codecListService_ = nullptr; + } + AVCODEC_LOGD("AVCodecListImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +std::string AVCodecListImpl::FindDecoder(const Format &format) +{ + return codecListService_->FindDecoder(format); +} + +std::string AVCodecListImpl::FindEncoder(const Format &format) +{ + return codecListService_->FindEncoder(format); +} + +CapabilityData AVCodecListImpl::CreateCapability(std::string codecName) +{ + return codecListService_->CreateCapability(codecName); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/avcodeclist/avcodeclist_impl.h b/frameworks/native/avcodeclist/avcodeclist_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..0bd09314e695364b44cae0e3b2c2fd865d2bf518 --- /dev/null +++ b/frameworks/native/avcodeclist/avcodeclist_impl.h @@ -0,0 +1,41 @@ +/* + * 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 AVCODEC_LIST_IMPL_H +#define AVCODEC_LIST_IMPL_H + +#include "avcodec_info.h" +#include "avcodec_list.h" +#include "nocopyable.h" +#include "i_codeclist_service.h" + +namespace OHOS { +namespace Media { +class AVCodecListImpl : public AVCodecList, public NoCopyable { +public: + AVCodecListImpl(); + ~AVCodecListImpl(); + int32_t Init(); + // AVCodecList + std::string FindDecoder(const Format &format) override; + std::string FindEncoder(const Format &format) override; + CapabilityData CreateCapability(const std::string codecName) override; + +private: + std::shared_ptr codecListService_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LIST_IMPL_H + diff --git a/frameworks/native/avdemuxer/avdemuxer_impl.cpp b/frameworks/native/avdemuxer/avdemuxer_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8daba6e51a3fc5ba8d4c70dfd0623222d81a6421 --- /dev/null +++ b/frameworks/native/avdemuxer/avdemuxer_impl.cpp @@ -0,0 +1,156 @@ +/* + * 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 "avdemuxer_impl.h" +#include +#include +#include +#include +#include "securec.h" +#include "avcodec_log.h" +#include "avsharedmemorybase.h" +#include "avcodec_dfx.h" +#include "i_avcodec_service.h" +#include "avcodec_errors.h" + +static int LOOP_LOG_MAX_COUNT = 1000; + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVDemuxerImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr AVDemuxerFactory::CreateWithSource(AVSource &source) +{ + AVCodecTrace trace("AVDemuxerFactory::CreateWithSource"); + + AVCODEC_LOGI("create demuxerImpl from source %{public}s", source.sourceUri.c_str()); + + std::shared_ptr demuxerImpl = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(demuxerImpl != nullptr, nullptr, "New AVDemuxerImpl failed when create demuxer"); + + int32_t ret = demuxerImpl->Init(source); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init AVDemuxerImpl failed when create demuxer"); + + return demuxerImpl; +} + +int32_t AVDemuxerImpl::Init(AVSource &source) +{ + AVCodecTrace trace("AVDemuxer::Init"); + + demuxerClient_ = AVCodecServiceFactory::GetInstance().CreateDemuxerService(); + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, + AVCS_ERR_CREATE_DEMUXER_SUB_SERVICE_FAILED, "Create demuxer service failed when init demuxerImpl"); + + uintptr_t sourceAddr = source.GetSourceAddr(); + + sourceUri_ = source.sourceUri; + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "demuxer service died when load add sourceTrack!"); + + return demuxerClient_->Init(sourceAddr); +} + +AVDemuxerImpl::AVDemuxerImpl() +{ + AVCODEC_LOGI("init demuxerImpl"); + AVCODEC_LOGD("AVDemuxerImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVDemuxerImpl::~AVDemuxerImpl() +{ + AVCODEC_LOGI("uninit demuxerImpl for source %{public}s", sourceUri_.c_str()); + if (demuxerClient_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroyDemuxerService(demuxerClient_); + demuxerClient_ = nullptr; + } + AVCODEC_LOGD("AVDemuxerImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVDemuxerImpl::SelectSourceTrackByID(uint32_t trackIndex) +{ + AVCodecTrace trace("AVDemuxer::SelectSourceTrackByID"); + + AVCODEC_LOGI("select source track: trackIndex=%{public}d", trackIndex); + + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "demuxer service died when load add sourceTrack!"); + return demuxerClient_->SelectSourceTrackByID(trackIndex); +} + +int32_t AVDemuxerImpl::UnselectSourceTrackByID(uint32_t trackIndex) +{ + AVCodecTrace trace("AVDemuxer::UnselectSourceTrackByID"); + + AVCODEC_LOGI("unselect source track: trackIndex=%{public}d", trackIndex); + + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "demuxer service died when remove sourceTrack!"); + return demuxerClient_->UnselectSourceTrackByID(trackIndex); +} + +int32_t AVDemuxerImpl::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + AVCodecTrace trace("AVDemuxer::CopyNextSample"); + + AVCODEC_LOGI("CopyNextSample"); + + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "demuxer service died when copy sample!"); + + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_INVALID_VAL, + "Copy sample failed because input buffer is nullptr!"); + + if (trackLogCount < LOOP_LOG_MAX_COUNT) { + if (trackLogCount==0) { + AVCodecTrace::TraceBegin(std::string(__FUNCTION__), FAKE_POINTER(this)); + } + trackLogCount++; + } + + std::shared_ptr memory = + std::make_shared(bufferInfo.size, AVSharedMemory::FLAGS_READ_WRITE, "sampleBuffer"); + int32_t ret = memory->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_NO_MEMORY, "Copy sample failed by demuxerService!"); + + ret = demuxerClient_->CopyNextSample(trackIndex, memory->GetBase(), bufferInfo, flag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, "Copy sample failed by demuxerService!"); + + errno_t rc = memcpy_s(buffer, memory->GetSize(), memory->GetBase(), memory->GetSize()); + CHECK_AND_RETURN_RET_LOG(rc == EOK, AVCS_ERR_UNKNOWN, "memcpy_s failed"); + + if (trackLogCount == LOOP_LOG_MAX_COUNT) { + AVCodecTrace::TraceEnd(std::string(__FUNCTION__), FAKE_POINTER(this)); + } + return AVCS_ERR_OK; +} + +int32_t AVDemuxerImpl::SeekToTime(int64_t mSeconds, AVSeekMode mode) +{ + AVCodecTrace trace("AVDemuxer::SeekToTime"); + + AVCODEC_LOGI("seek to time: mSeconds=%{public}" PRId64 "; mode=%{public}d", mSeconds, mode); + + CHECK_AND_RETURN_RET_LOG(demuxerClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, "demuxer service died when seek!"); + + CHECK_AND_RETURN_RET_LOG(mSeconds >= 0, AVCS_ERR_INVALID_VAL, "Seek failed because input mSeconds is negative!"); + + return demuxerClient_->SeekToTime(mSeconds, mode); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/avdemuxer/avdemuxer_impl.h b/frameworks/native/avdemuxer/avdemuxer_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..a9d6f3d91cf1ac233cc964e9a1fc86853e368b4d --- /dev/null +++ b/frameworks/native/avdemuxer/avdemuxer_impl.h @@ -0,0 +1,46 @@ +/* + * 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 AVDEMUXER_IMPL_H +#define AVDEMUXER_IMPL_H + +#include +#include "avdemuxer.h" +#include "i_demuxer_service.h" +#include "nocopyable.h" +#include "avsource_impl.h" + +namespace OHOS { +namespace Media { +class AVDemuxerImpl : public AVDemuxer, public NoCopyable { +public: + AVDemuxerImpl(); + ~AVDemuxerImpl(); + + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) override; + int32_t Init(AVSource &source); + +private: + std::shared_ptr demuxerClient_ = nullptr; + uint16_t trackLogCount = 0; + std::string sourceUri_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVDEMUXER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avmuxer/avmuxer_impl.cpp b/frameworks/native/avmuxer/avmuxer_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45b0b4faedfe9d325c466cb88039cfbe95f798fd --- /dev/null +++ b/frameworks/native/avmuxer/avmuxer_impl.cpp @@ -0,0 +1,127 @@ +/* + * 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_impl.h" +#include +#include +#include "securec.h" +#include "i_avcodec_service.h" +#include "avcodec_log.h" +#include "avsharedmemorybase.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVMuxerImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr AVMuxerFactory::CreateAVMuxer(int32_t fd, OutputFormat format) +{ + 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"); + + std::shared_ptr impl = std::make_shared(fd, format); + + int32_t ret = impl->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init avmuxer implementation failed"); + return impl; +} + +AVMuxerImpl::AVMuxerImpl(int32_t fd, OutputFormat format) : fd_(fd), format_(format) +{ + (void)fd_; + (void)format_; + AVCODEC_LOGD("AVMuxerImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVMuxerImpl::~AVMuxerImpl() +{ + 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("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("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("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::AddTrack(int32_t &trackIndex, const MediaDescription &trackDesc) +{ + 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("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(uint8_t *sampleBuffer, const TrackSampleInfo &info) +{ + 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 = + 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 muxerService_->WriteSampleBuffer(sharedSampleBuffer, info); +} + +int32_t AVMuxerImpl::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 new file mode 100644 index 0000000000000000000000000000000000000000..a909f08f6b1bd9a3f16a82881ae5bd8a91817be9 --- /dev/null +++ b/frameworks/native/avmuxer/avmuxer_impl.h @@ -0,0 +1,43 @@ +/* + * 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_IMPL_H +#define AVMUXER_IMPL_H + +#include "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, OutputFormat format); + ~AVMuxerImpl() override; + int32_t Init(); + 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(uint8_t *sampleBuffer, const TrackSampleInfo &info) override; + int32_t Stop() override; + +private: + std::shared_ptr muxerService_ = nullptr; + int32_t fd_ = -1; + OutputFormat format_ = OUTPUT_FORMAT_DEFAULT; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_IMPL_H \ No newline at end of file diff --git a/frameworks/native/avsource/avsource_impl.cpp b/frameworks/native/avsource/avsource_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1310f3458649c309064365e148e8e5fa782d16b1 --- /dev/null +++ b/frameworks/native/avsource/avsource_impl.cpp @@ -0,0 +1,265 @@ +/* + * 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 "avcodec_common.h" +#include "i_avcodec_service.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "avsource_impl.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVSourceImpl"}; +} + +namespace OHOS { +namespace Media { +std::vector setTrackFormatSupportedList = { + AVSourceTrackFormat::VIDEO_BIT_STREAM_FORMAT, +}; + +std::shared_ptr AVSourceFactory::CreateWithURI(const std::string &uri) +{ + AVCodecTrace trace("AVSourceFactory::CreateWithURI"); + + AVCODEC_LOGI("create source with uri: uri=%{private}s", uri.c_str()); + + std::shared_ptr sourceImpl = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(sourceImpl != nullptr, nullptr, "New AVSourceImpl failed when create source with uri"); + + int32_t ret = sourceImpl->Init(uri); + + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init AVSourceImpl failed when create source with uri"); + + return sourceImpl; +} + +std::shared_ptr AVSourceFactory::CreateWithFD(int32_t fd, int64_t offset, int64_t size) +{ + AVCodecTrace trace("AVSourceFactory::CreateWithFD"); + + AVCODEC_LOGI("create source with fd: fd=%{private}d, offset=%{public}" PRId64 ", size=%{public}" PRId64, + fd, offset, size); + + CHECK_AND_RETURN_RET_LOG(fd > 2, nullptr, + "Create source with uri failed because input fd is illegal, fd must be greater than 2!"); + CHECK_AND_RETURN_RET_LOG(size >= 0, nullptr, "Create source with uri failed because input size is negative"); + + 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::string uri = "fd://" + std::to_string(fd) + "?offset=" + \ + std::to_string(offset) + "&size=" + std::to_string(size); + + std::shared_ptr sourceImpl = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(sourceImpl != nullptr, nullptr, "New AVSourceImpl failed when create source with uri"); + + int32_t ret = sourceImpl->Init(uri); + + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Init AVSourceImpl failed when create source with uri"); + + return sourceImpl; +} + +int32_t AVSourceImpl::Init(const std::string &uri) +{ + AVCodecTrace trace("AVSource::Init"); + + sourceClient_ = AVCodecServiceFactory::GetInstance().CreateSourceService(); + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "Create source service failed when init sourceImpl"); + + int32_t ret = sourceClient_->Init(uri); + if (ret == AVCS_ERR_OK) { + uint32_t trackCount = 0; + ret = sourceClient_->GetTrackCount(trackCount); + trackCount_ = trackCount; + } + return ret; +} + +AVSourceImpl::AVSourceImpl() +{ + AVCODEC_LOGI("init sourceImpl"); + AVCODEC_LOGD("AVSourceImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVSourceImpl::~AVSourceImpl() +{ + AVCODEC_LOGI("uninit sourceImpl for source %{public}s", sourceUri.c_str()); + if (sourceClient_ != nullptr) { + (void)AVCodecServiceFactory::GetInstance().DestroySourceService(sourceClient_); + sourceClient_ = nullptr; + } + + for (auto track : tracks_) { + track = nullptr; + } + tracks_.clear(); + + AVCODEC_LOGD("AVSourceImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +uintptr_t AVSourceImpl::GetSourceAddr() +{ + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "source service died when get source addr!"); + + return sourceClient_->GetSourceAddr(); +} + +int32_t AVSourceImpl::GetTrackCount(uint32_t &trackCount) +{ + AVCodecTrace trace("AVSource::GetTrackCount"); + + AVCODEC_LOGI("get track count by source"); + + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "source service died when get source track!"); + + if (trackCount_ < 0) { + int32_t ret = sourceClient_->GetTrackCount(trackCount); + trackCount_ = trackCount; + return ret; + } else { + trackCount = trackCount_; + return AVCS_ERR_OK; + } +} + +std::shared_ptr AVSourceImpl::GetSourceTrackByID(uint32_t trackIndex) +{ + AVCodecTrace trace("AVSource::GetSourceTrackByID"); + + AVCODEC_LOGI("get source track from source: trackIndex=%{public}d", trackIndex); + + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, nullptr, "source service died when load track!"); + + auto trackIndexIsValid = TrackIndexIsValid(trackIndex); + CHECK_AND_RETURN_RET_LOG(trackIndexIsValid, nullptr, "track index is invalid!"); + + std::shared_ptr track = std::make_shared(this, trackIndex); + tracks_.emplace_back(track); + return track; +} + +int32_t AVSourceImpl::GetSourceFormat(Format &format) +{ + AVCodecTrace trace("AVSource::GetSourceFormat"); + + AVCODEC_LOGI("get source format: format=%{public}s", format.Stringify().c_str()); + + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "source service died when get source format!"); + + return sourceClient_->GetSourceFormat(format); +} + +int32_t AVSourceImpl::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + AVCodecTrace trace("AVSource::GetTrackFormat"); + + AVCODEC_LOGI("get source track format: trackIndex=%{public}d, format=%{public}s", + trackIndex, format.Stringify().c_str()); + + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "source service died when get track format!"); + + auto trackIndexIsValid = TrackIndexIsValid(trackIndex); + CHECK_AND_RETURN_RET_LOG(trackIndexIsValid, AVCS_ERR_INVALID_VAL, "track index is invalid!"); + + return sourceClient_->GetTrackFormat(format, trackIndex); +} + +int32_t AVSourceImpl::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + AVCodecTrace trace("AVSource::SetTrackFormat"); + + AVCODEC_LOGI("set source track format: trackIndex=%{public}d, format=%{public}s", + trackIndex, format.Stringify().c_str()); + + CHECK_AND_RETURN_RET_LOG(sourceClient_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "source service died when set format!"); + + auto trackIndexIsValid = TrackIndexIsValid(trackIndex); + CHECK_AND_RETURN_RET_LOG(trackIndexIsValid, AVCS_ERR_INVALID_VAL, "track index is invalid!"); + + auto &formatMap = format.GetFormatMap(); + bool allKeySupported = true; + for (auto pair : formatMap) { + auto index = std::find_if(setTrackFormatSupportedList.begin(), setTrackFormatSupportedList.end(), + [pair](std::string_view support) { return pair.first == support; }); + if (index == setTrackFormatSupportedList.end()) { + AVCODEC_LOGE("key %{punlic}s is not supported to set!", pair.first.c_str()); + allKeySupported = false; + break; + } + } + + CHECK_AND_RETURN_RET_LOG(allKeySupported, AVCS_ERR_INVALID_VAL, + "Set track format failed because input format is invalid!"); + + return sourceClient_->SetTrackFormat(format, trackIndex); +} + +bool AVSourceImpl::TrackIndexIsValid(uint32_t trackIndex) +{ + if (trackCount_ < 0) { + uint32_t trackCount = 0; + int32_t ret = sourceClient_->GetTrackCount(trackCount); + if (ret != AVCS_ERR_OK) { + return false; + } + trackCount_ = trackCount; + } + return (trackIndex>=0 && (uint32_t)trackCount_>=0 && trackIndex<=(uint32_t)trackCount_); +} + +AVSourceTrackImpl::AVSourceTrackImpl(AVSourceImpl *source, uint32_t trackIndex) +{ + AVCODEC_LOGI("init source track: trackIndex=%{public}d", trackIndex); + + trackIndex_ = trackIndex; + sourceImpl_ = source; + + AVCODEC_LOGD("AVSourceTrackImpl:0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVSourceTrackImpl::~AVSourceTrackImpl() +{ + AVCODEC_LOGI("uninit sourceTrackImpl"); + if (sourceImpl_ != nullptr) { + sourceImpl_ = nullptr; + } + AVCODEC_LOGD("AVSourceTrackImpl:0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t AVSourceTrackImpl::SetTrackFormat(const Format &format) +{ + AVCodecTrace trace("AVSourceTrack::SetTrackFormat"); + + return sourceImpl_->SetTrackFormat(format, trackIndex_); +} + +int32_t AVSourceTrackImpl::GetTrackFormat(Format &format) +{ + AVCodecTrace trace("AVSourceTrack::GetTrackFormat"); + + return sourceImpl_->GetTrackFormat(format, trackIndex_); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/avsource/avsource_impl.h b/frameworks/native/avsource/avsource_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..3d173512961075c3bd4079d1e1aa812ad1ac1585 --- /dev/null +++ b/frameworks/native/avsource/avsource_impl.h @@ -0,0 +1,61 @@ +/* + * 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 AVSOURCE_IMPL_H +#define AVSOURCE_IMPL_H + +#include "avsource.h" +#include "nocopyable.h" +#include "i_source_service.h" + +namespace OHOS { +namespace Media { +class AVSourceImpl : public AVSource, public NoCopyable { +public: + AVSourceImpl(); + ~AVSourceImpl() override; + + int32_t GetTrackCount(uint32_t &trackCount) override; + std::shared_ptr GetSourceTrackByID(uint32_t trackIndex) override; + uintptr_t GetSourceAddr() override; + int32_t GetSourceFormat(Format &format) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex); + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex); + int32_t Init(const std::string &uri); + + std::string sourceUri; + +private: + std::shared_ptr sourceClient_ = nullptr; + std::vector> tracks_ {}; + int32_t trackCount_ = -1; + bool TrackIndexIsValid(uint32_t trackIndex); +}; + +class AVSourceTrackImpl : public AVSourceTrack, public NoCopyable { +public: + AVSourceTrackImpl(AVSourceImpl *source, uint32_t trackIndex); + ~AVSourceTrackImpl(); + + int32_t SetTrackFormat(const Format &format) override; + int32_t GetTrackFormat(Format &format) override; +private: + uint32_t trackIndex_; + AVSourceImpl* sourceImpl_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVSOURCE_IMPL_H + diff --git a/frameworks/native/capi/avcodec/native_audio_decoder.cpp b/frameworks/native/capi/avcodec/native_audio_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66cf77df279bd2560e6dc0414a4a117c583a92dc --- /dev/null +++ b/frameworks/native/capi/avcodec/native_audio_decoder.cpp @@ -0,0 +1,437 @@ +/* + * 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 +#include +#include "native_avcodec_base.h" +#include "native_avcodec_audiodecoder.h" +#include "native_avmagic.h" +#include "avcodec_audio_decoder.h" +#include "avsharedmemory.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAudioDecoder"}; +} + +using namespace OHOS::Media; +class NativeAudioDecoder; + +struct AudioDecoderObject : public OH_AVCodec { + explicit AudioDecoderObject(const std::shared_ptr &decoder) + : OH_AVCodec(AVMagic::AVCODEC_MAGIC_AUDIO_DECODER), audioDecoder_(decoder) {} + ~AudioDecoderObject() = default; + + const std::shared_ptr audioDecoder_; + std::list> memoryObjList_; + std::shared_ptr callback_ = nullptr; + std::atomic isFlushing_ = false; + std::atomic isStop_ = false; + std::atomic isEOS_ = false; +}; + +class NativeAudioDecoder : public AVCodecCallback { +public: + NativeAudioDecoder(OH_AVCodec *codec, struct OH_AVCodecAsyncCallback cb, void *userData) + : codec_(codec), callback_(cb), userData_(userData) {} + virtual ~NativeAudioDecoder() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override + { + std::unique_lock lock(mutex_); + (void)errorType; + if (codec_ != nullptr && callback_.onError != nullptr) { + int32_t extErr = AVCSErrorToOHAVErrCode(static_cast(errorCode)); + callback_.onError(codec_, extErr, userData_); + } + } + + void OnOutputFormatChanged(const Format &format) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onStreamChanged != nullptr) { + OHOS::sptr object = new(std::nothrow) OH_AVFormat(format); + // The object lifecycle is controlled by the current function stack + callback_.onStreamChanged(codec_, reinterpret_cast(object.GetRefPtr()), userData_); + } + } + + void OnInputBufferAvailable(uint32_t index) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onNeedInputData != nullptr) { + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(audioDecObj->audioDecoder_ != nullptr, "audioDecoder_ is nullptr!"); + if (audioDecObj->isFlushing_.load() || audioDecObj->isStop_.load() || audioDecObj->isEOS_.load()) { + AVCODEC_LOGD("At flush, eos or stop, no buffer available"); + return; + } + + OH_AVMemory *data = GetInputData(codec_, index); + if (data != nullptr) { + callback_.onNeedInputData(codec_, index, data, userData_); + } + } + } + + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onNeedOutputData != nullptr) { + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(audioDecObj->audioDecoder_ != nullptr, "audioDecoder_ is nullptr!"); + if (audioDecObj->isFlushing_.load() || audioDecObj->isStop_.load()) { + AVCODEC_LOGD("At flush or stop, ignore"); + return; + } + + struct OH_AVCodecBufferAttr bufferAttr; + bufferAttr.pts = info.presentationTimeUs; + bufferAttr.size = info.size; + bufferAttr.offset = info.offset; + bufferAttr.flags = flag; + // The bufferInfo lifecycle is controlled by the current function stack + OH_AVMemory *data = GetOutputData(codec_, index); + callback_.onNeedOutputData(codec_, index, data, &bufferAttr, userData_); + } + } + + void StopCallback() + { + std::unique_lock lock(mutex_); + codec_ = nullptr; + } + +private: + OH_AVMemory *GetInputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, nullptr, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, nullptr, "audioDecoder_ is nullptr!"); + + std::shared_ptr memory = audioDecObj->audioDecoder_->GetInputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "get input buffer is nullptr!"); + + for (auto &memoryObj : audioDecObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new(std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVMemory"); + + audioDecObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + OH_AVMemory *GetOutputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, nullptr, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, nullptr, "audioDecoder_ is nullptr!"); + + std::shared_ptr memory = audioDecObj->audioDecoder_->GetOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "get output buffer is nullptr!"); + + for (auto &memoryObj : audioDecObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new(std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVMemory"); + + audioDecObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + struct OH_AVCodec *codec_; + struct OH_AVCodecAsyncCallback callback_; + void *userData_; + std::mutex mutex_; +}; + +namespace OHOS { +namespace Media { +#ifdef __cplusplus + extern "C" { +#endif + +struct OH_AVCodec *OH_AudioDecoder_CreateByMime(const char *mime) +{ + CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "input mime is nullptr!"); + + std::shared_ptr audioDecoder = AudioDecoderFactory::CreateByMime(mime); + CHECK_AND_RETURN_RET_LOG(audioDecoder != nullptr, nullptr, "failed to AudioDecoderFactory::CreateByMime"); + + struct AudioDecoderObject *object = new(std::nothrow) AudioDecoderObject(audioDecoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new AudioDecoderObject"); + + return object; +} + +struct OH_AVCodec *OH_AudioDecoder_CreateByName(const char *name) +{ + CHECK_AND_RETURN_RET_LOG(name != nullptr, nullptr, "input name is nullptr!"); + + std::shared_ptr audioDecoder = AudioDecoderFactory::CreateByName(name); + CHECK_AND_RETURN_RET_LOG(audioDecoder != nullptr, nullptr, "failed to AudioDecoderFactory::CreateByMime"); + + struct AudioDecoderObject *object = new(std::nothrow) AudioDecoderObject(audioDecoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new AudioDecoderObject"); + + return object; +} + +OH_AVErrCode OH_AudioDecoder_Destroy(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + + if (audioDecObj != nullptr && audioDecObj->audioDecoder_ != nullptr) { + audioDecObj->callback_->StopCallback(); + audioDecObj->memoryObjList_.clear(); + audioDecObj->isStop_.store(true); + int32_t ret = audioDecObj->audioDecoder_->Release(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("audioDecoder Release failed!"); + delete codec; + return AV_ERR_OPERATE_NOT_PERMIT; + } + } else { + AVCODEC_LOGD("audioDecoder_ is nullptr!"); + } + + delete codec; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Configure(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder is nullptr!"); + + int32_t ret = audioDecObj->audioDecoder_->Configure(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder Configure failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Prepare(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + int32_t ret = audioDecObj->audioDecoder_->Prepare(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder Prepare failed!"); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Start(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + audioDecObj->isStop_.store(false); + audioDecObj->isEOS_.store(false); + int32_t ret = audioDecObj->audioDecoder_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder Start failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Stop(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + audioDecObj->isStop_.store(true); + AVCODEC_LOGD("set stop status to true"); + + int32_t ret = audioDecObj->audioDecoder_->Stop(); + if (ret != AVCS_ERR_OK) { + audioDecObj->isStop_.store(false); + AVCODEC_LOGE("audioDecoder Stop failed!, set stop status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + audioDecObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Flush(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + audioDecObj->isFlushing_.store(true); + AVCODEC_LOGD("Set flush status to true"); + int32_t ret = audioDecObj->audioDecoder_->Flush(); + if (ret != AVCS_ERR_OK) { + audioDecObj->isFlushing_.store(false); + AVCODEC_LOGE("audioDecoder Flush failed! Set flush status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + + audioDecObj->memoryObjList_.clear(); + audioDecObj->isFlushing_.store(false); + AVCODEC_LOGD("set flush status to false"); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_Reset(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + audioDecObj->isStop_.store(true); + AVCODEC_LOGD("Set stop status to true"); + + int32_t ret = audioDecObj->audioDecoder_->Reset(); + if (ret != AVCS_ERR_OK) { + audioDecObj->isStop_.store(false); + AVCODEC_LOGE("audioDecoder Reset failed! Set stop status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + + audioDecObj->memoryObjList_.clear(); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_PushInputData(struct OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + struct AVCodecBufferInfo bufferInfo; + bufferInfo.presentationTimeUs = attr.pts; + bufferInfo.size = attr.size; + bufferInfo.offset = attr.offset; + AVCodecBufferFlag bufferFlag = static_cast(attr.flags); + + int32_t ret = audioDecObj->audioDecoder_->QueueInputBuffer(index, bufferInfo, bufferFlag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder QueueInputBuffer failed!"); + if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) { + audioDecObj->isEOS_.store(true); + AVCODEC_LOGD("Set eos status to true"); + } + + return AV_ERR_OK; +} + +OH_AVFormat *OH_AudioDecoder_GetOutputDescription(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, nullptr, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, nullptr, "audioDecoder_ is nullptr!"); + + Format format; + int32_t ret = audioDecObj->audioDecoder_->GetOutputFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "audioDecoder GetOutputFormat failed!"); + + OH_AVFormat *avFormat = OH_AVFormat_Create(); + avFormat->format_ = format; + + return avFormat; +} + +OH_AVErrCode OH_AudioDecoder_FreeOutputData(struct OH_AVCodec *codec, uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + int32_t ret = audioDecObj->audioDecoder_->ReleaseOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder ReleaseOutputBuffer failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_SetParameter(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + int32_t ret = audioDecObj->audioDecoder_->SetParameter(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder SetParameter failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_SetCallback( + struct OH_AVCodec *codec, struct OH_AVCodecAsyncCallback callback, void *userData) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_DECODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioDecoderObject *audioDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioDecObj->audioDecoder_ != nullptr, AV_ERR_INVALID_VAL, "audioDecoder_ is nullptr!"); + + audioDecObj->callback_ = std::make_shared(codec, callback, userData); + + int32_t ret = audioDecObj->audioDecoder_->SetCallback(audioDecObj->callback_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioDecoder SetCallback failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioDecoder_IsValid(OH_AVCodec *codec, bool *isVaild) +{ + return AV_ERR_UNSUPPORT; +} + +#ifdef __cplusplus + }; +#endif +} // namesapce Media +} // OHOS \ No newline at end of file diff --git a/frameworks/native/capi/avcodec/native_audio_encoder.cpp b/frameworks/native/capi/avcodec/native_audio_encoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e682e7f5e0526ce79693e67260ad2ce2f0cf63c9 --- /dev/null +++ b/frameworks/native/capi/avcodec/native_audio_encoder.cpp @@ -0,0 +1,438 @@ +/* + * 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 +#include +#include "native_avcodec_base.h" +#include "native_avcodec_audioencoder.h" +#include "native_avmagic.h" +#include "avcodec_audio_encoder.h" +#include "avsharedmemory.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAudioEncoder"}; +} + +using namespace OHOS::Media; +class NativeAudioEncoderCallback; + +struct AudioEncoderObject : public OH_AVCodec { + explicit AudioEncoderObject(const std::shared_ptr &encoder) + : OH_AVCodec(AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER), audioEncoder_(encoder) + { + } + ~AudioEncoderObject() = default; + + const std::shared_ptr audioEncoder_; + std::list> memoryObjList_; + std::shared_ptr callback_ = nullptr; + std::atomic isFlushing_ = false; + std::atomic isStop_ = false; + std::atomic isEOS_ = false; +}; + +class NativeAudioEncoderCallback : public AVCodecCallback { +public: + NativeAudioEncoderCallback(OH_AVCodec *codec, struct OH_AVCodecAsyncCallback cb, void *userData) + : codec_(codec), callback_(cb), userData_(userData) + { + } + virtual ~NativeAudioEncoderCallback() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override + { + std::unique_lock lock(mutex_); + (void)errorType; + if (codec_ != nullptr && callback_.onError != nullptr) { + int32_t extErr = AVCSErrorToOHAVErrCode(static_cast(errorCode)); + callback_.onError(codec_, extErr, userData_); + } + } + + void OnOutputFormatChanged(const Format &format) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onStreamChanged != nullptr) { + OHOS::sptr object = new (std::nothrow) OH_AVFormat(format); + // The object lifecycle is controlled by the current function stack + callback_.onStreamChanged(codec_, reinterpret_cast(object.GetRefPtr()), userData_); + } + } + + void OnInputBufferAvailable(uint32_t index) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onNeedInputData != nullptr) { + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(audioEncObj->audioEncoder_ != nullptr, "audioEncoder_ is nullptr!"); + if (audioEncObj->isFlushing_.load() || audioEncObj->isStop_.load() || audioEncObj->isEOS_.load()) { + AVCODEC_LOGD("At flush, eos or stop, no buffer available"); + return; + } + + OH_AVMemory *data = GetInputData(codec_, index); + if (data != nullptr) { + callback_.onNeedInputData(codec_, index, data, userData_); + } + } + } + + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override + { + std::unique_lock lock(mutex_); + if (codec_ != nullptr && callback_.onNeedOutputData != nullptr) { + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(audioEncObj->audioEncoder_ != nullptr, "audioEncoder_ is nullptr!"); + if (audioEncObj->isFlushing_.load() || audioEncObj->isStop_.load()) { + AVCODEC_LOGD("At flush or stop, ignore"); + return; + } + struct OH_AVCodecBufferAttr bufferAttr; + bufferAttr.pts = info.presentationTimeUs; + bufferAttr.size = info.size; + bufferAttr.offset = info.offset; + bufferAttr.flags = flag; + // The bufferInfo lifecycle is controlled by the current function stack + OH_AVMemory *data = GetOutputData(codec_, index); + callback_.onNeedOutputData(codec_, index, data, &bufferAttr, userData_); + } + } + + void StopCallback() + { + std::unique_lock lock(mutex_); + codec_ = nullptr; + } + +private: + OH_AVMemory *GetInputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, nullptr, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, nullptr, "audioEncoder_ is nullptr!"); + + std::shared_ptr memory = audioEncObj->audioEncoder_->GetInputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "get input buffer is nullptr!"); + + for (auto &memoryObj : audioEncObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new (std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVMemory"); + + audioEncObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + OH_AVMemory *GetOutputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, nullptr, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, nullptr, "audioEncoder_ is nullptr!"); + + std::shared_ptr memory = audioEncObj->audioEncoder_->GetOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "get output buffer is nullptr!"); + + for (auto &memoryObj : audioEncObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new (std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new OH_AVMemory"); + + audioEncObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + struct OH_AVCodec *codec_; + struct OH_AVCodecAsyncCallback callback_; + void *userData_; + std::mutex mutex_; +}; + +namespace OHOS { +namespace Media { +#ifdef __cplusplus +extern "C" { +#endif + +struct OH_AVCodec *OH_AudioEncoder_CreateByMime(const char *mime) +{ + CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "input mime is nullptr!"); + + std::shared_ptr audioEncoder = AudioEncoderFactory::CreateByMime(mime); + CHECK_AND_RETURN_RET_LOG(audioEncoder != nullptr, nullptr, "failed to AudioEncoderFactory::CreateByMime"); + + struct AudioEncoderObject *object = new (std::nothrow) AudioEncoderObject(audioEncoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new AudioEncoderObject"); + + return object; +} + +struct OH_AVCodec *OH_AudioEncoder_CreateByName(const char *name) +{ + CHECK_AND_RETURN_RET_LOG(name != nullptr, nullptr, "input name is nullptr!"); + + std::shared_ptr audioEncoder = AudioEncoderFactory::CreateByName(name); + CHECK_AND_RETURN_RET_LOG(audioEncoder != nullptr, nullptr, "failed to AudioEncoderFactory::CreateByMime"); + + struct AudioEncoderObject *object = new (std::nothrow) AudioEncoderObject(audioEncoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "failed to new AudioEncoderObject"); + + return object; +} + +OH_AVErrCode OH_AudioEncoder_Destroy(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + + if (audioEncObj != nullptr && audioEncObj->audioEncoder_ != nullptr) { + audioEncObj->callback_->StopCallback(); + audioEncObj->memoryObjList_.clear(); + int32_t ret = audioEncObj->audioEncoder_->Release(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("audioEncoder Release failed!"); + delete codec; + return AV_ERR_OPERATE_NOT_PERMIT; + } + } else { + AVCODEC_LOGD("audioEncoder_ is nullptr!"); + } + + delete codec; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Configure(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder is nullptr!"); + + int32_t ret = audioEncObj->audioEncoder_->Configure(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder Configure failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Prepare(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + int32_t ret = audioEncObj->audioEncoder_->Prepare(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder Prepare failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Start(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + audioEncObj->isStop_.store(false); + audioEncObj->isEOS_.store(false); + AVCODEC_LOGD("Set stop and eos status to false"); + int32_t ret = audioEncObj->audioEncoder_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder Start failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Stop(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + audioEncObj->isStop_.store(true); + AVCODEC_LOGD("Set stop status to true"); + + int32_t ret = audioEncObj->audioEncoder_->Stop(); + if (ret != AVCS_ERR_OK) { + audioEncObj->isStop_.store(false); + AVCODEC_LOGE("audioEncoder Stop failed! Set stop status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + audioEncObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Flush(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + audioEncObj->isFlushing_.store(true); + AVCODEC_LOGD("Set flush status to true"); + + int32_t ret = audioEncObj->audioEncoder_->Flush(); + if (ret != AVCS_ERR_OK) { + audioEncObj->isFlushing_.store(false); + AVCODEC_LOGE("audioEncObj Flush failed! Set flush status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + audioEncObj->memoryObjList_.clear(); + audioEncObj->isFlushing_.store(false); + AVCODEC_LOGD("Set flush status to false"); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_Reset(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + audioEncObj->isStop_.store(true); + int32_t ret = audioEncObj->audioEncoder_->Reset(); + if (ret != AVCS_ERR_OK) { + audioEncObj->isStop_.store(false); + AVCODEC_LOGE("audioEncoder Reset failed! Set stop status to false"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + audioEncObj->memoryObjList_.clear(); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_PushInputData(struct OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + struct AVCodecBufferInfo bufferInfo; + bufferInfo.presentationTimeUs = attr.pts; + bufferInfo.size = attr.size; + bufferInfo.offset = attr.offset; + AVCodecBufferFlag bufferFlag = static_cast(attr.flags); + + int32_t ret = audioEncObj->audioEncoder_->QueueInputBuffer(index, bufferInfo, bufferFlag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder QueueInputBuffer failed!"); + if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) { + audioEncObj->isEOS_.store(true); + AVCODEC_LOGD("Set eos status to true"); + } + + return AV_ERR_OK; +} + +OH_AVFormat *OH_AudioEncoder_GetOutputDescription(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, nullptr, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, nullptr, "audioEncoder_ is nullptr!"); + + Format format; + int32_t ret = audioEncObj->audioEncoder_->GetOutputFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "audioEncoder GetOutputFormat failed!"); + + OH_AVFormat *avFormat = OH_AVFormat_Create(); + avFormat->format_ = format; + + return avFormat; +} + +OH_AVErrCode OH_AudioEncoder_FreeOutputData(struct OH_AVCodec *codec, uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + int32_t ret = audioEncObj->audioEncoder_->ReleaseOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder ReleaseOutputBuffer failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_SetParameter(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + int32_t ret = audioEncObj->audioEncoder_->SetParameter(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder SetParameter failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_SetCallback(struct OH_AVCodec *codec, struct OH_AVCodecAsyncCallback callback, + void *userData) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "input codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_AUDIO_ENCODER, AV_ERR_INVALID_VAL, "magic error!"); + + struct AudioEncoderObject *audioEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(audioEncObj->audioEncoder_ != nullptr, AV_ERR_INVALID_VAL, "audioEncoder_ is nullptr!"); + + audioEncObj->callback_ = std::make_shared(codec, callback, userData); + + int32_t ret = audioEncObj->audioEncoder_->SetCallback(audioEncObj->callback_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "audioEncoder SetCallback failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AudioEncoder_IsValid(OH_AVCodec *codec, bool *isVaild) +{ + return AV_ERR_UNSUPPORT; +} + +#ifdef __cplusplus +}; +#endif +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/capi/avcodec/native_avcodec_base.cpp b/frameworks/native/capi/avcodec/native_avcodec_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c24eb5f8b6587fe3c280f161384e06c3da10efff --- /dev/null +++ b/frameworks/native/capi/avcodec/native_avcodec_base.cpp @@ -0,0 +1,67 @@ +/* + * 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 "native_avcodec_base.h" + +#ifdef __cplusplus +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"; +const char *OH_MD_KEY_CODEC_MIME = "codec_mime"; +const char *OH_MD_KEY_DURATION = "duration"; +const char *OH_MD_KEY_BITRATE = "bitrate"; +const char *OH_MD_KEY_MAX_INPUT_SIZE = "max_input_size"; +const char *OH_MD_KEY_WIDTH = "width"; +const char *OH_MD_KEY_HEIGHT = "height"; +const char *OH_MD_KEY_PIXEL_FORMAT = "pixel_format"; +const char *OH_MD_KEY_AUDIO_SAMPLE_FORMAT = "audio_sample_format"; +const char *OH_MD_KEY_FRAME_RATE = "frame_rate"; +const char *OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE = "video_encode_bitrate_mode"; +const char *OH_MD_KEY_PROFILE = "codec_profile"; +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"; + +const char *OH_MD_KEY_TRACK_INDEX = "track_index"; +const char *OH_MD_KEY_TRACK_SAMPLE_COUNT = "track_sample_count"; +const char *OH_MD_KEY_BIT_STREAM_FORMAT = "bit_stream_format"; +const char *OH_MD_KEY_TITLE = "title"; +const char *OH_MD_KEY_ARTIST = "artist"; +const char *OH_MD_KEY_ALBUM = "album"; +const char *OH_MD_KEY_ALBUM_ARTIST = "album_artist"; +const char *OH_MD_KEY_DATE = "date"; +const char *OH_MD_KEY_COMMENT = "comment"; +const char *OH_MD_KEY_GENRE = "genre"; +const char *OH_MD_KEY_COPYRIGHT = "copyright"; +const char *OH_MD_KEY_LANGUAGE = "language"; +const char *OH_MD_KEY_DESCRIPTION = "description"; +const char *OH_MD_KEY_LYRICS = "lyrics"; +const char *OH_MD_KEY_START_TIME = "start_time"; +const char *OH_MD_KEY_TYPE = "media_type"; +#ifdef __cplusplus +} +#endif diff --git a/frameworks/native/capi/avcodec/native_codeclist.cpp b/frameworks/native/capi/avcodec/native_codeclist.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5aea04dd539aacdc8ec669586f4574973227b768 --- /dev/null +++ b/frameworks/native/capi/avcodec/native_codeclist.cpp @@ -0,0 +1,61 @@ +/* + * 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 "native_avmagic.h" +#include "avcodec_list.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "native_avcodec_list.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeCodecList"}; +} + +using namespace OHOS::Media; +const char *OH_AVCodec_FindEncoder(const OH_AVFormat *format) +{ + std::shared_ptr codeclist = AVCodecListFactory::CreateAVCodecList(); + std::string strname = codeclist->FindEncoder(format->format_); + char *ret = new char[strname.length() + 1]; + std::strcpy(ret, strname.c_str()); + AVCODEC_LOGD("get codecname: %{public}s", ret); + return ret; +} + +const char *OH_AVCodec_FindDecoder(const OH_AVFormat *format) +{ + std::shared_ptr codeclist = AVCodecListFactory::CreateAVCodecList(); + std::string strname = codeclist->FindDecoder(format->format_); + char *ret = new char[strname.length() + 1]; + std::strcpy(ret, strname.c_str()); + AVCODEC_LOGD("get codecname: %{public}s", ret); + return ret; +} + +OH_AVCapability *OH_AVCodec_CreateCapability(const char *name) +{ + std::shared_ptr codeclist = AVCodecListFactory::CreateAVCodecList(); + CapabilityData capabilityData = codeclist->CreateCapability(name); + return new (std::nothrow) OH_AVCapability(capabilityData); +} + +OH_AVErrCode OH_AVCodec_DestroyCapability(OH_AVCapability *capability) +{ + if (capability == nullptr) { + return AV_ERR_INVALID_VAL; + } + delete capability; + return AV_ERR_OK; +} diff --git a/frameworks/native/capi/avcodec/native_video_decoder.cpp b/frameworks/native/capi/avcodec/native_video_decoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56a589fb85692bb18838c7618e68cf5bb0748a35 --- /dev/null +++ b/frameworks/native/capi/avcodec/native_video_decoder.cpp @@ -0,0 +1,474 @@ +/* + * 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 +#include +#include "native_avcodec_base.h" +#include "native_avcodec_videodecoder.h" +#include "native_avmagic.h" +#include "native_window.h" +#include "avcodec_video_decoder.h" +#include "avsharedmemory.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeVideoDecoder"}; +} + +using namespace OHOS::Media; +class NativeVideoDecoderCallback; + +struct VideoDecoderObject : public OH_AVCodec { + explicit VideoDecoderObject(const std::shared_ptr &decoder) + : OH_AVCodec(AVMagic::AVCODEC_MAGIC_VIDEO_DECODER), videoDecoder_(decoder) + { + } + ~VideoDecoderObject() = default; + + const std::shared_ptr videoDecoder_; + std::list> memoryObjList_; + std::shared_ptr callback_ = nullptr; + std::atomic isFlushing_ = false; + std::atomic isStop_ = false; + std::atomic isEOS_ = false; +}; + +class NativeVideoDecoderCallback : public AVCodecCallback { +public: + NativeVideoDecoderCallback(OH_AVCodec *codec, struct OH_AVCodecAsyncCallback cb, void *userData) + : codec_(codec), callback_(cb), userData_(userData) + { + } + virtual ~NativeVideoDecoderCallback() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override + { + std::unique_lock lock(mutex_); + (void)errorType; + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onError != nullptr, "Callback is nullptr"); + int32_t extErr = AVCSErrorToOHAVErrCode(static_cast(errorCode)); + callback_.onError(codec_, extErr, userData_); + } + + void OnOutputFormatChanged(const Format &format) override + { + std::unique_lock lock(mutex_); + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onStreamChanged != nullptr, "Callback is nullptr"); + OHOS::sptr object = new (std::nothrow) OH_AVFormat(format); + callback_.onStreamChanged(codec_, reinterpret_cast(object.GetRefPtr()), userData_); + } + + void OnInputBufferAvailable(uint32_t index) override + { + std::unique_lock lock(mutex_); + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onNeedInputData != nullptr, "Callback is nullptr"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(videoDecObj->videoDecoder_ != nullptr, "Video decoder is nullptr!"); + + if (videoDecObj->isFlushing_.load() || videoDecObj->isStop_.load() || videoDecObj->isEOS_.load()) { + AVCODEC_LOGD("At flush, eos or stop, no buffer available"); + return; + } + + OH_AVMemory *data = GetInputData(codec_, index); + CHECK_AND_RETURN_LOG(data != nullptr, "Data is nullptr, get input data failed"); + callback_.onNeedInputData(codec_, index, data, userData_); + } + + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override + { + std::unique_lock lock(mutex_); + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onNeedOutputData != nullptr, "Callback is nullptr"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(videoDecObj->videoDecoder_ != nullptr, "Video decoder is nullptr!"); + + if (videoDecObj->isFlushing_.load() || videoDecObj->isStop_.load()) { + AVCODEC_LOGD("At flush or stop, ignore"); + return; + } + + struct OH_AVCodecBufferAttr bufferAttr; + bufferAttr.pts = info.presentationTimeUs; + bufferAttr.size = info.size; + bufferAttr.offset = info.offset; + bufferAttr.flags = flag; + callback_.onNeedOutputData(codec_, index, nullptr, &bufferAttr, userData_); + } + + void StopCallback() + { + std::unique_lock lock(mutex_); + codec_ = nullptr; + } + +private: + OH_AVMemory *GetInputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, nullptr, "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, nullptr, "Video decoder is nullptr!"); + + std::shared_ptr memory = videoDecObj->videoDecoder_->GetInputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "Memory is nullptr, get input buffer failed!"); + + for (auto &memoryObj : videoDecObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new (std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "AV memory create failed"); + + videoDecObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + OH_AVMemory *GetOutputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, nullptr, "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, nullptr, "Video decoder is nullptr!"); + + std::shared_ptr memory = videoDecObj->videoDecoder_->GetOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "Memory is nullptr, get output buffer failed!"); + + for (auto &memoryObj : videoDecObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new (std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "AV memory create failed"); + + videoDecObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + struct OH_AVCodec *codec_; + struct OH_AVCodecAsyncCallback callback_; + void *userData_; + std::mutex mutex_; +}; + +struct OH_AVCodec *OH_VideoDecoder_CreateByMime(const char *mime) +{ + CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "Mime is nullptr!"); + + std::shared_ptr videoDecoder = VideoDecoderFactory::CreateByMime(mime); + CHECK_AND_RETURN_RET_LOG(videoDecoder != nullptr, nullptr, "Video decoder create by mime failed!"); + + struct VideoDecoderObject *object = new (std::nothrow) VideoDecoderObject(videoDecoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Video decoder create by mime failed!"); + + return object; +} + +struct OH_AVCodec *OH_VideoDecoder_CreateByName(const char *name) +{ + CHECK_AND_RETURN_RET_LOG(name != nullptr, nullptr, "Name is nullptr!"); + + std::shared_ptr videoDecoder = VideoDecoderFactory::CreateByName(name); + CHECK_AND_RETURN_RET_LOG(videoDecoder != nullptr, nullptr, "Video decoder create by name failed!"); + + struct VideoDecoderObject *object = new (std::nothrow) VideoDecoderObject(videoDecoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Video decoder create by name failed!"); + + return object; +} + +OH_AVErrCode OH_VideoDecoder_Destroy(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + + if (videoDecObj != nullptr && videoDecObj->videoDecoder_ != nullptr) { + videoDecObj->callback_->StopCallback(); + videoDecObj->memoryObjList_.clear(); + videoDecObj->isStop_.store(false); + int32_t ret = videoDecObj->videoDecoder_->Release(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Video decoder destroy failed!"); + delete codec; + return AV_ERR_OPERATE_NOT_PERMIT; + } + } else { + AVCODEC_LOGD("Video decoder is nullptr!"); + } + + delete codec; + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Configure(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "Format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, + "Format magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->Configure(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder configure failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Prepare(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->Prepare(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder prepare failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Start(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + videoDecObj->isStop_.store(false); + videoDecObj->isEOS_.store(false); + int32_t ret = videoDecObj->videoDecoder_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder start failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Stop(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + videoDecObj->isStop_.store(true); + int32_t ret = videoDecObj->videoDecoder_->Stop(); + if (ret != AVCS_ERR_OK) { + videoDecObj->isStop_.store(false); + AVCODEC_LOGE("Video decoder stop failed"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + videoDecObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Flush(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + videoDecObj->isFlushing_.store(true); + int32_t ret = videoDecObj->videoDecoder_->Flush(); + videoDecObj->isFlushing_.store(false); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder flush failed!"); + videoDecObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_Reset(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + videoDecObj->isStop_.store(true); + int32_t ret = videoDecObj->videoDecoder_->Reset(); + if (ret != AVCS_ERR_OK) { + videoDecObj->isStop_.store(false); + AVCODEC_LOGE("Video decoder reset failed!"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + videoDecObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_SetSurface(OH_AVCodec *codec, OHNativeWindow *window) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + CHECK_AND_RETURN_RET_LOG(window != nullptr, AV_ERR_INVALID_VAL, "Window is nullptr!"); + CHECK_AND_RETURN_RET_LOG(window->surface != nullptr, AV_ERR_INVALID_VAL, "Surface is nullptr!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->SetOutputSurface(window->surface); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder set output surface failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_PushInputData(struct OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + struct AVCodecBufferInfo bufferInfo; + bufferInfo.presentationTimeUs = attr.pts; + bufferInfo.size = attr.size; + bufferInfo.offset = attr.offset; + enum AVCodecBufferFlag bufferFlag = static_cast(attr.flags); + + int32_t ret = videoDecObj->videoDecoder_->QueueInputBuffer(index, bufferInfo, bufferFlag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder push input data failed!"); + if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) { + videoDecObj->isEOS_.store(true); + } + + return AV_ERR_OK; +} + +OH_AVFormat *OH_VideoDecoder_GetOutputDescription(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, nullptr, "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, nullptr, "Video decoder is nullptr!"); + + Format format; + int32_t ret = videoDecObj->videoDecoder_->GetOutputFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Video decoder get output description failed!"); + + OH_AVFormat *avFormat = OH_AVFormat_Create(); + CHECK_AND_RETURN_RET_LOG(avFormat != nullptr, nullptr, "Video decoder get output description failed!"); + avFormat->format_ = format; + + return avFormat; +} + +OH_AVErrCode OH_VideoDecoder_RenderOutputData(struct OH_AVCodec *codec, uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->ReleaseOutputBuffer(index, true); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder render output data failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_FreeOutputData(struct OH_AVCodec *codec, uint32_t index) +{ + AVCODEC_LOGD("In OH_VideoDecoder_FreeOutputData"); + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->ReleaseOutputBuffer(index, false); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder free output data failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_SetParameter(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "Format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, + "Format magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + int32_t ret = videoDecObj->videoDecoder_->SetParameter(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder set parameter failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_SetCallback(struct OH_AVCodec *codec, struct OH_AVCodecAsyncCallback callback, + void *userData) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_DECODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoDecoderObject *videoDecObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoDecObj->videoDecoder_ != nullptr, AV_ERR_INVALID_VAL, "Video decoder is nullptr!"); + + videoDecObj->callback_ = std::make_shared(codec, callback, userData); + + int32_t ret = videoDecObj->videoDecoder_->SetCallback(videoDecObj->callback_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video decoder set callback failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoDecoder_IsValid(OH_AVCodec *codec, bool *isVaild) +{ + (void)codec; + return AV_ERR_UNSUPPORT; +} \ No newline at end of file diff --git a/frameworks/native/capi/avcodec/native_video_encoder.cpp b/frameworks/native/capi/avcodec/native_video_encoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ebff642a46e93108d201fe2f7df38722c96d9313 --- /dev/null +++ b/frameworks/native/capi/avcodec/native_video_encoder.cpp @@ -0,0 +1,448 @@ +/* + * 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 +#include +#include "native_avcodec_base.h" +#include "native_avcodec_videoencoder.h" +#include "native_avmagic.h" +#include "native_window.h" +#include "avcodec_video_encoder.h" +#include "avsharedmemory.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeVideoEncoder"}; +} + +using namespace OHOS::Media; +class NativeVideoEncoderCallback; + +struct VideoEncoderObject : public OH_AVCodec { + explicit VideoEncoderObject(const std::shared_ptr &encoder) + : OH_AVCodec(AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER), videoEncoder_(encoder) {} + ~VideoEncoderObject() = default; + + const std::shared_ptr videoEncoder_; + std::list> memoryObjList_; + OHOS::sptr outputFormat_ = nullptr; + std::shared_ptr callback_ = nullptr; + std::atomic isFlushing_ = false; + std::atomic isStop_ = false; + std::atomic isEOS_ = false; +}; + +class NativeVideoEncoderCallback : public AVCodecCallback { +public: + NativeVideoEncoderCallback(OH_AVCodec *codec, struct OH_AVCodecAsyncCallback cb, void *userData) + : codec_(codec), callback_(cb), userData_(userData) {} + virtual ~NativeVideoEncoderCallback() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override + { + std::unique_lock lock(mutex_); + (void)errorType; + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onError != nullptr, "Callback is nullptr"); + int32_t extErr = AVCSErrorToOHAVErrCode(static_cast(errorCode)); + callback_.onError(codec_, extErr, userData_); + } + + void OnOutputFormatChanged(const Format &format) override + { + std::unique_lock lock(mutex_); + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onStreamChanged != nullptr, "Callback is nullptr"); + OHOS::sptr object = new(std::nothrow) OH_AVFormat(format); + // The object lifecycle is controlled by the current function stack + callback_.onStreamChanged(codec_, reinterpret_cast(object.GetRefPtr()), userData_); + } + + void OnInputBufferAvailable(uint32_t index) override + { + std::unique_lock lock(mutex_); + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onNeedInputData != nullptr, "Callback is nullptr"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video decoder is nullptr!"); + + if (videoEncObj->isFlushing_.load() || videoEncObj->isStop_.load() || videoEncObj->isEOS_.load()) { + AVCODEC_LOGD("At flush, eos or stop, no buffer available"); + return; + } + callback_.onNeedInputData(codec_, index, nullptr, userData_); + } + + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override + { + std::unique_lock lock(mutex_); + + CHECK_AND_RETURN_LOG(codec_ != nullptr, "Codec is nullptr"); + CHECK_AND_RETURN_LOG(callback_.onNeedOutputData != nullptr, "Callback is nullptr"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec_); + CHECK_AND_RETURN_LOG(videoEncObj->videoEncoder_ != nullptr, "Context video decoder is nullptr!"); + + if (videoEncObj->isFlushing_.load() || videoEncObj->isStop_.load()) { + AVCODEC_LOGD("At flush or stop, ignore"); + return; + } + + struct OH_AVCodecBufferAttr bufferAttr; + bufferAttr.pts = info.presentationTimeUs; + bufferAttr.size = info.size; + bufferAttr.offset = info.offset; + bufferAttr.flags = flag; + // The bufferInfo lifecycle is controlled by the current function stack + OH_AVMemory *data = GetOutputData(codec_, index); + callback_.onNeedOutputData(codec_, index, data, &bufferAttr, userData_); + } + + void StopCallback() + { + std::unique_lock lock(mutex_); + codec_ = nullptr; + } + +private: + OH_AVMemory *GetOutputData(struct OH_AVCodec *codec, uint32_t index) + { + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, nullptr, "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, nullptr, "Video encoder is nullptr!"); + + std::shared_ptr memory = videoEncObj->videoEncoder_->GetOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "Memory is nullptr, get output buffer failed!"); + + for (auto &memoryObj : videoEncObj->memoryObjList_) { + if (memoryObj->IsEqualMemory(memory)) { + return reinterpret_cast(memoryObj.GetRefPtr()); + } + } + + OHOS::sptr object = new(std::nothrow) OH_AVMemory(memory); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "AV memory create failed"); + + videoEncObj->memoryObjList_.push_back(object); + return reinterpret_cast(object.GetRefPtr()); + } + + struct OH_AVCodec *codec_; + struct OH_AVCodecAsyncCallback callback_; + void *userData_; + std::mutex mutex_; +}; + +struct OH_AVCodec *OH_VideoEncoder_CreateByMime(const char *mime) +{ + CHECK_AND_RETURN_RET_LOG(mime != nullptr, nullptr, "Mime is nullptr!"); + + std::shared_ptr videoEncoder = VideoEncoderFactory::CreateByMime(mime); + CHECK_AND_RETURN_RET_LOG(videoEncoder != nullptr, nullptr, "Video encoder create by mime failed"); + + struct VideoEncoderObject *object = new(std::nothrow) VideoEncoderObject(videoEncoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Video encoder create by mime failed"); + + return object; +} + +struct OH_AVCodec *OH_VideoEncoder_CreateByName(const char *name) +{ + CHECK_AND_RETURN_RET_LOG(name != nullptr, nullptr, "Name is nullptr!"); + + std::shared_ptr videoEncoder = VideoEncoderFactory::CreateByName(name); + CHECK_AND_RETURN_RET_LOG(videoEncoder != nullptr, nullptr, "Video encoder create by name failed"); + + struct VideoEncoderObject *object = new(std::nothrow) VideoEncoderObject(videoEncoder); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Video encoder create by name failed"); + + return object; +} + +OH_AVErrCode OH_VideoEncoder_Destroy(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, + AV_ERR_INVALID_VAL, "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + + if (videoEncObj != nullptr && videoEncObj->videoEncoder_ != nullptr) { + videoEncObj->callback_->StopCallback(); + videoEncObj->memoryObjList_.clear(); + videoEncObj->isStop_.store(true); + int32_t ret = videoEncObj->videoEncoder_->Release(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Video encoder destroy failed!"); + delete codec; + return AV_ERR_OPERATE_NOT_PERMIT; + } + } else { + AVCODEC_LOGD("Video encoder is nullptr!"); + } + + delete codec; + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Configure(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "Format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, + "Format magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + int32_t ret = videoEncObj->videoEncoder_->Configure(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder configure failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Prepare(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + int32_t ret = videoEncObj->videoEncoder_->Prepare(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder prepare failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Start(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + videoEncObj->isStop_.store(false); + videoEncObj->isEOS_.store(false); + int32_t ret = videoEncObj->videoEncoder_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder start failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Stop(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + videoEncObj->isStop_.store(true); + int32_t ret = videoEncObj->videoEncoder_->Stop(); + if (ret != AVCS_ERR_OK) { + videoEncObj->isStop_.store(false); + AVCODEC_LOGE("Video encoder stop failed"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + videoEncObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Flush(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + videoEncObj->isFlushing_.store(true); + int32_t ret = videoEncObj->videoEncoder_->Flush(); + videoEncObj->isFlushing_.store(false); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder flush failed!"); + videoEncObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_Reset(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + videoEncObj->isStop_.store(true); + int32_t ret = videoEncObj->videoEncoder_->Reset(); + if (ret != AVCS_ERR_OK) { + videoEncObj->isStop_.store(false); + AVCODEC_LOGE("Video encoder reset failed"); + return AV_ERR_OPERATE_NOT_PERMIT; + } + videoEncObj->memoryObjList_.clear(); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_GetSurface(OH_AVCodec *codec, OHNativeWindow **window) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr && window != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + OHOS::sptr surface = videoEncObj->videoEncoder_->CreateInputSurface(); + CHECK_AND_RETURN_RET_LOG(surface != nullptr, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder get surface failed!"); + + *window = CreateNativeWindowFromSurface(&surface); + CHECK_AND_RETURN_RET_LOG(*window != nullptr, AV_ERR_INVALID_VAL, "Video encoder get surface failed!"); + + return AV_ERR_OK; +} + +OH_AVFormat *OH_VideoEncoder_GetOutputDescription(struct OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, nullptr, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, nullptr, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, nullptr, "Video encoder is nullptr!"); + + Format format; + int32_t ret = videoEncObj->videoEncoder_->GetOutputFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Video encoder get output description failed!"); + + videoEncObj->outputFormat_ = new(std::nothrow) OH_AVFormat(format); + CHECK_AND_RETURN_RET_LOG(videoEncObj->outputFormat_ != nullptr, nullptr, + "Video encoder get output description failed!"); + + return reinterpret_cast(videoEncObj->outputFormat_.GetRefPtr()); +} + +OH_AVErrCode OH_VideoEncoder_FreeOutputData(struct OH_AVCodec *codec, uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + int32_t ret = videoEncObj->videoEncoder_->ReleaseOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder free output data failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_NotifyEndOfStream(OH_AVCodec *codec) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + int32_t ret = videoEncObj->videoEncoder_->NotifyEos(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder notify end of stream failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_SetParameter(struct OH_AVCodec *codec, struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, "Format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, AV_ERR_INVALID_VAL, + "Format magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + int32_t ret = videoEncObj->videoEncoder_->SetParameter(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder set parameter failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_SetCallback( + struct OH_AVCodec *codec, struct OH_AVCodecAsyncCallback callback, void *userData) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + videoEncObj->callback_ = std::make_shared(codec, callback, userData); + + int32_t ret = videoEncObj->videoEncoder_->SetCallback(videoEncObj->callback_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder set callback failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_PushInputData(struct OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr) +{ + CHECK_AND_RETURN_RET_LOG(codec != nullptr, AV_ERR_INVALID_VAL, "Codec is nullptr!"); + CHECK_AND_RETURN_RET_LOG(codec->magic_ == AVMagic::AVCODEC_MAGIC_VIDEO_ENCODER, AV_ERR_INVALID_VAL, + "Codec magic error!"); + + struct VideoEncoderObject *videoEncObj = reinterpret_cast(codec); + CHECK_AND_RETURN_RET_LOG(videoEncObj->videoEncoder_ != nullptr, AV_ERR_INVALID_VAL, "Video encoder is nullptr!"); + + struct AVCodecBufferInfo bufferInfo; + bufferInfo.presentationTimeUs = attr.pts; + bufferInfo.size = attr.size; + bufferInfo.offset = attr.offset; + enum AVCodecBufferFlag bufferFlag = static_cast(attr.flags); + + int32_t ret = videoEncObj->videoEncoder_->QueueInputBuffer(index, bufferInfo, bufferFlag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "Video encoder push input data failed!"); + if (bufferFlag == AVCODEC_BUFFER_FLAG_EOS) { + videoEncObj->isEOS_.store(true); + } + + return AV_ERR_OK; +} + +OH_AVErrCode OH_VideoEncoder_IsValid(OH_AVCodec *codec, bool *isVaild) +{ + return AV_ERR_UNSUPPORT; +} \ No newline at end of file diff --git a/frameworks/native/capi/avdemuxer/native_avdemuxer.cpp b/frameworks/native/capi/avdemuxer/native_avdemuxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07e283f19bd1254a9b474f566b73266894c23729 --- /dev/null +++ b/frameworks/native/capi/avdemuxer/native_avdemuxer.cpp @@ -0,0 +1,141 @@ +/* + * 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 "avdemuxer.h" +#include "native_avmagic.h" +#include "avcodec_errors.h" +#include "native_object.h" +#include "avcodec_log.h" +#include "av_common.h" +#include "native_avdemuxer.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAVDemuxer"}; +} + +using namespace OHOS::Media; + +struct DemuxerObject : public OH_AVDemuxer { + explicit DemuxerObject(const std::shared_ptr &demuxer) + : OH_AVDemuxer(AVMagic::AVCODEC_MAGIC_AVDEMUXER), demuxer_(demuxer) {} + ~DemuxerObject() = default; + + const std::shared_ptr demuxer_; +}; + +struct OH_AVDemuxer *OH_AVDemuxer_CreateWithSource(OH_AVSource *source) +{ + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "Create demuxer failed because input source is nullptr!"); + + struct AVSourceObject *sourceObj = reinterpret_cast(source); + + std::shared_ptr demuxer = AVDemuxerFactory::CreateWithSource(*(sourceObj->source_)); + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, nullptr, "New demuxer with fd by AVDemuxerFactory failed!"); + + struct DemuxerObject *object = new(std::nothrow) DemuxerObject(demuxer); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "New demuxerObject failed when create demuxer!"); + + return object; +} + +OH_AVErrCode OH_AVDemuxer_Destroy(OH_AVDemuxer *demuxer) +{ + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, AV_ERR_INVALID_VAL, + "Destroy demuxer failed because input demuxer is nullptr!"); + + delete demuxer; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVDemuxer_SelectSourceTrackByID(OH_AVDemuxer *demuxer, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, AV_ERR_INVALID_VAL, + "Add sourceTrack failed because input demuxer is nullptr!"); + CHECK_AND_RETURN_RET_LOG(demuxer->magic_ == AVMagic::AVCODEC_MAGIC_AVDEMUXER, AV_ERR_INVALID_VAL, "magic error!"); + + struct DemuxerObject *demuxerObj = reinterpret_cast(demuxer); + CHECK_AND_RETURN_RET_LOG(demuxerObj->demuxer_ != nullptr, AV_ERR_INVALID_VAL, + "New DemuxerObject failed when add sourceTrack!"); + + int32_t ret = demuxerObj->demuxer_->SelectSourceTrackByID(trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "demuxer_ SelectSourceTrackByID failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVDemuxer_UnselectSourceTrackByID(OH_AVDemuxer *demuxer, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, AV_ERR_INVALID_VAL, + "Remove sourceTrack failed because input demuxer is nullptr!"); + CHECK_AND_RETURN_RET_LOG(demuxer->magic_ == AVMagic::AVCODEC_MAGIC_AVDEMUXER, AV_ERR_INVALID_VAL, "magic error!"); + + struct DemuxerObject *demuxerObj = reinterpret_cast(demuxer); + CHECK_AND_RETURN_RET_LOG(demuxerObj->demuxer_ != nullptr, AV_ERR_INVALID_VAL, + "New DemuxerObject failed when remove sourceTrack!"); + + int32_t ret = demuxerObj->demuxer_->UnselectSourceTrackByID(trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "demuxer_ UnselectSourceTrackByID failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVDemuxer_CopyNextSample(OH_AVDemuxer *demuxer, uint32_t *trackIndex, + uint8_t *buffer, OH_AVCodecBufferAttr *bufferInfo) +{ + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, AV_ERR_INVALID_VAL, + "Copy sample failed because input demuxer is nullptr!"); + CHECK_AND_RETURN_RET_LOG(demuxer->magic_ == AVMagic::AVCODEC_MAGIC_AVDEMUXER, AV_ERR_INVALID_VAL, "magic error!"); + + CHECK_AND_RETURN_RET_LOG(trackIndex != nullptr, AV_ERR_INVALID_VAL, + "Copy sample failed because input trackIndex is nullptr!"); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AV_ERR_INVALID_VAL, + "Copy sample failed because input buffer is nullptr!"); + CHECK_AND_RETURN_RET_LOG(bufferInfo != nullptr, AV_ERR_INVALID_VAL, + "Copy sample failed because input attr is nullptr!"); + + struct DemuxerObject *demuxerObj = reinterpret_cast(demuxer); + CHECK_AND_RETURN_RET_LOG(demuxerObj->demuxer_ != nullptr, AV_ERR_INVALID_VAL, + "New DemuxerObject failed when copy sample!"); + + struct AVCodecBufferInfo bufferInfoInner; + enum AVCodecBufferFlag *flag = nullptr; + *flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + int32_t ret = demuxerObj->demuxer_->CopyNextSample(*trackIndex, buffer, bufferInfoInner, *flag); + bufferInfo->pts = bufferInfoInner.presentationTimeUs; + bufferInfo->size = bufferInfoInner.size; + bufferInfo->offset = bufferInfoInner.offset; + bufferInfo->flags =static_cast(*flag); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "demuxer_ CopyNextSample failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVDemuxer_SeekToTime(OH_AVDemuxer *demuxer, int64_t mSeconds, OH_AVSeekMode mode) +{ + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, AV_ERR_INVALID_VAL, "Seek failed because input demuxer is nullptr!"); + CHECK_AND_RETURN_RET_LOG(demuxer->magic_ == AVMagic::AVCODEC_MAGIC_AVDEMUXER, AV_ERR_INVALID_VAL, "magic error!"); + + CHECK_AND_RETURN_RET_LOG(mSeconds >= 0, AV_ERR_INVALID_VAL, "Seek failed because input mSeconds is negative!"); + + struct DemuxerObject *demuxerObj = reinterpret_cast(demuxer); + CHECK_AND_RETURN_RET_LOG(demuxerObj->demuxer_ != nullptr, AV_ERR_INVALID_VAL, + "New DemuxerObject failed when seek!"); + + int32_t ret = demuxerObj->demuxer_->SeekToTime(mSeconds, static_cast(mode)); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "demuxer_ SeekToTime failed!"); + + return AV_ERR_OK; +} \ No newline at end of file diff --git a/frameworks/native/capi/avmuxer/native_avmuxer.cpp b/frameworks/native/capi/avmuxer/native_avmuxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95244ff86a24acc6b3e51e7d33afe33200879508 --- /dev/null +++ b/frameworks/native/capi/avmuxer/native_avmuxer.cpp @@ -0,0 +1,149 @@ +/* + * 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 "native_avmuxer.h" +#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"}; +} + +using namespace OHOS::Media; + +struct AVMuxerObject : public OH_AVMuxer { + explicit AVMuxerObject(const std::shared_ptr &muxer) + : OH_AVMuxer(AVMagic::AVCODEC_MAGIC_AVMUXER), muxer_(muxer) {} + ~AVMuxerObject() = default; + + const std::shared_ptr muxer_; +}; + +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)); + CHECK_AND_RETURN_RET_LOG(avmuxer != nullptr, nullptr, "create muxer failed!"); + struct AVMuxerObject *object = new(std::nothrow) AVMuxerObject(avmuxer); + return object; +} + +OH_AVErrCode OH_AVMuxer_SetLocation(OH_AVMuxer *muxer, float latitude, float longitude) +{ + 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!"); + + struct AVMuxerObject *object = reinterpret_cast(muxer); + CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); + + int32_t ret = object->muxer_->SetLocation(latitude, longitude); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ SetLocation failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVMuxer_SetRotation(OH_AVMuxer *muxer, int32_t rotation) +{ + 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!"); + + struct AVMuxerObject *object = reinterpret_cast(muxer); + CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); + + 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, 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_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!"); + + int32_t ret = object->muxer_->AddTrack(*trackIndex, trackFormat->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ AddTrack failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVMuxer_Start(OH_AVMuxer *muxer) +{ + 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!"); + + struct AVMuxerObject *object = reinterpret_cast(muxer); + CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); + + int32_t ret = object->muxer_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ Start failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVMuxer_WriteSampleBuffer(OH_AVMuxer *muxer, + uint32_t trackIndex, + uint8_t *sampleBuffer, + OH_AVCodecBufferAttr info) +{ + 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!"); + + struct AVMuxerObject *object = reinterpret_cast(muxer); + CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); + + 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; +} + +OH_AVErrCode OH_AVMuxer_Stop(OH_AVMuxer *muxer) +{ + 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!"); + + struct AVMuxerObject *object = reinterpret_cast(muxer); + CHECK_AND_RETURN_RET_LOG(object->muxer_ != nullptr, AV_ERR_INVALID_VAL, "muxer_ is nullptr!"); + + int32_t ret = object->muxer_->Stop(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "muxer_ Stop failed!"); + + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVMuxer_Destroy(OH_AVMuxer *muxer) +{ + 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!"); + + delete muxer; + + return AV_ERR_OK; +} \ No newline at end of file diff --git a/frameworks/native/capi/avsource/native_avsource.cpp b/frameworks/native/capi/avsource/native_avsource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2eb3e8b83b551f501be3929e98c8ef85107ef66c --- /dev/null +++ b/frameworks/native/capi/avsource/native_avsource.cpp @@ -0,0 +1,169 @@ +/* + * 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 "avsource.h" +#include "native_avmagic.h" +#include "avcodec_errors.h" +#include "native_object.h" +#include "native_avformat.h" +#include "avcodec_log.h" +#include "native_avsource.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "NativeAVSource"}; +} + +using namespace OHOS::Media; + +struct AVSourceTrackObject : public OH_AVSourceTrack { + explicit AVSourceTrackObject(const std::shared_ptr &sourceTrack) + : OH_AVSourceTrack(AVMagic::AVCODEC_MAGIC_AVSOURCETRACK), sourceTrack_(sourceTrack) {} + ~AVSourceTrackObject() = default; + + const std::shared_ptr sourceTrack_; +}; + +struct OH_AVSource *OH_AVSource_CreateWithURI(char *uri) +{ + CHECK_AND_RETURN_RET_LOG(uri != nullptr, nullptr, "Create source with uri failed because input uri is nullptr!"); + + std::shared_ptr source = AVSourceFactory::CreateWithURI(uri); + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "New source with uri failed by AVSourceFactory!"); + + struct AVSourceObject *object = new(std::nothrow) AVSourceObject(source); + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "New AVSourceObject failed when create source with uri!"); + + return object; +} + +struct OH_AVSource *OH_AVSource_CreateWithFD(int32_t fd, int64_t offset, int64_t size) +{ + // 0-err, 1-in, 2-out + CHECK_AND_RETURN_RET_LOG(fd > 2, nullptr, + "Create source with uri failed because input fd is illegal, fd must be greater than 2!"); + CHECK_AND_RETURN_RET_LOG(size >= 0, nullptr, "Create source with uri failed because input size is negative"); + + std::shared_ptr source = AVSourceFactory::CreateWithFD(fd, offset, size); + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "New source with fd failed by AVSourceFactory!"); + + struct AVSourceObject *object = new(std::nothrow) AVSourceObject(source); + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "New AVSourceObject failed when create source with fd!"); + + return object; +} + +OH_AVErrCode OH_AVSource_Destroy(OH_AVSource *source) +{ + CHECK_AND_RETURN_RET_LOG(source != nullptr, AV_ERR_INVALID_VAL, + "Destroy source failed because input source is nullptr!"); + + delete source; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVSource_GetTrackCount(OH_AVSource *source, uint32_t *trackCount) +{ + CHECK_AND_RETURN_RET_LOG(source != nullptr, AV_ERR_INVALID_VAL, + "Get track count failed because input source is nullptr!"); + CHECK_AND_RETURN_RET_LOG(source->magic_ == AVMagic::AVCODEC_MAGIC_AVSOURCE, AV_ERR_INVALID_VAL, "magic error!"); + + CHECK_AND_RETURN_RET_LOG(trackCount != nullptr, AV_ERR_INVALID_VAL, + "Get track count failed because input trackCount is nullptr!"); + + struct AVSourceObject *sourceObj = reinterpret_cast(source); + CHECK_AND_RETURN_RET_LOG(sourceObj->source_ != nullptr, AV_ERR_INVALID_VAL, + "New AVSourceObject failed when get track count!"); + + int32_t ret = sourceObj->source_->GetTrackCount(*trackCount); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "source_ GetTrackCount failed!"); + + return AV_ERR_OK; +} + +struct OH_AVSourceTrack *OH_AVSource_GetSourceTrackByID(OH_AVSource *source, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "Load track failed because input source is nullptr!"); + CHECK_AND_RETURN_RET_LOG(source->magic_ == AVMagic::AVCODEC_MAGIC_AVSOURCE, nullptr, "magic error!"); + + struct AVSourceObject *sourceObj = reinterpret_cast(source); + CHECK_AND_RETURN_RET_LOG(sourceObj->source_ != nullptr, nullptr, "New AVSourceObject failed when load track!"); + + std::shared_ptr sourceTrack = sourceObj->source_->GetSourceTrackByID(trackIndex); + CHECK_AND_RETURN_RET_LOG(sourceTrack != nullptr, nullptr, "source_ GetSourceTrackByID failed!"); + + struct AVSourceTrackObject *object = new(std::nothrow) AVSourceTrackObject(sourceTrack); + + return object; +} + +OH_AVFormat *OH_AVSource_GetSourceFormat(OH_AVSource *source) +{ + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "Get source format failed because input source is nullptr!"); + CHECK_AND_RETURN_RET_LOG(source->magic_ == AVMagic::AVCODEC_MAGIC_AVSOURCE, nullptr, "magic error!"); + + struct AVSourceObject *sourceObj = reinterpret_cast(source); + CHECK_AND_RETURN_RET_LOG(sourceObj->source_ != nullptr, nullptr, + "New AVSourceObject failed when get source format!"); + + Format format; + int32_t ret = sourceObj->source_->GetSourceFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "source_ GetSourceFormat failed!"); + + OH_AVFormat *avFormat = OH_AVFormat_Create(); + avFormat->format_ = format; + + return avFormat; +} + + +OH_AVErrCode OH_AVSourceTrack_SetTrackFormat(OH_AVSourceTrack *sourceTrack, OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(sourceTrack != nullptr, AV_ERR_INVALID_VAL, + "Set format failed because input sourceTrack is nullptr!"); + CHECK_AND_RETURN_RET_LOG(sourceTrack->magic_ == AVMagic::AVCODEC_MAGIC_AVSOURCETRACK, AV_ERR_INVALID_VAL, + "magic error!"); + + CHECK_AND_RETURN_RET_LOG(format != nullptr, AV_ERR_INVALID_VAL, + "Set format failed because input param is nullptr!"); + + struct AVSourceTrackObject *sourceTrackObj = reinterpret_cast(sourceTrack); + CHECK_AND_RETURN_RET_LOG(sourceTrackObj->sourceTrack_ != nullptr, AV_ERR_INVALID_VAL, + "New AVSourceObject failed when set track format!"); + + int32_t ret = sourceTrackObj->sourceTrack_->SetTrackFormat(format->format_); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AV_ERR_OPERATE_NOT_PERMIT, "sourceTrack SetTrackFormat failed!"); + + return AV_ERR_OK; +} + +OH_AVFormat *OH_AVSourceTrack_GetTrackFormat(OH_AVSourceTrack *sourceTrack) +{ + CHECK_AND_RETURN_RET_LOG(sourceTrack != nullptr, nullptr, + "Set format failed because input sourceTrack is nullptr!"); + CHECK_AND_RETURN_RET_LOG(sourceTrack->magic_ == AVMagic::AVCODEC_MAGIC_AVSOURCETRACK, nullptr, "magic error!"); + + struct AVSourceTrackObject *sourceTrackObj = reinterpret_cast(sourceTrack); + CHECK_AND_RETURN_RET_LOG(sourceTrackObj->sourceTrack_ != nullptr, nullptr, + "New AVSourceObject failed when get track format!"); + + Format format; + int32_t ret = sourceTrackObj->sourceTrack_->GetTrackFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "sourceTrack GetTrackFormat failed!"); + + OH_AVFormat *avFormat = OH_AVFormat_Create(); + avFormat->format_ = format; + + return avFormat; +} \ No newline at end of file diff --git a/frameworks/native/capi/common/native_avcapability.cpp b/frameworks/native/capi/common/native_avcapability.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a69c8a6837da94d07c86d423a72ed731f1820823 --- /dev/null +++ b/frameworks/native/capi/common/native_avcapability.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 +#include "native_avmagic.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "native_avcapability.h" + +using namespace OHOS::Media; +OH_AVCapability::OH_AVCapability(const CapabilityData &capabilityData) : capabilityData_(capabilityData) {} + +OH_AVCapability::~OH_AVCapability() {} + +bool OH_AVCapability_IsHardware(OH_AVCapability *capability) +{ + if (capability == nullptr) { + return false; + } + return capability->capabilityData_.isVendor; +} + +const char *OH_AVCapability_GetMimeType(OH_AVCapability *capability) +{ + if (capability == nullptr) { + std::string empty; + return empty.data(); + } + + return capability->capabilityData_.mimeType.data(); +} + +int32_t OH_AVCapability_GetMaxSupportedInstances(OH_AVCapability *capability) +{ + if (capability == nullptr) { + return 0; + } + + return capability->capabilityData_.maxInstance; +} + +OH_AVErrCode OH_AVCapability_GetSupportedProfiles(OH_AVCapability *capability, const int32_t **profiles, + uint32_t *profileNum) +{ + if (capability == nullptr) { + std::vector empty; + *profiles = empty.data(); + *profileNum = empty.size(); + return AV_ERR_INVALID_VAL; + } + + auto &vec = capability->capabilityData_.profiles; + *profiles = vec.data(); + *profileNum = vec.size(); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetSupportedLevelsForProfile(OH_AVCapability *capability, int32_t profile, + const int32_t **levels, uint32_t *levelNum) +{ + std::vector empty; + *levels = empty.data(); + *levelNum = empty.size(); + if (capability == nullptr) { + return AV_ERR_INVALID_VAL; + } + + auto &profileLevelsMap = capability->capabilityData_.profileLevelsMap; + auto levelsmatch = profileLevelsMap.find(profile); + if (levelsmatch == profileLevelsMap.end()) { + return AV_ERR_INVALID_VAL; + } + *levels = levelsmatch->second.data(); + *levelNum = levelsmatch->second.size(); + return AV_ERR_OK; +} + +bool OH_AVCapability_ValidateProfileAndLevel(OH_AVCapability *capability, int32_t profile, int32_t level) +{ + if (capability == nullptr) { + return false; + } + auto &profileLevelsMap = capability->capabilityData_.profileLevelsMap; + auto levels = profileLevelsMap.find(profile); + if (levels == profileLevelsMap.end()) { + return false; + } + + return find(levels->second.begin(), levels->second.end(), level) != levels->second.end(); +} + +OH_AVErrCode OH_AVCapability_GetEncoderBitrateRange(OH_AVCapability *capability, OH_AVRange *bitrateRange) +{ + if (capability == nullptr) { + bitrateRange->minVal = 0; + bitrateRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + bitrateRange->minVal = capability->capabilityData_.bitrate.minVal; + bitrateRange->maxVal = capability->capabilityData_.bitrate.maxVal; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetEncoderQualityRange(OH_AVCapability *capability, OH_AVRange *qualityRange) +{ + if (capability == nullptr) { + qualityRange->minVal = 0; + qualityRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + qualityRange->minVal = capability->capabilityData_.encodeQuality.minVal; + qualityRange->maxVal = capability->capabilityData_.encodeQuality.maxVal; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetEncoderComplexityRange(OH_AVCapability *capability, OH_AVRange *complexityRange) +{ + if (capability == nullptr) { + complexityRange->minVal = 0; + complexityRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + complexityRange->minVal = capability->capabilityData_.complexity.minVal; + complexityRange->maxVal = capability->capabilityData_.complexity.maxVal; + return AV_ERR_OK; +} + +bool OH_AVCapability_ValidateVideoEncoderBitrateMode(OH_AVCapability *capability, OH_BitrateMode bitrateMode) +{ + if (capability == nullptr) { + return false; + } + auto &bitrateModeVec = capability->capabilityData_.bitrateMode; + return find(bitrateModeVec.begin(), bitrateModeVec.end(), bitrateMode) != bitrateModeVec.end(); +} + +OH_AVErrCode OH_AVCapability_GetAudioSupportedSampleRates(OH_AVCapability *capability, const int32_t **sampleRates, + uint32_t *sampleRateNum) +{ + if (capability == nullptr) { + std::vector empty; + *sampleRates = empty.data(); + *sampleRateNum = empty.size(); + return AV_ERR_INVALID_VAL; + } + + auto &vec = capability->capabilityData_.sampleRate; + *sampleRates = vec.data(); + *sampleRateNum = vec.size(); + return AV_ERR_OK; +} + +bool OH_AVCapability_ValidateAudioSampleRate(OH_AVCapability *capability, int32_t sampleRate) +{ + if (capability == nullptr) { + return false; + } + auto &sampeleRateVec = capability->capabilityData_.sampleRate; + return find(sampeleRateVec.begin(), sampeleRateVec.end(), sampleRate) != sampeleRateVec.end(); +} + +OH_AVErrCode OH_AVCapability_GetAudioChannelsRange(OH_AVCapability *capability, OH_AVRange *channelsRange) +{ + if (capability == nullptr) { + channelsRange->minVal = 0; + channelsRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + channelsRange->minVal = capability->capabilityData_.channels.minVal; + channelsRange->maxVal = capability->capabilityData_.channels.maxVal; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoSupportedPixFormats(OH_AVCapability *capability, const int32_t **pixFormats, + uint32_t *pixFormatNum) +{ + if (capability == nullptr) { + std::vector empty; + *pixFormats = empty.data(); + *pixFormatNum = empty.size(); + return AV_ERR_INVALID_VAL; + } + auto &vec = capability->capabilityData_.pixFormat; + *pixFormats = vec.data(); + *pixFormatNum = vec.size(); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoWidthAlignment(OH_AVCapability *capability, int32_t *widthAlignment) +{ + if (capability == nullptr) { + *widthAlignment = 0; + return AV_ERR_INVALID_VAL; + } + *widthAlignment = capability->capabilityData_.alignment.width; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoHeightAlignment(OH_AVCapability *capability, int32_t *heightAlignment) +{ + if (capability == nullptr) { + *heightAlignment = 0; + return AV_ERR_INVALID_VAL; + } + *heightAlignment = capability->capabilityData_.alignment.height; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoWidthRangeForHeight(OH_AVCapability *capability, int32_t height, + OH_AVRange *widthRange) +{ + if (capability == nullptr) { + widthRange->minVal = 0; + widthRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoHeightRangeForWidth(OH_AVCapability *capability, int32_t width, + OH_AVRange *heightRange) +{ + if (capability == nullptr) { + heightRange->minVal = 0; + heightRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoWidthRange(OH_AVCapability *capability, OH_AVRange *widthRange) +{ + if (capability == nullptr) { + widthRange->minVal = 0; + widthRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + widthRange->minVal = capability->capabilityData_.width.minVal; + widthRange->maxVal = capability->capabilityData_.width.maxVal; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoHeightRange(OH_AVCapability *capability, OH_AVRange *heightRange) +{ + if (capability == nullptr) { + heightRange->minVal = 0; + heightRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + heightRange->minVal = capability->capabilityData_.height.minVal; + heightRange->maxVal = capability->capabilityData_.height.maxVal; + return AV_ERR_OK; +} + +bool OH_AVCapability_ValidateVideoSize(OH_AVCapability *capability, int32_t width, int32_t height) +{ + if (capability == nullptr) { + return false; + } + + auto &alignment = capability->capabilityData_.alignment; + if (width == 0 || height == 0 || alignment.width == 0 || alignment.height == 0 || width % alignment.width != 0 || + height % alignment.height != 0) { + return false; + } + + auto &widthRange = capability->capabilityData_.width; + auto &heightRange = capability->capabilityData_.height; + if (width < widthRange.minVal || width > widthRange.maxVal || height < heightRange.minVal || + height > heightRange.maxVal) { + return false; + } + + auto &blockSize = capability->capabilityData_.blockSize; + if (blockSize.width == 0 || blockSize.height == 0) { + return false; + } + int blockNum = + ((width + blockSize.width - 1) / blockSize.width) * ((height + blockSize.height - 1) / blockSize.height); + + auto &blockPerFrame = capability->capabilityData_.blockPerFrame; + if (blockNum < blockPerFrame.minVal || blockNum > blockPerFrame.maxVal) { + return false; + } + + return true; +} + +OH_AVErrCode OH_AVCapability_GetVideoFrameRateRange(OH_AVCapability *capability, OH_AVRange *frameRateRange) +{ + if (capability == nullptr) { + frameRateRange->minVal = 0; + frameRateRange->maxVal = 0; + return AV_ERR_INVALID_VAL; + } + frameRateRange->minVal = capability->capabilityData_.frameRate.minVal; + frameRateRange->maxVal = capability->capabilityData_.frameRate.maxVal; + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoFrameRateRangeForSize(OH_AVCapability *capability, int32_t width, int32_t height, + OH_AVRange *frameRateRange) +{ + frameRateRange->minVal = 0; + frameRateRange->maxVal = 0; + if (capability == nullptr) { + return AV_ERR_INVALID_VAL; + } + + if (OH_AVCapability_ValidateVideoSize(capability, width, height) != AV_ERR_OK) { + return AV_ERR_INVALID_VAL; + } + + auto &blockSize = capability->capabilityData_.blockSize; + auto &blockPerSecond = capability->capabilityData_.blockPerSecond; + if (blockSize.width == 0 || blockSize.height == 0 || blockPerSecond.minVal <= 0 || blockPerSecond.maxVal <= 0) { + return AV_ERR_UNKNOWN; + } + int blockNum = + ((width + blockSize.width - 1) / blockSize.width) * ((height + blockSize.height - 1) / blockSize.height); + + auto &fpsRange = capability->capabilityData_.frameRate; + frameRateRange->minVal = std::max((blockPerSecond.minVal + blockNum - 1) / blockNum, fpsRange.minVal); + frameRateRange->maxVal = std::min(blockPerSecond.maxVal / blockNum, fpsRange.maxVal); + return AV_ERR_OK; +} + +OH_AVErrCode OH_AVCapability_GetVideoMeasuredFrameRateRangeForSize(OH_AVCapability *capability, int32_t width, + int32_t height, OH_AVRange *frameRateRange) +{ + frameRateRange->minVal = 0; + frameRateRange->maxVal = 0; + if (capability == nullptr) { + return AV_ERR_INVALID_VAL; + } + + if (OH_AVCapability_ValidateVideoSize(capability, width, height) != AV_ERR_OK) { + return AV_ERR_INVALID_VAL; + } + + auto &blockSize = capability->capabilityData_.blockSize; + if (blockSize.width == 0 || blockSize.height == 0) { + return AV_ERR_UNKNOWN; + } + int32_t blockNum = + ((width + blockSize.width - 1) / blockSize.width) * ((height + blockSize.height - 1) / blockSize.height); + + int32_t minDiff = INT32_MAX; + Range fpsRange; + float factor = 1.0f; + float blockNumFloat{blockNum}; + auto &measureFps = capability->capabilityData_.measuredFrameRate; + auto iter = measureFps.begin(); + while (iter != measureFps.end()) { + int32_t curBlockNum = (iter->first.width + blockSize.width - 1) / blockSize.width * + ((iter->first.height + blockSize.height - 1) / blockSize.height); + int32_t curDiff = std::abs(curBlockNum - blockNum); + if (curDiff < minDiff) { + minDiff = curDiff; + fpsRange = iter->second; + factor = blockNumFloat / curBlockNum; + } + iter++; + } + + frameRateRange->minVal = static_cast(fpsRange.minVal * factor); + frameRateRange->maxVal = static_cast(fpsRange.maxVal * factor); + return AV_ERR_OK; +} + +bool OH_AVCapability_ValidateVideoSizeAndFrameRate(OH_AVCapability *capability, int32_t width, int32_t height, + int32_t frameRate) +{ + if (capability == nullptr) { + return false; + } + + auto &alignment = capability->capabilityData_.alignment; + if (width == 0 || height == 0 || alignment.width == 0 || alignment.height == 0 || width % alignment.width != 0 || + height % alignment.height != 0) { + return false; + } + + auto &widthRange = capability->capabilityData_.width; + auto &heightRange = capability->capabilityData_.height; + auto &fpsRange = capability->capabilityData_.frameRate; + if (width < widthRange.minVal || width > widthRange.maxVal || height < heightRange.minVal || + height > heightRange.maxVal || frameRate < fpsRange.minVal || frameRate > fpsRange.maxVal) { + return false; + } + + auto &blockSize = capability->capabilityData_.blockSize; + if (blockSize.width == 0 || blockSize.height == 0) { + return false; + } + int blockNum = + ((width + blockSize.width - 1) / blockSize.width) * ((height + blockSize.height - 1) / blockSize.height); + int blockOneSecond = blockNum * frameRate; + auto &blockPerFrame = capability->capabilityData_.blockPerFrame; + auto &blockPerSecond = capability->capabilityData_.blockPerSecond; + if (blockNum < blockPerFrame.minVal || blockNum > blockPerFrame.maxVal || blockOneSecond < blockPerSecond.minVal || + blockOneSecond > blockPerSecond.maxVal) { + return false; + } + return true; +} diff --git a/frameworks/native/capi/common/native_avformat.cpp b/frameworks/native/capi/common/native_avformat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..987ede49013f285ee9d68218b782b1ef91075057 --- /dev/null +++ b/frameworks/native/capi/common/native_avformat.cpp @@ -0,0 +1,234 @@ +/* + * 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 "native_avformat.h" + +#include "securec.h" +#include "native_avmagic.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "OH_AVFormat"}; +constexpr uint32_t MAX_STRING_LENGTH = 256; +constexpr uint32_t MAX_DUMP_LENGTH = 1024; +} + +using namespace OHOS::Media; + +OH_AVFormat::OH_AVFormat() + : AVObjectMagic(AVMagic::AVCODEC_MAGIC_FORMAT) +{ +} + +OH_AVFormat::OH_AVFormat(const Format &fmt) + : AVObjectMagic(AVMagic::AVCODEC_MAGIC_FORMAT), format_(fmt) +{ +} + +OH_AVFormat::~OH_AVFormat() +{ + if (outString_ != nullptr) { + free(outString_); + outString_ = nullptr; + } + if (dumpInfo_ != nullptr) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } +} + +struct OH_AVFormat *OH_AVFormat_Create(void) +{ + return new(std::nothrow) OH_AVFormat(); +} + +void OH_AVFormat_Destroy(struct OH_AVFormat *format) +{ + delete format; +} + +bool OH_AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from) +{ + CHECK_AND_RETURN_RET_LOG(to != nullptr, false, "to format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(to->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(from != nullptr, false, "from format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(from->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + + to->format_ = from->format_; + return true; +} + +bool OH_AVFormat_SetIntValue(struct OH_AVFormat *format, const char *key, int32_t value) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + + return format->format_.PutIntValue(key, value); +} + +bool OH_AVFormat_SetLongValue(struct OH_AVFormat *format, const char *key, int64_t value) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + + return format->format_.PutLongValue(key, value); +} + +bool OH_AVFormat_SetFloatValue(struct OH_AVFormat *format, const char *key, float value) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + + return format->format_.PutFloatValue(key, value); +} + +bool OH_AVFormat_SetDoubleValue(struct OH_AVFormat *format, const char *key, double value) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + + return format->format_.PutDoubleValue(key, value); +} + +bool OH_AVFormat_SetStringValue(struct OH_AVFormat *format, const char *key, const char *value) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(value != nullptr, false, "value is nullptr!"); + + return format->format_.PutStringValue(key, value); +} + +bool OH_AVFormat_SetBuffer(struct OH_AVFormat *format, const char *key, const uint8_t *addr, size_t size) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(addr != nullptr, false, "addr is nullptr!"); + CHECK_AND_RETURN_RET_LOG(size != 0, false, "size is zero!"); + + return format->format_.PutBuffer(key, addr, size); +} + +bool OH_AVFormat_GetIntValue(struct OH_AVFormat *format, const char *key, int32_t *out) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(out != nullptr, false, "out is nullptr!"); + + return format->format_.GetIntValue(key, *out); +} + +bool OH_AVFormat_GetLongValue(struct OH_AVFormat *format, const char *key, int64_t *out) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(out != nullptr, false, "out is nullptr!"); + + return format->format_.GetLongValue(key, *out); +} + +bool OH_AVFormat_GetFloatValue(struct OH_AVFormat *format, const char *key, float *out) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(out != nullptr, false, "out is nullptr!"); + + return format->format_.GetFloatValue(key, *out); +} + +bool OH_AVFormat_GetDoubleValue(struct OH_AVFormat *format, const char *key, double *out) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(out != nullptr, false, "out is nullptr!"); + + return format->format_.GetDoubleValue(key, *out); +} + +bool OH_AVFormat_GetStringValue(struct OH_AVFormat *format, const char *key, const char **out) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(out != nullptr, false, "out is nullptr!"); + + if (format->outString_ != nullptr) { + free(format->outString_); + format->outString_ = nullptr; + } + + std::string str; + bool ret = format->format_.GetStringValue(key, str); + if (!ret) { + return false; + } + uint32_t bufLength = str.size() > MAX_STRING_LENGTH ? MAX_STRING_LENGTH : str.size(); + + format->outString_ = static_cast(malloc((bufLength + 1) * sizeof(char))); + CHECK_AND_RETURN_RET_LOG(format->outString_ != nullptr, false, "malloc out string nullptr!"); + + if (strcpy_s(format->outString_, bufLength + 1, str.c_str()) != EOK) { + AVCODEC_LOGE("Failed to strcpy_s"); + free(format->outString_); + format->outString_ = nullptr; + return false; + } + + *out = format->outString_; + return true; +} + +bool OH_AVFormat_GetBuffer(struct OH_AVFormat *format, const char *key, uint8_t **addr, size_t *size) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, false, "input format is nullptr!"); + CHECK_AND_RETURN_RET_LOG(format->magic_ == AVMagic::AVCODEC_MAGIC_FORMAT, false, "magic error!"); + CHECK_AND_RETURN_RET_LOG(key != nullptr, false, "key is nullptr!"); + CHECK_AND_RETURN_RET_LOG(addr != nullptr, false, "addr is nullptr!"); + CHECK_AND_RETURN_RET_LOG(size != nullptr, false, "size is nullptr!"); + + return format->format_.GetBuffer(key, addr, *size); +} + +const char *OH_AVFormat_DumpInfo(struct OH_AVFormat *format) +{ + CHECK_AND_RETURN_RET_LOG(format != nullptr, nullptr, "input format is nullptr!"); + if (format->dumpInfo_ != nullptr) { + free(format->dumpInfo_); + format->dumpInfo_ = nullptr; + } + std::string info = format->format_.Stringify(); + if (info.empty()) { + return nullptr; + } + uint32_t bufLength = info.size() > MAX_DUMP_LENGTH ? MAX_DUMP_LENGTH : info.size(); + format->dumpInfo_ = static_cast(malloc((bufLength + 1) * sizeof(char))); + CHECK_AND_RETURN_RET_LOG(format->dumpInfo_ != nullptr, nullptr, "malloc dump info nullptr!"); + if (strcpy_s(format->dumpInfo_, bufLength + 1, info.c_str()) != EOK) { + AVCODEC_LOGE("Failed to strcpy_s"); + free(format->dumpInfo_); + format->dumpInfo_ = nullptr; + } + return format->dumpInfo_; +} diff --git a/frameworks/native/capi/common/native_avmagic.h b/frameworks/native/capi/common/native_avmagic.h new file mode 100644 index 0000000000000000000000000000000000000000..c50d4a361d4f4014a01a1c4f04b148f51ef40b4a --- /dev/null +++ b/frameworks/native/capi/common/native_avmagic.h @@ -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. + */ + +#ifndef NATIVE_AVMAGIC_H +#define NATIVE_AVMAGIC_H + +#include +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "avcodec_common.h" +#include "format.h" + + +#define AV_MAGIC(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + ((d) << 0)) + +enum class AVMagic { + AVCODEC_MAGIC_VIDEO_DECODER = AV_MAGIC('V', 'D', 'E', 'C'), + AVCODEC_MAGIC_VIDEO_ENCODER = AV_MAGIC('V', 'E', 'N', 'C'), + AVCODEC_MAGIC_AUDIO_DECODER = AV_MAGIC('A', 'D', 'E', 'C'), + AVCODEC_MAGIC_AUDIO_ENCODER = AV_MAGIC('A', 'E', 'N', 'C'), + AVCODEC_MAGIC_AVMUXER = AV_MAGIC('M', 'U', 'X', 'R'), + AVCODEC_MAGIC_AVDEMUXER = AV_MAGIC('D', 'M', 'U', 'X'), + AVCODEC_MAGIC_AVSOURCE = AV_MAGIC('S', 'O', 'U', 'C'), + AVCODEC_MAGIC_AVSOURCETRACK = AV_MAGIC('T', 'R', 'A', 'C'), + AVCODEC_MAGIC_FORMAT = AV_MAGIC('F', 'R', 'M', 'T'), + AVCODEC_MAGIC_SHARED_MEMORY = AV_MAGIC('S', 'M', 'E', 'M'), +}; + +struct AVObjectMagic : public OHOS::RefBase { + explicit AVObjectMagic(enum AVMagic m) : magic_(m) {} + virtual ~AVObjectMagic() = default; + enum AVMagic magic_; +}; + +struct OH_AVFormat : public AVObjectMagic { + OH_AVFormat(); + explicit OH_AVFormat(const OHOS::Media::Format &fmt); + ~OH_AVFormat() override; + OHOS::Media::Format format_; + char *outString_ = nullptr; + char *dumpInfo_ = nullptr; +}; + +struct OH_AVMemory : public AVObjectMagic { + explicit OH_AVMemory(const std::shared_ptr &mem); + ~OH_AVMemory() override; + bool IsEqualMemory(const std::shared_ptr &mem); + const std::shared_ptr memory_; +}; + +struct OH_AVCodec : public AVObjectMagic { + explicit OH_AVCodec(enum AVMagic m) : AVObjectMagic(m) {} + virtual ~OH_AVCodec() = default; +}; + +struct OH_AVCapability : public OHOS::RefBase { + explicit OH_AVCapability(const OHOS::Media::CapabilityData &capabilityData); + ~OH_AVCapability() override; + OHOS::Media::CapabilityData capabilityData_; +}; + +struct OH_AVMuxer : public AVObjectMagic { + explicit OH_AVMuxer(enum AVMagic m) : AVObjectMagic(m) {} + virtual ~OH_AVMuxer() = default; +}; + +struct OH_AVDemuxer : public AVObjectMagic { + explicit OH_AVDemuxer(enum AVMagic m) : AVObjectMagic(m) {} + virtual ~OH_AVDemuxer() = default; +}; + +struct OH_AVSource : public AVObjectMagic { + explicit OH_AVSource(enum AVMagic m) : AVObjectMagic(m) {} + virtual ~OH_AVSource() = default; +}; + +struct OH_AVSourceTrack : public AVObjectMagic { + explicit OH_AVSourceTrack(enum AVMagic m) : AVObjectMagic(m) {} + virtual ~OH_AVSourceTrack() = default; +}; +#endif // NATIVE_AVMAGIC_H \ No newline at end of file diff --git a/frameworks/native/capi/common/native_avmemory.cpp b/frameworks/native/capi/common/native_avmemory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b9e801e14281c6f78275a2cfca056c5a9fe5db6b --- /dev/null +++ b/frameworks/native/capi/common/native_avmemory.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 "native_avmemory.h" +#include "native_avmagic.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "OH_AVMemory"}; +} + +using namespace OHOS::Media; + +OH_AVMemory::OH_AVMemory(const std::shared_ptr &mem) + : AVObjectMagic(AVMagic::AVCODEC_MAGIC_SHARED_MEMORY), memory_(mem) +{ +} + +OH_AVMemory::~OH_AVMemory() +{ +} + +bool OH_AVMemory::IsEqualMemory(const std::shared_ptr &mem) +{ + return (mem == memory_) ? true : false; +} + +uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem) +{ + CHECK_AND_RETURN_RET_LOG(mem != nullptr, nullptr, "input mem is nullptr!"); + CHECK_AND_RETURN_RET_LOG(mem->magic_ == AVMagic::AVCODEC_MAGIC_SHARED_MEMORY, nullptr, "magic error!"); + CHECK_AND_RETURN_RET_LOG(mem->memory_ != nullptr, nullptr, "memory is nullptr!"); + return mem->memory_->GetBase(); +} + +int32_t OH_AVMemory_GetSize(struct OH_AVMemory *mem) +{ + CHECK_AND_RETURN_RET_LOG(mem != nullptr, -1, "input mem is nullptr!"); + CHECK_AND_RETURN_RET_LOG(mem->magic_ == AVMagic::AVCODEC_MAGIC_SHARED_MEMORY, -1, "magic error!"); + CHECK_AND_RETURN_RET_LOG(mem->memory_ != nullptr, -1, "memory is nullptr!"); + return mem->memory_->GetSize(); +} diff --git a/frameworks/native/capi/common/native_object.h b/frameworks/native/capi/common/native_object.h new file mode 100644 index 0000000000000000000000000000000000000000..6582db39af7f141fcde5300fa432ce0d51bafab1 --- /dev/null +++ b/frameworks/native/capi/common/native_object.h @@ -0,0 +1,27 @@ +/* + * 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 "avsource.h" +#include "native_avsource.h" +#include "native_avmagic.h" + +struct AVSourceObject : public OH_AVSource { + explicit AVSourceObject(const std::shared_ptr &source) + : OH_AVSource(AVMagic::AVCODEC_MAGIC_AVSOURCE), source_(source) {} + ~AVSourceObject() = default; + + const std::shared_ptr source_; +}; \ No newline at end of file diff --git a/frameworks/native/common/avcodec_errors.cpp b/frameworks/native/common/avcodec_errors.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d74c529301fe69e45a2a06bae17a0b4de6214314 --- /dev/null +++ b/frameworks/native/common/avcodec_errors.cpp @@ -0,0 +1,243 @@ +/* + * 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 "avcodec_errors.h" +#include +#include + +namespace OHOS { +namespace Media { +using ErrorMessageFunc = std::function; +const std::map AVCS_ERRCODE_INFOS = { + {AVCS_ERR_OK, "success"}, + {AVCS_ERR_NO_MEMORY, "no memory"}, + {AVCS_ERR_INVALID_OPERATION, "operation not be permitted"}, + {AVCS_ERR_INVALID_VAL, "invalid argument"}, + {AVCS_ERR_UNKNOWN, "unkown error"}, + {AVCS_ERR_SERVICE_DIED, "avcodec service died"}, + {AVCS_ERR_CREATE_AVCODEC_SUB_SERVICE_FAILED, "create avcodec sub service failed"}, + {AVCS_ERR_CREATE_MUXER_SUB_SERVICE_FAILED, "create muxer sub service failed"}, + {AVCS_ERR_CREATE_DEMUXER_SUB_SERVICE_FAILED, "create demuxer sub service failed"}, + {AVCS_ERR_INVALID_STATE, "the state is not support this operation"}, + {AVCS_ERR_UNSUPPORT, "unsupport interface"}, + {AVCS_ERR_UNSUPPORT_AUD_SRC_TYPE, "unsupport audio source type"}, + {AVCS_ERR_UNSUPPORT_AUD_SAMPLE_RATE, "unsupport audio sample rate"}, + {AVCS_ERR_UNSUPPORT_AUD_CHANNEL_NUM, "unsupport audio channel"}, + {AVCS_ERR_UNSUPPORT_AUD_ENC_TYPE, "unsupport audio encoder type"}, + {AVCS_ERR_UNSUPPORT_AUD_PARAMS, "unsupport audio params(other params)"}, + {AVCS_ERR_UNSUPPORT_VID_SRC_TYPE, "unsupport video source type"}, + {AVCS_ERR_UNSUPPORT_VID_ENC_TYPE, "unsupport video encoder type"}, + {AVCS_ERR_UNSUPPORT_VID_PARAMS, "unsupport video params(other params)"}, + {AVCS_ERR_UNSUPPORT_CONTAINER_TYPE, "unsupport container format type"}, + {AVCS_ERR_UNSUPPORT_PROTOCOL_TYPE, "unsupport protocol type"}, + {AVCS_ERR_UNSUPPORT_VID_DEC_TYPE, "unsupport video decoder type"}, + {AVCS_ERR_UNSUPPORT_AUD_DEC_TYPE, "unsupport audio decoder type"}, + {AVCS_ERR_UNSUPPORT_STREAM, "internal data stream error"}, + {AVCS_ERR_UNSUPPORT_FILE, "this appears to be a text file"}, + {AVCS_ERR_UNSUPPORT_SOURCE, "unsupport source type"}, + {AVCS_ERR_AUD_ENC_FAILED, "audio encode failed"}, + {AVCS_ERR_AUD_RENDER_FAILED, "audio render failed"}, + {AVCS_ERR_VID_ENC_FAILED, "video encode failed"}, + {AVCS_ERR_AUD_DEC_FAILED, "audio decode failed"}, + {AVCS_ERR_VID_DEC_FAILED, "video decode failed"}, + {AVCS_ERR_MUXER_FAILED, "stream avmuxer failed"}, + {AVCS_ERR_DEMUXER_FAILED, "stream demuxer or parser failed"}, + {AVCS_ERR_OPEN_FILE_FAILED, "open file failed"}, + {AVCS_ERR_FILE_ACCESS_FAILED, "read or write file failed"}, + {AVCS_ERR_START_FAILED, "audio or video start failed"}, + {AVCS_ERR_PAUSE_FAILED, "audio or video pause failed"}, + {AVCS_ERR_STOP_FAILED, "audio or video stop failed"}, + {AVCS_ERR_SEEK_FAILED, "audio or video seek failed"}, + {AVCS_ERR_NETWORK_TIMEOUT, "network timeout"}, + {AVCS_ERR_NOT_FIND_CONTAINER, "not find a demuxer"}, + {AVCS_ERR_EXTEND_START, "extend start error code"}, +}; + +const std::map AVCSERRCODE_TO_OHAVCODECERRCODE = { + {AVCS_ERR_OK, AV_ERR_OK}, + {AVCS_ERR_NO_MEMORY, AV_ERR_NO_MEMORY}, + {AVCS_ERR_INVALID_OPERATION, AV_ERR_OPERATE_NOT_PERMIT}, + {AVCS_ERR_INVALID_VAL, AV_ERR_INVALID_VAL}, + {AVCS_ERR_UNKNOWN, AV_ERR_UNKNOWN}, + {AVCS_ERR_SERVICE_DIED, AV_ERR_SERVICE_DIED}, + {AVCS_ERR_CREATE_AVCODEC_SUB_SERVICE_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_CREATE_MUXER_SUB_SERVICE_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_CREATE_DEMUXER_SUB_SERVICE_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_INVALID_STATE, AV_ERR_INVALID_STATE}, + {AVCS_ERR_UNSUPPORT, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_SRC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_SAMPLE_RATE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_CHANNEL_NUM, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_ENC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_PARAMS, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_VID_SRC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_VID_ENC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_VID_PARAMS, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_CONTAINER_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_PROTOCOL_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_VID_DEC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_AUD_DEC_TYPE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_STREAM, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_FILE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_UNSUPPORT_SOURCE, AV_ERR_UNSUPPORT}, + {AVCS_ERR_AUD_RENDER_FAILED, AV_ERR_UNSUPPORT}, + {AVCS_ERR_AUD_ENC_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_VID_ENC_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_AUD_DEC_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_VID_DEC_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_MUXER_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_DEMUXER_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_OPEN_FILE_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_FILE_ACCESS_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_START_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_PAUSE_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_STOP_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_SEEK_FAILED, AV_ERR_UNKNOWN}, + {AVCS_ERR_NETWORK_TIMEOUT, AV_ERR_TIMEOUT}, + {AVCS_ERR_NOT_FIND_CONTAINER, AV_ERR_UNSUPPORT}, + {AVCS_ERR_EXTEND_START, AV_ERR_EXTEND_START}, +}; + +const std::map OHAVCODECERRCODE_INFOS = { + {AV_ERR_OK, "success"}, + {AV_ERR_NO_MEMORY, "no memory"}, + {AV_ERR_OPERATE_NOT_PERMIT, "operation not be permitted"}, + {AV_ERR_INVALID_VAL, "invalid argument"}, + {AV_ERR_IO, "IO error"}, + {AV_ERR_TIMEOUT, "network timeout"}, + {AV_ERR_UNKNOWN, "unkown error"}, + {AV_ERR_SERVICE_DIED, "avcodec service died"}, + {AV_ERR_INVALID_STATE, "the state is not support this operation"}, + {AV_ERR_UNSUPPORT, "unsupport interface"}, + {AV_ERR_EXTEND_START, "extend err start"}, +}; + +std::string ErrorMessageOk(const std::string& param1, const std::string& param2) +{ + (void)param1; + (void)param2; + return "success"; +} + +std::string ErrorMessageNoPermission(const std::string& param1, const std::string& param2) +{ + std::string message = "Try to do " + param1 + " failed. User should request permission " + param2 +" first."; + return message; +} + +std::string ErrorMessageInvalidParameter(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "The Parameter " + param1 + " is invalid. Please check the type and range."; + return message; +} + +std::string ErrorMessageUnsupportCapability(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "Function " + param1 + " can not work correctly due to limited device capability."; + return message; +} + +std::string ErrorMessageNoMemory(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "Create " + param1 + " failed due to system memory."; + return message; +} + +std::string ErrorMessageOperateNotPermit(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "The operate " + param1 + " failed due to not permit in current state."; + return message; +} + +std::string ErrorMessageIO(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "IO error happened due to " + param1 + "."; + return message; +} + +std::string ErrorMessageTimeout(const std::string& param1, const std::string& param2) +{ + std::string message = "Timeout happend when " + param1 + " due to " + param2 + "."; + return message; +} + +std::string ErrorMessageServiceDied(const std::string& param1, const std::string& param2) +{ + (void)param1; + (void)param2; + std::string message = "AVCodec Serviced Died."; + return message; +} + +std::string ErrorMessageUnsupportFormat(const std::string& param1, const std::string& param2) +{ + (void)param2; + std::string message = "The format " + param1 + " is not support."; + return message; +} + +std::string AVCSErrorToString(AVCodecServiceErrCode code) +{ + if (AVCS_ERRCODE_INFOS.count(code) != 0) { + return AVCS_ERRCODE_INFOS.at(code); + } + + if (code > static_cast(AV_ERR_EXTEND_START)) { + return "extend error:" + std::to_string(code - static_cast(AV_ERR_EXTEND_START)); + } + + return "invalid error code:" + std::to_string(static_cast(code)); +} + +std::string OHAVErrCodeToString(OH_AVErrCode code) +{ + if (OHAVCODECERRCODE_INFOS.count(code) != 0) { + return OHAVCODECERRCODE_INFOS.at(code); + } + + if (code > static_cast(AV_ERR_EXTEND_START)) { + return "extend error:" + std::to_string(code - static_cast(AV_ERR_EXTEND_START)); + } + + return "invalid error code:" + std::to_string(static_cast(code)); +} + +std::string AVCSErrorToOHAVErrCodeString(AVCodecServiceErrCode code) +{ + if (AVCS_ERRCODE_INFOS.count(code) != 0 && AVCSERRCODE_TO_OHAVCODECERRCODE.count(code) != 0) { + OH_AVErrCode extCode = AVCSERRCODE_TO_OHAVCODECERRCODE.at(code); + if (OHAVCODECERRCODE_INFOS.count(extCode) != 0) { + return OHAVCODECERRCODE_INFOS.at(extCode); + } + } + + return "unkown error"; +} + +OH_AVErrCode AVCSErrorToOHAVErrCode(AVCodecServiceErrCode code) +{ + if (AVCS_ERRCODE_INFOS.count(code) != 0 && AVCSERRCODE_TO_OHAVCODECERRCODE.count(code) != 0) { + return AVCSERRCODE_TO_OHAVCODECERRCODE.at(code); + } + + return AV_ERR_UNKNOWN; +} +} // namespace Media +} // namespace OHOS diff --git a/hisysevent.yaml b/hisysevent.yaml new file mode 100644 index 0000000000000000000000000000000000000000..aa9890172f41501236975df1c62bb30703dbe8b9 --- /dev/null +++ b/hisysevent.yaml @@ -0,0 +1,29 @@ +# 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. + +domain: AVCODEC + +AVCODEC_ERR: + __BASE: {type: FAULT, level: CRITICAL, desc: AVCodec error} + PID: {type: INT32, desc: The pid of the AVCODEC_ERR event} + UID: {type: INT32, desc: The uid of the AVCODEC_ERR event} + MODULE: {type: STRING, desc: module name} + ERRORCODE: {type: INT32, desc: error code} + MSG: {type: STRING, desc: error description} + +AVCODEC_STATE: + __BASE: {type: BEHAVIOR, level: MINOR, desc: state change} + PID: {type: INT32, desc: The pid of the AVCODEC_STATE event} + UID: {type: INT32, desc: The uid of the AVCODEC_STATE event} + MODULE: {type: STRING, desc: module name} + STATE: {type: STRING, desc: current state} diff --git a/interfaces/inner_api/native/BUILD.gn b/interfaces/inner_api/native/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0f02e701f2939146066f37b89349fa7c539f3dfd --- /dev/null +++ b/interfaces/inner_api/native/BUILD.gn @@ -0,0 +1,213 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("av_codec_packege_include") { + include_dirs = [ + "$av_codec_root_dir/frameworks/native/avcodec", + "$av_codec_root_dir/frameworks/native/avcodeclist", + "$av_codec_root_dir/frameworks/native/avdemuxer", + "$av_codec_root_dir/frameworks/native/avmuxer", + "$av_codec_root_dir/frameworks/native/avsource", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/include", + "$av_codec_root_dir/services/services/codec/client", + "$av_codec_root_dir/services/services/codec/ipc", + "$av_codec_root_dir/services/services/codeclist/client", + "$av_codec_root_dir/services/services/codeclist/ipc", + "$av_codec_root_dir/services/services/common", + "$av_codec_root_dir/services/services/demuxer/client", + "$av_codec_root_dir/services/services/demuxer/ipc", + "$av_codec_root_dir/services/services/muxer/client", + "$av_codec_root_dir/services/services/muxer/ipc", + "$av_codec_root_dir/services/services/sa_avcodec/client", + "$av_codec_root_dir/services/services/sa_avcodec/ipc", + "$av_codec_root_dir/services/services/source/client", + "$av_codec_root_dir/services/services/source/ipc", + "$av_codec_root_dir/services/utils/include", + ] +} + +config("av_codec_client_local_config") { + include_dirs = [ + "$av_codec_root_dir/services/services/factory", + "$av_codec_root_dir/services/engine/factory", + + # "$av_codec_root_dir/services/engine/muxer", + # "$av_codec_root_dir/services/engine/plugin/common", + # "$av_codec_root_dir/services/engine/plugin/core", + # "$av_codec_root_dir/services/engine/plugin/interface", + ] +} + +config("av_codec_client_ipc_config") { + include_dirs = [ + "$av_codec_root_dir/services/services/codec/client", + "$av_codec_root_dir/services/services/codec/ipc", + "$av_codec_root_dir/services/services/codeclist/client", + "$av_codec_root_dir/services/services/codeclist/ipc", + "$av_codec_root_dir/services/services/common", + "$av_codec_root_dir/services/services/demuxer/client", + "$av_codec_root_dir/services/services/demuxer/ipc", + "$av_codec_root_dir/services/services/muxer/client", + "$av_codec_root_dir/services/services/muxer/ipc", + "$av_codec_root_dir/services/services/sa_avcodec/client", + "$av_codec_root_dir/services/services/sa_avcodec/ipc", + "$av_codec_root_dir/services/services/source/client", + "$av_codec_root_dir/services/services/source/ipc", + ] +} + +config("av_codec_client_public_config") { + include_dirs = [ + "./", + "$av_codec_root_dir/frameworks/native/avcodec", + "$av_codec_root_dir/frameworks/native/avcodeclist", + "$av_codec_root_dir/frameworks/native/avdemuxer", + "$av_codec_root_dir/frameworks/native/avmuxer", + "$av_codec_root_dir/frameworks/native/avsource", + "$av_codec_root_dir/interfaces/kits/c", + "$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", + # "//commonlibrary/c_utils/base/include", + ] + + cflags = [ + "-fno-exceptions", + "-Wall", + "-fno-common", + "-fstack-protector-strong", + "-Wshadow", + "-FPIC", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-Wformat=2", + "-Wdate-time", + ] + + cflags_cc = [ + "-std=c++17", + "-fno-rtti", + ] + + if (target_cpu == "arm") { + cflags += [ "-DBINDER_IPC_32BIT" ] + } + + defines = [] + defines += av_codec_defines + + 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_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", + ] + + configs = [ ":av_codec_packege_include" ] + + sources = [ + # "$av_codec_root_dir/frameworks/native/avsource/avsource_impl.cpp", + "$av_codec_root_dir/frameworks/native/common/avcodec_errors.cpp", + "$av_codec_root_dir/services/services/common/avsharedmemory_ipc.cpp", + "$av_codec_root_dir/services/services/sa_avcodec/client/avcodec_client.cpp", + "$av_codec_root_dir/services/services/sa_avcodec/ipc/avcodec_listener_stub.cpp", + "$av_codec_root_dir/services/services/sa_avcodec/ipc/avcodec_parcel.cpp", + "$av_codec_root_dir/services/services/sa_avcodec/ipc/avcodec_service_proxy.cpp", + ] + if (multimedia_av_codec_support_codec) { + sources += [ + "$av_codec_root_dir/frameworks/native/avcodec/avcodec_audio_decoder_impl.cpp", + "$av_codec_root_dir/frameworks/native/avcodec/avcodec_audio_encoder_impl.cpp", + "$av_codec_root_dir/frameworks/native/avcodec/avcodec_video_decoder_impl.cpp", + "$av_codec_root_dir/frameworks/native/avcodec/avcodec_video_encoder_impl.cpp", + "$av_codec_root_dir/services/services/codec/client/codec_client.cpp", + "$av_codec_root_dir/services/services/codec/ipc/codec_listener_stub.cpp", + "$av_codec_root_dir/services/services/codec/ipc/codec_service_proxy.cpp", + ] + } + if (multimedia_av_codec_support_codeclist) { + sources += [ + "$av_codec_root_dir/frameworks/native/avcodeclist/avcodeclist_impl.cpp", + "$av_codec_root_dir/services/services/codeclist/client/codeclist_client.cpp", + "$av_codec_root_dir/services/services/codeclist/ipc/codeclist_service_proxy.cpp", + "$av_codec_root_dir/services/services/sa_avcodec/ipc/codeclist_parcel.cpp", + ] + } + if (multimedia_av_codec_support_demuxer) { + sources += [ + "$av_codec_root_dir/frameworks/native/avdemuxer/avdemuxer_impl.cpp", + "$av_codec_root_dir/services/services/demuxer/client/demuxer_client.cpp", + "$av_codec_root_dir/services/services/demuxer/ipc/demuxer_service_proxy.cpp", + ] + } + if (multimedia_av_codec_support_source) { + sources += [ + "$av_codec_root_dir/frameworks/native/avsource/avsource_impl.cpp", + "$av_codec_root_dir/services/services/source/client/source_client.cpp", + "$av_codec_root_dir/services/services/source/ipc/source_service_proxy.cpp", + ] + } + 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/muxer_client.cpp", + "$av_codec_root_dir/services/services/muxer/ipc/muxer_service_proxy.cpp", + ] + } + + deps = [ + "$av_codec_root_dir/services/dfx:av_codec_service_dfx", + "$av_codec_root_dir/services/utils:av_codec_format", + "//third_party/bounds_checking_function:libsec_static", + ] + + if (multimedia_av_codec_support_codeclist) { + deps += [ "$av_codec_root_dir/services/engine:av_codec_engine_package" ] + } + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/interfaces/inner_api/native/av_common.h b/interfaces/inner_api/native/av_common.h new file mode 100644 index 0000000000000000000000000000000000000000..8a5ed35ce9f44ab6f44cc5dd7cef7120cdfd9282 --- /dev/null +++ b/interfaces/inner_api/native/av_common.h @@ -0,0 +1,191 @@ +/* + * 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 AV_COMMOM_H +#define AV_COMMOM_H + +#include +#include +#include "format.h" + +namespace OHOS { +namespace Media { +/** + * @brief Media type + * + * @since 3.1 + * @version 3.1 + */ +enum MediaType : int32_t { + /** + * track is audio. + */ + MEDIA_TYPE_AUD = 0, + /** + * track is video. + */ + MEDIA_TYPE_VID = 1, + /** + * track is subtitle. + */ + MEDIA_TYPE_SUBTITLE = 2, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum VideoPixelFormat { + YUV420P = 0, + /** + * yuv 420 planar. + */ + YUVI420 = 1, + /** + * NV12. yuv 420 semiplanar. + */ + NV12 = 2, + /** + * NV21. yvu 420 semiplanar. + */ + NV21 = 3, + /** + * format from surface. + */ + SURFACE_FORMAT = 4, + /** + * RGBA. + */ + RGBA = 5, + BGRA = 6, +}; + +/** + * @brief the struct of geolocation + * + * @param latitude float: latitude in degrees. Its value must be in the range [-90, 90]. + * @param longitude float: longitude in degrees. Its value must be in the range [-180, 180]. + * @since 3.1 + * @version 3.1 + */ +struct Location { + float latitude = 0; + float longitude = 0; +}; + +/** + * @brief Enumerates the seek mode. + */ +enum AVSeekMode : uint8_t { + /* seek to sync sample after the time */ + SEEK_MODE_NEXT_SYNC = 0, + /* seek to sync sample before the time */ + SEEK_MODE_PREVIOUS_SYNC, + /* seek to sync sample closest to time */ + SEEK_MODE_CLOSEST_SYNC, +}; + +/** + * @brief Enumerates the video rotation. + * + * @since 3.2 + * @version 3.2 + */ +enum VideoRotation : uint32_t { + /** + * Video without rotation + */ + VIDEO_ROTATION_0 = 0, + /** + * Video rotated 90 degrees + */ + VIDEO_ROTATION_90 = 90, + /** + * Video rotated 180 degrees + */ + VIDEO_ROTATION_180 = 180, + /** + * Video rotated 270 degrees + */ + VIDEO_ROTATION_270 = 270, +}; + +/** + * @brief Enumerates the state change reason. + * + * @since 3.2 + * @version 3.2 + */ +enum StateChangeReason { + /** + * audio/video state change by user + */ + USER = 1, + /** + * audio/video state change by system + */ + BACKGROUND = 2, +}; + +/** + * @brief Enumerates the output format. + * + * @since 10 + * @version 4.0 + */ +enum OutputFormat : uint32_t { + /** + * output format default mp4 + */ + OUTPUT_FORMAT_DEFAULT = 0, + /** + * output format mp4 + */ + OUTPUT_FORMAT_MPEG_4 = 2, + /** + * output format m4a + */ + OUTPUT_FORMAT_M4A = 6, +}; + +/** + * @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_audio_codec_key.h b/interfaces/inner_api/native/avcodec_audio_codec_key.h new file mode 100644 index 0000000000000000000000000000000000000000..b5220acaa4679574c90eaf7a082ec85039af1c8f --- /dev/null +++ b/interfaces/inner_api/native/avcodec_audio_codec_key.h @@ -0,0 +1,39 @@ +/* + * 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 AVCODEC_AUDIO_CODEC_KEY_H +#define AVCODEC_AUDIO_CODEC_KEY_H +#include + +namespace OHOS { +namespace Media { +class AVCodecAudioCodecKey { +public: + static constexpr std::string_view AUDIO_DECODER_MP3_NAME_KEY = "avdec_mp3"; + static constexpr std::string_view AUDIO_DECODER_AAC_NAME_KEY = "avdec_aac"; + static constexpr std::string_view AUDIO_DECODER_VORBIS_NAME_KEY = "avdec_vorbis"; + static constexpr std::string_view AUDIO_DECODER_FLAC_NAME_KEY = "avdec_flac"; + + static constexpr std::string_view AUDIO_ENCODER_FLAC_NAME_KEY = "avenc_flac"; + static constexpr std::string_view AUDIO_ENCODER_AAC_NAME_KEY = "avenc_aac"; + +private: + AVCodecAudioCodecKey() = delete; + ~AVCodecAudioCodecKey() = delete; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/interfaces/inner_api/native/avcodec_audio_decoder.h b/interfaces/inner_api/native/avcodec_audio_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..0a216c4a3e3a90d6a964de8187964a41a1a61121 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_audio_decoder.h @@ -0,0 +1,226 @@ +/* + * 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 AVCODEC_AUDIO_DECODER_H +#define AVCODEC_AUDIO_DECODER_H + +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class AVCodecAudioDecoder { +public: + virtual ~AVCodecAudioDecoder() = default; + + /** + * @brief Configure the decoder. + * + * @param format The format of the input data and the desired format of the output data. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Configure(const Format &format) = 0; + + /** + * @brief Prepare for decoding. + * + * This function must be called after {@link Configure} and before {@link Start} + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Prepare() = 0; + + /** + * @brief Start decoding. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Start() = 0; + + /** + * @brief Stop decoding. + * + * This function must be called during running + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Stop() = 0; + + /** + * @brief Flush both input and output buffers of the decoder. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Flush() = 0; + + /** + * @brief Restores the decoder to the initial state. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Reset() = 0; + + /** + * @brief Releases decoder resources. All methods are unavailable after calling this. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Release() = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a input buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + + /** + * @brief Submits input buffer to decoder. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @param info The info of the input buffer. For details, see {@link AVCodecBufferInfo} + * @param flag The flag of the input buffer. For details, see {@link AVCodecBufferFlag} + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a output buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + + /** + * @brief Gets the format of the output data. + * + * This function must be called after {@link Configure} + * + * @param format + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t GetOutputFormat(Format &format) = 0; + + /** + * @brief Returns the output buffer to the decoder. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t ReleaseOutputBuffer(uint32_t index) = 0; + + /** + * @brief Sets the parameters to the decoder. + * + * This function must be called after {@link Configure} + * + * @param format The parameters. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetParameter(const Format &format) = 0; + + /** + * @brief Registers a decoder listener. + * + * This function must be called before {@link Configure} + * + * @param callback Indicates the decoder listener to register. For details, see {@link AVCodecCallback}. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; +}; + +class __attribute__((visibility("default"))) AudioDecoderFactory { +public: +#ifdef UNSUPPORT_CODEC + static std::shared_ptr CreateByMime(const std::string &mime) + { + (void)mime; + return nullptr; + } + + static std::shared_ptr CreateByName(const std::string &name) + { + (void)name; + return nullptr; + } +#else + /** + * @brief Instantiate the preferred decoder of the given mime type. + * + * @param mime The mime type. + * @return Returns the preferred decoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByMime(const std::string &mime); + + /** + * @brief Instantiates the designated decoder. + * + * @param name The decoder's name. + * @return Returns the designated decoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByName(const std::string &name); +#endif +private: + AudioDecoderFactory() = default; + ~AudioDecoderFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avcodec_audio_encoder.h b/interfaces/inner_api/native/avcodec_audio_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..d7b572328ff1438665f035eeeef90afa83bf3ea8 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_audio_encoder.h @@ -0,0 +1,226 @@ +/* + * 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 AVCODEC_AUDIO_ENCODER_H +#define AVCODEC_AUDIO_ENCODER_H + +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class AVCodecAudioEncoder { +public: + virtual ~AVCodecAudioEncoder() = default; + + /** + * @brief Configure the encoder. + * + * @param format The format of the input data and the desired format of the output data. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Configure(const Format &format) = 0; + + /** + * @brief Prepare for decoding. + * + * This function must be called after {@link Configure} and before {@link Start} + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Prepare() = 0; + + /** + * @brief Start decoding. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Start() = 0; + + /** + * @brief Stop decoding. + * + * This function must be called during running + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Stop() = 0; + + /** + * @brief Flush both input and output buffers of the encoder. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Flush() = 0; + + /** + * @brief Restores the encoder to the initial state. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Reset() = 0; + + /** + * @brief Releases encoder resources. All methods are unavailable after calling this. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Release() = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a input buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + + /** + * @brief Submits input buffer to encoder. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @param info The info of the input buffer. For details, see {@link AVCodecBufferInfo} + * @param flag The flag of the input buffer. For details, see {@link AVCodecBufferFlag} + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a output buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + + /** + * @brief Gets the format of the output data. + * + * This function must be called after {@link Configure} + * + * @param format + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t GetOutputFormat(Format &format) = 0; + + /** + * @brief Returns the output buffer to the encoder. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t ReleaseOutputBuffer(uint32_t index) = 0; + + /** + * @brief Sets the parameters to the encoder. + * + * This function must be called after {@link Configure} + * + * @param format The parameters. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetParameter(const Format &format) = 0; + + /** + * @brief Registers a encoder listener. + * + * This function must be called before {@link Configure} + * + * @param callback Indicates the encoder listener to register. For details, see {@link AVCodecCallback}. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; +}; + +class __attribute__((visibility("default"))) AudioEncoderFactory { +public: +#ifdef UNSUPPORT_CODEC + static std::shared_ptr CreateByMime(const std::string &mime) + { + (void)mime; + return nullptr; + } + + static std::shared_ptr CreateByName(const std::string &name) + { + (void)name; + return nullptr; + } +#else + /** + * @brief Instantiate the preferred encoder of the given mime type. + * + * @param mime The mime type. + * @return Returns the preferred encoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByMime(const std::string &mime); + + /** + * @brief Instantiates the designated encoder. + * + * @param name The encoder's name. + * @return Returns the designated encoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByName(const std::string &name); +#endif +private: + AudioEncoderFactory() = default; + ~AudioEncoderFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_ENCODER_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 new file mode 100644 index 0000000000000000000000000000000000000000..95c3dc5f594068696510e39627d25e26e33f2de1 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_common.h @@ -0,0 +1,168 @@ +/* + * 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 AVCODEC_COMMOM_H +#define AVCODEC_COMMOM_H + +#include +#include +#include "av_common.h" +#include "format.h" + +namespace OHOS { +namespace Media { +/** + * @brief Error type of AVCodec + * + * @since 3.1 + * @version 3.1 + */ +enum AVCodecErrorType : int32_t { + /* internal errors, error code passed by the errorCode, and definition see "AVCodecServiceErrCode" */ + AVCODEC_ERROR_INTERNAL, + /* extend error start. The extension error code agreed upon by the plug-in and + the application will be transparently transmitted by the service. */ + AVCODEC_ERROR_EXTEND_START = 0X10000, +}; + +enum AVCodecBufferFlag : uint32_t { + AVCODEC_BUFFER_FLAG_NONE = 0, + /* This signals the end of stream */ + AVCODEC_BUFFER_FLAG_EOS = 1 << 0, + /* This indicates that the buffer contains the data for a sync frame */ + AVCODEC_BUFFER_FLAG_SYNC_FRAME = 1 << 1, + /* This indicates that the buffer only contains part of a frame */ + AVCODEC_BUFFER_FLAG_PARTIAL_FRAME = 1 << 2, + /* This indicated that the buffer contains codec specific data */ + AVCODEC_BUFFER_FLAG_CODEC_DATA = 1 << 3, +}; + +struct AVCodecBufferInfo { + /* The presentation timestamp in microseconds for the buffer */ + int64_t presentationTimeUs = 0; + /* The amount of data (in bytes) in the buffer */ + int32_t size = 0; + /* The start-offset of the data in the buffer */ + int32_t offset = 0; +}; + +class AVCodecCallback { +public: + virtual ~AVCodecCallback() = default; + /** + * Called when an error occurred. + * + * @param errorType Error type. For details, see {@link AVCodecErrorType}. + * @param errorCode Error code. + * @since 3.1 + * @version 3.1 + */ + virtual void OnError(AVCodecErrorType errorType, int32_t errorCode) = 0; + + /** + * Called when the output format has changed. + * + * @param format The new output format. + * @since 3.1 + * @version 3.1 + */ + virtual void OnOutputFormatChanged(const Format &format) = 0; + + /** + * Called when an input buffer becomes available. + * + * @param index The index of the available input buffer. + * @since 3.1 + * @version 3.1 + */ + virtual void OnInputBufferAvailable(uint32_t index) = 0; + + /** + * Called when an output buffer becomes available. + * + * @param index The index of the available output buffer. + * @param info The info of the available output buffer. For details, see {@link AVCodecBufferInfo} + * @param flag The flag of the available output buffer. For details, see {@link AVCodecBufferFlag} + * @since 3.1 + * @version 3.1 + */ + virtual void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; +}; + +class SurfaceBufferExtratDataKey { +public: + /** + * Key for timeStamp in surface's extraData, value type is int64 + */ + static constexpr std::string_view ED_KEY_TIME_STAMP = "timeStamp"; + + /** + * Key for endOfStream in surface's extraData, value type is bool + */ + static constexpr std::string_view ED_KEY_END_OF_STREAM = "endOfStream"; + +private: + SurfaceBufferExtratDataKey() = delete; + ~SurfaceBufferExtratDataKey() = delete; +}; + +class AVSourceFormat { +public: + static constexpr std::string_view SOURCE_TITLE = "title"; // string + static constexpr std::string_view SOURCE_ARTIST = "artist"; // std::string, artist + static constexpr std::string_view SOURCE_ALBUM = "album"; // std::string, album + static constexpr std::string_view SOURCE_ALBUM_ARTIST = "album_artist"; // std::string, album artist + static constexpr std::string_view SOURCE_DATE = "date"; // std::string, media date, + // format: YYYY-MM-DD + static constexpr std::string_view SOURCE_COMMENT = "comment"; // std::string, comment + static constexpr std::string_view SOURCE_GENRE = "genre"; // std::string, genre + static constexpr std::string_view SOURCE_COPYRIGHT = "copyright"; // std::string, copyright + static constexpr std::string_view SOURCE_LANGUAGE = "language"; // std::string, language + static constexpr std::string_view SOURCE_DESCRIPTION = "description"; // std::string, description + static constexpr std::string_view SOURCE_LYRICS = "lyrics"; // std::string, cyrics + static constexpr std::string_view SOURCE_DURATION = "duration"; // int64_t, duration based on + // {@link HST_TIME_BASE} + static constexpr std::string_view SOURCE_TYPE = "media_type"; // std::string, sourece type +private: + AVSourceFormat() = delete; + ~AVSourceFormat() = delete; +}; + + +class AVSourceTrackFormat { +public: + static constexpr std::string_view TRACK_INDEX = "track_index"; + static constexpr std::string_view TRACK_SAMPLE_COUNT = "track_sample_count"; + static constexpr std::string_view TRACK_TYPE = "track_type"; + static constexpr std::string_view TRACK_DURATION = "duration"; + static constexpr std::string_view TRACK_BITRATE = "bitrate"; + static constexpr std::string_view VIDEO_TRACK_ROTATION = "rotation_angle"; + static constexpr std::string_view VIDEO_TRACK_WIDTH = "width"; + static constexpr std::string_view VIDEO_TRACK_HEIGHT = "height"; + static constexpr std::string_view VIDEO_PIXEL_FORMAT = "pixel_format"; + static constexpr std::string_view VIDEO_BIT_STREAM_FORMAT = "bit_stream_format"; +private: + AVSourceTrackFormat() = delete; + ~AVSourceTrackFormat() = delete; +}; + +enum VideoBitStreamFormat { + UNKNOWN = 0, + AVCC, + HVCC, + ANNEXB +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_COMMOM_H diff --git a/interfaces/inner_api/native/avcodec_errors.h b/interfaces/inner_api/native/avcodec_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..18291059ea8c4f225e49d24c2c5bf81b227df29b --- /dev/null +++ b/interfaces/inner_api/native/avcodec_errors.h @@ -0,0 +1,97 @@ +/* + * 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 AVCODEC_ERRORS_H +#define AVCODEC_ERRORS_H + +#include +#include +#include "native_averrors.h" +#include "errors.h" + +namespace OHOS { +namespace Media { +using AVCSErrCode = ErrCode; + +// bit 28~21 is subsys, bit 20~16 is Module. bit 15~0 is code +// confirm module offset +constexpr AVCSErrCode AVCS_MODULE = 10; +constexpr AVCSErrCode AVCS_ERR_OFFSET = ErrCodeOffset(SUBSYS_MULTIMEDIA, AVCS_MODULE); +typedef enum AVCodecServiceErrCode : ErrCode { + AVCS_ERR_OK = ERR_OK, + AVCS_ERR_NO_MEMORY = AVCS_ERR_OFFSET + ENOMEM, // no memory + AVCS_ERR_INVALID_OPERATION = AVCS_ERR_OFFSET + ENOSYS, // opertation not be permitted + AVCS_ERR_INVALID_VAL = AVCS_ERR_OFFSET + EINVAL, // invalid argument + AVCS_ERR_UNKNOWN = AVCS_ERR_OFFSET + 0x200, // unkown error. + AVCS_ERR_SERVICE_DIED, // avcodec service died + AVCS_ERR_CREATE_AVCODEC_SUB_SERVICE_FAILED, // create avcodec sub service failed. + AVCS_ERR_CREATE_MUXER_SUB_SERVICE_FAILED, // create muxer sub service failed. + AVCS_ERR_CREATE_DEMUXER_SUB_SERVICE_FAILED, // create demuxer sub service failed. + AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, // create source sub service failed. + AVCS_ERR_INVALID_STATE, // the state is not support this operation. + AVCS_ERR_UNSUPPORT, // unsupport interface. + AVCS_ERR_UNSUPPORT_AUD_SRC_TYPE, // unsupport audio source type. + AVCS_ERR_UNSUPPORT_AUD_SAMPLE_RATE, // unsupport audio sample rate. + AVCS_ERR_UNSUPPORT_AUD_CHANNEL_NUM, // unsupport audio channel. + AVCS_ERR_UNSUPPORT_AUD_ENC_TYPE, // unsupport audio encoder type. + AVCS_ERR_UNSUPPORT_AUD_PARAMS, // unsupport audio params(other params). + AVCS_ERR_UNSUPPORT_VID_SRC_TYPE, // unsupport video source type. + AVCS_ERR_UNSUPPORT_VID_ENC_TYPE, // unsupport video encoder type. + AVCS_ERR_UNSUPPORT_VID_PARAMS, // unsupport video params(other params). + AVCS_ERR_UNSUPPORT_CONTAINER_TYPE, // unsupport container format type. + AVCS_ERR_UNSUPPORT_PROTOCOL_TYPE, // unsupport protocol type. + AVCS_ERR_UNSUPPORT_VID_DEC_TYPE, // unsupport video decoder type. + AVCS_ERR_UNSUPPORT_AUD_DEC_TYPE, // unsupport audio decoder type. + AVCS_ERR_UNSUPPORT_STREAM, // internal data stream error. + AVCS_ERR_UNSUPPORT_FILE, // this appears to be a text file. + AVCS_ERR_UNSUPPORT_SOURCE, // unsupport source type. + AVCS_ERR_AUD_RENDER_FAILED, // audio render failed. + AVCS_ERR_AUD_ENC_FAILED, // audio encode failed. + AVCS_ERR_VID_ENC_FAILED, // video encode failed. + AVCS_ERR_AUD_DEC_FAILED, // audio decode failed. + AVCS_ERR_VID_DEC_FAILED, // video decode failed. + AVCS_ERR_MUXER_FAILED, // stream avmuxer failed. + AVCS_ERR_DEMUXER_FAILED, // stream demuxer or parser failed. + AVCS_ERR_OPEN_FILE_FAILED, // open file failed. + AVCS_ERR_FILE_ACCESS_FAILED, // read or write file failed. + AVCS_ERR_START_FAILED, // audio/video start failed. + AVCS_ERR_PAUSE_FAILED, // audio/video pause failed. + AVCS_ERR_STOP_FAILED, // audio/video stop failed. + AVCS_ERR_SEEK_FAILED, // audio/video seek failed. + AVCS_ERR_NETWORK_TIMEOUT, // network timeout. + AVCS_ERR_NOT_FIND_CONTAINER, // not find a demuxer. + AVCS_ERR_DATA_SOURCE_IO_ERROR, // avcodec data source IO failed. + AVCS_ERR_DATA_SOURCE_OBTAIN_MEM_ERROR, // avcodec data source get mem failed. + AVCS_ERR_DATA_SOURCE_ERROR_UNKNOWN, // avcodec data source error unknow. + + AVCS_ERR_NOT_ENOUGH_DATA, + AVCS_ERR_END_OF_STREAM, + AVCS_ERR_AGAIN, + AVCS_ERR_WRONG_STATE, + AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT, + AVCS_ERR_MISMATCH_SAMPLE_RATE, + AVCS_ERR_MISMATCH_BIT_RATE, + AVCS_ERR_CONFIGURE_ERROR, + + AVCS_ERR_EXTEND_START = AVCS_ERR_OFFSET + 0xF000, // extend err start. +} AVCodecServiceErrCode; + +__attribute__((visibility("default"))) std::string AVCSErrorToString(AVCodecServiceErrCode code); +__attribute__((visibility("default"))) std::string OHAVErrCodeToString(OH_AVErrCode code); +__attribute__((visibility("default"))) std::string AVCSErrorToOHAVErrCodeString(AVCodecServiceErrCode code); +__attribute__((visibility("default"))) OH_AVErrCode AVCSErrorToOHAVErrCode(AVCodecServiceErrCode code); +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_ERRORS_H diff --git a/interfaces/inner_api/native/avcodec_info.h b/interfaces/inner_api/native/avcodec_info.h new file mode 100644 index 0000000000000000000000000000000000000000..71ff153ca815e66c19e2039c64641b0ed4b984c9 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_info.h @@ -0,0 +1,741 @@ +/* + * 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 AVCODEC_INFO_H +#define AVCODEC_INFO_H + +#include +#include +#include +#include "av_common.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +/** + * @brief AVCodec Type + * + * @since 3.1 + * @version 3.1 + */ +enum AVCodecType : int32_t { + AVCODEC_TYPE_NONE = -1, + AVCODEC_TYPE_VIDEO_ENCODER = 0, + AVCODEC_TYPE_VIDEO_DECODER, + AVCODEC_TYPE_AUDIO_ENCODER, + AVCODEC_TYPE_AUDIO_DECODER, +}; + +enum AudioSampleFormat { + SAMPLE_U8 = 0, + SAMPLE_S16LE = 1, + SAMPLE_S24LE = 2, + SAMPLE_S32LE = 3, + SAMPLE_F32LE = 4, + INVALID_WIDTH = -1 +}; + +/** + * @brief Range contain min and max value + * + * @since 3.1 + * @version 3.1 + */ +struct Range { + int32_t minVal; + int32_t maxVal; + Range() : minVal(0), maxVal(0) {} + Range(const int32_t &min, const int32_t &max) + { + if (min <= max) { + this->minVal = min; + this->maxVal = max; + } else { + this->minVal = 0; + this->maxVal = 0; + } + } + + Range Create(const int32_t &min, const int32_t &max) + { + return Range(min, max); + } + + Range Intersect(const int32_t &min, const int32_t &max) + { + int32_t minCmp = this->minVal > min ? this->minVal : min; + int32_t maxCmp = this->maxVal < max ? this->maxVal : max; + return this->Create(minCmp, maxCmp); + } + + Range Intersect(const Range &range) + { + int32_t minCmp = this->minVal > range.minVal ? this->minVal : range.minVal; + int32_t maxCmp = this->maxVal < range.maxVal ? this->maxVal : range.maxVal; + return this->Create(minCmp, maxCmp); + } +}; + +/** + * @brief ImgSize contain width and height + * + * @since 3.1 + * @version 3.1 + */ +struct ImgSize { + int32_t width; + int32_t height; + + ImgSize() : width(0), height(0) {} + + ImgSize(const int32_t &width, const int32_t &height) + { + this->width = width; + this->height = height; + } + + bool operator<(const ImgSize &p) const + { + return (width < p.width) || (width == p.width && height < p.height); + } +}; + +/** + * @brief Capability Data struct of Codec, parser from config file + * + * @since 3.1 + * @version 3.1 + */ +struct CapabilityData { + std::string codecName = ""; + int32_t codecType = AVCODEC_TYPE_NONE; + std::string mimeType = ""; + bool isVendor = false; + int32_t maxInstance = 0; + Range bitrate; + Range channels; + Range complexity; + ImgSize alignment; + Range width; + Range height; + Range frameRate; + Range encodeQuality; + Range blockPerFrame; + Range blockPerSecond; + ImgSize blockSize; + std::vector sampleRate; + std::vector pixFormat; + std::vector bitDepth; + std::vector profiles; + std::vector bitrateMode; + std::map> profileLevelsMap; + std::map measuredFrameRate; + bool supportSwapWidthHeight = false; +}; + +struct LevelParams { + int32_t maxBlockPerFrame = 0; + int32_t maxBlockPerSecond = 0; + int32_t maxFrameRate = 0; + int32_t maxWidth = 0; + int32_t maxHeight = 0; + LevelParams(const int32_t &blockPerFrame, const int32_t &blockPerSecond, + const int32_t &frameRate, const int32_t &width, const int32_t height) + { + this->maxBlockPerFrame = blockPerFrame; + this->maxBlockPerSecond = blockPerSecond; + this->maxFrameRate = frameRate; + this->maxWidth = width; + this->maxHeight = height; + } + LevelParams(const int32_t &blockPerFrame, const int32_t &blockPerSecond) + { + this->maxBlockPerFrame = blockPerFrame; + this->maxBlockPerSecond = blockPerSecond; + } +}; + +class __attribute__((visibility("default"))) AVCodecInfo { +public: + explicit AVCodecInfo(CapabilityData &capabilityData); + ~AVCodecInfo(); + + /** + * @brief Get name of this codec, used to create the codec instance. + * @return Returns codec name. + * @since 3.1 + * @version 3.1 + */ + std::string GetName(); + + /** + * @brief Get type of this codec + * @return Returns codec type, see {@link AVCodecType} + * @since 3.1 + * @version 3.1 + */ + AVCodecType GetType(); + + /** + * @brief Get mime type of this codec + * @return Returns codec mime type, see {@link CodecMimeType} + * @since 3.1 + * @version 3.1 + */ + std::string GetMimeType(); + + /** + * @brief Check whether the codec is accelerated by hardware. + * @return Returns true if the codec is hardware accelerated; false otherwise. + * @since 3.1 + * @version 3.1 + */ + bool IsHardwareAccelerated(); + + /** + * @brief Check whether the codec is software implemented only. + * @return Returns true if the codec is software implemented only; false otherwise. + * @since 3.1 + * @version 3.1 + */ + bool IsSoftwareOnly(); + + /** + * @brief Check whether the codec is provided by vendor. + * @return Returns true if the codec is provided by vendor; false otherwise. + * @since 3.1 + * @version 3.1 + */ + bool IsVendor(); + +private: + CapabilityData data_; +}; + +class __attribute__((visibility("default"))) VideoCaps { +public: + explicit VideoCaps(CapabilityData &capabilityData); + ~VideoCaps(); + + /** + * @brief Get codec information, such as the codec name, codec type, + * whether hardware acceleration is supported, whether only software is supported, + * and whether the codec is provided by the vendor. + * @return Returns the pointer of {@link AVCodecInfo}. + * @since 3.1 + * @version 3.1 + */ + std::shared_ptr GetCodecInfo(); + + /** + * @brief Get supported bitrate range. + * @return Returns the range of supported bitrates. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedBitrate(); + + /** + * @brief Get supported video raw formats. + * @return Returns an array of supported formats. For Details, see {@link VideoPixelFormat}. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedFormats(); + + /** + * @brief Get supported alignment of video height, only used for video codecs. + * @return Returns the supported alignment of video height (in pixels). + * @since 3.1 + * @version 3.1 + */ + int32_t GetSupportedHeightAlignment(); + + /** + * @brief Get supported alignment of video width, only used for video codecs. + * @return Returns the supported alignment of video width (in pixels). + * @since 3.1 + * @version 3.1 + */ + int32_t GetSupportedWidthAlignment(); + + /** + * @brief Get supported width range of video. + * @return Returns the supported width range of video. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedWidth(); + + /** + * @brief Get supported height range of video. + * @return Returns the supported height range of video. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedHeight(); + + /** + * @brief Get supported profiles of this codec. + * @return Returns an array of supported profiles: + * returns {@link H263Profile} array if codec is h263, + * returns {@link AVCProfile} array if codec is h264, + * returns {@link HEVCProfile} array if codec is h265, + * returns {@link MPEG2Profile} array if codec is mpeg2, + * returns {@link MPEG4Profile} array if codec is mpeg4, + * returns {@link VP8Profile} array if codec is vp8. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedProfiles(); + + /** + * @brief Get supported codec level array. + * @return Returns an array of supported codec level number. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedLevels(); + + /** + * @brief Get supported video encode quality Range. + * @return Returns an array of supported video encode quality Range. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedEncodeQuality(); + + /** + * @brief Check whether the width and height is supported. + * @param width Indicates the specified video width (in pixels). + * @param height Indicates the specified video height (in pixels). + * @return Returns true if the codec supports {@link width} * {@link height} size video, false otherwise. + * @since 3.1 + * @version 3.1 + */ + bool IsSizeSupported(int32_t width, int32_t height); + + /** + * @brief Get supported frameRate. + * @return Returns the supported frameRate range of video. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedFrameRate(); + + /** + * @brief Get supported frameRate range for the specified width and height. + * @param width Indicates the specified video width (in pixels). + * @param height Indicates the specified video height (in pixels). + * @return Returns the supported frameRate range for the specified width and height. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedFrameRatesFor(int32_t width, int32_t height); + + /** + * @brief Check whether the size and frameRate is supported. + * @param width Indicates the specified video width (in pixels). + * @param height Indicates the specified video height (in pixels). + * @param frameRate Indicates the specified video frameRate. + * @return Returns true if the codec supports the specified size and frameRate; false otherwise. + * @since 3.1 + * @version 3.1 + */ + bool IsSizeAndRateSupported(int32_t width, int32_t height, double frameRate); + + /** + * @brief Get preferred frameRate range for the specified width and height, + * these framerates can be reach the performance. + * @param width Indicates the specified video width (in pixels). + * @param height Indicates the specified video height (in pixels). + * @return Returns preferred frameRate range for the specified width and height. + * @since 3.1 + * @version 3.1 + */ + Range GetPreferredFrameRate(int32_t width, int32_t height); + + /** + * @brief Get supported encode bitrate mode. + * @return Returns an array of supported encode bitrate mode. For details, see {@link VideoEncodeBitrateMode}. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedBitrateMode(); + + /** + * @brief Get supported encode qualit range. + * @return Returns supported encode qualit range. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedQuality(); + + /** + * @brief Get supported encode complexity range. + * @return Returns supported encode complexity range. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedComplexity(); + + /** + * @brief Check video encoder wether support request key frame dynamicly. + * @return Returns true if support, false not support. + * @since 3.1 + * @version 3.1 + */ + bool IsSupportDynamicIframe(); + +private: + CapabilityData data_; + int32_t blockWidth_; + int32_t blockHeight_; + Range horizontalBlockRange_; + Range verticalBlockRange_; + Range blockPerFrameRange_; + Range blockPerSecondRange_; + Range widthRange_; + Range heightRange_; + Range frameRateRange_; + void InitParams(); + void UpdateParams(); + void LoadLevelParams(); + void LoadAVCLevelParams(); + void LoadMPEG2LevelParams(); + void LoadMPEG4LevelParams(); + ImgSize MatchClosestSize(const ImgSize &imgSize); + int32_t DivCeil(const int32_t ÷nd, const int32_t &divisor); + Range DivRange(const Range &range, const int32_t &divisor); + void UpdateBlockParams(const int32_t &blockWidth, const int32_t &blockHeight, + Range &blockPerFrameRange, Range &blockPerSecondRange); +}; + +class __attribute__((visibility("default"))) AudioCaps { +public: + explicit AudioCaps(CapabilityData &capabilityData); + ~AudioCaps(); + + /** + * @brief Get codec information, such as the codec name, codec type, + * whether hardware acceleration is supported, whether only software is supported, + * and whether the codec is provided by the vendor. + * @return Returns the pointer of {@link AVCodecInfo} + * @since 3.1 + * @version 3.1 + */ + std::shared_ptr GetCodecInfo(); + + /** + * @brief Get supported bitrate range. + * @return Returns the range of supported bitrates. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedBitrate(); + + /** + * @brief Get supported channel range. + * @return Returns the range of supported channel. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedChannel(); + + /** + * @brief Get supported audio raw format range. + * @return Returns the range of supported audio raw format. For details, see {@link AudioSampleFormat}. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedFormats(); + + /** + * @brief Get supported audio samplerates. + * @return Returns an array of supported samplerates. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedSampleRates(); + + /** + * @brief Get supported codec profile number. + * @return Returns an array of supported codec profile number. For details, see {@link AACProfile}. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedProfiles(); + + /** + * @brief Get supported codec level array. + * @return Returns an array of supported codec level number. + * @since 3.1 + * @version 3.1 + */ + std::vector GetSupportedLevels(); + + /** + * @brief Get supported encode complexity range. + * @return Returns supported encode complexity range. + * @since 3.1 + * @version 3.1 + */ + Range GetSupportedComplexity(); + +private: + CapabilityData data_; +}; + +/** + * @brief Enumerates the codec mime type. + */ +class CodecMimeType { +public: + static constexpr std::string_view VIDEO_H263 = "video/h263"; + static constexpr std::string_view VIDEO_AVC = "video/avc"; + static constexpr std::string_view VIDEO_MPEG2 = "video/mpeg2"; + static constexpr std::string_view VIDEO_HEVC = "video/hevc"; + static constexpr std::string_view VIDEO_MPEG4 = "video/mp4v-es"; + static constexpr std::string_view VIDEO_VP8 = "video/x-vnd.on2.vp8"; + static constexpr std::string_view VIDEO_VP9 = "video/x-vnd.on2.vp9"; + static constexpr std::string_view AUDIO_AMR_NB = "audio/3gpp"; + static constexpr std::string_view AUDIO_AMR_WB = "audio/amr-wb"; + static constexpr std::string_view AUDIO_MPEG = "audio/mpeg"; + static constexpr std::string_view AUDIO_AAC = "audio/mp4a-latm"; + static constexpr std::string_view AUDIO_VORBIS = "audio/vorbis"; + 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"; +}; + +/** + * @brief AVC Profile + * + * @since 3.1 + * @version 3.1 + */ +enum AVCProfile : int32_t { + AVC_PROFILE_BASELINE = 0, + AVC_PROFILE_CONSTRAINED_BASELINE = 1, + AVC_PROFILE_CONSTRAINED_HIGH = 2, + AVC_PROFILE_EXTENDED = 3, + AVC_PROFILE_HIGH = 4, + AVC_PROFILE_HIGH_10 = 5, + AVC_PROFILE_HIGH_422 = 6, + AVC_PROFILE_HIGH_444 = 7, + AVC_PROFILE_MAIN = 8, +}; + +/** + * @brief HEVC Profile + * + * @since 3.1 + * @version 3.1 + */ +enum HEVCProfile : int32_t { + HEVC_PROFILE_MAIN = 0, + HEVC_PROFILE_MAIN_10 = 1, + HEVC_PROFILE_MAIN_STILL = 2, + HEVC_PROFILE_MAIN_10_HDR10 = 3, + HEVC_PROFILE_MAIN_10_HDR10_PLUS = 4, +}; + +/** + * @brief MPEG2 Profile + * + * @since 3.1 + * @version 3.1 + */ +enum MPEG2Profile : int32_t { + MPEG2_PROFILE_422 = 0, + MPEG2_PROFILE_HIGH = 1, + MPEG2_PROFILE_MAIN = 2, + MPEG2_PROFILE_SNR = 3, + MPEG2_PROFILE_SIMPLE = 4, + MPEG2_PROFILE_SPATIAL = 5, +}; + +/** + * @brief MPEG4 Profile + * + * @since 3.1 + * @version 3.1 + */ +enum MPEG4Profile : int32_t { + MPEG4_PROFILE_ADVANCED_CODING = 0, + MPEG4_PROFILE_ADVANCED_CORE = 1, + MPEG4_PROFILE_ADVANCED_REAL_TIME = 2, + MPEG4_PROFILE_ADVANCED_SCALABLE = 3, + MPEG4_PROFILE_ADVANCED_SIMPLE = 4, + MPEG4_PROFILE_BASIC_ANIMATED = 5, + MPEG4_PROFILE_CORE = 6, + MPEG4_PROFILE_CORE_SCALABLE = 7, + MPEG4_PROFILE_HYBRID = 8, + MPEG4_PROFILE_MAIN = 9, + MPEG4_PROFILE_NBIT = 10, + MPEG4_PROFILE_SCALABLE_TEXTURE = 11, + MPEG4_PROFILE_SIMPLE = 12, + MPEG4_PROFILE_SIMPLE_FBA = 13, + MPEG4_PROFILE_SIMPLE_FACE = 14, + MPEG4_PROFILE_SIMPLE_SCALABLE = 15, +}; + +/** + * @brief H263 Profile + * + * @since 3.1 + * @version 3.1 + */ +enum H263Profile : int32_t { + H263_PROFILE_BACKWARD_COMPATIBLE = 0, + H263_PROFILE_BASELINE = 1, + H263_PROFILE_H320_CODING = 2, + H263_PROFILE_HIGH_COMPRESSION = 3, + H263_PROFILE_HIGH_LATENCY = 4, + H263_PROFILE_ISW_V2 = 5, + H263_PROFILE_ISW_V3 = 6, + H263_PROFILE_INTERLACE = 7, + H263_PROFILE_INTERNET = 8, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum VP8Profile : int32_t { + VP8_PROFILE_MAIN = 0, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum AACProfile : int32_t { + AAC_PROFILE_LC = 0, + AAC_PROFILE_ELD = 1, + AAC_PROFILE_ERLC = 2, + AAC_PROFILE_HE = 3, + AAC_PROFILE_HE_V2 = 4, + AAC_PROFILE_LD = 5, + AAC_PROFILE_MAIN = 6, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum AVCLevel : int32_t { + AVC_LEVEL_1 = 0, + AVC_LEVEL_1b = 1, + AVC_LEVEL_11 = 2, + AVC_LEVEL_12 = 3, + AVC_LEVEL_13 = 4, + AVC_LEVEL_2 = 5, + AVC_LEVEL_21 = 6, + AVC_LEVEL_22 = 7, + AVC_LEVEL_3 = 8, + AVC_LEVEL_31 = 9, + AVC_LEVEL_32 = 10, + AVC_LEVEL_4 = 11, + AVC_LEVEL_41 = 12, + AVC_LEVEL_42 = 13, + AVC_LEVEL_5 = 14, + AVC_LEVEL_51 = 15, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum HEVCLevel : int32_t { + HEVC_LEVEL_1 = 0, + HEVC_LEVEL_2 = 1, + HEVC_LEVEL_21 = 2, + HEVC_LEVEL_3 = 3, + HEVC_LEVEL_31 = 4, + HEVC_LEVEL_4 = 5, + HEVC_LEVEL_41 = 6, + HEVC_LEVEL_5 = 7, + HEVC_LEVEL_51 = 8, + HEVC_LEVEL_52 = 9, + HEVC_LEVEL_6 = 10, + HEVC_LEVEL_61 = 11, + HEVC_LEVEL_62 = 12, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum MPEG2Level : int32_t { + MPEG2_LEVEL_LL = 0, + MPEG2_LEVEL_ML = 1, + MPEG2_LEVEL_H14 = 2, + MPEG2_LEVEL_HL = 3, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum MPEG4Level : int32_t { + MPEG4_LEVEL_0 = 0, + MPEG4_LEVEL_0B = 1, + MPEG4_LEVEL_1 = 2, + MPEG4_LEVEL_2 = 3, + MPEG4_LEVEL_3 = 4, + MPEG4_LEVEL_4 = 5, + MPEG4_LEVEL_4A = 6, + MPEG4_LEVEL_5 = 7, +}; + +/** + * @brief + * + * @since 3.1 + * @version 3.1 + */ +enum VideoEncodeBitrateMode : int32_t { + /** + * constant bit rate mode. + */ + CBR = 0, + /** + * variable bit rate mode. + */ + VBR = 1, + /** + * constant quality mode. + */ + CQ = 2, +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_INFO_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avcodec_list.h b/interfaces/inner_api/native/avcodec_list.h new file mode 100644 index 0000000000000000000000000000000000000000..65c0f74fe6b883189caa658ae085ed4543d18bfa --- /dev/null +++ b/interfaces/inner_api/native/avcodec_list.h @@ -0,0 +1,73 @@ +/* + * 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 AVCODEC_LIST_H +#define AVCODEC_LIST_H + +#include +#include +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class AVCodecList { +public: + virtual ~AVCodecList() = default; + + /** + * @brief Find the supported decoder name by format(must contains video or audio MIME). + * @param format Indicates a media description which contains required decoder capability. + * @return Returns decoder name, if not find, return empty string. + * @since 10 + * @version 1.0 + */ + virtual std::string FindDecoder(const Format &format) = 0; + + /** + * @brief Find the supported encoder name by format(must contains video or audio MIME). + * @param format Indicates a media description which contains required encoder capability. + * @return Returns encoder name, if not find, return empty string. + * @since 10 + * @version 1.0 + */ + virtual std::string FindEncoder(const Format &format) = 0; + + /** + * @brief Create a capability by codec name + * @param codeName Codec name + * @return Returns an array of supported video decoder capability, if not find, return invalid CapabilityData. + * @since 10 + * @version 1.0 + */ + virtual CapabilityData CreateCapability(const std::string codecName) = 0; +}; + +class __attribute__((visibility("default"))) AVCodecListFactory { +public: +#ifdef UNSUPPORT_CODECLIST + static std::shared_ptr CreateAVCodecList() + { + return nullptr; + } +#else + static std::shared_ptr CreateAVCodecList(); +#endif +private: + AVCodecListFactory() = default; + ~AVCodecListFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LIST_H diff --git a/interfaces/inner_api/native/avcodec_video_decoder.h b/interfaces/inner_api/native/avcodec_video_decoder.h new file mode 100644 index 0000000000000000000000000000000000000000..fdabf8100f20cc54740856769fd916d95e759274 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_video_decoder.h @@ -0,0 +1,239 @@ +/* + * 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 AVCODEC_VIDEO_DECODER_H +#define AVCODEC_VIDEO_DECODER_H + +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "format.h" +#include "surface.h" + +namespace OHOS { +namespace Media { +class AVCodecVideoDecoder { +public: + virtual ~AVCodecVideoDecoder() = default; + + /** + * @brief Configure the decoder. + * + * @param format The format of the input data and the desired format of the output data. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Configure(const Format &format) = 0; + + /** + * @brief Prepare for decoding. + * + * This function must be called after {@link Configure} and before {@link Start} + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Prepare() = 0; + + /** + * @brief Start decoding. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Start() = 0; + + /** + * @brief Stop decoding. + * + * This function must be called during running + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Stop() = 0; + + /** + * @brief Flush both input and output buffers of the decoder. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Flush() = 0; + + /** + * @brief Restores the decoder to the initial state. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Reset() = 0; + + /** + * @brief Releases decoder resources. All methods are unavailable after calling this. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Release() = 0; + + /** + * @brief Sets the surface on which to render the output of this decoder. + * + * This function must be called before {@link Prepare} + * + * @param index The index of the output buffer. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetOutputSurface(sptr surface) = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a input buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + + /** + * @brief Submits input buffer to decoder. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @param info The info of the input buffer. For details, see {@link AVCodecBufferInfo} + * @param flag The flag of the input buffer. For details, see {@link AVCodecBufferFlag} + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a output buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + + /** + * @brief Gets the format of the output data. + * + * This function must be called after {@link Configure} + * + * @param format + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t GetOutputFormat(Format &format) = 0; + + /** + * @brief Returns the output buffer to the decoder. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t ReleaseOutputBuffer(uint32_t index, bool render) = 0; + + /** + * @brief Sets the parameters to the decoder. + * + * This function must be called after {@link Configure} + * + * @param format The parameters. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetParameter(const Format &format) = 0; + + /** + * @brief Registers a decoder listener. + * + * This function must be called before {@link Configure} + * + * @param callback Indicates the decoder listener to register. For details, see {@link AVCodecCallback}. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; +}; + +class __attribute__((visibility("default"))) VideoDecoderFactory { +public: +#ifdef UNSUPPORT_CODEC + static std::shared_ptr CreateByMime(const std::string &mime) + { + (void)mime; + return nullptr; + } + + static std::shared_ptr CreateByName(const std::string &name) + { + (void)name; + return nullptr; + } +#else + /** + * @brief Instantiate the preferred decoder of the given mime type. + * + * @param mime The mime type. + * @return Returns the preferred decoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByMime(const std::string &mime); + + /** + * @brief Instantiates the designated decoder. + * + * @param name The decoder's name. + * @return Returns the designated decoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByName(const std::string &name); +#endif +private: + VideoDecoderFactory() = default; + ~VideoDecoderFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_VIDEO_DECODER_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avcodec_video_encoder.h b/interfaces/inner_api/native/avcodec_video_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..909dd81a00507250175ba60a0b56ab08a7598c54 --- /dev/null +++ b/interfaces/inner_api/native/avcodec_video_encoder.h @@ -0,0 +1,247 @@ +/* + * 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 AVCODEC_VIDEO_ENCODER_H +#define AVCODEC_VIDEO_ENCODER_H + +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "format.h" +#include "surface.h" + +namespace OHOS { +namespace Media { +class AVCodecVideoEncoder { +public: + virtual ~AVCodecVideoEncoder() = default; + + /** + * @brief Configure the encoder. + * + * @param format The format of the input data and the desired format of the output data. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Configure(const Format &format) = 0; + + /** + * @brief Prepare for decoding. + * + * This function must be called after {@link Configure} and before {@link Start} + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Prepare() = 0; + + /** + * @brief Start decoding. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Start() = 0; + + /** + * @brief Stop decoding. + * + * This function must be called during running + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Stop() = 0; + + /** + * @brief Flush both input and output buffers of the encoder. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Flush() = 0; + + /** + * @brief Notify eos of the encoder. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t NotifyEos() = 0; + + /** + * @brief Restores the encoder to the initial state. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Reset() = 0; + + /** + * @brief Releases encoder resources. All methods are unavailable after calling this. + * + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t Release() = 0; + + /** + * @brief Obtains the surface from encoder. + * + * This function can only be called after {@link Configure} and before {@link Prepare} + * + * @return Returns the pointer to the surface. + * @since 3.1 + * @version 3.1 + */ + virtual sptr CreateInputSurface() = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a input buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + + /** + * @brief Submits input buffer to encoder. + * + * This function must be called during running + * + * @param index The index of the input buffer. + * @param info The info of the input buffer. For details, see {@link AVCodecBufferInfo} + * @param flag The flag of the input buffer. For details, see {@link AVCodecBufferFlag} + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + + /** + * @brief Returns a {@link AVSharedMemory} object for a output buffer index that contains the data. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVSharedMemory} if success; returns nullptr otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + + /** + * @brief Gets the format of the output data. + * + * This function must be called after {@link Configure} + * + * @param format + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t GetOutputFormat(Format &format) = 0; + + /** + * @brief Returns the output buffer to the encoder. + * + * This function must be called during running + * + * @param index The index of the output buffer. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t ReleaseOutputBuffer(uint32_t index) = 0; + + /** + * @brief Sets the parameters to the encoder. + * + * This function must be called after {@link Configure} + * + * @param format The parameters. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetParameter(const Format &format) = 0; + + /** + * @brief Registers a encoder listener. + * + * This function must be called before {@link Configure} + * + * @param callback Indicates the encoder listener to register. For details, see {@link AVCodecCallback}. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 3.1 + * @version 3.1 + */ + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; +}; + +class __attribute__((visibility("default"))) VideoEncoderFactory { +public: +#ifdef UNSUPPORT_CODEC + static std::shared_ptr CreateByMime(const std::string &mime) + { + (void)mime; + return nullptr; + } + + static std::shared_ptr CreateByName(const std::string &name) + { + (void)name; + return nullptr; + } +#else + /** + * @brief Instantiate the preferred encoder of the given mime type. + * + * @param mime The mime type. + * @return Returns the preferred encoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByMime(const std::string &mime); + + /** + * @brief Instantiates the designated encoder. + * + * @param name The encoder's name. + * @return Returns the designated encoder. + * @since 3.1 + * @version 3.1 + */ + static std::shared_ptr CreateByName(const std::string &name); +#endif +private: + VideoEncoderFactory() = default; + ~VideoEncoderFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_VIDEO_ENCODER_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avdemuxer.h b/interfaces/inner_api/native/avdemuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..2bcb5d0a44fb6d520aab4ee92f7733575e7d9412 --- /dev/null +++ b/interfaces/inner_api/native/avdemuxer.h @@ -0,0 +1,97 @@ +/* + * 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 AVDEMUXER_H +#define AVDEMUXER_H + +#include +#include "avcodec_common.h" +#include "avsource.h" + +namespace OHOS { +namespace Media { +class AVDemuxer { +public: + ~AVDemuxer() = default; + + /** + * @brief Add the sourceTrack by track id. + * This function can only by called before {@link CopyNextSample}. + * @param trackIndex The index of the track to add. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t SelectSourceTrackByID(uint32_t trackIndex) = 0; + + /** + * @brief Remove the sourceTrack by track id. + * This function can only by called before {@link CopyNextSample}. + * @param trackIndex The index of the track to remove. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t UnselectSourceTrackByID(uint32_t trackIndex) = 0; + + /** + * @brief Copy the current sample to buffer, and save buffer attribute to attr. + * @param trackIndex The param storing trackIndex of the buffer. + * @param buffer The buffer pointer to store data. + * @param attr The CodecBufferAttr pointer to store data attribute. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) = 0; + + /** + * @brief All selected tracks seek near to the requested time according to the seek mode. + * @param mSeconds The millisecond for seeking, the timestamp is the position of + * the file relative to the start of the file.. + * @param mode The mode for seeking. Value. For details, see {@link SeekMode}. + * @return Returns {@link AVCS_ERR_OK} if success; returns an error code otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode) = 0; +}; + +class __attribute__((visibility("default"))) AVDemuxerFactory { +public: +#ifdef UNSUPPORT_DEMUXER + static std::shared_ptr CreateWithSource(AVSource& source) + { + return nullptr; + } +#else + /** + * @brief Instantiate the preferred demuxer of the given source instance. + * @param sourceAddr The address for source instance. + * @return Returns the preferred demuxer. + * @since 4.0 + * @version 4.0 + */ + static std::shared_ptr CreateWithSource(AVSource& source); +#endif +private: + AVDemuxerFactory() = default; + ~AVDemuxerFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // AVDEMUXER_H diff --git a/interfaces/inner_api/native/avmuxer.h b/interfaces/inner_api/native/avmuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..fe89b3b02bee45e69740ea47d07ca1f50f1444fd --- /dev/null +++ b/interfaces/inner_api/native/avmuxer.h @@ -0,0 +1,45 @@ +/* + * 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_H +#define AVMUXER_H + +#include "media_description.h" +#include "av_common.h" + +namespace OHOS { +namespace Media { +class AVMuxer { +public: + virtual ~AVMuxer() = 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(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, OutputFormat format); +private: + AVMuxerFactory() = default; + ~AVMuxerFactory() = default; +}; +} // namespace Media +} // namespace OHOS + +#endif // AVMUXER_H diff --git a/interfaces/inner_api/native/avsharedmemory.h b/interfaces/inner_api/native/avsharedmemory.h new file mode 100644 index 0000000000000000000000000000000000000000..f37b33479de0e6e15b69bc0573eb8c55c06afe5a --- /dev/null +++ b/interfaces/inner_api/native/avsharedmemory.h @@ -0,0 +1,75 @@ +/* + * 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 AVSHAREDMEMORY_H +#define AVSHAREDMEMORY_H + +#include +#include + +namespace OHOS { +namespace Media { +/** + * @brief Provides a unified interface to implement convenient memory sharing + * mechanism. For those platforms that do not support multi-process, it may + * simply encapsulate ordinary memory blocks, not really multi-process shareable memory. + */ +class __attribute__((visibility("default"))) AVSharedMemory { +public: + virtual ~AVSharedMemory() = default; + + /** + * @brief Enumerates the flag bits used to create a new shared memory. + */ + enum Flags : uint32_t { + /** + * This flag bit indicates that the remote process is allowed to read and write + * the shared memory. If no flags are specified, this is the default memory + * sharing policy. If the FLAGS_READ_ONLY bit is set, this flag bit is ignored. + */ + FLAGS_READ_WRITE = 0x1, + /** + * For platforms that support multiple processes, this flag bit indicates that the + * remote process can only read data in the shared memory. If this flag is not set, + * the remote process has both read and write permissions by default. Adding this + * flag does not affect the process that creates the memory, which always has the + * read and write permission on the shared memory. For platforms that do not support + * multi-processes, the memory read and write permission control capability may + * not be available. In this case, this flag is invalid. + */ + FLAGS_READ_ONLY = 0x2, + }; + + /** + * @brief Get the memory's virtual address + * @return the memory's virtual address if the memory is valid, otherwise nullptr. + */ + virtual uint8_t *GetBase() const = 0; + + /** + * @brief Get the memory's size + * @return the memory's size if the memory is valid, otherwise -1. + */ + virtual int32_t GetSize() const = 0; + + /** + * @brief Get the memory's flags set by the creator, refer to {@Flags} + * @return the memory's flags if the memory is valid, otherwise 0. + */ + virtual uint32_t GetFlags() const = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // AVSHAREDMEMORY_H \ No newline at end of file diff --git a/interfaces/inner_api/native/avsource.h b/interfaces/inner_api/native/avsource.h new file mode 100644 index 0000000000000000000000000000000000000000..a459ea658a047562cecbda7ca88ead0ec10f0c2c --- /dev/null +++ b/interfaces/inner_api/native/avsource.h @@ -0,0 +1,140 @@ +/* + * 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 AVSOURCE_H +#define AVSOURCE_H + +#include +#include +#include +#include "avcodec_common.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class AVSourceTrack; + +class AVSource { +public: + virtual ~AVSource() = default; + + /** + * @brief Count number of the track in source. + * @return Returns the tracks's count. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t GetTrackCount(uint32_t &trackCount) = 0; + + /** + * @brief Return a {@link AVSourceTrack} object. + * @param trackIndex The index of the track. + * @return Returns {@link AVSourceTrack} if success; returns nullptr otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual std::shared_ptr GetSourceTrackByID(uint32_t trackIndex) = 0; + + /** + * @brief Gets the parameters of the source. + * @param format The empty parameters for storing data. + * @return Returns {@link Format} if success; returns nullptr otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t GetSourceFormat(Format &format) = 0; + + /** + * @brief Gets the address of the source. + * @return Returns {@link Format} if success; returns nullptr otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual uintptr_t GetSourceAddr() = 0; + + std::string sourceUri; + +private: + std::vector tracks_ {}; +}; + +class __attribute__((visibility("default"))) AVSourceFactory { +public: +#ifdef UNSUPPORT_SOURCE + static std::shared_ptr CreateWithURI(const std::string &uri) + { + (void)uri; + return nullptr; + } + + static std::shared_ptr CreateWithFD(int32_t fd, int64_t offset, int64_t size) + { + (void)uri; + return nullptr; + } + +#else + /** + * @brief Instantiate the preferred source of the uri. + * @param uri The file's uri. + * @return Returns the preferred source. + * @since 4.0 + * @version 4.0 + */ + static std::shared_ptr CreateWithURI(const std::string &uri); + + /** + * @brief Instantiate the preferred source of the fd. + * @param fd The fileDescriptor data source. + * @param offset The offset into the file where the data be read starts. + * @param size the length in bytes of the data to be read. + * @return Returns the preferred source. + * @since 4.0 + * @version 4.0 + */ + static std::shared_ptr CreateWithFD(int32_t fd, int64_t offset, int64_t size); + +#endif +private: + AVSourceFactory() = default; + ~AVSourceFactory() = default; +}; + +class AVSourceTrack { +public: + virtual ~AVSourceTrack() = default; + + /** + * @brief Sets the parameters to the track. + * @param format The parameters to set. + * @return Returns {@link MSEER_OK} if success; returns nullptr otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t SetTrackFormat(const Format &format) = 0; + + /** + * @brief Gets the parameters of the track. + * @param format The empty parameters for storing data. + * @return Returns {@link Format} if success; returns nullptr otherwise. + * @since 4.0 + * @version 4.0 + */ + virtual int32_t GetTrackFormat(Format &format) = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // AVSOURCE_H + diff --git a/interfaces/inner_api/native/format.h b/interfaces/inner_api/native/format.h new file mode 100644 index 0000000000000000000000000000000000000000..4f8e9eb1d3508b1e1235ddff09509b8baeb87d72 --- /dev/null +++ b/interfaces/inner_api/native/format.h @@ -0,0 +1,255 @@ +/* + * 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 FORMAT_H +#define FORMAT_H + +#include +#include +#include + +namespace OHOS { +namespace Media { +enum FormatDataType : uint32_t { + /* None */ + FORMAT_TYPE_NONE, + /* Int32 */ + FORMAT_TYPE_INT32, + /* Int64 */ + FORMAT_TYPE_INT64, + /* Float */ + FORMAT_TYPE_FLOAT, + /* Double */ + FORMAT_TYPE_DOUBLE, + /* String */ + FORMAT_TYPE_STRING, + /* Addr */ + FORMAT_TYPE_ADDR, +}; + +struct FormatData { + FormatDataType type = FORMAT_TYPE_NONE; + union Val { + int32_t int32Val; + int64_t int64Val; + float floatVal; + double doubleVal; + } val = {0}; + std::string stringVal = ""; + uint8_t *addr = nullptr; + size_t size = 0; +}; + +class __attribute__((visibility("default"))) Format { +public: + Format() = default; + ~Format(); + + Format(const Format &rhs); + Format(Format &&rhs) noexcept; + Format &operator=(const Format &rhs); + Format &operator=(Format &&rhs) noexcept; + + /** + * @brief Sets metadata of the integer type. + * + * @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 10 + * @version 1.0 + */ + bool PutIntValue(const std::string_view &key, int32_t value); + + /** + * @brief Sets metadata of the long integer type. + * + * @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 10 + * @version 1.0 + */ + bool PutLongValue(const std::string_view &key, int64_t value); + + /** + * @brief Sets metadata of the single-precision floating-point type. + * + * @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 10 + * @version 1.0 + */ + bool PutFloatValue(const std::string_view &key, float value); + + /** + * @brief Sets metadata of the double-precision floating-point type. + * + * @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 10 + * @version 1.0 + */ + bool PutDoubleValue(const std::string_view &key, double value); + + /** + * @brief Sets metadata of the string type. + * + * @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 10 + * @version 1.0 + */ + bool PutStringValue(const std::string_view &key, const std::string_view &value); + + /** + * @brief Sets metadata of the string type. + * + * @param key Indicates the metadata key. + * @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 10 + * @version 1.0 + */ + bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size); + + /** + * @brief Obtains the metadata value of the integer type. + * + * @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 10 + * @version 1.0 + */ + bool GetIntValue(const std::string_view &key, int32_t &value) const; + + /** + * @brief Obtains the metadata value of the long integer type. + * + * @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 10 + * @version 1.0 + */ + bool GetLongValue(const std::string_view &key, int64_t &value) const; + + /** + * @brief Obtains the metadata value of the single-precision floating-point type. + * + * @param key Indicates the metadata key. + * @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 10 + * @version 1.0 + */ + bool GetFloatValue(const std::string_view &key, float &value) const; + + /** + * @brief Obtains the metadata value of the double-precision floating-point type. + * + * @param key Indicates the metadata key. + * @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 10 + * @version 1.0 + */ + bool GetDoubleValue(const std::string_view &key, double &value) const; + + /** + * @brief Obtains the metadata value of the string type. + * + * @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 10 + * @version 1.0 + */ + bool GetStringValue(const std::string_view &key, std::string &value) const; + + /** + * @brief Obtains the metadata value of the string type. + * + * @param key Indicates the metadata key. + * @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 10 + * @version 1.0 + */ + bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) const; + + /** + * @brief Query whether the key exists in this Format. + * + * @param key Indicates the metadata key. + * @return true + * @return false + */ + bool ContainKey(const std::string_view &key) const; + + /** + * @brief Get the value type for the key if the key exists in this Format. + * + * @param key Indicates the metadata key. + * @return FormatDataType. If the key does not exists, return FORMAT_TYPE_NONE. + */ + FormatDataType GetValueType(const std::string_view &key) const; + + /** + * @brief Remove the key from the Format + * + * @param keys the key will be removed. + */ + void RemoveKey(const std::string_view &key); + + /** + * @brief A trick to enable the comparision between the std::string and std::string_view for + * std::map, the trick called Transparent Comparator. + * + */ + using FormatDataMap = std::map>; + + /** + * @brief Obtains the metadata map. + * + * @return Returns the map object. + * @since 10 + * @version 1.0 + */ + const FormatDataMap &GetFormatMap() const; + + /** + * @brief Convert the metadata map to string. + * + * @return Returns a converted string. + * @since 10 + * @version 1.0 + */ + std::string Stringify() const; + +private: + FormatDataMap formatMap_; +}; +} // namespace Media +} // namespace OHOS +#endif // FORMAT_H diff --git a/interfaces/inner_api/native/media_description.h b/interfaces/inner_api/native/media_description.h new file mode 100644 index 0000000000000000000000000000000000000000..356c73b321a9b7a9ea9f3038c5c5e6df5c6783fb --- /dev/null +++ b/interfaces/inner_api/native/media_description.h @@ -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. + */ + +#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 codec name, value type is string + */ + static constexpr std::string_view MD_KEY_CODEC_NAME = "codec_name"; + + /** + * Key for duration, value type is int64_t + */ + static constexpr std::string_view MD_KEY_DURATION = "duration"; + + /** + * Key for bitrate, value type is int64_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 max input buffer count, value type is int32_t + */ + static constexpr std::string_view MD_KEY_MAX_INPUT_BUFFER_COUNT = "max_input_buffer_count"; + + /** + * Key for max output buffer count, value type is int32_t + */ + static constexpr std::string_view MD_KEY_MAX_OUTPUT_BUFFER_COUNT = "max_output_buffer_count"; + + /** + * Key for video width, value type is int32_t + */ + static constexpr std::string_view MD_KEY_WIDTH = "width"; + + /** + * Key for video height, value type is int32_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 scale type, value type is int32_t + */ + static constexpr std::string_view MD_KEY_SCALE_TYPE = "scale_type"; + + /** + * Key for video rotation angle, value type is int32_t + */ + static constexpr std::string_view MD_KEY_ROTATION_ANGLE = "rotation_angle"; + + /** + * 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"; + + /** + * Key for audio channel layout, value type is int64_t + */ + static constexpr std::string_view MD_KEY_CHANNEL_LAYOUT = "channel_layout"; + + /** + * Key for audio sample format, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_SAMPLE_FORMAT = "sample_format"; + + /** + * Key for the number of bits used to encode each sample, value type is uint32_t + */ + static constexpr std::string_view MD_BITS_PER_CODED_SAMPLE_KEY = "bits_per_coded_sample"; + + /** + * Key for aac type, value type is uint32_t + */ + static constexpr std::string_view MD_KEY_AAC_IS_ADTS = "aac_is_adts"; + +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 new file mode 100644 index 0000000000000000000000000000000000000000..19da919ec5f626b33b2cd803872724565777c5f1 --- /dev/null +++ b/interfaces/kits/c/BUILD.gn @@ -0,0 +1,208 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +group("capi_packages") { + deps = [] + if (multimedia_av_codec_support_capi) { + deps += [ + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_avdemuxer", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_avmuxer", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_avsource", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_codec", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_core", + ] + } +} + +config("av_codec_capi_config") { + include_dirs = [ + "$av_codec_root_dir/frameworks/native/capi/common", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/utils/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + ] + + cflags = [ + "-fno-exceptions", + "-Wall", + "-fno-common", + "-fstack-protector-all", + "-Wshadow", + "-FPIC", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-Wformat=2", + "-Wdate-time", + ] + + cflags_cc = [ + "-std=c++17", + "-fno-rtti", + ] +} + +ohos_shared_library("native_av_codec_core") { + install_enable = true + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../../cfi_blocklist.txt" + } + + configs = [ ":av_codec_capi_config" ] + + sources = [ + "$av_codec_root_dir/frameworks/native/capi/common/native_avformat.cpp", + "$av_codec_root_dir/frameworks/native/capi/common/native_avmemory.cpp", + ] + + if (multimedia_av_codec_support_codeclist) { + sources += [ + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_codeclist.cpp", + "$av_codec_root_dir/frameworks/native/capi/common/native_avcapability.cpp", + ] + } + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + ] + output_extension = "so" + subsystem_name = "multimedia" + part_name = "av_codec" +} + +ohos_shared_library("native_av_codec_codec") { + install_enable = true + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + blocklist = "../../../cfi_blocklist.txt" + } + + sources = [ + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_audio_decoder.cpp", + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_audio_encoder.cpp", + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_avcodec_base.cpp", + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_video_decoder.cpp", + "$av_codec_root_dir/frameworks/native/capi/avcodec/native_video_encoder.cpp", + ] + + configs = [ ":av_codec_capi_config" ] + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_core", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + ] + output_extension = "so" + subsystem_name = "multimedia" + part_name = "av_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/avmuxer/native_avmuxer.cpp", + "$av_codec_root_dir/frameworks/native/capi/common/native_avformat.cpp", + "$av_codec_root_dir/frameworks/native/capi/common/native_avmemory.cpp", + ] + + public_configs = [ ":av_codec_capi_config" ] + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + ] + output_extension = "so" + subsystem_name = "multimedia" + part_name = "av_codec" +} + +ohos_shared_library("native_av_codec_avdemuxer") { + install_enable = true + sources = [ + "$av_codec_root_dir/frameworks/native/capi/avdemuxer/native_avdemuxer.cpp", + ] + + public_configs = [ ":av_codec_capi_config" ] + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_core", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + ] + output_extension = "so" + subsystem_name = "multimedia" + part_name = "av_codec" +} + +ohos_shared_library("native_av_codec_avsource") { + install_enable = true + sources = [ + "$av_codec_root_dir/frameworks/native/capi/avsource/native_avsource.cpp", + ] + + public_configs = [ ":av_codec_capi_config" ] + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_core", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + ] + output_extension = "so" + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/interfaces/kits/c/native_avcapability.h b/interfaces/kits/c/native_avcapability.h new file mode 100644 index 0000000000000000000000000000000000000000..bcee6ea68bc26317a2ae36bc52ae389b1a4b3830 --- /dev/null +++ b/interfaces/kits/c/native_avcapability.h @@ -0,0 +1,344 @@ +/* + * 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 NATIVE_AVCAPABILITY_H +#define NATIVE_AVCAPABILITY_H + +#include +#include "native_averrors.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AVCapability OH_AVCapability; +/** + * @brief The bitrate mode of video encoder. + * @since 10 + * @version 1.0 + */ +typedef enum OH_BitrateMode { + /* constant bit rate mode. */ + CBR = 0, + /* variable bit rate mode. */ + VBR = 1, + /* constant quality mode. */ + CQ = 2, + /* Constrained VariableBit Rate. */ + VCBR = 3, + /* Average Bit Rate. */ + ABR = 4 +} OH_BitrateMode; + +/** + * @brief Range contain min and max value + * @since 10 + * @version 1.0 + */ +typedef struct OH_AVRange { + int32_t minVal; + int32_t maxVal; +} OH_AVRange; + +/** + * @brief Check whether the codec is accelerated by hardware. + * @param capability codec capability get from OH_AVCodec_GetCapability + * @return true indicate vendor codec, false indicate software codec + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_IsHardwareAccelerated(OH_AVCapability *capability); + +/** + * @brief Get mime type + * @param capability codec capability get from OH_AVCodec_GetCapability + * @return mime type string + * @since 10 + * @version 1.0 + */ +const char *OH_AVCapability_GetMimeType(OH_AVCapability *capability); + +/** + * @brief Get Supported max instance + * @param capability codec capability get from OH_AVCodec_GetCapability + * @return instance count + * @since 10 + * @version 1.0 + */ +int32_t OH_AVCapability_GetMaxSupportedInstances(OH_AVCapability *capability); + +/** + * @brief Get Supported profiles of this codec + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param profiles profiles array pointer + * @param profileNum profiles num + * @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_AVCapability_GetSupportedProfiles(OH_AVCapability *capability, const int32_t **profiles, + uint32_t *profileNum); + +/** + * @brief Get levels array for a specified profile. + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param profile codec profiles + * @param levels levels array pointer + * @param levelNum levels num + * @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_AVCapability_GetSupportedLevelsForProfile(OH_AVCapability *capability, int32_t profile, + const int32_t **levels, uint32_t *levelNum); + +/** + * @brief Check whether the profile and level is supported. + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param profile AVCProfile if codec is h264, HEVCProfile array if codec is h265 + * @param level level id + * @return true indicate supported, false indicate not supported + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_ValidateProfileAndLevel(OH_AVCapability *capability, int32_t profile, int32_t level); + +/** + * @brief Get encoder bitrate range + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param bitrateRange encoder bitrate range + * @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_AVCapability_GetEncoderBitrateRange(OH_AVCapability *capability, OH_AVRange *bitrateRange); + +/** + * @brief Get encoder quality range + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param bitrateRange encoder quality range + * @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_AVCapability_GetEncoderQualityRange(OH_AVCapability *capability, OH_AVRange *qualityRange); + +/** + * @brief Get encoder complexity range + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param complexityRange encoder complexity range + * @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_AVCapability_GetEncoderComplexityRange(OH_AVCapability *capability, OH_AVRange *complexityRange); + +/** + * @brief Check whether is this bitrate mode supported, only used for video encoder codecs. + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param mode bitrateMode + * @return true indicate supported, false indicate not supported + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_ValidateVideoEncoderBitrateMode(OH_AVCapability *capability, OH_BitrateMode bitrateMode); + +/** + * @brief Get sampleRate array, only used for audio codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param sampleRates sampleRates array pointer + * @param sampleRateNum sampleRate num + * @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_AVCapability_GetAudioSupportedSampleRates(OH_AVCapability *capability, const int32_t **sampleRates, + uint32_t *sampleRateNum); + +/** + * @brief Check whether is this sampleRate supported, only used for audio codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param sampleRate sample rate + * @return true indicate supported, false indicate not supported + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_ValidateAudioSampleRate(OH_AVCapability *capability, int32_t sampleRate); + +/** + * @brief Get channels range, only used for audio codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param channelsRange channels range + * @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_AVCapability_GetAudioChannelsRange(OH_AVCapability *capability, OH_AVRange *channelsRange); + +/** + * @brief Get supported pixFormat array, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param pixFormats pixFormats array pointer + * @param pixFormatNum pixFormat num + * @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_AVCapability_GetVideoSupportedPixFormats(OH_AVCapability *capability, const int32_t **pixFormats, + uint32_t *pixFormatNum); + +/** + * @brief Get width alignment, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param widthAlignment width alignment + * @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_AVCapability_GetVideoWidthAlignment(OH_AVCapability *capability, int32_t *widthAlignment); + +/** + * @brief Get height alignment, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param heightAlignment height alignment + * @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_AVCapability_GetVideoHeightAlignment(OH_AVCapability *capability, int32_t *heightAlignment); + +/** + * @brief Get width range for a specified height, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param widthRange width range + * @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_AVCapability_GetVideoWidthRangeForHeight(OH_AVCapability *capability, int32_t height, + OH_AVRange *widthRange); + +/** + * @brief Get height range for a specified width, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param widthRange height range + * @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_AVCapability_GetVideoHeightRangeForWidth(OH_AVCapability *capability, int32_t width, + OH_AVRange *heightRange); + +/** + * @brief Get width range, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param widthRange width range + * @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_AVCapability_GetVideoWidthRange(OH_AVCapability *capability, OH_AVRange *widthRange); + +/** + * @brief Get height range, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param heightRange height range + * @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_AVCapability_GetVideoHeightRange(OH_AVCapability *capability, OH_AVRange *heightRange); + +/** + * @brief Check whether is this video size supported, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param width video width + * @param height video height + * @return true indicate supported, false indicate not supported + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_ValidateVideoSize(OH_AVCapability *capability, int32_t width, int32_t height); + +/** + * @brief Get frame rate range, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param frameRateRange frame rate range + * @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_AVCapability_GetVideoFrameRateRange(OH_AVCapability *capability, OH_AVRange *frameRateRange); + +/** + * @brief Get frame rate range for a specified video size, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param width video width + * @param height video height + * @param frameRateRange frame rate range + * @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_AVCapability_GetVideoFrameRateRangeForSize(OH_AVCapability *capability, int32_t width, int32_t height, + OH_AVRange *frameRateRange); + +/** + * @brief Get measured frame rate range for a specified video size, + * these frame rates is reachable, only used for video codecs + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param width video width + * @param height video height + * @param frameRateRange frame rate range + * @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_AVCapability_GetVideoMeasuredFrameRateRangeForSize(OH_AVCapability *capability, int32_t width, + int32_t height, OH_AVRange *frameRateRange); + +/** + * @brief Check whether are this video size and fps supported. + * @param capability codec capability get from OH_AVCodec_GetCapability + * @param width video width + * @param height vidoe height + * @param frameRate frames every second + * @return true indicate supported, false indicate not supported + * @since 10 + * @version 1.0 + */ +bool OH_AVCapability_ValidateVideoSizeAndFrameRate(OH_AVCapability *capability, int32_t width, int32_t height, + int32_t frameRate); +#ifdef __cplusplus +} +#endif +#endif // NATIVE_AVCAPABILITY_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avcodec_audiodecoder.h b/interfaces/kits/c/native_avcodec_audiodecoder.h new file mode 100644 index 0000000000000000000000000000000000000000..093582f748e646982ef92d6e01cdb2ddda8bbdbf --- /dev/null +++ b/interfaces/kits/c/native_avcodec_audiodecoder.h @@ -0,0 +1,229 @@ +/* + * 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. + */ + +#ifndef NATIVE_AVCODEC_AUDIODECODER_H +#define NATIVE_AVCODEC_AUDIODECODER_H + +#include +#include +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmemory.h" +#include "native_avcodec_base.h" + +namespace OHOS { +namespace Media { +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Creates an audio decoder instance from the mime type, which is recommended in most cases. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param mime mime type description string, refer to {@link AVCODEC_MIME_TYPE} + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_AudioDecoder_CreateByMime(const char *mime); + +/** + * @brief Create an audio decoder instance through the audio decoder name. + * The premise of using this interface is to know the exact name of the decoder. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param name Audio codec name + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_AudioDecoder_CreateByName(const char *name); + +/** + * @brief Clear the internal resources of the decoder and destroy the decoder instance + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Destroy(OH_AVCodec *codec); + +/** + * @brief Set the asynchronous callback function so that your application + * can respond to the events generated by the audio decoder. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param callback A collection of all callback functions, see {@link OH_AVCodecAsyncCallback} + * @param userData User specific data + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_SetCallback(OH_AVCodec *codec, OH_AVCodecAsyncCallback callback, void *userData); + +/** + * @brief To configure the audio decoder, typically, you need to configure the description information of the decoded + * audio track, which can be extracted from the container. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param format A pointer to an OH_AVFormat giving a description of the audio track to be decoded + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Configure(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief To prepare the internal resources of the decoder, the Configure interface must be called + * before calling this interface. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Prepare(OH_AVCodec *codec); + +/** + * @brief Start the decoder, this interface must be called after the Prepare is successful. + * After being successfully started, the decoder will start reporting NeedInputData events. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Start(OH_AVCodec *codec); + +/** + * @brief Stop the decoder. After stopping, you can re-enter the Started state through Start, + * but it should be noted that need to re-enter if the decoder has been input before + * Codec-Specific-Data. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Stop(OH_AVCodec *codec); + +/** + * @brief Clear the input and output data buffered in the decoder. After this interface is called, all the Buffer + * indexes previously reported through the asynchronous callback will be invalidated, make sure not to access + * the Buffers corresponding to these indexes. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_Flush(OH_AVCodec *codec); + +/** + * @brief Reset the decoder. To continue decoding, you need to call the Configure interface again to + * configure the decoder instance. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ + +OH_AVErrCode OH_AudioDecoder_Reset(OH_AVCodec *codec); + +/** + * @brief Get the description information of the output data of the decoder, refer to {@link OH_AVFormat} for details. + * It should be noted that the life cycle of the OH_AVFormat instance pointed to by the return value * needs to + * be manually released by the caller + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns the OH_AVFormat handle pointer, the life cycle is refreshed with the next GetOutputMediaDescription, + * or destroyed with OH_AVCodec; + * @since 9 + * @version 1.0 + */ +OH_AVFormat *OH_AudioDecoder_GetOutputDescription(OH_AVCodec *codec); + +/** + * @brief Set dynamic parameters to the decoder. Note: This interface can only be called after the decoder is started. + * At the same time, incorrect parameter settings may cause decoding failure. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param format OH_AVFormat handle pointer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_SetParameter(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief Submit the input buffer filled with data to the audio decoder. The {@link OH_AVCodecOnNeedInputData} callback + * will report the available input buffer and the corresponding index value. Once the buffer with the specified index + * is submitted to the audio decoder, the buffer cannot be accessed again until the {@link OH_AVCodecOnNeedInputData} + * callback is received again reporting that the buffer with the same index is available. In addition, for some + * decoders, it is required to input Codec-Specific-Data to the decoder at the beginning to initialize the decoding + * process of the decoder. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param index Enter the index value corresponding to the Buffer + * @param attr Information describing the data contained in the Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_PushInputData(OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr); + +/** + * @brief Return the processed output Buffer to the decoder. + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param index The index value corresponding to the output Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioDecoder_FreeOutputData(OH_AVCodec *codec, uint32_t index); + +/** + * @brief Check whether the current codec instance is valid. It can be used fault recovery or app + * switchback from the background + * @syscap SystemCapability.Multimedia.Media.AudioDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param isVaild Pointer to an bool instance, true: the codec instance is vaild, false: the codec + * instance is invalid + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 + */ +OH_AVErrCode OH_AudioDecoder_IsValid(OH_AVCodec *codec, bool *isVaild); + +#ifdef __cplusplus +} +#endif +} // namespace Media +} // namespace OHOS +#endif // NATIVE_AVCODEC_AUDIODECODER_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avcodec_audioencoder.h b/interfaces/kits/c/native_avcodec_audioencoder.h new file mode 100644 index 0000000000000000000000000000000000000000..78f33facdf36dc475209231f5d51f032262c6a62 --- /dev/null +++ b/interfaces/kits/c/native_avcodec_audioencoder.h @@ -0,0 +1,223 @@ +/* + * 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. + */ + +#ifndef NATIVE_AVCODEC_AUDIOENCODER_H +#define NATIVE_AVCODEC_AUDIOENCODER_H + +#include +#include +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmemory.h" +#include "native_avcodec_base.h" +namespace OHOS { +namespace Media { +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Creates an audio encoder instance from the mime type, this interface is recommended in most cases. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param mime mime type description string, refer to {@link AVCODEC_MIME_TYPE} + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_AudioEncoder_CreateByMime(const char *mime); + +/** + * @brief Create an audio encoder instance through the audio encoder name. + * The premise of using this interface is to know the exact name of the encoder. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param name Audio encoder name + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_AudioEncoder_CreateByName(const char *name); + +/** + * @brief Clear the internal resources of the encoder and destroy the encoder instance + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Destroy(OH_AVCodec *codec); + +/** + * @brief Set the asynchronous callback function so that your application can respond to + * the events generated by the audio encoder. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param callback A collection of all callback functions, see {@link OH_AVCodecAsyncCallback} + * @param userData User specific data + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_SetCallback(OH_AVCodec *codec, OH_AVCodecAsyncCallback callback, void *userData); + +/** + * @brief To configure the audio encoder, typically, you need to configure the description information of + * the encoded audio track. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param format OH_AVFormat handle pointer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Configure(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief To prepare the internal resources of the encoder, + * the Configure interface must be called before calling this interface. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Prepare(OH_AVCodec *codec); + +/** + * @brief Start the encoder, this interface must be called after the Prepare is successful. + * After being successfully started, the encoder will start reporting NeedInputData events. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Start(OH_AVCodec *codec); + +/** + * @brief Stop the encoder. After stopping, you can re-enter the Started state through Start. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Stop(OH_AVCodec *codec); + +/** + * @brief Clear the input and output data buffered in the encoder. After this interface is called, + * all the Buffer indexes previously reported through the asynchronous callback will be invalidated, + * make sure not to access the Buffers corresponding to these indexes. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Flush(OH_AVCodec *codec); + +/** + * @brief Reset the encoder. To continue coding, you need to call the Configure interface + * again to configure the encoder instance. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_Reset(OH_AVCodec *codec); + +/** + * @brief Get the description information of the output data of the encoder, refer to {@link OH_AVFormat} for details. + * It should be noted that the life cycle of the OH_AVFormat instance pointed to by the return value * needs to + * be manually released by the caller. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns the OH_AVFormat handle pointer, the life cycle is refreshed with the next GetOutputMediaDescription, + * or destroyed with OH_AVCodec; + * @since 9 + * @version 1.0 + */ +OH_AVFormat *OH_AudioEncoder_GetOutputDescription(OH_AVCodec *codec); + +/** + * @brief Set dynamic parameters to the encoder. Note: This interface can only be called after the encoder is started. + * At the same time, incorrect parameter settings may cause the encoding to fail. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param format OH_AVFormat handle pointer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_SetParameter(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief Submit the input buffer filled with data to the audio encoder. The {@link OH_AVCodecOnNeedInputData} + * callback will report the available input buffer and the corresponding index value. Once the buffer with the + * specified index is submitted to the audio encoder, the buffer cannot be accessed again until the + * callback is received again reporting that the buffer with the same index is available + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param index Enter the index value corresponding to the Buffer + * @param attr Information describing the data contained in the Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_PushInputData(OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr); + +/** + * @brief Return the processed output Buffer to the encoder. + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param index The index value corresponding to the output Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_AudioEncoder_FreeOutputData(OH_AVCodec *codec, uint32_t index); + +/** + * @brief Check whether the current codec instance is valid. It can be used fault recovery or app + * switchback from the background + * @syscap SystemCapability.Multimedia.Media.AudioEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param isVaild Pointer to an bool instance, true: the codec instance is vaild, false: the codec + * instance is invalid + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 + */ +OH_AVErrCode OH_AudioEncoder_IsValid(OH_AVCodec *codec, bool *isVaild); + +#ifdef __cplusplus +} +#endif +} // namespace Media +} // namespace OHOS +#endif // NATIVE_AVCODEC_AUDIOENCODER_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avcodec_base.h b/interfaces/kits/c/native_avcodec_base.h new file mode 100644 index 0000000000000000000000000000000000000000..29c625d95434a1332cb29d085c5883bcdaeed8fe --- /dev/null +++ b/interfaces/kits/c/native_avcodec_base.h @@ -0,0 +1,322 @@ +/* + * 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. + */ + +#ifndef NATIVE_AVCODEC_BASE_H +#define NATIVE_AVCODEC_BASE_H + +#include +#include +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmemory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NativeWindow OHNativeWindow; +typedef struct OH_AVCodec OH_AVCodec; + +/** + * @brief Enumerate the categories of OH_AVCodec's Buffer tags + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +typedef enum OH_AVCodecBufferFlags { + AVCODEC_BUFFER_FLAGS_NONE = 0, + /* Indicates that the Buffer is an End-of-Stream frame */ + AVCODEC_BUFFER_FLAGS_EOS = 1 << 0, + /* Indicates that the Buffer contains keyframes */ + AVCODEC_BUFFER_FLAGS_SYNC_FRAME = 1 << 1, + /* Indicates that the data contained in the Buffer is only part of a frame */ + AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME = 1 << 2, + /* Indicates that the Buffer contains Codec-Specific-Data */ + 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_DEFAULT = 0, + AV_OUTPUT_FORMAT_MPEG_4 = 2, + AV_OUTPUT_FORMAT_M4A = 6, +} OH_AVOutputFormat; + +/** + * @brief Define the Buffer description information of OH_AVCodec + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +typedef struct OH_AVCodecBufferAttr { + /* Presentation timestamp of this Buffer in microseconds */ + int64_t pts; + /* The size of the data contained in the Buffer in bytes */ + int32_t size; + /* The starting offset of valid data in this Buffer */ + int32_t offset; + /* The flags this Buffer has, which is also a combination of multiple {@link OH_AVCodecBufferFlags}. */ + uint32_t flags; +} OH_AVCodecBufferAttr; + +/** + * @brief When an error occurs in the running of the OH_AVCodec instance, the function pointer will be called + * to report specific error information. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @param codec OH_AVCodec instance + * @param errorCode specific error code + * @param userData User specific data + * @since 9 + * @version 1.0 + */ +typedef void (*OH_AVCodecOnError)(OH_AVCodec *codec, int32_t errorCode, void *userData); + +/** + * @brief When the output stream changes, the function pointer will be called to report the new stream description + * information. It should be noted that the life cycle of the OH_AVFormat pointer + * is only valid when the function pointer is called, and it is forbidden to continue to access after the call ends. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @param codec OH_AVCodec instance + * @param format New output stream description information + * @param userData User specific data + * @since 9 + * @version 1.0 + */ +typedef void (*OH_AVCodecOnStreamChanged)(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + +/** + * @brief When OH_AVCodec needs new input data during the running process, + * the function pointer will be called and carry an available Buffer to fill in the new input data. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @param codec OH_AVCodec instance + * @param index The index corresponding to the newly available input buffer. + * @param data New available input buffer. + * @param userData User specific data + * @since 9 + * @version 1.0 + */ +typedef void (*OH_AVCodecOnNeedInputData)(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData); + +/** + * @brief When new output data is generated during the operation of OH_AVCodec, the function pointer will be + * called and carry a Buffer containing the new output data. It should be noted that the life cycle of the + * OH_AVCodecBufferAttr pointer is only valid when the function pointer is called. , which prohibits continued + * access after the call ends. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @param codec OH_AVCodec instance + * @param index The index corresponding to the new output Buffer. + * @param data Buffer containing the new output data + * @param attr The description of the new output Buffer, please refer to {@link OH_AVCodecBufferAttr} + * @param userData specified data + * @since 9 + * @version 1.0 + */ +typedef void (*OH_AVCodecOnNewOutputData)(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, + OH_AVCodecBufferAttr *attr, void *userData); + +/** + * @brief A collection of all asynchronous callback function pointers in OH_AVCodec. Register an instance of this + * structure to the OH_AVCodec instance, and process the information reported through the callback to ensure the + * normal operation of OH_AVCodec. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @param onError Monitor OH_AVCodec operation errors, refer to {@link OH_AVCodecOnError} + * @param onStreamChanged Monitor codec stream information, refer to {@link OH_AVCodecOnStreamChanged} + * @param onNeedInputData Monitoring codec requires input data, refer to {@link OH_AVCodecOnNeedInputData} + * @param onNeedInputData Monitor codec to generate output data, refer to {@link onNeedInputData} + * @since 9 + * @version 1.0 + */ +typedef struct OH_AVCodecAsyncCallback { + OH_AVCodecOnError onError; + OH_AVCodecOnStreamChanged onStreamChanged; + OH_AVCodecOnNeedInputData onNeedInputData; + OH_AVCodecOnNewOutputData onNeedOutputData; +} OH_AVCodecAsyncCallback; + +/** + * @brief Enumerates the MIME types of audio and video codecs + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @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 + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +/* Key for timeStamp in surface's extraData, value type is int64 */ +extern const char *OH_ED_KEY_TIME_STAMP; +/* Key for endOfStream in surface's extraData, value type is bool */ +extern const char *OH_ED_KEY_EOS; + +/** + * @brief Provides the uniform container for storing the media description. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +/* Key for track type, value type is uint8_t, see @OH_MediaType. */ +extern const char *OH_MD_KEY_TRACK_TYPE; +/* Key for codec mime type, value type is string. */ +extern const char *OH_MD_KEY_CODEC_MIME; +/* Key for duration, value type is int64_t. */ +extern const char *OH_MD_KEY_DURATION; +/* Key for bitrate, value type is uint32_t. */ +extern const char *OH_MD_KEY_BITRATE; +/* Key for max input size, value type is uint32_t */ +extern const char *OH_MD_KEY_MAX_INPUT_SIZE; +/* Key for video width, value type is uint32_t */ +extern const char *OH_MD_KEY_WIDTH; +/* Key for video height, value type is uint32_t */ +extern const char *OH_MD_KEY_HEIGHT; +/* Key for video pixel format, value type is int32_t, see @OH_AVPixelFormat */ +extern const char *OH_MD_KEY_PIXEL_FORMAT; +/* key for audio raw format, value type is uint32_t , see @AudioSampleFormat */ +extern const char *OH_MD_KEY_AUDIO_SAMPLE_FORMAT; +/* Key for video frame rate, value type is double. */ +extern const char *OH_MD_KEY_FRAME_RATE; +/* video encode bitrate mode, the value type is int32_t, see @OH_VideoEncodeBitrateMode */ +extern const char *OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE; +/* encode profile, the value type is number. see @OH_AVCProfile, OH_AACProfile. */ +extern const char *OH_MD_KEY_PROFILE; +/* Key for audio channel count, value type is uint32_t */ +extern const char *OH_MD_KEY_AUD_CHANNEL_COUNT; +/* Key for audio sample rate, value type is uint32_t */ +extern const char *OH_MD_KEY_AUD_SAMPLE_RATE; +/* Key for the interval of key frame. value type is int32_t, the unit is milliseconds. */ +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; + +/* Key for track index, value type is uint32_t */ +extern const char *OH_MD_KEY_TRACK_INDEX; +/* Key for track sample count, value type is uint64_t */ +extern const char *OH_MD_KEY_TRACK_SAMPLE_COUNT; +/* Key for bit stream format, see @OH_VideoBitStreamFormat, OH_VideoBitStreamFormat */ +extern const char *OH_MD_KEY_BIT_STREAM_FORMAT; + +/* source format Key for title, value type is string */ +extern const char *OH_MD_KEY_TITLE; +/* source format Key for artist, value type is string */ +extern const char *OH_MD_KEY_ARTIST; +/* source format Key for album, value type is string */ +extern const char *OH_MD_KEY_ALBUM; +/* source format Key for album_artist, value type is string */ +extern const char *OH_MD_KEY_ALBUM_ARTIST; +/* source format Key for date, value type is string */ +extern const char *OH_MD_KEY_DATE; +/* source format Key for comment, value type is string */ +extern const char *OH_MD_KEY_COMMENT; +/* source format Key for genre, value type is string */ +extern const char *OH_MD_KEY_GENRE; +/* source format Key for copyright, value type is string */ +extern const char *OH_MD_KEY_COPYRIGHT; +/* source format Key for language, value type is string */ +extern const char *OH_MD_KEY_LANGUAGE; +/* source format Key for description, value type is string */ +extern const char *OH_MD_KEY_DESCRIPTION; +/* source format Key for lyrics, value type is string */ +extern const char *OH_MD_KEY_LYRICS; +/* source format Key for duration, value type is int64_t */ +extern const char *OH_MD_KEY_DURATION; +/* source format Key for start_time, value type is string */ +extern const char *OH_MD_KEY_START_TIME; +/* source format Key for type, value type is string */ +extern const char *OH_MD_KEY_TYPE; + +/** + * @brief Format of video bitStream + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 10 + * @version 4.0 + */ +typedef enum OH_VideoBitStreamFormat { + UNKNOWN = 0, + AVCC, + HVCC, + ANNEXB +} OH_VideoBitStreamFormat; + +/** + * @brief Media type. + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +typedef enum OH_MediaType { + /* track is audio. */ + MEDIA_TYPE_AUD = 0, + /* track is video. */ + MEDIA_TYPE_VID = 1, +} OH_MediaType; + +/** + * @brief AVC Profile + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +typedef enum OH_AVCProfile { + AVC_PROFILE_BASELINE = 0, + AVC_PROFILE_HIGH = 4, + AVC_PROFILE_MAIN = 8, +} OH_AVCProfile; + +/** + * @brief AAC Profile + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 9 + * @version 1.0 + */ +typedef enum OH_AACProfile { + AAC_PROFILE_LC = 0, +} OH_AACProfile; + +/** + * @brief Seek Mode + * @syscap SystemCapability.Multimedia.Media.CodecBase + * @since 10 + * @version 4.0 + */ +typedef enum OH_AVSeekMode { + /* seek to sync sample after the time */ + SEEK_MODE_NEXT_SYNC = 0, + /* seek to sync sample before the time */ + SEEK_MODE_PREVIOUS_SYNC, + /* seek to sync sample closest to time */ + SEEK_MODE_CLOSEST_SYNC, +} OH_AVSeekMode; + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVCODEC_BASE_H diff --git a/interfaces/kits/c/native_avcodec_list.h b/interfaces/kits/c/native_avcodec_list.h new file mode 100644 index 0000000000000000000000000000000000000000..cb6b62ca78bfa0cf98b9450045222ed8ec106860 --- /dev/null +++ b/interfaces/kits/c/native_avcodec_list.h @@ -0,0 +1,70 @@ +/* + * 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 NATIVE_AVCODEC_LIST_H +#define NATIVE_AVCODEC_LIST_H + +#include +#include +#include "native_avformat.h" +#include "native_avcodec_base.h" +#include "native_avcapability.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Find the supported encoder name by format(must contains video or audio MIME). + * @param format Indicates a media description which contains required encoder capability. + * @return Returns encoder name, if not find, return null. + * @since 10 + * @version 1.0 + */ +const char *OH_AVCodec_FindEncoder(const OH_AVFormat *format); + +/** + * @brief Find the supported decoder name by format(must contains video or audio MIME). + * @param format Indicates a media description which contains required decoder capability. + * @return Returns decoder name, if not find, return null. + * @since 10 + * @version 1.0 + */ +const char *OH_AVCodec_FindDecoder(const OH_AVFormat *format); + +/** + * @brief Create a capability by codec name + * @param codeName Codec name + * @return A OH_AVCapability instance + * @since 10 + * @version 1.0 + */ +OH_AVCapability *OH_AVCodec_CreateCapability(const char *name); + +/** + * @brief Destroy the capability + * @param capability codec capability get from OH_AVCodec_GetCapability + * @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_AVCodec_DestroyCapability(OH_AVCapability *capability); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVCODEC_LIST_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avcodec_videodecoder.h b/interfaces/kits/c/native_avcodec_videodecoder.h new file mode 100644 index 0000000000000000000000000000000000000000..0c3c3555308129062004055e52fd22994a96798e --- /dev/null +++ b/interfaces/kits/c/native_avcodec_videodecoder.h @@ -0,0 +1,250 @@ +/* + * 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. + */ + +#ifndef NATIVE_AVCODEC_VIDEODECODER_H +#define NATIVE_AVCODEC_VIDEODECODER_H + +#include +#include +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmemory.h" +#include "native_avcodec_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Creates a video decoder instance from the mime type, which is recommended in most cases. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param mime mime type description string, refer to {@link AVCODEC_MIME_TYPE} + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_VideoDecoder_CreateByMime(const char *mime); + +/** + * @brief Create a video decoder instance through the video decoder name. + * The premise of using this interface is to know the exact name of the decoder. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param name video codec name + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_VideoDecoder_CreateByName(const char *name); + +/** + * @brief Clear the internal resources of the decoder and destroy the decoder instance + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Destroy(OH_AVCodec *codec); + +/** + * @brief Set the asynchronous callback function so that your application can respond to the events + * generated by the video decoder. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param callback A collection of all callback functions, see {@link OH_AVCodecAsyncCallback} + * @param userData User specific data + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_SetCallback(OH_AVCodec *codec, OH_AVCodecAsyncCallback callback, void *userData); + +/** + * @brief Specify the output Surface to provide video decoding output, + * this interface must be called before Prepare is called + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param window A pointer to a OHNativeWindow instance, see {@link OHNativeWindow} + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_SetSurface(OH_AVCodec *codec, OHNativeWindow *window); + +/** + * @brief To configure the video decoder, typically, you need to configure the description information of the decoded + * video track, which can be extracted from the container. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param format A pointer to an OH_AVFormat to give the description of the video track to be decoded + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Configure(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief To prepare the internal resources of the decoder, the Configure interface must be called before + * calling this interface. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Prepare(OH_AVCodec *codec); + +/** + * @brief Start the decoder, this interface must be called after the Prepare is successful. + * After being successfully started, the decoder will start reporting NeedInputData events. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Start(OH_AVCodec *codec); + +/** + * @brief Stop the decoder. After stopping, you can re-enter the Started state through Start, + * but it should be noted that if Codec-Specific-Data has been input to the decoder before, it needs to be input again. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Stop(OH_AVCodec *codec); + +/** + * @brief Clear the input and output data buffered in the decoder. After this interface is called, all the Buffer + * indexes previously reported through the asynchronous callback will be invalidated, make sure not to access + * the Buffers corresponding to these indexes. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Flush(OH_AVCodec *codec); + +/** + * @brief Reset the decoder. To continue decoding, you need to call the Configure interface again + * to configure the decoder instance. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_Reset(OH_AVCodec *codec); + +/** + * @brief Get the description information of the output data of the decoder, refer to {@link OH_AVFormat} + * It should be noted that the life cycle of the OH_AVFormat instance pointed to by the return value * needs + * to be manually released by the caller. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns a pointer to an OH_AVFormat instance + * @since 9 + * @version 1.0 + */ +OH_AVFormat *OH_VideoDecoder_GetOutputDescription(OH_AVCodec *codec); + +/** + * @brief Set dynamic parameters to the decoder. Note: This interface can only be called after the decoder is started. + * At the same time, incorrect parameter settings may cause decoding failure. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param format pointer to an OH_AVFormat instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_SetParameter(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief Submit the input buffer filled with data to the video decoder. The {@link OH_AVCodecOnNeedInputData} callback + * will report the available input buffer and the corresponding index value. Once the buffer with the specified index + * is submitted to the video decoder, the buffer cannot be accessed again until the {@link OH_AVCodecOnNeedInputData} + * callback is received again reporting that the buffer with the same index is available. In addition, for some + * decoders, it is required to input Codec-Specific-Data to the decoder at the beginning to initialize the decoding + * process of the decoder, such as PPS/SPS data in H264 format. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param index Enter the index value corresponding to the Buffer + * @param attr Information describing the data contained in the Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_PushInputData(OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr); + +/** + * @brief Return the processed output Buffer to the decoder, and notify the decoder to finish rendering the + * decoded data contained in the Buffer on the output Surface. If the output surface is not configured before, + * calling this interface only returns the output buffer corresponding to the specified index to the decoder. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param index The index value corresponding to the output Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_RenderOutputData(OH_AVCodec *codec, uint32_t index); + +/** + * @brief Return the processed output Buffer to the decoder. + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param index The index value corresponding to the output Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoDecoder_FreeOutputData(OH_AVCodec *codec, uint32_t index); + +/** + * @brief Check whether the current codec instance is valid. It can be used fault recovery or app + * switchback from the background + * @syscap SystemCapability.Multimedia.Media.VideoDecoder + * @param codec Pointer to an OH_AVCodec instance + * @param isVaild Pointer to an bool instance, true: the codec instance is vaild, false: the codec + * instance is invalid + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 + */ +OH_AVErrCode OH_VideoDecoder_IsValid(OH_AVCodec *codec, bool *isValid); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVCODEC_VIDEODECODER_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avcodec_videoencoder.h b/interfaces/kits/c/native_avcodec_videoencoder.h new file mode 100644 index 0000000000000000000000000000000000000000..8afe627441a826cfe944261c1915867bbf72c2bd --- /dev/null +++ b/interfaces/kits/c/native_avcodec_videoencoder.h @@ -0,0 +1,256 @@ +/* + * 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. + */ + +#ifndef NATIVE_AVCODEC_VIDEOENCODER_H +#define NATIVE_AVCODEC_VIDEOENCODER_H + +#include +#include +#include "native_averrors.h" +#include "native_avformat.h" +#include "native_avmemory.h" +#include "native_avcodec_base.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Creates a video encoder instance from the mime type, which is recommended in most cases. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param mime mime type description string, refer to {@link AVCODEC_MIME_TYPE} + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_VideoEncoder_CreateByMime(const char *mime); + +/** + * @brief Create a video encoder instance through the video encoder name. The premise of using this interface is to + * know the exact name of the encoder. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param name Video encoder name + * @return Returns a Pointer to an OH_AVCodec instance + * @since 9 + * @version 1.0 + */ +OH_AVCodec *OH_VideoEncoder_CreateByName(const char *name); + +/** + * @brief Clear the internal resources of the encoder and destroy the encoder instance + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Destroy(OH_AVCodec *codec); + +/** + * @brief Set the asynchronous callback function so that your application can respond to the events generated by the + * video encoder. This interface must be called before Prepare is called + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param callback A collection of all callback functions, see {@link OH_AVCodecAsyncCallback} + * @param userData User specific data + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_SetCallback(OH_AVCodec *codec, OH_AVCodecAsyncCallback callback, void *userData); + +/** + * @brief To configure the video encoder, typically, you need to configure the description information of the + * encoded video track. This interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param format A pointer to an OH_AVFormat that gives the description of the video track to be encoded + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Configure(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief To prepare the internal resources of the encoder, the Configure interface must be called before + * calling this interface. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Prepare(OH_AVCodec *codec); + +/** + * @brief Start the encoder, this interface must be called after the Prepare is successful. After being + * successfully started, the encoder will start reporting NeedInputData events. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Start(OH_AVCodec *codec); + +/** + * @brief Stop the encoder. After stopping, you can re-enter the Started state through Start. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Stop(OH_AVCodec *codec); + +/** + * @brief Clear the input and output data buffered in the encoder. After this interface is called, all the Buffer + * indexes previously reported through the asynchronous callback will be invalidated, make sure not to access the + * Buffers corresponding to these indexes. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Flush(OH_AVCodec *codec); + +/** + * @brief Reset the encoder. To continue coding, you need to call the Configure interface again to + * configure the encoder instance. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_Reset(OH_AVCodec *codec); + +/** + * @brief Get the description information of the output data of the encoder, refer to {@link OH_AVFormat} for details. + * It should be noted that the life cycle of the OH_AVFormat instance pointed to by the return value * needs to + * be manually released by the caller. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns a pointer to an OH_AVFormat instance + * @since 9 + * @version 1.0 + */ +OH_AVFormat *OH_VideoEncoder_GetOutputDescription(OH_AVCodec *codec); + +/** + * @brief Set dynamic parameters to the encoder. Note: This interface can only be called after the encoder is started. + * At the same time, incorrect parameter settings may cause the encoding to fail. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param format OH_AVFormat handle pointer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_SetParameter(OH_AVCodec *codec, OH_AVFormat *format); + +/** + * @brief Get the input Surface from the video encoder, this interface must be called before Prepare is called. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param window A pointer to a OHNativeWindow instance, see {@link OHNativeWindow} + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_GetSurface(OH_AVCodec *codec, OHNativeWindow **window); + +/** + * @brief Return the processed output Buffer to the encoder. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param index The index value corresponding to the output Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_FreeOutputData(OH_AVCodec *codec, uint32_t index); + +/** + * @brief Notifies the video encoder that the input stream has ended. It is recommended to use this interface to notify + * the encoder of the end of the stream in surface mode + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 9 + * @version 1.0 + */ +OH_AVErrCode OH_VideoEncoder_NotifyEndOfStream(OH_AVCodec *codec); + +/** + * @brief Submit the input buffer filled with data to the video encoder. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param index Enter the index value corresponding to the Buffer + * @param attr Information describing the data contained in the Buffer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 + */ +OH_AVErrCode OH_VideoEncoder_PushInputData(OH_AVCodec *codec, uint32_t index, OH_AVCodecBufferAttr attr); + +/** + * @brief Check whether the current codec instance is valid. It can be used fault recovery or app + * switchback from the background + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @param codec Pointer to an OH_AVCodec instance + * @param isVaild Pointer to an bool instance, true: the codec instance is vaild, false: the codec + * instance is invalid + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 + */ +OH_AVErrCode OH_VideoEncoder_IsValid(OH_AVCodec *codec, bool *isVaild); + +/** + * @brief The bitrate mode of video encoder. + * @syscap SystemCapability.Multimedia.Media.VideoEncoder + * @since 9 + * @version 1.0 + */ +typedef enum OH_VideoEncodeBitrateMode { + /* constant bit rate mode. */ + CBR = 0, + /* variable bit rate mode. */ + VBR = 1, + /* constant quality mode. */ + CQ = 2, +} OH_VideoEncodeBitrateMode; + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVCODEC_VIDEOENCODER_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avdemuxer.h b/interfaces/kits/c/native_avdemuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..c60b1174a6a1923bede34b8b59274a34fb1a66bc --- /dev/null +++ b/interfaces/kits/c/native_avdemuxer.h @@ -0,0 +1,114 @@ +/* + * 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 NATIVE_AVDEMUXER_H +#define NATIVE_AVDEMUXER_H + +#include +#include "native_avcodec_base.h" +#include "native_averrors.h" +#include "native_avsource.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AVDemuxer OH_AVDemuxer; + +/** + * @brief Creates a demuxer to demux media from source. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param source Pointer to an OH_AVSource instance. + * @return Returns a pointer to an OH_AVDemuxer instance + * @since 10 + * @version 4.0 +*/ +OH_AVDemuxer *OH_AVDemuxer_CreateWithSource(OH_AVSource *source); + +/** + * @brief Destroy the demuxer and free its resources. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param demuxer Pointer to an OH_AVDemuxer instance. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVDemuxer_Destroy(OH_AVDemuxer *demuxer); + +/** + * @brief Add a track to the demuxer. Subsequent calls to `OH_AVDemuxer_CopyNextSample` + * only retrieve information for the subset of tracks selected. One track can only be added once, + * and add the same track multiple times has no effect. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param demuxer Pointer to an OH_AVDemuxer instance. + * @param trackIndex Enter the index value corresponding to the track. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVDemuxer_SelectSourceTrackByID(OH_AVDemuxer *demuxer, uint32_t trackIndex); + +/** + * @brief Remove a track from the demuxer. Subsequent calls to `OH_AVDemuxer_CopyNextSample` + * only retrieve information for the subset of tracks selected. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param demuxer Pointer to an OH_AVDemuxer instance. + * @param trackIndex Enter the index value corresponding to the Track. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVDemuxer_UnselectSourceTrackByID(OH_AVDemuxer *demuxer, uint32_t trackIndex); + +/** + * @brief Retrieve the current sample in selected tracks and store it in buffer, and store buffer's info to attr. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param demuxer Pointer to an OH_AVDemuxer instance. + * @param trackIndex The param storing trackIndex of the buffer. + * @param buffer The empty buffer for storing data. + * @param attr The empty OH_AVCodecBufferAttr struct for storing buffer info. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVDemuxer_CopyNextSample(OH_AVDemuxer *demuxer, uint32_t *trackIndex, + uint8_t *buffer, OH_AVCodecBufferAttr *bufferInfo); + +/** + * @brief All selected tracks seek near to the requested time according to the seek mode. + * @syscap SystemCapability.Multimedia.Media.Spliter + * @param demuxer Pointer to an OH_AVDemuxer instance. + * @param mSeconde The millisecond for seeking, the timestamp is the position of + * the file relative to the start of the file. + * @param mode The mode for seeking. Value is: + * SEEK_MODE_NEXT_SYNC > seek to sync sample after the time. + * SEEK_MODE_PREVIOUS_SYNC > seek to sync sample before the time. + * SEEK_MODE_CLOSEST_SYNC > seek to sync sample closest to time. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVDemuxer_SeekToTime(OH_AVDemuxer *demuxer, int64_t mSeconds, OH_AVSeekMode mode); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVDEMUXER_H diff --git a/interfaces/kits/c/native_averrors.h b/interfaces/kits/c/native_averrors.h new file mode 100644 index 0000000000000000000000000000000000000000..fe02f4aeeaa604db25429623e85dd8bbcc44a3a7 --- /dev/null +++ b/interfaces/kits/c/native_averrors.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 NATIVE_AVERRORS_H +#define NATIVE_AVERRORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief AV error code + * @syscap SystemCapability.Multimedia.Media.Core + * @since 9 + * @version 1.0 + */ +typedef enum OH_AVErrCode { + /** + * the operation completed successfully. + */ + AV_ERR_OK = 0, + /** + * no memory. + */ + AV_ERR_NO_MEMORY = 1, + /** + * opertation not be permitted. + */ + AV_ERR_OPERATE_NOT_PERMIT = 2, + /** + * invalid argument. + */ + AV_ERR_INVALID_VAL = 3, + /** + * IO error. + */ + AV_ERR_IO = 4, + /** + * network timeout. + */ + AV_ERR_TIMEOUT = 5, + /** + * unknown error. + */ + AV_ERR_UNKNOWN = 6, + /** + * media service died. + */ + AV_ERR_SERVICE_DIED = 7, + /** + * the state is not support this operation. + */ + AV_ERR_INVALID_STATE = 8, + /** + * unsupport interface. + */ + AV_ERR_UNSUPPORT = 9, + /** + * extend err start. + */ + AV_ERR_EXTEND_START = 100, +} OH_AVErrCode; + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVERRORS_H diff --git a/interfaces/kits/c/native_avformat.h b/interfaces/kits/c/native_avformat.h new file mode 100644 index 0000000000000000000000000000000000000000..8590b1f9bf948e002966b93e8416a54abf47b5f6 --- /dev/null +++ b/interfaces/kits/c/native_avformat.h @@ -0,0 +1,250 @@ +/* + * 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 NATIVE_AVFORMAT_H +#define NATIVE_AVFORMAT_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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 + * @return Returns a pointer to an OH_AVFormat instance + * @since 9 + * @version 1.0 + */ +struct OH_AVFormat *OH_AVFormat_Create(void); + +/** + * @brief Destroy the specified OH_AVFormat handle resource + * @syscap SystemCapability.Multimedia.Media.Core + * @param format pointer to an OH_AVFormat instance + * @return void + * @since 9 + * @version 1.0 + */ +void OH_AVFormat_Destroy(struct OH_AVFormat *format); + +/** + * @brief Copy OH_AVFormat handle resource + * @syscap SystemCapability.Multimedia.Media.Core + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @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 + * @param format pointer to an OH_AVFormat instance + * @return Returns a string consisting of key and data + * @since 9 + * @version 1.0 + */ +const char *OH_AVFormat_DumpInfo(struct OH_AVFormat *format); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVFORMAT_H diff --git a/interfaces/kits/c/native_avmemory.h b/interfaces/kits/c/native_avmemory.h new file mode 100644 index 0000000000000000000000000000000000000000..04278b81394260c2705ff8cd11a2347d18e599bd --- /dev/null +++ b/interfaces/kits/c/native_avmemory.h @@ -0,0 +1,51 @@ +/* + * 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 NATIVE_AVMEMORY_H +#define NATIVE_AVMEMORY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AVMemory OH_AVMemory; + +/** + * @brief Get the memory's virtual address + * @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 + * @version 1.0 + */ +uint8_t *OH_AVMemory_GetAddr(struct OH_AVMemory *mem); + +/** + * @brief Get the memory's size + * @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 + * @version 1.0 + */ +int32_t OH_AVMemory_GetSize(struct OH_AVMemory *mem); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVMEMORY_H diff --git a/interfaces/kits/c/native_avmuxer.h b/interfaces/kits/c/native_avmuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..4e33144fc29ff34f63f96e392b04829dad326170 --- /dev/null +++ b/interfaces/kits/c/native_avmuxer.h @@ -0,0 +1,147 @@ +/* + * 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 NATIVE_AVMUXER_H +#define NATIVE_AVMUXER_H + +#include +#include +#include "native_avcodec_base.h" +#include "native_averrors.h" +#include "native_avformat.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AVMuxer OH_AVMuxer; + +/** + * @brief Create an OH_AVMuxer instance by output file handler and format. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param fd Must be opened with read and write permission. Caller is responsible for closing fd. + * @param format The output format is {@link OH_AVOutputFormat} . + * @return Returns a pointer to an OH_AVMuxer instance, needs to be freed by OH_AVMuxer_Destroy. + * @since 10 + * @version 1.0 + */ +OH_AVMuxer *OH_AVMuxer_Create(int32_t fd, OH_AVOutputFormat format); + +/** + * @brief Set and store the location to the output file. + * Note: This interface can only be called before OH_AVMuxer_Start. + * The location is stored in the output file if the output format is {@link OH_AVOutputFormat} + * AV_OUTPUT_FORMAT_MPEG_4, and is ignored for other output formats. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance. + * @param latitude Must be in the range [-90, 90]. + * @param longitude Must be in the range [-180, 180]. + * @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_SetLocation(OH_AVMuxer *muxer, float latitude, float longitude); + +/** + * @brief Set the rotation for output video playback. + * Note: This interface can only be called before OH_AVMuxer_Start. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance. + * @param rotation The supported angles are 0, 90, 180, and 270 degrees. {@link OH_VideoRotation} + * @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_SetRotation(OH_AVMuxer *muxer, int32_t rotation); + +/** + * @brief Add track format to the muxer. + * Note: This interface can only be called before OH_AVMuxer_Start. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance + * @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, int32_t *trackIndex, OH_AVFormat *trackFormat); + +/** + * @brief Start the muxer. + * Note: This interface is called after OH_AVMuxer_AddTrack and before OH_AVMuxer_WriteSampleBuffer. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance + * @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_Start(OH_AVMuxer *muxer); + +/** + * @brief Write an encoded sample to the muxer. + * Note: This interface can only be called after OH_AVMuxer_Start and before OH_AVMuxer_Stop. The application needs to + * make sure that the samples are written to the right tacks. Also, it needs to make sure the samples for each track are + * written in chronological order. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance + * @param trackIndex The track index for this sample + * @param sampleBuffer The encoded sample buffer + * @param info The buffer information related to this sample {@link OH_AVCodecBufferAttr} + * @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_WriteSampleBuffer(OH_AVMuxer *muxer, + uint32_t trackIndex, + uint8_t *sampleBuffer, + OH_AVCodecBufferAttr info); + +/** + * @brief Stop the muxer. + * Note: Once the muxer stops, it can not be restarted. + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param muxer Pointer to an OH_AVMuxer instance + * @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_Stop(OH_AVMuxer *muxer); + +/** + * @brief Clear the internal resources of the muxer and destroy the muxer instance + * @syscap SystemCapability.Multimedia.Media.Muxer + * @param codec Pointer to an OH_AVMuxer instance + * @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_Destroy(OH_AVMuxer *muxer); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVMUXER_H \ No newline at end of file diff --git a/interfaces/kits/c/native_avsource.h b/interfaces/kits/c/native_avsource.h new file mode 100644 index 0000000000000000000000000000000000000000..b7839887dd61a5587a6dd71138b4cac10281e517 --- /dev/null +++ b/interfaces/kits/c/native_avsource.h @@ -0,0 +1,124 @@ +/* + * 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 NATIVE_AVSOURCE_H +#define NATIVE_AVSOURCE_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OH_AVSource OH_AVSource; + +typedef struct OH_AVSourceTrack OH_AVSourceTrack; + +/** + * @brief Creates a source that models the media at the specified URI. + * @syscap SystemCapability.Multimedia.Media.Core + * @param uri A URI to a local, remote, ot HTTP Live Streaming media resource. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVSource *OH_AVSource_CreateWithURI(char *uri); + +/** + * @brief Creates a source that models the media at the specified FileDescriptor. + * @syscap SystemCapability.Multimedia.Media.Core + * @param fd The fileDescriptor data source. + * @param offset The offset into the file where the data be read starts. + * @param size the length in bytes of the data to be read. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVSource *OH_AVSource_CreateWithFD(int32_t fd, int64_t offset, int64_t size); + +/** + * @brief Destroy the source and free its resources. + * @syscap SystemCapability.Multimedia.Media.Core + * @param source Pointer to an OH_AVSource instance. + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVSource_Destroy(OH_AVSource *source); + +/** + * @brief Get the count of tracks in the source. + * @syscap SystemCapability.Multimedia.Media.Core + * @param source Pointer to an OH_AVSource instance. + * @return Returns the count of tracks in the source. + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVSource_GetTrackCount(OH_AVSource *source, uint32_t *trackCount); + +/** + * @brief Get the format and metadata of source. + * @syscap SystemCapability.Multimedia.Media.Core + * @param source Pointer to an OH_AVSource instance. + * @return Returns the source format and metadata. + * @since 10 + * @version 4.0 +*/ +OH_AVFormat *OH_AVSource_GetSourceFormat(OH_AVSource *source); + +/** + * @brief loads a track contains the specified identifier from the source. + * @syscap SystemCapability.Multimedia.Media.Core + * @param source Pointer to an OH_AVSource instance. + * @param trackIndex The identifier of the track to load. + * @return Returns the track's format at the specified index. + * @since 10 + * @version 4.0 +*/ +OH_AVSourceTrack *OH_AVSource_GetSourceTrackByID(OH_AVSource *source, uint32_t trackIndex); + +/** + * @brief Set the parameters to track at the specified index. + * @syscap SystemCapability.Multimedia.Media.Core + * @param sourceTrack Pointer to an OH_AVSourceTrack instance. + * @param format OH_AVFormat handle pointer + * @return Returns AV_ERR_OK if the execution is successful, + * otherwise returns a specific error code, refer to {@link OH_AVErrCode} + * @since 10 + * @version 4.0 +*/ +OH_AVErrCode OH_AVSourceTrack_SetTrackFormat(OH_AVSourceTrack *sourceTrack, OH_AVFormat *format); + +/** + * @brief Get the track format at the specified index. + * @syscap SystemCapability.Multimedia.Media.Core + * @param sourceTrack Pointer to an AVSourceTrack instance. + * @return Returns the track's format. + * @since 10 + * @version 4.0 +*/ +OH_AVFormat *OH_AVSourceTrack_GetTrackFormat(OH_AVSourceTrack *sourceTrack); + +#ifdef __cplusplus +} +#endif + +#endif // NATIVE_AVSOURCE_H \ No newline at end of file diff --git a/sa_profile/3011.xml b/sa_profile/3011.xml new file mode 100644 index 0000000000000000000000000000000000000000..804c8ef4fe13893f954a21a598f51f557ffa6c17 --- /dev/null +++ b/sa_profile/3011.xml @@ -0,0 +1,25 @@ + + + + av_codec_service + + 3011 + libav_codec_service.z.so + true + false + 1 + + \ No newline at end of file diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..260bdecfebe9854e1e3cc1a13ae40de1ef6eb9e7 --- /dev/null +++ b/sa_profile/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("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("av_codec_service_profile") { + sources = [ "3011.xml" ] + part_name = "av_codec" +} diff --git a/services/BUILD.gn b/services/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2a6e9a619dc38af216d4791f679f56d0ab0533aa --- /dev/null +++ b/services/BUILD.gn @@ -0,0 +1,22 @@ +# 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/ohos.gni") + +group("av_codec_services_package") { + deps = [ + "etc:av_codec_service.cfg", + "services:av_codec_service", + "utils:av_codec_service_utils", + ] +} diff --git a/services/dfx/BUILD.gn b/services/dfx/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..586e3b8b94be9e6db5ee642376d24bf3a396e155 --- /dev/null +++ b/services/dfx/BUILD.gn @@ -0,0 +1,87 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("av_codec_service_log_dfx_public_config") { + cflags = [ "-DOHOS_AV_CODEC_LOG_DFX" ] + include_dirs = [ "$av_codec_root_dir/services/dfx/include" ] +} + +ohos_shared_library("av_codec_service_dfx") { + install_enable = true + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + sources = [ + "avcodec_dfx.cpp", + "avcodec_log_dump.cpp", + "avcodec_xcollie.cpp", + "avcodec_dump_utils.cpp", + ] + + include_dirs = [ + "./include", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + + # "//commonlibrary/c_utils/base/include", + ] + + defines = [] + defines += av_codec_defines + + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + + deps = [ + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "c_utils:utils", + "hicollie_native:libhicollie", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + "init:libbegetutil", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/dfx/avcodec_dfx.cpp b/services/dfx/avcodec_dfx.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dbc01105f80bffa2c1a658ff99ffc919882aebef --- /dev/null +++ b/services/dfx/avcodec_dfx.cpp @@ -0,0 +1,142 @@ +/* + * 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 "securec.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "hitrace_meter.h" + + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecDFX"}; + constexpr uint32_t MAX_STRING_SIZE = 256; + constexpr char HISYSEVENT_DOMAIN_AVCODEC[] = "AVCODEC"; +} + +namespace OHOS { +namespace Media { +bool AVCodecEvent::CreateMsg(const char *format, ...) +{ + va_list args; + va_start(args, format); + char msg[MAX_STRING_SIZE] = {0}; + if (vsnprintf_s(msg, sizeof(msg), sizeof(msg) - 1, format, args) < 0) { + AVCODEC_LOGE("failed to call vsnprintf_s"); + va_end(args); + return false; + } + va_end(args); + msg_ = msg; + return true; +} + +void AVCodecEvent::StatisticEventWrite(std::string eventName, + OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module) +{ + int32_t pid = getpid(); + uint32_t uid = getuid(); + HiSysEventWrite(HISYSEVENT_DOMAIN_AVCODEC, eventName, type, + "PID", pid, + "UID", uid, + "MODULE", module, + "MSG", msg_); +} + +void AVCodecEvent::BehaviorEventWrite(std::string eventName, + OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module) +{ + int32_t pid = getpid(); + uint32_t uid = getuid(); + HiSysEventWrite(HISYSEVENT_DOMAIN_AVCODEC, eventName, type, + "PID", pid, + "UID", uid, + "MODULE", module, + "STATE", msg_); +} + +void AVCodecEvent::FaultEventWrite(std::string eventName, int32_t errorCode, + OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module) +{ + int32_t pid = getpid(); + uint32_t uid = getuid(); + HiSysEventWrite(HISYSEVENT_DOMAIN_AVCODEC, eventName, type, + "PID", pid, + "UID", uid, + "MODULE", module, + "ERRORCODE", errorCode, + "MSG", msg_); +} + +void BehaviorEventWrite(std::string status, std::string moudle) +{ + AVCodecEvent event; + if (event.CreateMsg("%s, current state is: %s", "state change", status.c_str())) { + event.BehaviorEventWrite("AVCODEC_STATE", OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR, moudle); + } else { + AVCODEC_LOGW("Failed to call CreateMsg"); + } +} + +void FaultEventWrite(int32_t errorCode, std::string msg, std::string moudle) +{ + AVCodecEvent event; + if (event.CreateMsg("%s", msg.c_str())) { + event.FaultEventWrite("AVCODEC_ERR", errorCode, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, moudle); + } else { + AVCODEC_LOGW("Failed to call CreateMsg"); + } +} + +void StatisticEventWrite(std::string msg, std::string moudle) +{ + AVCodecEvent event; + if (event.CreateMsg("%s", msg.c_str())) { + event.StatisticEventWrite("AVCODEC_STATISTIC", OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, moudle); + } else { + AVCODEC_LOGW("Failed to call CreateMsg"); + } +} + +AVCodecTrace::AVCodecTrace(const std::string &funcName) +{ + StartTrace(HITRACE_TAG_ZMEDIA, funcName); + isSync_ = true; +} + +void AVCodecTrace::TraceBegin(const std::string &funcName, int32_t taskId) +{ + StartAsyncTrace(HITRACE_TAG_ZMEDIA, funcName, taskId); +} + +void AVCodecTrace::TraceEnd(const std::string &funcName, int32_t taskId) +{ + FinishAsyncTrace(HITRACE_TAG_ZMEDIA, funcName, taskId); +} + +void AVCodecTrace::CounterTrace(const std::string &varName, int32_t val) +{ + CountTrace(HITRACE_TAG_ZMEDIA, varName, val); +} + +AVCodecTrace::~AVCodecTrace() +{ + if (isSync_) { + FinishTrace(HITRACE_TAG_ZMEDIA); + } +} +} // namespace Media +} // namespace OHOS diff --git a/services/dfx/avcodec_dump_utils.cpp b/services/dfx/avcodec_dump_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54e7ccd13a99890b572c1ce075e8f0d47f23cf97 --- /dev/null +++ b/services/dfx/avcodec_dump_utils.cpp @@ -0,0 +1,124 @@ +/* + * 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 "avcodec_dump_utils.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecDumpUtils"}; + constexpr uint32_t DUMP_LEVEL_4 = 4; + constexpr uint32_t DUMP_LEVEL_3 = 3; + constexpr uint32_t DUMP_LEVEL_2 = 2; + constexpr uint32_t DUMP_SPACE_LENGTH = 4; + constexpr uint32_t DUMP_OFFSET_24 = 24; + constexpr uint32_t DUMP_OFFSET_16 = 16; + constexpr uint32_t DUMP_OFFSET_8 = 8; +} + +namespace OHOS { +namespace Media { +int32_t AVCodecDumpControler::AddInfo(const uint32_t dumpIdx, const std::string &name, const std::string &value) +{ + CHECK_AND_RETURN_RET_LOG((dumpIdx >> DUMP_OFFSET_24) > 0, AVCS_ERR_INVALID_VAL, + "Add dump info failed, get a invalid dump index."); + CHECK_AND_RETURN_RET_LOG(!name.empty(), AVCS_ERR_INVALID_VAL, + "Add dump info failed, get a empty name."); + if (dumpInfoMap_.find(dumpIdx) != dumpInfoMap_.end()) { + AVCODEC_LOGW("Dump info index already exist, index: %{public}d", dumpIdx); + return AVCS_ERR_OK; + } + + int32_t level = GetLevel(dumpIdx); + length_[level - 1] = length_[level - 1] > name.length() ? length_[level - 1] : name.length(); + dumpInfoMap_.emplace(dumpIdx, make_pair(name, value)); + return AVCS_ERR_OK; +} + +int32_t AVCodecDumpControler::AddInfoFromFormat(const uint32_t dumpIdx, const Format &format, + const std::string_view &key, const std::string &name) +{ + CHECK_AND_RETURN_RET_LOG(!key.empty(), AVCS_ERR_INVALID_VAL, "Add dump info failed, get a empty key."); + + std::string value; + switch (format.GetValueType(key)) { + case FORMAT_TYPE_INT32: { + int32_t valueTemp = 0; + format.GetIntValue(key, valueTemp); + value = std::to_string(valueTemp); + break; + } + case FORMAT_TYPE_INT64: { + int64_t valueTemp = 0; + format.GetLongValue(key, valueTemp); + value = std::to_string(valueTemp); + break; + } + case FORMAT_TYPE_FLOAT: { + float valueTemp = 0; + format.GetFloatValue(key, valueTemp); + value = std::to_string(valueTemp); + break; + } + case FORMAT_TYPE_DOUBLE: { + double valueTemp = 0; + format.GetDoubleValue(key, valueTemp); + value = std::to_string(valueTemp); + break; + } + case FORMAT_TYPE_STRING: { + format.GetStringValue(key, value); + break; + } + case FORMAT_TYPE_ADDR: + break; + default: + AVCODEC_LOGE("Add info from format failed. Key: %{public}s", key.data()); + } + + this->AddInfo(dumpIdx, name, value); + return AVCS_ERR_OK; +} + +int32_t AVCodecDumpControler::GetDumpString(std::string &dumpString) +{ + for (auto iter : dumpInfoMap_) { + int level = GetLevel(iter.first); + std::string name = iter.second.first; + std::string value = iter.second.second; + dumpString += std::string((level - 1) * DUMP_SPACE_LENGTH, ' ') + + name + std::string(length_[level - 1] - name.length(), ' '); + if (!value.empty()) { + dumpString += " - " + value; + } + dumpString += std::string("\n"); + } + return 0; +} + +uint32_t AVCodecDumpControler::GetLevel(const uint32_t dumpIdx) +{ + int level = 1; + if (dumpIdx & UINT8_MAX) { + level = DUMP_LEVEL_4; + } else if ((dumpIdx >> DUMP_OFFSET_8) & UINT8_MAX) { + level = DUMP_LEVEL_3; + } else if ((dumpIdx >> DUMP_OFFSET_16) & UINT8_MAX) { + level = DUMP_LEVEL_2; + } + return level; +} +} // namespace OHOS +} // namespace Media \ No newline at end of file diff --git a/services/dfx/avcodec_log_dump.cpp b/services/dfx/avcodec_log_dump.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cf3477020fbbd00f1335732453fe6eb77797aec --- /dev/null +++ b/services/dfx/avcodec_log_dump.cpp @@ -0,0 +1,180 @@ +/* + * 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 "avcodec_log_dump.h" +#include +#include +#include +#include +#include "securec.h" +#include "avcodec_log.h" + +namespace { +constexpr int32_t FILE_MAX = 100; +constexpr int32_t FILE_LINE_MAX = 50000; +constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecLogDump"}; +} + +namespace OHOS { +namespace Media { +AVCodecLogDump &AVCodecLogDump::GetInstance() +{ + static AVCodecLogDump avcodecLogDump; + return avcodecLogDump; +} + +AVCodecLogDump::AVCodecLogDump() +{ + CHECK_AND_RETURN_LOG(thread_ == nullptr, "TaskProcessor is existed"); + thread_ = std::make_unique(&AVCodecLogDump::TaskProcessor, this); +} + +AVCodecLogDump::~AVCodecLogDump() +{ + { + std::unique_lock lock(mutex_); + isExit_ = true; + cond_.notify_all(); + } + if (thread_ != nullptr && thread_->joinable()) { + thread_->join(); + } +} + +static void AddNewLog(std::string &logStr) +{ + struct timeval time = {}; + (void)gettimeofday(&time, nullptr); + int64_t second = time.tv_sec % 60; + int64_t allMinute = time.tv_sec / 60; + int64_t minute = allMinute % 60; + int64_t hour = allMinute / 60 % 24; + int64_t mSecond = time.tv_usec / 1000; + + logStr += std::to_string(hour); + logStr += ":"; + logStr += std::to_string(minute); + logStr += ":"; + logStr += std::to_string(second); + logStr += ":"; + logStr += std::to_string(mSecond); + logStr += " "; + logStr += " pid:"; + logStr += std::to_string(getpid()); + logStr += " tid:"; + logStr += std::to_string(gettid()); + logStr += " "; +} + +void AVCodecLogDump::SaveLog(const char *fmt, ...) +{ + std::unique_lock lock(mutex_); + if (!isEnable_) { + return; + } + std::string temp = ""; + std::string fmtStr = fmt; + int32_t srcPos = 0; + auto dtsPos = fmtStr.find("{public}", srcPos); + const int32_t pubLen = 8; + while (dtsPos != std::string::npos) { + temp += fmtStr.substr(srcPos, dtsPos - srcPos); + srcPos = static_cast(dtsPos) + pubLen; + dtsPos = fmtStr.find("{public}", srcPos); + } + temp += fmtStr.substr(srcPos); + + va_list ap; + va_start(ap, fmt); + constexpr uint8_t maxLogLen = 255; + char logBuf[maxLogLen]; + auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap); + va_end(ap); + + AddNewLog(logString_); + if (ret < 0) { + logString_ += "dump log error"; + } else { + logString_ += logBuf; + } + logString_ += "\n"; + lineCount_++; + if (lineCount_ >= FILE_LINE_MAX) { + cond_.notify_all(); + } +} + +void AVCodecLogDump::UpdateCheckEnable() +{ + std::string file = "/data/media/log/check.config"; + std::ofstream ofStream(file); + if (!ofStream.is_open()) { + isEnable_ = false; + return; + } + ofStream.close(); + isEnable_ = true; +} + +void AVCodecLogDump::TaskProcessor() +{ + pthread_setname_np(pthread_self(), "AVCodecLogDumpTask"); + (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE); + (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE); + while (true) { + std::string temp; + int32_t lineCount = 0; + { + std::unique_lock lock(mutex_); + if (isExit_) { + return; + } + static constexpr int32_t timeout = 60; // every 1 minute have a log + cond_.wait_for(lock, std::chrono::seconds(timeout), + [this] { + UpdateCheckEnable(); + return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty(); + }); + isDump_ = false; + lineCount = lineCount_; + lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_; + swap(logString_, temp); + } + + std::string file = "/data/media/avcodec/log/"; + file += std::to_string(getpid()); + file += "dump_log_avcodec.log"; + file += std::to_string(fileCount_); + std::ofstream ofStream; + if (isNewFile_) { + ofStream.open(file, std::ios::out | std::ios::trunc); + } else { + ofStream.open(file, std::ios::out | std::ios::app); + } + if (!ofStream.is_open()) { + continue; + } + isNewFile_ = false; + if (lineCount >= FILE_LINE_MAX) { + isNewFile_ = true; + fileCount_++; + fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_; + } + ofStream.write(temp.c_str(), temp.size()); + ofStream.close(); + } +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/dfx/avcodec_xcollie.cpp b/services/dfx/avcodec_xcollie.cpp new file mode 100644 index 0000000000000000000000000000000000000000..badbace0fa3de1491d33129d5895a49ea3d2eb59 --- /dev/null +++ b/services/dfx/avcodec_xcollie.cpp @@ -0,0 +1,120 @@ +/* + * 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 "avcodec_xcollie.h" +#include +#include "avcodec_errors.h" +#include "param_wrapper.h" +#ifdef HICOLLIE_ENABLE +#include "xcollie/xcollie.h" +#include "xcollie/xcollie_define.h" +#endif + +namespace OHOS { +namespace Media { +AVCodecXCollie &AVCodecXCollie::GetInstance() +{ + static AVCodecXCollie instance; + return instance; +} + +void AVCodecXCollie::TimerCallback(void *data) +{ + std::lock_guard lock(mutex_); + threadDeadlockCount_++; + static constexpr uint32_t threshold = 5; // >5 Restart service + if (threadDeadlockCount_ >= threshold) { + _exit(-1); + } +} + +int32_t AVCodecXCollie::Dump(int32_t fd) +{ + if (dfxDumper_.empty()) { + return AVCS_ERR_OK; + } + + std::lock_guard lock(mutex_); + std::string dumpString = "[AVCodec_XCollie]\n"; + for (const auto &iter : dfxDumper_) { + dumpString += "WaitTask-----"; + dumpString += iter.second; + dumpString += "-----\n"; + } + if (fd != -1) { + write(fd, dumpString.c_str(), dumpString.size()); + dumpString.clear(); + return AVCS_ERR_INVALID_VAL; + } + return AVCS_ERR_OK; +} + +int32_t AVCodecXCollie::SetTimer(const std::string &name, bool recovery, uint32_t timeout) +{ +#ifdef HICOLLIE_ENABLE + auto func = [this](void *data) { + this->TimerCallback(data); + }; + + unsigned int flag = HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_NOOP; + if (recovery) { + flag |= HiviewDFX::XCOLLIE_FLAG_RECOVERY; + } + int32_t id = HiviewDFX::XCollie::GetInstance().SetTimer(name, timeout, func, this, flag); + if (id != HiviewDFX::INVALID_ID) { + std::lock_guard lock(mutex_); + dfxDumper_.emplace(id, name); + } + return id; +#else + return -1; +#endif +} + +int32_t AVCodecXCollie::SetTimerByLog(const std::string &name, uint32_t timeout) +{ +#ifdef HICOLLIE_ENABLE + unsigned int flag = HiviewDFX::XCOLLIE_FLAG_LOG; + int32_t id = HiviewDFX::XCollie::GetInstance().SetTimer(name, timeout, nullptr, this, flag); + if (id != HiviewDFX::INVALID_ID) { + std::lock_guard lock(mutex_); + dfxDumper_.emplace(id, name); + } + return id; +#else + return -1; +#endif +} + +void AVCodecXCollie::CancelTimer(int32_t id) +{ +#ifdef HICOLLIE_ENABLE + if (id != HiviewDFX::INVALID_ID) { + std::lock_guard lock(mutex_); + auto it = dfxDumper_.find(id); + if (it == dfxDumper_.end()) { + return; + } + + dfxDumper_.erase(it); + return HiviewDFX::XCollie::GetInstance().CancelTimer(id); + } +#else + (void)id; + return; +#endif +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/dfx/include/avcodec_dfx.h b/services/dfx/include/avcodec_dfx.h new file mode 100644 index 0000000000000000000000000000000000000000..eea2877e584a3e8de840018162d00ee80de02529 --- /dev/null +++ b/services/dfx/include/avcodec_dfx.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 AVCODEC_DFX_H +#define AVCODEC_DFX_H + +#include +#include +#include "nocopyable.h" +#include "hisysevent.h" + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) AVCodecEvent : public NoCopyable { +public: + AVCodecEvent() = default; + ~AVCodecEvent() = default; + bool CreateMsg(const char *format, ...) __attribute__((__format__(printf, 2, 3))); + void StatisticEventWrite(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, + std::string module); + void BehaviorEventWrite(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, + std::string module); + void FaultEventWrite(std::string eventName, int32_t errorCode, OHOS::HiviewDFX::HiSysEvent::EventType type, + std::string module); +private: + std::string msg_; +}; + +__attribute__((visibility("default"))) void BehaviorEventWrite(std::string status, std::string moudle); +__attribute__((visibility("default"))) void FaultEventWrite(int32_t errorCode, std::string msg, std::string moudle); +__attribute__((visibility("default"))) void StatisticEventWrite(std::string msg, std::string moudle); + +#define AVCODEC_SYNC_TRACE AVCodecTrace trace(std::string(__FUNCTION__)) + +class __attribute__((visibility("default"))) AVCodecTrace : public NoCopyable { +public: + explicit AVCodecTrace(const std::string &funcName); + static void TraceBegin(const std::string &funcName, int32_t taskId); + static void TraceEnd(const std::string &funcName, int32_t taskId); + static void CounterTrace(const std::string &varName, int32_t val); + ~AVCodecTrace(); +private: + bool isSync_ = false; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_DFX_H \ No newline at end of file diff --git a/services/dfx/include/avcodec_dump_utils.h b/services/dfx/include/avcodec_dump_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..dac3eac931c70a1da8f1e99e638ad3fbe87d54b0 --- /dev/null +++ b/services/dfx/include/avcodec_dump_utils.h @@ -0,0 +1,40 @@ +/* + * 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 AVCODEC_DUMP_UTILS_H +#define AVCODEC_DUMP_UTILS_H + +#include +#include +#include +#include "format.h" + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) AVCodecDumpControler { +public: + int32_t AddInfo(const uint32_t dumpIdx, const std::string &name, const std::string &value = ""); + int32_t AddInfoFromFormat(const uint32_t dumpIdx, const Format &format, + const std::string_view &key, const std::string &name); + int32_t GetDumpString(std::string &dumpString); + +private: + uint32_t GetLevel(const uint32_t dumpIdx); + std::map> dumpInfoMap_; // > + std::vector length_ = std::vector(4, 0); +}; +} // namespace OHOS +} // namespace Media +#endif // AVCODEC_DUMP_UTILS_H \ No newline at end of file diff --git a/services/dfx/include/avcodec_log.h b/services/dfx/include/avcodec_log.h new file mode 100644 index 0000000000000000000000000000000000000000..3a3e25a8c7dfb82c9ae77ab5771be72df0c93f8d --- /dev/null +++ b/services/dfx/include/avcodec_log.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 AVCODEC_LOG_H +#define AVCODEC_LOG_H + +#include +#include + +namespace OHOS { +namespace Media { +#undef LOG_DOMAIN +#define LOG_DOMAIN 0xD002BAC + +#define AVCODEC_LOG(func, fmt, args...) \ + do { \ + (void)func(LABEL, "{%{public}s():%{public}d} " fmt, __FUNCTION__, __LINE__, ##args); \ + } while (0) + +#define AVCODEC_LOGD(fmt, ...) AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Debug, fmt, ##__VA_ARGS__) +#define AVCODEC_LOGI(fmt, ...) AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Info, fmt, ##__VA_ARGS__) +#define AVCODEC_LOGW(fmt, ...) AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Warn, fmt, ##__VA_ARGS__) +#define AVCODEC_LOGE(fmt, ...) AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Error, fmt, ##__VA_ARGS__) +#define AVCODEC_LOGF(fmt, ...) AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Fatal, fmt, ##__VA_ARGS__) + +#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (!(cond)) { \ + AVCODEC_LOGE(fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) + +#define CHECK_AND_RETURN_LOG(cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + AVCODEC_LOGE(fmt, ##__VA_ARGS__); \ + return; \ + } \ + } while (0) + +#define CHECK_AND_BREAK_LOG(cond, fmt, ...) \ + if (1) { \ + if (!(cond)) { \ + AVCODEC_LOGE(fmt, ##__VA_ARGS__); \ + break; \ + } \ + } else void (0) + +#define CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \ + if (1) { \ + if (!(cond)) { \ + AVCODEC_LOGE(fmt, ##__VA_ARGS__); \ + continue; \ + } \ + } else void (0) + +#define POINTER_MASK 0x00FFFFFF +#define FAKE_POINTER(addr) (POINTER_MASK & reinterpret_cast(addr)) +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LOG_H \ No newline at end of file diff --git a/services/dfx/include/avcodec_log_dump.h b/services/dfx/include/avcodec_log_dump.h new file mode 100644 index 0000000000000000000000000000000000000000..c677e0305927e8c242ec963dea401ed88d065185 --- /dev/null +++ b/services/dfx/include/avcodec_log_dump.h @@ -0,0 +1,60 @@ +/* + * 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 AVCODEC_LOG_DUMP_H +#define AVCODEC_LOG_DUMP_H + +#include +#include +#include + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) AVCodecLogDump { +public: + static AVCodecLogDump &GetInstance(); + void SaveLog(const char *fmt, ...); + +private: + AVCodecLogDump(); + ~AVCodecLogDump(); + void UpdateCheckEnable(); + int32_t fileCount_ = 0; + int32_t lineCount_ = 0; + std::unique_ptr thread_; + void TaskProcessor(); + std::mutex mutex_; + std::condition_variable cond_; + std::string logString_; + bool isDump_ = false; + bool isExit_ = false; + bool isEnable_ = false; + bool isNewFile_ = true; +}; + +// AVCodec log dump macro interface +#ifdef OHOS_MEDIA_AVCODEC_LOG_DUMP +#define AVCODEC_DUMP_LOG(fmt, args...) \ + do { \ + (void)OHOS::Media::AVCodecLogDump::GetInstance().SaveLog( \ + "{%s():%d} " fmt, __FUNCTION__, __LINE__, ##args); \ + } while (0) +#else +#define AVCODEC_DUMP_LOG(fmt, args...) +#endif +} // namespace Media +} // namespace OHOS + +#endif // AVCODEC_LOG_DUMP_H \ No newline at end of file diff --git a/services/dfx/include/avcodec_xcollie.h b/services/dfx/include/avcodec_xcollie.h new file mode 100644 index 0000000000000000000000000000000000000000..84fdfa3e49173fbe8396edc8a20870c5d90b2449 --- /dev/null +++ b/services/dfx/include/avcodec_xcollie.h @@ -0,0 +1,66 @@ +/* + * 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 AVCODEC_XCOLLIE_H +#define AVCODEC_XCOLLIE_H + +#include +#include +#include + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) AVCodecXCollie { +public: + static AVCodecXCollie &GetInstance(); + int32_t SetTimer(const std::string &name, bool recovery = false, uint32_t timeout = 10); // 10s + int32_t SetTimerByLog(const std::string &name, uint32_t timeout = 10); // 10s + void CancelTimer(int32_t id); + int32_t Dump(int32_t fd); + constexpr static uint32_t timerTimeout = 10; +private: + AVCodecXCollie() = default; + ~AVCodecXCollie() = default; + void TimerCallback(void *data); + + std::mutex mutex_; + std::map dfxDumper_; + uint32_t threadDeadlockCount_ = 0; +}; + +class __attribute__((visibility("hidden"))) AVCodecXcollieTimer { +public: + AVCodecXcollieTimer(const std::string &name, bool recovery = false, uint32_t timeout = 10) + { + id_ = AVCodecXCollie::GetInstance().SetTimer(name, recovery, timeout); + }; + + AVCodecXcollieTimer(const std::string &name, uint32_t timeout) + { + id_ = AVCodecXCollie::GetInstance().SetTimerByLog(name, timeout); + } + + ~AVCodecXcollieTimer() + { + AVCodecXCollie::GetInstance().CancelTimer(id_); + } +private: + int32_t id_ = 0; +}; + +#define COLLIE_LISTEN(statement, args...) { AVCodecXcollieTimer xCollie(args); statement; } +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_XCOLLIE_H \ No newline at end of file diff --git a/services/engine/BUILD.gn b/services/engine/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5c9be180dd516f86eef72bb6625d29cc959d49de --- /dev/null +++ b/services/engine/BUILD.gn @@ -0,0 +1,22 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +group("av_codec_engine_package") { + deps = [ + "codec:av_codec_engine_codec", + "plugin:av_codec_plugin", + ] +} diff --git a/services/engine/base/BUILD.gn b/services/engine/base/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..7721b9be14ca9e39c629f821127df3fbf6d91d72 --- /dev/null +++ b/services/engine/base/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_static_library("av_codec_codec_base") { + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wno-deprecated-declarations", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/utils/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include", + "//third_party/ffmpeg", + + # "$av_codec_root_dir/services/engine/common/include", + ] + + sources = [ "$av_codec_root_dir/services/engine/base/codecbase.cpp" ] + + deps = [ + "$av_codec_root_dir/services/engine/common:av_codec_engine_common", + "//third_party/ffmpeg:libohosffmpeg", + ] + + public_deps = [ + "$av_codec_root_dir/services/dfx:av_codec_service_dfx", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ + "graphic_standard:surface", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/engine/base/codecbase.cpp b/services/engine/base/codecbase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6ea08b789cd472f6b3e8076c456d970495faccf --- /dev/null +++ b/services/engine/base/codecbase.cpp @@ -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. + */ + +#include "avcodec_log.h" +#include "codecbase.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecBase"}; +} + +namespace OHOS { +namespace Media { +int32_t CodecBase::NotifyEos() +{ + AVCODEC_LOGW("NotifyEos is not supported"); + return 0; +} + +sptr CodecBase::CreateInputSurface() +{ + AVCODEC_LOGW("CreateInputSurface is not supported"); + return nullptr; +} + +int32_t CodecBase::SetOutputSurface(sptr surface) +{ + (void)surface; + AVCODEC_LOGW("SetOutputSurface is not supported"); + return 0; +} + +int32_t CodecBase::RenderOutputBuffer(size_t index) +{ + (void)index; + AVCODEC_LOGW("RenderOutputBuffer is not supported"); + return 0; +} + +int32_t CodecBase::SignalRequestIDRFrame() +{ + AVCODEC_LOGW("SignalRequestIDRFrame is not supported"); + return 0; +} +} // namespace Media +} // namespace OHOS diff --git a/services/engine/base/include/codecbase.h b/services/engine/base/include/codecbase.h new file mode 100644 index 0000000000000000000000000000000000000000..250c32f5af0b507ac3c6d697f42c132aab401ea7 --- /dev/null +++ b/services/engine/base/include/codecbase.h @@ -0,0 +1,53 @@ +/* + * 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 CODECBASE_H +#define CODECBASE_H + +#include +#include "avcodec_common.h" +#include "avsharedmemorybase.h" +#include "surface.h" + +namespace OHOS { +namespace Media { +class CodecBase { +public: + CodecBase() = default; + virtual ~CodecBase() = default; + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; + virtual int32_t Configure(const Format &format) = 0; + virtual int32_t Start() = 0; + virtual int32_t Pause() = 0; + virtual int32_t Resume() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t SetParameter(const Format& format) = 0; + virtual int32_t GetOutputFormat(Format& format) = 0; + virtual std::shared_ptr GetInputBuffer(size_t index) = 0; + virtual int32_t QueueInputBuffer(size_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag &flag) = 0; + virtual std::shared_ptr GetOutputBuffer(size_t index) = 0; + virtual int32_t ReleaseOutputBuffer(size_t index) = 0; + + virtual int32_t NotifyEos(); + virtual sptr CreateInputSurface(); + virtual int32_t SetOutputSurface(sptr surface); + virtual int32_t RenderOutputBuffer(size_t index); + virtual int32_t SignalRequestIDRFrame(); +}; +} // namespace Media +} // namespace OHOS +#endif // CODECBASE_H \ No newline at end of file diff --git a/services/engine/base/include/codeclistbase.h b/services/engine/base/include/codeclistbase.h new file mode 100644 index 0000000000000000000000000000000000000000..3d69b9bd892992a3fc53a841b5b2bb1f41554970 --- /dev/null +++ b/services/engine/base/include/codeclistbase.h @@ -0,0 +1,30 @@ +/* + * 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 AVCODECLISTBASE_H +#define AVCODECLISTBASE_H + +#include +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class CodecListBase { +public: + virtual ~CodecListBase() = default; + virtual int32_t GetCapabilityList(std::vector &caps) = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLISTBASE_H \ No newline at end of file diff --git a/services/engine/base/include/sourcebase.h b/services/engine/base/include/sourcebase.h new file mode 100644 index 0000000000000000000000000000000000000000..0ffa0af0fef9e4cf9078a1e8a17f52cbcf9870f8 --- /dev/null +++ b/services/engine/base/include/sourcebase.h @@ -0,0 +1,35 @@ +/* + * 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 SOURCEBASE_H +#define SOURCEBASE_H + +#include +#include "format.h" + +namespace OHOS { +namespace Media { +class SourceBase { +public: + virtual ~SourceBase() = default; + virtual int32_t Create(std::string& uri) = 0; + virtual int32_t GetTrackCount(uint32_t &trackCount) = 0; + virtual int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetSourceFormat(Format &format) = 0; + virtual int32_t GetTrackFormat(Format &format, uint32_t trackIndex) = 0; + virtual uintptr_t GetSourceAddr() = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCEBASE_H \ No newline at end of file diff --git a/services/engine/codec/BUILD.gn b/services/engine/codec/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..04a2a1f9243aa2f7e240e5f40e8ad50fc86321ff --- /dev/null +++ b/services/engine/codec/BUILD.gn @@ -0,0 +1,22 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +group("av_codec_engine_codec") { + deps = [ + "audio:av_codec_audio_ffmpeg_codec", + "video:av_codec_video_ffmpeg_codec", + ] +} diff --git a/services/engine/codec/audio/BUILD.gn b/services/engine/codec/audio/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..131ee1a77a5883fc01374a6d9a877ad5d6e4c9cc --- /dev/null +++ b/services/engine/codec/audio/BUILD.gn @@ -0,0 +1,106 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_static_library("av_codec_audio_ffmpeg_codec") { + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wno-deprecated-declarations", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/engine/codec/include/audio", + "$av_codec_root_dir/services/engine/codec/include/audio/decoder", + "$av_codec_root_dir/services/engine/codec/include/audio/encoder", + "$av_codec_root_dir/services/engine/factory", + "$av_codec_root_dir/services/utils/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//commonlibrary/c_utils/base/include", + "//base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include", + "//third_party/ffmpeg", + + # "$av_codec_root_dir/services/engine/common/include", + # "$av_codec_root_dir/services/engine/codec/include/audio/encoder", + ] + + sources = [ + "$av_codec_root_dir/services/engine/codec/audio/audio_buffer_info.cpp", + "$av_codec_root_dir/services/engine/codec/audio/audio_buffers_manager.cpp", + "$av_codec_root_dir/services/engine/codec/audio/audio_codec_worker.cpp", + "$av_codec_root_dir/services/engine/codec/audio/audio_ffmpeg_adapter.cpp", + "$av_codec_root_dir/services/engine/codec/audio/decoder/audio_ffmpeg_aac_decoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/decoder/audio_ffmpeg_decoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/decoder/audio_ffmpeg_flac_decoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/encoder/audio_ffmpeg_encoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/encoder/audio_ffmpeg_aac_encoder_plugin.cpp", + "$av_codec_root_dir/services/engine/codec/audio/encoder/audio_ffmpeg_flac_encoder_plugin.cpp", + ] + + deps = [ + "$av_codec_root_dir/services/engine/base:av_codec_codec_base", + "$av_codec_root_dir/services/engine/common:av_codec_engine_common", + "//third_party/ffmpeg:libohosffmpeg", + ] + + public_deps = [ + "$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", + "//commonlibrary/c_utils/base:utils", + "//third_party/bounds_checking_function:libsec_static", + ] + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/engine/codec/audio/audio_buffer_info.cpp b/services/engine/codec/audio/audio_buffer_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1fb1f2f33aa4a851252b676a296bca6041d14a27 --- /dev/null +++ b/services/engine/codec/audio/audio_buffer_info.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2023-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 "audio_buffer_info.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "securec.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioBufferInfo"}; +} + +namespace OHOS { +namespace Media { +AudioBufferInfo::AudioBufferInfo(const uint32_t &bufferSize, const std::string_view &name, const uint32_t &metaSize, + size_t align) + : isHasMeta_(false), + isEos_(false), + status_(BufferStatus::IDEL), + bufferSize_(bufferSize), + metaSize_(metaSize), + name_(name), + buffer_(nullptr), + metadata_(nullptr), + flag_(AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE) +{ + if (metaSize_ > 0) { + metadata_ = + std::make_shared(metaSize_, AVSharedMemory::Flags::FLAGS_READ_ONLY, std::string(name_)); + int32_t ret = metadata_->Init(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Create metadata avsharedmemory failed, ret = %{public}d", ret); + } + isHasMeta_ = true; + } + + buffer_ = + std::make_shared(bufferSize_, AVSharedMemory::Flags::FLAGS_READ_WRITE, std::string(name_)); + int32_t ret = buffer_->Init(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Create buffer avsharedmemory failed, ret = %{public}d", ret); + } + AVCODEC_LOGI("AudioBufferInfo constructor %{public}s buffer.", name_.data()); +} + +AudioBufferInfo::~AudioBufferInfo() +{ + AVCODEC_LOGI("AudioBufferInfo destructor %{public}s buffer.", name_.data()); + isEos_ = false; + status_ = BufferStatus::IDEL; + + if (buffer_) { + buffer_.reset(); + buffer_ = nullptr; + } + + if (metadata_) { + metadata_.reset(); + metadata_ = nullptr; + } +} + +std::shared_ptr AudioBufferInfo::GetBuffer() const noexcept +{ + return buffer_; +} + +BufferStatus AudioBufferInfo::GetStatus() const noexcept +{ + return status_; +} + +bool AudioBufferInfo::IsAvilable() const noexcept +{ + return status_ == BufferStatus::IDEL; +} + +bool AudioBufferInfo::CheckIsEos() const noexcept +{ + return isEos_; +} + +bool AudioBufferInfo::SetBufferOwned() +{ + if (buffer_) { + status_ = BufferStatus::OWNE_BY_CLIENT; + return true; + } + return false; +} + +void AudioBufferInfo::SetEos(bool eos) +{ + isEos_ = eos; + if (isEos_) { + flag_ = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS; + } else { + flag_ = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + } +} + +void AudioBufferInfo::SetBufferAttr(const AVCodecBufferInfo &attr) +{ + info_ = attr; +} + +AVCodecBufferInfo AudioBufferInfo::GetBufferAttr() const noexcept +{ + return info_; +} + +AVCodecBufferFlag AudioBufferInfo::GetFlag() const noexcept +{ + return flag_; +} + +std::shared_ptr AudioBufferInfo::GetMetadata() const noexcept +{ + return metadata_; +} + +bool AudioBufferInfo::IsHasMetaData() const noexcept +{ + return isHasMeta_; +} + +bool AudioBufferInfo::ResetBuffer() +{ + isEos_ = false; + status_ = BufferStatus::IDEL; + if (buffer_) { + buffer_->ClearUsedSize(); + } + return true; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/audio_buffers_manager.cpp b/services/engine/codec/audio/audio_buffers_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2af145665c8f471dccde805843fd1ab446a0d00 --- /dev/null +++ b/services/engine/codec/audio/audio_buffers_manager.cpp @@ -0,0 +1,137 @@ +/* + * 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 "audio_buffers_manager.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioBuffersManager"}; +} + +namespace OHOS { +namespace Media { +constexpr short DEFALT_BUFFER_LENGTH = 8; +constexpr short DEFALT_SLEEP_TIME = 500; + +AudioBuffersManager::~AudioBuffersManager() {} + +AudioBuffersManager::AudioBuffersManager(const uint32_t &bufferSize, const std::string_view &name, + const uint32_t &metaSize, size_t align) + : isRunning_(true), + bufferSize_(bufferSize), + metaSize_(metaSize), + align_(align), + name_(name), + bufferInfo_(DEFALT_BUFFER_LENGTH) +{ + initBuffers(); +} + +std::shared_ptr AudioBuffersManager::getMemory(const uint32_t &index) const noexcept +{ + if (index >= bufferInfo_.size()) { + return nullptr; + } + auto bufferInfo = bufferInfo_[index]; + return bufferInfo; +} + +bool AudioBuffersManager::SetBufferBusy(const uint32_t &index) +{ + if (index < bufferInfo_.size()) { + bufferInfo_[index]->SetBufferOwned(); + return true; + } + return false; +} + +void AudioBuffersManager::initBuffers() +{ + std::unique_lock lock(stateMutex_); + AVCODEC_LOGI("start allocate %{public}s buffers,buffer size:%{public}d", name_.data(), bufferSize_); + for (size_t i = 0; i < DEFALT_BUFFER_LENGTH; i++) { + bufferInfo_[i] = std::make_shared(bufferSize_, name_, metaSize_, align_); + inBufIndexQue_.push(i); + } + AVCODEC_LOGI("end allocate %{public}s buffers", name_.data()); +} + +bool AudioBuffersManager::RequestNewBuffer(uint32_t *index, std::shared_ptr &buffer) +{ + buffer = createNewBuffer(); + if (buffer == nullptr) { + return false; + } + *index = bufferInfo_.size() - 1; + return true; +} + +bool AudioBuffersManager::RequestAvialbaleIndex(uint32_t *index) +{ + while (inBufIndexQue_.empty() && isRunning_) { + AVCODEC_LOGD("Request empty %{public}s buffer", name_.data()); + std::unique_lock aLock(avilableMuxt_); + avilableCondition_.wait_for(aLock, std::chrono::milliseconds(DEFALT_SLEEP_TIME), + [this] { return !inBufIndexQue_.empty() || !isRunning_; }); + } + + if (!isRunning_) { + return false; + } + + std::unique_lock lock(stateMutex_); + *index = inBufIndexQue_.front(); + bufferInfo_[*index]->SetBufferOwned(); + inBufIndexQue_.pop(); + return true; +} + +void AudioBuffersManager::ReleaseAll() +{ + AVCODEC_LOGI("step in release all %{public}s buffer.", name_.data()); + for (uint32_t i = 0; i < bufferInfo_.size(); ++i) { + bufferInfo_[i]->ResetBuffer(); + inBufIndexQue_.push(i); + } + AVCODEC_LOGI("step out release all %{public}s buffer.", name_.data()); + isRunning_ = false; + avilableCondition_.notify_all(); +} + +void AudioBuffersManager::SetRunning() +{ + isRunning_ = true; +} + +bool AudioBuffersManager::RelaseBuffer(const uint32_t &index) +{ + if (index < bufferInfo_.size()) { + std::unique_lock lock(avilableMuxt_); + bufferInfo_[index]->ResetBuffer(); + inBufIndexQue_.push(index); + avilableCondition_.notify_all(); + return true; + } + return false; +} + +std::shared_ptr AudioBuffersManager::createNewBuffer() +{ + std::shared_ptr buffer = std::make_shared(bufferSize_, name_, metaSize_, align_); + bufferInfo_.emplace_back(buffer); + return buffer; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/audio_codec_worker.cpp b/services/engine/codec/audio/audio_codec_worker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25710ff797bc03cd88969c5cd2af5685dbfc1e56 --- /dev/null +++ b/services/engine/codec/audio/audio_codec_worker.cpp @@ -0,0 +1,379 @@ +/* + * 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 "audio_codec_worker.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "utils.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioCodecWorker"}; +} + +namespace OHOS { +namespace Media { +constexpr short DEFAULT_TRY_DECODE_TIME = 10; +constexpr int timeoutMs = 1000; +const std::string_view INPUT_BUFFER = "inputBuffer"; +const std::string_view OUTPUT_BUFFER = "outputBuffer"; +const std::string_view ASYNC_HANDLE_INPUT = "AsyncHandleInput"; +const std::string_view ASYNC_DECODE_FRAME = "AsyncDecodeFrame"; + +AudioCodecWorker::AudioCodecWorker(const std::shared_ptr &codec, + const std::shared_ptr &callback) + : isRunning(true), + isProduceInput(true), + codec_(codec), + inputBufferSize(codec_->getInputBufferSize()), + outputBufferSize(codec_->getOutputBufferSize()), + inputTask_(std::make_unique(ASYNC_HANDLE_INPUT)), + outputTask_(std::make_unique(ASYNC_DECODE_FRAME)), + callback_(callback), + inputBuffer_(std::make_shared(inputBufferSize, INPUT_BUFFER, 0, 0)), + outputBuffer_(std::make_shared(outputBufferSize, OUTPUT_BUFFER, 0, 0)) +{ + inputTask_->RegisterHandler([this] { produceInputBuffer(); }); + outputTask_->RegisterHandler([this] { consumerOutputBuffer(); }); +} + +AudioCodecWorker::~AudioCodecWorker() +{ + AVCODEC_LOGD("release all data of codec worker in destructor."); + dispose(); + + if (inputTask_) { + inputTask_->Stop(); + inputTask_.reset(); + inputTask_ = nullptr; + } + if (outputTask_) { + outputTask_->Stop(); + outputTask_.reset(); + outputTask_ = nullptr; + } + + if (codec_) { + codec_ = nullptr; + } + + if (callback_) { + callback_.reset(); + callback_ = nullptr; + } +} + +bool AudioCodecWorker::PushInputData(const uint32_t &index) +{ + AVCODEC_LOGD("Worker PushInputData enter"); + + if (!isRunning) { + return true; + } + + if (!callback_) { + AVCODEC_LOGE("push input buffer failed in worker, callback is nullptr, please check the callback."); + dispose(); + return false; + } + if (!codec_) { + AVCODEC_LOGE("push input buffer failed in worker, codec is nullptr, please check the codec."); + dispose(); + return false; + } + + { + std::unique_lock lock(stateMutex_); + inBufIndexQue_.push(index); + } + + isProduceInput = true; + inputCondition_.notify_all(); + outputCondition_.notify_all(); + return true; +} + +bool AudioCodecWorker::Configure() +{ + AVCODEC_LOGD("Worker Configure enter"); + if (!codec_) { + AVCODEC_LOGE("Configure failed in worker, codec is nullptr, please check the codec."); + return false; + } + if (inputTask_ != nullptr) { + inputTask_->RegisterHandler([this] { produceInputBuffer(); }); + } else { + AVCODEC_LOGE("Configure failed in worker, inputTask_ is nullptr, please check the inputTask_."); + return false; + } + if (outputTask_ != nullptr) { + outputTask_->RegisterHandler([this] { consumerOutputBuffer(); }); + } else { + AVCODEC_LOGE("Configure failed in worker, outputTask_ is nullptr, please check the outputTask_."); + return false; + } + return true; +} + +bool AudioCodecWorker::Start() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker Start enter"); + if (!callback_) { + AVCODEC_LOGE("Start failed in worker, callback is nullptr, please check the callback."); + return false; + } + if (!codec_) { + AVCODEC_LOGE("Start failed in worker, codec_ is nullptr, please check the codec_."); + return false; + } + bool result = begin(); + return result; +} + +bool AudioCodecWorker::Stop() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker Stop enter"); + dispose(); + + if (inputTask_) { + inputTask_->Stop(); + } else { + AVCODEC_LOGE("Stop failed in worker, inputTask_ is nullptr, please check the inputTask_."); + return false; + } + if (outputTask_) { + outputTask_->Stop(); + } else { + AVCODEC_LOGE("Stop failed in worker, outputTask_ is nullptr, please check the outputTask_."); + return false; + } + return true; +} + +bool AudioCodecWorker::Pause() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker Pause enter"); + dispose(); + + if (inputTask_) { + inputTask_->Pause(); + } else { + AVCODEC_LOGE("Pause failed in worker, inputTask_ is nullptr, please check the inputTask_."); + return false; + } + if (outputTask_) { + outputTask_->Pause(); + } else { + AVCODEC_LOGE("Pause failed in worker, outputTask_ is nullptr, please check the outputTask_."); + return false; + } + return true; +} + +bool AudioCodecWorker::Resume() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker Resume enter"); + if (!callback_) { + AVCODEC_LOGE("Resume failed in worker, callback_ is nullptr, please check the callback_."); + return false; + } + if (!codec_) { + AVCODEC_LOGE("Resume failed in worker, codec_ is nullptr, please check the codec_."); + return false; + } + bool result = begin(); + return result; +} + +bool AudioCodecWorker::Release() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker Release enter"); + dispose(); + + if (inputTask_) { + inputTask_->Stop(); + inputTask_.reset(); + inputTask_ = nullptr; + } + if (outputTask_) { + outputTask_->Stop(); + outputTask_.reset(); + outputTask_ = nullptr; + } + if (codec_) { + codec_ = nullptr; + } + if (callback_) { + callback_.reset(); + callback_ = nullptr; + } + AVCODEC_LOGD("Worker Release end"); + return true; +} + +std::shared_ptr AudioCodecWorker::GetInputBuffer() const noexcept +{ + AVCODEC_LOGD("Worker GetInputBuffer enter"); + return inputBuffer_; +} + +std::shared_ptr AudioCodecWorker::GetOutputBuffer() const noexcept +{ + AVCODEC_LOGD("Worker GetOutputBuffer enter"); + return outputBuffer_; +} + +std::shared_ptr AudioCodecWorker::GetOutputBufferInfo(const uint32_t &index) const noexcept +{ + return outputBuffer_->getMemory(index); +} + +std::shared_ptr AudioCodecWorker::GetInputBufferInfo(const uint32_t &index) const noexcept +{ + return inputBuffer_->getMemory(index); +} + +void AudioCodecWorker::produceInputBuffer() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker produceInputBuffer enter"); + if (!isRunning) { + SleepFor(DEFAULT_TRY_DECODE_TIME); + return; + } + if (isProduceInput) { + isProduceInput = false; + uint32_t index; + if (inputBuffer_->RequestAvialbaleIndex(&index)) { + AVCODEC_LOGD("produceInputBuffer request success."); + auto inputBuffer = GetInputBufferInfo(index); + callback_->OnInputBufferAvailable(index); + } else { + AVCODEC_LOGD("produceInputBuffer request failed."); + SleepFor(DEFAULT_TRY_DECODE_TIME); + isProduceInput = true; + } + } + + std::unique_lock lock(inputMuxt_); + inputCondition_.wait_for(lock, std::chrono::milliseconds(timeoutMs), + [this] { return (isProduceInput.load() || !isRunning); }); + AVCODEC_LOGD("Worker produceInputBuffer exit"); +} + +void AudioCodecWorker::consumerOutputBuffer() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Worker consumerOutputBuffer enter"); + if (!isRunning) { + SleepFor(DEFAULT_TRY_DECODE_TIME); + return; + } + while (!inBufIndexQue_.empty() && isRunning) { + uint32_t index; + if (outputBuffer_->RequestAvialbaleIndex(&index)) { + uint32_t inputIndex = inBufIndexQue_.front(); + inBufIndexQue_.pop(); + + auto inputBuffer = GetInputBufferInfo(inputIndex); + + int32_t ret = codec_->processSendData(inputBuffer); + inputBuffer_->RelaseBuffer(inputIndex); + + if (ret == AVCodecServiceErrCode::AVCS_ERR_NOT_ENOUGH_DATA) { + AVCODEC_LOGW("current input buffer is not enough,skip this frame."); + outputBuffer_->RelaseBuffer(index); + continue; + } + + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK && ret != AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM) { + AVCODEC_LOGE("process input buffer error!"); + outputBuffer_->RelaseBuffer(index); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, ret); + return; + } + + auto outBuffer = GetOutputBufferInfo(index); + ret = codec_->processRecieveData(outBuffer); + if (ret == AVCodecServiceErrCode::AVCS_ERR_NOT_ENOUGH_DATA) { + AVCODEC_LOGW("current ouput buffer is not enough,skip this frame."); + outputBuffer_->RelaseBuffer(index); + continue; + } + + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK && ret != AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM) { + AVCODEC_LOGE("process output buffer error!"); + outputBuffer_->RelaseBuffer(index); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, ret); + return; + } + AVCODEC_LOGD("Work consumerOutputBuffer callback_"); + callback_->OnOutputBufferAvailable(index, outBuffer->GetBufferAttr(), outBuffer->GetFlag()); + } + } + + std::unique_lock lock(outputMuxt_); + outputCondition_.wait_for(lock, std::chrono::milliseconds(timeoutMs), + [this] { return (inBufIndexQue_.size() > 0 || !isRunning); }); + AVCODEC_LOGD("Work consumerOutputBuffer exit"); +} + +void AudioCodecWorker::dispose() +{ + AVCODEC_LOGD("Worker dispose enter"); + isRunning = false; + isProduceInput = false; + + while (!inBufIndexQue_.empty()) { + inBufIndexQue_.pop(); + } + + inputCondition_.notify_all(); + outputCondition_.notify_all(); + + inputBuffer_->ReleaseAll(); + outputBuffer_->ReleaseAll(); +} + +bool AudioCodecWorker::begin() +{ + AVCODEC_LOGD("Worker begin enter"); + isRunning = true; + isProduceInput = true; + + inputBuffer_->SetRunning(); + outputBuffer_->SetRunning(); + + if (inputTask_) { + inputTask_->Start(); + } else { + return false; + } + if (outputTask_) { + outputTask_->Start(); + } else { + return false; + } + inputCondition_.notify_all(); + outputCondition_.notify_all(); + return true; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/audio_ffmpeg_adapter.cpp b/services/engine/codec/audio/audio_ffmpeg_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4236433587813b5c1db8b5f7aed68b08861f0ac9 --- /dev/null +++ b/services/engine/codec/audio/audio_ffmpeg_adapter.cpp @@ -0,0 +1,523 @@ +/* + * 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 "audio_ffmpeg_adapter.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "media_description.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegAdapter"}; +} + +namespace OHOS { +namespace Media { +AudioFFMpegAdapter::AudioFFMpegAdapter(const std::string &name) : state_(CodecState::RELEASED), name_(name) +{ + AVCODEC_LOGD("enter constructor of adapter,name:%{public}s,name after:%{public}s", name.data(), name_.data()); +} + +AudioFFMpegAdapter::~AudioFFMpegAdapter() +{ + callback_ = nullptr; + if (audioCodec) { + audioCodec->release(); + } + state_ = CodecState::RELEASED; + audioCodec = nullptr; +} + +int32_t AudioFFMpegAdapter::SetCallback(const std::shared_ptr &callback) +{ + AVCODEC_SYNC_TRACE; + callback_ = callback; + AVCODEC_LOGD("SetCallback success"); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::Configure(const Format &format) +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Configure enter"); + + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT)) { + AVCODEC_LOGE("Configure failed, missing channel count key in format."); + return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT; + } + + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_SAMPLE_RATE)) { + AVCODEC_LOGE("Configure failed,missing sample rate key in format."); + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE; + } + + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_BITRATE)) { + AVCODEC_LOGE("adapter configure error,missing bits rate key in format."); + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_BIT_RATE; + } + + if (state_ != CodecState::RELEASED) { + AVCODEC_LOGE("Configure failed, state = %{public}s .", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + AVCODEC_LOGI("state from %{public}s to INITLIZING,name:%{public}s,name size:%{public}d", + stateToString(state_).data(), name_.data(), name_.size()); + state_ = CodecState::INITLIZING; + auto ret = doInit(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + return ret; + } + + if (state_ != CodecState::INITLIZED) { + AVCODEC_LOGE("Configure failed, state =%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_ERROR; + } + + ret = doConfigure(format); + AVCODEC_LOGD("Configure exit"); + return ret; +} + +int32_t AudioFFMpegAdapter::Start() +{ + AVCODEC_LOGD("Start enter"); + if (!callback_) { + AVCODEC_LOGE("adapter start error, callback not initlized ."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + if (!audioCodec) { + AVCODEC_LOGE("adapter start error, audio codec not initlized ."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + if (state_ == CodecState::FLUSHED) { + AVCODEC_LOGI("Start, doResume"); + return doResume(); + } + + if (state_ != CodecState::INITLIZED) { + AVCODEC_LOGE("Start is incorrect, state = %{public}s .", stateToString(state_).data()); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + AVCODEC_LOGI("Start, state from %{public}s to STARTING", stateToString(state_).data()); + state_ = CodecState::STARTING; + auto ret = doStart(); + return ret; +} + +int32_t AudioFFMpegAdapter::Pause() +{ + return AVCodecServiceErrCode::AVCS_ERR_OK; +} +int32_t AudioFFMpegAdapter::Resume() +{ + return AVCodecServiceErrCode::AVCS_ERR_OK; +} +int32_t AudioFFMpegAdapter::Stop() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("Stop enter"); + if (!callback_) { + AVCODEC_LOGE("Stop failed, call back not initlized."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + if (state_ == CodecState::INITLIZED || state_ == CodecState::RELEASED || state_ == CodecState::STOPPING || + state_ == CodecState::RRELEASING) { + AVCODEC_LOGD("Stop, state_=%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + state_ = CodecState::STOPPING; + auto ret = doStop(); + AVCODEC_LOGI("adapter Stop, state from %{public}s to INITLIZED", stateToString(state_).data()); + state_ = CodecState::INITLIZED; + return ret; +} + +int32_t AudioFFMpegAdapter::Flush() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter Flush enter"); + if (!callback_) { + AVCODEC_LOGE("adapter flush error, call back not initlized ."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + if (state_ == CodecState::FLUSHED) { + AVCODEC_LOGW("Flush, state is already flushed, state_=%{public}s .", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + if (state_ != CodecState::RUNNING) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("Flush failed, state =%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; + } + AVCODEC_LOGI("Flush, state from %{public}s to FLUSHING", stateToString(state_).data()); + state_ = CodecState::FLUSHING; + auto ret = doFlush(); + return ret; +} + +int32_t AudioFFMpegAdapter::Reset() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter Reset enter"); + if (worker_) { + worker_->Release(); + } + int32_t status = audioCodec->reset(); + state_ = CodecState::INITLIZED; + AVCODEC_LOGI("adapter Reset, state from %{public}s to INITLIZED", stateToString(state_).data()); + return status; +} + +int32_t AudioFFMpegAdapter::Release() +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter Release enter"); + if (state_ == CodecState::RELEASED || state_ == CodecState::RRELEASING) { + AVCODEC_LOGW("adapter Release, state isnot completely correct, state =%{public}s .", + stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + + if (state_ == CodecState::INITLIZING) { + AVCODEC_LOGW("adapter Release, state isnot completely correct, state =%{public}s .", + stateToString(state_).data()); + state_ = CodecState::RRELEASING; + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + + if (state_ == CodecState::STARTING || state_ == CodecState::RUNNING || state_ == CodecState::STOPPING) { + AVCODEC_LOGE("adapter Release, state is incorrect, state =%{public}s .", stateToString(state_).data()); + } + AVCODEC_LOGI("adapter Release, state from %{public}s to RRELEASING", stateToString(state_).data()); + state_ = CodecState::RRELEASING; + auto ret = doRelease(); + return ret; +} + +int32_t AudioFFMpegAdapter::NotifyEos() +{ + AVCODEC_SYNC_TRACE; + Flush(); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::SetParameter(const Format &format) +{ + AVCODEC_SYNC_TRACE; + (void)format; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::GetOutputFormat(Format &format) +{ + AVCODEC_SYNC_TRACE; + format = audioCodec->GetFormat(); + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_CODEC_NAME)) { + format.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_NAME, name_); + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +std::shared_ptr AudioFFMpegAdapter::GetInputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter GetInputBuffer enter"); + if (!callback_) { + AVCODEC_LOGE("adapter get input buffer error, call back not initlized ."); + return nullptr; + } + if (index < 0) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL); + AVCODEC_LOGE("index=%{public}d error", index); + return nullptr; + } + + std::shared_ptr result = worker_->GetInputBufferInfo(index); + if (result == nullptr) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + AVCODEC_LOGE("getMemory failed"); + return nullptr; + } + + if (result->GetStatus() == BufferStatus::IDEL) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("GetStatus is IDEL"); + return nullptr; + } + + return result->GetBuffer(); +} + +int32_t AudioFFMpegAdapter::QueueInputBuffer(size_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag &flag) +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter QueueInputBuffer enter"); + if (!callback_) { + AVCODEC_LOGE("adapter queue input buffer error, call back not initlized ."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + if (index < 0) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL); + AVCODEC_LOGE("index=%{public}d error", index); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + + auto result = worker_->GetInputBufferInfo(index); + if (result == nullptr) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + AVCODEC_LOGE("getMemory failed"); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + + if (result->GetStatus() != BufferStatus::OWNE_BY_CLIENT) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("GetStatus failed"); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + result->SetBufferAttr(info); + if (flag == AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS) { + result->SetEos(true); + } + worker_->PushInputData(index); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +std::shared_ptr AudioFFMpegAdapter::GetOutputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter GetOutputBuffer enter"); + if (!callback_) { + AVCODEC_LOGE("adapter get output buffer error, call back not initlized ."); + return nullptr; + } + + if (index < 0) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL); + AVCODEC_LOGE("index=%{public}d error", index); + return nullptr; + } + + auto result = worker_->GetOutputBufferInfo(index); + if (result == nullptr) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + AVCODEC_LOGE("getMemory failed"); + return nullptr; + } + + if (result->GetStatus() == BufferStatus::IDEL) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + return nullptr; + } + + return result->GetBuffer(); +} + +int32_t AudioFFMpegAdapter::ReleaseOutputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + AVCODEC_LOGD("adapter ReleaseOutputBuffer enter"); + if (!callback_) { + AVCODEC_LOGE("adapter release output buffer error, call back not initlized ."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + if (index < 0) { + AVCODEC_LOGE("index=%{public}d error", index); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + + auto outBufferInfo = worker_->GetOutputBufferInfo(index); + if (outBufferInfo == nullptr) { + AVCODEC_LOGE("index=%{public}d error", index); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + bool isEos = outBufferInfo->CheckIsEos(); + + auto outBuffer = worker_->GetOutputBuffer(); + if (outBuffer == nullptr) { + AVCODEC_LOGE("index=%{public}d error", index); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + bool result = outBuffer->RelaseBuffer(index); + if (!result) { + AVCODEC_LOGE("RelaseBuffer failed"); + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + + if (isEos) { + NotifyEos(); + } + + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doInit() +{ + AVCODEC_SYNC_TRACE; + if (name_.empty()) { + state_ = CodecState::RELEASED; + AVCODEC_LOGE("doInit failed, because name is empty"); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + AVCODEC_LOGI("adapter doInit, codec name:%{public}s", name_.data()); + audioCodec = AudioFFMpegBaseCodec::make_sharePtr(name_); + if (audioCodec == nullptr) { + state_ = CodecState::RELEASED; + AVCODEC_LOGE("Initlize failed, because create codec failed. name: %{public}s.", name_.data()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + AVCODEC_LOGI("adapter doInit, state from %{public}s to INITLIZED", stateToString(state_).data()); + state_ = CodecState::INITLIZED; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doConfigure(const Format &format) +{ + AVCODEC_SYNC_TRACE; + if (state_ != CodecState::INITLIZED) { + AVCODEC_LOGE("adapter configure failed because state is incrrect,state:%{public}d.", + static_cast(state_.load())); + state_ = CodecState::RELEASED; + if (callback_) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + } + AVCODEC_LOGE("state_=%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; + } + int32_t ret = audioCodec->init(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("configure failed, because codec init failed,error:%{public}d.", static_cast(ret)); + state_ = CodecState::RELEASED; + if (callback_) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, ret); + } + return ret; + } + return ret; +} + +int32_t AudioFFMpegAdapter::doStart() +{ + AVCODEC_SYNC_TRACE; + if (state_ != CodecState::STARTING) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("doStart failed, state = %{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; + } + + AVCODEC_LOGI("adapter doStart, state from %{public}s to RUNNING", stateToString(state_).data()); + state_ = CodecState::RUNNING; + worker_ = std::make_shared(audioCodec, callback_); + worker_->Start(); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doResume() +{ + AVCODEC_LOGI("adapter doResume, state from %{public}s to RESUMING", stateToString(state_).data()); + state_ = CodecState::RESUMING; + worker_->Resume(); + AVCODEC_LOGI("adapter doResume, state from %{public}s to RUNNING", stateToString(state_).data()); + state_ = CodecState::RUNNING; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doStop() +{ + AVCODEC_SYNC_TRACE; + if (state_ == CodecState::RRELEASING) { + AVCODEC_LOGW("adapter doStop, state is not completely correct, state_=%{public}s .", + stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + + if (state_ != CodecState::STOPPING) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("doStop failed, state =%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE; + } + worker_->Stop(); + if (state_ == CodecState::STOPPING) { + AVCODEC_LOGI("adapter doStop, state from %{public}s to INITLIZED", stateToString(state_).data()); + state_ = CodecState::INITLIZED; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doFlush() +{ + AVCODEC_SYNC_TRACE; + if (state_ != CodecState::FLUSHING) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("doFlush failed, state_=%{public}s", stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + int32_t status = audioCodec->flush(); + + worker_->Pause(); + + state_ = CodecState::FLUSHED; + if (status != AVCodecServiceErrCode::AVCS_ERR_OK) { + callback_->OnError(AVCodecErrorType::AVCODEC_ERROR_INTERNAL, AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE); + AVCODEC_LOGE("status=%{public}d", static_cast(status)); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAdapter::doRelease() +{ + AVCODEC_SYNC_TRACE; + if (state_ == CodecState::RELEASED) { + AVCODEC_LOGW("adapter doRelease, state is not completely correct, state_=%{public}s .", + stateToString(state_).data()); + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + if (audioCodec != nullptr) { + audioCodec->release(); + } + if (worker_ != nullptr) { + worker_->Release(); + } + AVCODEC_LOGI("adapter doRelease, state from %{public}s to RELEASED", stateToString(state_).data()); + state_ = CodecState::RELEASED; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +std::string_view AudioFFMpegAdapter::stateToString(CodecState state) +{ + std::map stateStrMap = { + {CodecState::RELEASED, " RELEASED"}, {CodecState::INITLIZED, " INITLIZED"}, + {CodecState::FLUSHED, " FLUSHED"}, {CodecState::RUNNING, " RUNNING"}, + {CodecState::INITLIZING, " INITLIZING"}, {CodecState::STARTING, " STARTING"}, + {CodecState::STOPPING, " STOPPING"}, {CodecState::FLUSHING, " FLUSHING"}, + {CodecState::RESUMING, " RESUMING"}, {CodecState::RRELEASING, " RRELEASING"}, + }; + return stateStrMap[state]; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/decoder/audio_ffmpeg_aac_decoder_plugin.cpp b/services/engine/codec/audio/decoder/audio_ffmpeg_aac_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..413852c9f1dddc6f55cd5ea269df25a595ecd30e --- /dev/null +++ b/services/engine/codec/audio/decoder/audio_ffmpeg_aac_decoder_plugin.cpp @@ -0,0 +1,106 @@ +/* + * 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 "audio_ffmpeg_aac_decoder_plugin.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "media_description.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegAacDecoderPlugin"}; +} + +namespace OHOS { +namespace Media { +static constexpr uint32_t INPUT_BUFFER_SIZE_DEFAULT = 8192; +static constexpr uint32_t OUTPUT_BUFFER_SIZE_DEFAULT = 4 * 1024 * 8; + +AudioFFMpegAacDecoderPlugin::AudioFFMpegAacDecoderPlugin() : basePlugin(std::make_unique()) {} + +AudioFFMpegAacDecoderPlugin::~AudioFFMpegAacDecoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +int32_t AudioFFMpegAacDecoderPlugin::init(const Format &format) +{ + int type; + format.GetIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, type); + int32_t ret = AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + if (type == 1) { + ret = basePlugin->AllocateContext("aac"); + } else if (type == 0) { + ret = basePlugin->AllocateContext("aac_latm"); + } + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("AllocateContext failed, ret=%{public}d", ret); + return ret; + } + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("InitContext failed, ret=%{public}d", ret); + return ret; + } + return basePlugin->OpenContext(); +} + +int32_t AudioFFMpegAacDecoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegAacDecoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegAacDecoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegAacDecoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegAacDecoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegAacDecoderPlugin::getInputBufferSize() const +{ + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > INPUT_BUFFER_SIZE_DEFAULT) { + maxSize = INPUT_BUFFER_SIZE_DEFAULT; + } + return maxSize; +} + +uint32_t AudioFFMpegAacDecoderPlugin::getOutputBufferSize() const +{ + return OUTPUT_BUFFER_SIZE_DEFAULT; +} + +Format AudioFFMpegAacDecoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/decoder/audio_ffmpeg_decoder_plugin.cpp b/services/engine/codec/audio/decoder/audio_ffmpeg_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..33271afefab4edb46c80cae3cf5f30b984cdf448 --- /dev/null +++ b/services/engine/codec/audio/decoder/audio_ffmpeg_decoder_plugin.cpp @@ -0,0 +1,320 @@ +/* + * 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 "audio_ffmpeg_decoder_plugin.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "media_description.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFfmpegDecoderPlugin"}; +} + +namespace OHOS { +namespace Media { +AudioFfmpegDecoderPlugin::AudioFfmpegDecoderPlugin() + : hasExtra_(false), + maxInputSize_(-1), + bufferNum_(1), + bufferIndex_(1), + preBufferGroupPts_(0), + curBufferGroupPts_(0), + bufferGroupPtsDistance(0), + avCodec_(nullptr), + avCodecContext_(nullptr), + cachedFrame_(nullptr), + avPacket_(nullptr) +{ +} + +AudioFfmpegDecoderPlugin::~AudioFfmpegDecoderPlugin() +{ + CloseCtxLocked(); + avCodecContext_.reset(); +} + +int32_t AudioFfmpegDecoderPlugin::ProcessSendData(const std::shared_ptr &inputBuffer) +{ + int32_t ret = AVCodecServiceErrCode::AVCS_ERR_OK; + { + std::unique_lock lock(avMutext_); + if (avCodecContext_ == nullptr) { + AVCODEC_LOGE("avCodecContext_ is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_WRONG_STATE; + } + ret = SendBuffer(inputBuffer); + } + return ret; +} + +static 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 AudioFfmpegDecoderPlugin::GetMaxInputSize() const noexcept +{ + return maxInputSize_; +} + +bool AudioFfmpegDecoderPlugin::hasExtraData() const noexcept +{ + return hasExtra_; +} + +int32_t AudioFfmpegDecoderPlugin::SendBuffer(const std::shared_ptr &inputBuffer) +{ + if (!inputBuffer) { + AVCODEC_LOGE("inputBuffer is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + auto attr = inputBuffer->GetBufferAttr(); + if (!inputBuffer->CheckIsEos()) { + auto memory = inputBuffer->GetBuffer(); + const uint8_t *ptr = memory->GetBase(); + avPacket_->size = attr.size; + avPacket_->data = const_cast(ptr); + avPacket_->pts = attr.presentationTimeUs; + } else { + avPacket_->size = 0; + avPacket_->data = nullptr; + avPacket_->pts = attr.presentationTimeUs; + } + auto ret = avcodec_send_packet(avCodecContext_.get(), avPacket_.get()); + av_packet_unref(avPacket_.get()); + if (ret == 0) { + return AVCodecServiceErrCode::AVCS_ERR_OK; + } else if (ret == AVERROR(EAGAIN)) { + AVCODEC_LOGE("ret=%{public}d", ret); + return AVCodecServiceErrCode::AVCS_ERR_AGAIN; + } else if (ret == AVERROR_EOF) { + AVCODEC_LOGE("ret=%{public}d", ret); + return AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM; + } else { + AVCODEC_LOGE("ret=%{public}d", ret); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } +} + +int32_t AudioFfmpegDecoderPlugin::ProcessRecieveData(std::shared_ptr &outBuffer) +{ + if (!outBuffer) { + AVCODEC_LOGE("outBuffer is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + if (avCodecContext_ == nullptr) { + AVCODEC_LOGE("avCodecContext_ is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_WRONG_STATE; + } + int32_t status; + { + std::unique_lock l(avMutext_); + status = ReceiveBuffer(outBuffer); + } + return status; +} + +int32_t AudioFfmpegDecoderPlugin::ReceiveBuffer(std::shared_ptr &outBuffer) +{ + auto ret = avcodec_receive_frame(avCodecContext_.get(), cachedFrame_.get()); + int32_t status; + if (ret >= 0) { + AVCODEC_LOGD("receive one frame"); + if (cachedFrame_->pts != AV_NOPTS_VALUE) { + preBufferGroupPts_ = curBufferGroupPts_; + curBufferGroupPts_ = cachedFrame_->pts; + if (bufferGroupPtsDistance == 0) { + bufferGroupPtsDistance = abs(curBufferGroupPts_ - preBufferGroupPts_); + } + if (bufferIndex_ >= bufferNum_) { + bufferNum_ = bufferIndex_; + } + bufferIndex_ = 1; + } else { + bufferIndex_++; + if (abs(curBufferGroupPts_ - preBufferGroupPts_) > bufferGroupPtsDistance) { + cachedFrame_->pts = curBufferGroupPts_; + preBufferGroupPts_ = curBufferGroupPts_; + } else { + cachedFrame_->pts = + curBufferGroupPts_ + abs(curBufferGroupPts_ - preBufferGroupPts_) * (bufferIndex_ - 1) / bufferNum_; + } + } + status = ReceiveFrameSucc(outBuffer); + } else if (ret == AVERROR_EOF) { + AVCODEC_LOGI("eos received"); + outBuffer->SetEos(true); + avcodec_flush_buffers(avCodecContext_.get()); + status = AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM; + } else if (ret == AVERROR(EAGAIN)) { + AVCODEC_LOGE("audio decoder not enough data"); + status = AVCodecServiceErrCode::AVCS_ERR_NOT_ENOUGH_DATA; + } else { + AVCODEC_LOGE("audio decoder receive unknow error"); + status = AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + av_frame_unref(cachedFrame_.get()); + return status; +} + +int32_t AudioFfmpegDecoderPlugin::ReceiveFrameSucc(std::shared_ptr &outBuffer) +{ + int32_t channels = cachedFrame_->channels; + int32_t samples = cachedFrame_->nb_samples; + auto sampleFormat = static_cast(cachedFrame_->format); + int32_t bytePerSample = av_get_bytes_per_sample(sampleFormat); + int32_t outputSize = samples * bytePerSample * channels; + auto ioInfoMem = outBuffer->GetBuffer(); + if (ioInfoMem->GetSize() < outputSize) { + AVCODEC_LOGW("output buffer size is not enough"); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + if (av_sample_fmt_is_planar(avCodecContext_->sample_fmt)) { + size_t planarSize = outputSize / channels; + for (int32_t idx = 0; idx < channels; idx++) { + ioInfoMem->Write(cachedFrame_->extended_data[idx], planarSize); + } + } else { + ioInfoMem->Write(cachedFrame_->data[0], outputSize); + } + auto attr = outBuffer->GetBufferAttr(); + attr.presentationTimeUs = static_cast(cachedFrame_->pts); + attr.size = outputSize; + outBuffer->SetBufferAttr(attr); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegDecoderPlugin::Reset() +{ + CloseCtxLocked(); + avCodecContext_.reset(); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegDecoderPlugin::Release() +{ + std::unique_lock lock(avMutext_); + auto ret = CloseCtxLocked(); + avCodecContext_.reset(); + return ret; +} + +int32_t AudioFfmpegDecoderPlugin::Flush() +{ + std::unique_lock lock(avMutext_); + if (avCodecContext_ != nullptr) { + avcodec_flush_buffers(avCodecContext_.get()); + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegDecoderPlugin::AllocateContext(const std::string &name) +{ + { + std::unique_lock lock(avMutext_); + avCodec_ = std::shared_ptr(const_cast(avcodec_find_decoder_by_name(name.c_str())), + [](AVCodec *ptr) { (void)ptr; }); + cachedFrame_ = std::shared_ptr(av_frame_alloc(), [](AVFrame *fp) { av_frame_free(&fp); }); + } + if (avCodec_ == nullptr) { + AVCODEC_LOGE("AllocateContext fail,parameter avcodec is nullptr."); + return AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT_PROTOCOL_TYPE; + } + + AVCodecContext *context = nullptr; + { + std::unique_lock lock(avMutext_); + context = avcodec_alloc_context3(avCodec_.get()); + + avCodecContext_ = std::shared_ptr(context, [](AVCodecContext *ptr) { + avcodec_free_context(&ptr); + avcodec_close(ptr); + }); + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegDecoderPlugin::InitContext(const Format &format) +{ + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, avCodecContext_->channels); + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, avCodecContext_->sample_rate); + format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, avCodecContext_->bit_rate); + format.GetLongValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize_); + + size_t extraSize; + if (format.GetBuffer(MediaDescriptionKey::MD_KEY_CODEC_CONFIG, &avCodecContext_->extradata, extraSize)) { + avCodecContext_->extradata_size = extraSize; + hasExtra_ = true; + } + + avCodecContext_->sample_fmt = AV_SAMPLE_FMT_S16; + avCodecContext_->request_sample_fmt = avCodecContext_->sample_fmt; + avCodecContext_->workaround_bugs = + static_cast(avCodecContext_->workaround_bugs) | static_cast(FF_BUG_AUTODETECT); + avCodecContext_->err_recognition = 1; + format_ = format; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegDecoderPlugin::OpenContext() +{ + avPacket_ = std::shared_ptr(av_packet_alloc(), [](AVPacket *ptr) { av_packet_free(&ptr); }); + { + std::unique_lock lock(avMutext_); + auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr); + if (res != 0) { + AVCODEC_LOGE("avcodec open error %{public}s", AVStrError(res).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +Format AudioFfmpegDecoderPlugin::GetFormat() const noexcept +{ + return format_; +} + +std::shared_ptr AudioFfmpegDecoderPlugin::GetCodecContext() const noexcept +{ + return avCodecContext_; +} + +std::shared_ptr AudioFfmpegDecoderPlugin::GetCodecAVPacket() const noexcept +{ + return avPacket_; +} + +std::shared_ptr AudioFfmpegDecoderPlugin::GetCodecCacheFrame() const noexcept +{ + return cachedFrame_; +} + +int32_t AudioFfmpegDecoderPlugin::CloseCtxLocked() +{ + if (avCodecContext_ != nullptr) { + auto res = avcodec_close(avCodecContext_.get()); + if (res != 0) { + AVCODEC_LOGE("avcodec close failed, res=%{public}d", res); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/decoder/audio_ffmpeg_flac_decoder_plugin.cpp b/services/engine/codec/audio/decoder/audio_ffmpeg_flac_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0af486d74f2c2366f805528427438c39242faa27 --- /dev/null +++ b/services/engine/codec/audio/decoder/audio_ffmpeg_flac_decoder_plugin.cpp @@ -0,0 +1,141 @@ +/* + * 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 "audio_ffmpeg_flac_decoder_plugin.h" +#include "avcodec_errors.h" +#include "media_description.h" + +namespace { +constexpr int getInputBufferSize_ = 65536; +constexpr int getOutputBufferSize_ = 65536; +constexpr int minChannels = 1; +constexpr int maxChannels = 8; +static const int flac_encoder_sample_rate_table[] = { + 0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, +}; +static const int flac_encoder_bits_sample_table[] = {16, 24, 32}; +} // namespace + +namespace OHOS { +namespace Media { +AudioFFMpegFlacDecoderPlugin::AudioFFMpegFlacDecoderPlugin() : basePlugin(std::make_unique()) +{ +} + +AudioFFMpegFlacDecoderPlugin::~AudioFFMpegFlacDecoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +static bool isTrueSampleRate(int sample) +{ + for (auto i : flac_encoder_sample_rate_table) { + if (i == sample) { + return true; + } + } + return false; +} + +static bool isTrueBitsPerSample(int bits_per_coded_sample) +{ + for (auto i : flac_encoder_bits_sample_table) { + if (i == bits_per_coded_sample) { + return true; + } + } + return false; +} + +int32_t AudioFFMpegFlacDecoderPlugin::init(const Format &format) +{ + int channels, sample_rate, bits_per_coded_sample; + int64_t bit_rate; + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channels); + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sample_rate); + format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, bit_rate); + format.GetIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, bits_per_coded_sample); + if (!isTrueSampleRate(sample_rate)) { + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE; + } else if (channels < minChannels || channels > maxChannels) { + return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT; + } else if (!isTrueBitsPerSample(bits_per_coded_sample)) { + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_BIT_RATE; + } + + int32_t ret = basePlugin->AllocateContext("flac"); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + return ret; + } + + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + return ret; + } + + ret = basePlugin->OpenContext(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + return ret; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegFlacDecoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegFlacDecoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegFlacDecoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegFlacDecoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegFlacDecoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegFlacDecoderPlugin::getInputBufferSize() const +{ + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > getInputBufferSize_) { + maxSize = getInputBufferSize_; + } + return maxSize; +} + +uint32_t AudioFFMpegFlacDecoderPlugin::getOutputBufferSize() const +{ + return getOutputBufferSize_; +} + +Format AudioFFMpegFlacDecoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.cpp b/services/engine/codec/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3d4bc8f8c053ff61caf2149e1c8a4b96afe8f77 --- /dev/null +++ b/services/engine/codec/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.cpp @@ -0,0 +1,138 @@ +/* + * 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 "audio_ffmpeg_mp3_decoder_plugin.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "media_description.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegMp3DecoderPlugin"}; + constexpr int minChannels = 1; + constexpr int maxChannels = 2; + constexpr int bitrate_ratio = 150; + constexpr int samplerate_ratio = 31; + constexpr int bitrate_max = 320000; + constexpr int support_sample_rate = 9; + constexpr int bufferDiff = 128; +} + +namespace OHOS { +namespace Media { +AudioFFMpegMp3DecoderPlugin::AudioFFMpegMp3DecoderPlugin() : basePlugin(std::make_unique()) +{ + channels = 0; + sample_rate = 0; + bit_rate = 0; +} + +AudioFFMpegMp3DecoderPlugin::~AudioFFMpegMp3DecoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +int32_t AudioFFMpegMp3DecoderPlugin::init(const Format &format) +{ + int32_t ret = basePlugin->AllocateContext("mp3"); + int32_t checkresult = AudioFFMpegMp3DecoderPlugin::checkinit(format); + if (checkresult != AVCodecServiceErrCode::AVCS_ERR_OK) { + return checkresult; + } + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("mp3 init error."); + return ret; + } + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("mp3 init error."); + return ret; + } + return basePlugin->OpenContext(); +} + +int32_t AudioFFMpegMp3DecoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegMp3DecoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegMp3DecoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegMp3DecoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegMp3DecoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegMp3DecoderPlugin::getInputBufferSize() const +{ + auto size = int(bit_rate / bitrate_ratio); + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > size) { + maxSize = size; + } + return maxSize; +} + +uint32_t AudioFFMpegMp3DecoderPlugin::getOutputBufferSize() const +{ + uint32_t size = (int(sample_rate / samplerate_ratio) + bufferDiff) * channels * sizeof(short); + return size; +} + +Format AudioFFMpegMp3DecoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} + +int32_t AudioFFMpegMp3DecoderPlugin::checkinit(const Format &format) +{ + int sample_rate_pick[support_sample_rate] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}; + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channels); + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sample_rate); + format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, bit_rate); + if (channels < minChannels || channels > maxChannels) { + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + + if (bit_rate > bitrate_max) { + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + + for (int i = 0; i < support_sample_rate; i++) { + if (sample_rate == sample_rate_pick[i]) { + break; + } else if (i == support_sample_rate - 1) { + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + } + + return AVCodecServiceErrCode::AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.cpp b/services/engine/codec/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5e5da2ef69847a46facea30937158d2fd0c8374 --- /dev/null +++ b/services/engine/codec/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.cpp @@ -0,0 +1,161 @@ +/* + * 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 "audio_ffmpeg_vorbis_decoder_plugin.h" +#include "avcodec_dfx.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "media_description.h" +#include "securec.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegVorbisEncoderPlugin"}; +} + +namespace OHOS { +namespace Media { +static constexpr uint32_t INPUT_BUFFER_SIZE_DEFAULT = 8192; +static constexpr uint32_t OUTPUT_BUFFER_SIZE_DEFAULT = 4 * 1024 * 8; + +AudioFFMpegVorbisDecoderPlugin::AudioFFMpegVorbisDecoderPlugin() + : basePlugin(std::make_unique()) +{ +} + +AudioFFMpegVorbisDecoderPlugin::~AudioFFMpegVorbisDecoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +std::shared_ptr AudioFFMpegVorbisDecoderPlugin::GenEncodeContext(const Format &format) +{ + auto encodec = avcodec_find_encoder_by_name("libvorbis"); + if (encodec == nullptr) { + return nullptr; + } + auto context = avcodec_alloc_context3(encodec); + if (context == nullptr) { + return nullptr; + } + auto encodeContext = + std::shared_ptr(context, [](AVCodecContext *ptr) { avcodec_free_context(&ptr); }); + if (encodeContext == nullptr) { + AVCODEC_LOGE("AVCodecContext null pointer."); + return nullptr; + } + encodeContext->sample_fmt = AV_SAMPLE_FMT_FLTP; + + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, encodeContext->channels); // todo: 统一KEY定义 + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, encodeContext->sample_rate); + + int ret = avcodec_open2(encodeContext.get(), encodec, nullptr); + if (ret != 0) { + AVCODEC_LOGE("avcodec_open2 failed."); + return nullptr; + } + return encodeContext; +} + +int32_t AudioFFMpegVorbisDecoderPlugin::AssignExtradata(std::shared_ptr &context, const Format &format) +{ + if (context == nullptr) { + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + auto encodeContext = GenEncodeContext(format); + if (encodeContext == nullptr) { + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + context->extradata_size = encodeContext->extradata_size; + context->extradata = static_cast(av_mallocz(encodeContext->extradata_size)); + if (context->extradata == nullptr) { + AVCODEC_LOGE("Alloc memory for extradata failed."); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + int ret = + memcpy_s(context->extradata, context->extradata_size, encodeContext->extradata, encodeContext->extradata_size); + if (ret != 0) { + AVCODEC_LOGE("Memory copy failed, error: %{public}d", ret); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegVorbisDecoderPlugin::init(const Format &format) +{ + int32_t ret = basePlugin->AllocateContext("vorbis"); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("AllocateContext failed, ret=%{public}d", ret); + return ret; + } + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("InitContext failed, ret=%{public}d", ret); + return ret; + } + auto codecCtx = basePlugin->GetCodecContext(); + if (!basePlugin->hasExtraData()) { + ret = AssignExtradata(codecCtx, format); + } + + return basePlugin->OpenContext(); +} + +int32_t AudioFFMpegVorbisDecoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegVorbisDecoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegVorbisDecoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegVorbisDecoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegVorbisDecoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegVorbisDecoderPlugin::getInputBufferSize() const +{ + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > INPUT_BUFFER_SIZE_DEFAULT) { + maxSize = INPUT_BUFFER_SIZE_DEFAULT; + } + return maxSize; +} + +uint32_t AudioFFMpegVorbisDecoderPlugin::getOutputBufferSize() const +{ + return OUTPUT_BUFFER_SIZE_DEFAULT; +} + +Format AudioFFMpegVorbisDecoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/encoder/audio_ffmpeg_aac_encoder_plugin.cpp b/services/engine/codec/audio/encoder/audio_ffmpeg_aac_encoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4d36a760c9767f81d2f6b58ed46db7549d5e4bf --- /dev/null +++ b/services/engine/codec/audio/encoder/audio_ffmpeg_aac_encoder_plugin.cpp @@ -0,0 +1,219 @@ +/* + * 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 "audio_ffmpeg_aac_encoder_plugin.h" +#include "avcodec_errors.h" +#include "avcodec_dfx.h" +#include "avcodec_log.h" +#include "media_description.h" +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegAacEncoderPlugin"}; +} + +namespace OHOS { +namespace Media { +constexpr int32_t INPUT_BUFFER_SIZE_DEFAULT = 4 * 1024 * 8; +constexpr int32_t OUTPUT_BUFFER_SIZE_DEFAULT = 8192; +constexpr uint32_t ADTS_HEADER_SIZE = 7; + +constexpr uint8_t SAMPLE_FREQUENCY_INDEX_DEFAULT = 4; +static std::map sampleFreqMap = {{96000, 0}, {88200, 1}, {64000, 2}, {48000, 3}, {44100, 4}, + {32000, 5}, {24000, 6}, {22050, 7}, {16000, 8}, {12000, 9}, + {11025, 10}, {8000, 11}, {7350, 12}}; + +AudioFFMpegAacEncoderPlugin::AudioFFMpegAacEncoderPlugin() : basePlugin(std::make_unique()) {} + +AudioFFMpegAacEncoderPlugin::~AudioFFMpegAacEncoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +static int32_t GetAdtsHeader(std::string &adtsHeader, uint32_t &headerSize, std::shared_ptr ctx, + int aacLength) +{ + uint8_t freqIdx = SAMPLE_FREQUENCY_INDEX_DEFAULT; // 0: 96000 Hz 3: 48000 Hz 4: 44100 Hz + auto iter = sampleFreqMap.find(ctx->sample_rate); + if (iter != sampleFreqMap.end()) { + freqIdx = iter->second; + } + uint8_t chanCfg = ctx->channels; + uint32_t frameLength = aacLength + ADTS_HEADER_SIZE; + adtsHeader += 0xFF; + adtsHeader += 0xF1; + adtsHeader += ((ctx->profile) << 0x6) + (freqIdx << 0x2) + (chanCfg >> 0x2); + adtsHeader += (((chanCfg & 0x3) << 0x6) + (frameLength >> 0xB)); + adtsHeader += ((frameLength & 0x7FF) >> 0x3); + adtsHeader += (((frameLength & 0x7) << 0x5) + 0x1F); + adtsHeader += 0xFC; + headerSize = ADTS_HEADER_SIZE; + + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +static bool CheckSampleFormat(const std::shared_ptr &codec, AVSampleFormat sample_fmt) +{ + const AVSampleFormat *p = codec->sample_fmts; + while (*p != AV_SAMPLE_FMT_NONE) { // 通过AV_SAMPLE_FMT_NONE作为结束符 + if (*p == sample_fmt) { + return true; + } + p++; + } + return false; +} + +static bool CheckSampleRate(const std::shared_ptr &codec, const int sample_rate) +{ + const int *p = codec->supported_samplerates; + while (*p != 0) { // 0作为退出条件,比如libfdk-aacenc.c的aac_sample_rates + if (*p == sample_rate) { + return true; + } + p++; + } + return false; +} + +static bool CheckChannelLayout(const std::shared_ptr &codec, const uint64_t channel_layout) +{ + // 不是每个codec都给出支持的channel_layout + const uint64_t *p = codec->channel_layouts; + if (!p) { + AVCODEC_LOGI("The encoder %{public}s do not set channel_layouts", codec->name); + return true; + } + while (*p != 0) { // 0作为退出条件,比如libfdk-aacenc.c的aac_channel_layout + if (*p == channel_layout) { + return true; + } + p++; + } + return false; +} + +bool AudioFFMpegAacEncoderPlugin::CheckFormat(const Format &format) const +{ + if (!format.ContainKey(MediaDescriptionKey::MD_KEY_SAMPLE_FORMAT) || + !format.ContainKey(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT) || + !format.ContainKey(MediaDescriptionKey::MD_KEY_SAMPLE_RATE)) { + AVCODEC_LOGE("Format parameter missing"); + return false; + } + + auto avCodec = basePlugin->GetAVCodec(); + int sampleFormat; + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_FORMAT, sampleFormat); + if (!CheckSampleFormat(avCodec, (AVSampleFormat)sampleFormat)) { + AVCODEC_LOGE("Sample format not supported"); + return false; + } + + int sampleRate; + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sampleRate); + if (!CheckSampleRate(avCodec, sampleRate)) { + AVCODEC_LOGE("Sample rate not supported"); + return false; + } + + int64_t channelLayout; + format.GetLongValue(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT, channelLayout); + if (!CheckChannelLayout(avCodec, channelLayout)) { + AVCODEC_LOGE("Channel layout not supported"); + return false; + } + + return true; +} + +int32_t AudioFFMpegAacEncoderPlugin::init(const Format &format) +{ + int32_t ret = basePlugin->AllocateContext("aac"); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Allocat aac context failed, ret = %{publid}d", ret); + return ret; + } + if (!CheckFormat(format)) { + AVCODEC_LOGE("Format check failed."); + return AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT_AUD_PARAMS; + } + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Init context failed, ret = %{publid}d", ret); + return ret; + } + ret = basePlugin->OpenContext(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Open context failed, ret = %{publid}d", ret); + return ret; + } + + ret = basePlugin->InitFrame(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("Init frame failed, ret = %{publid}d", ret); + return ret; + } + + basePlugin->RegisterHeaderFunc(GetAdtsHeader); + + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegAacEncoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegAacEncoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegAacEncoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegAacEncoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegAacEncoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegAacEncoderPlugin::getInputBufferSize() const +{ + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > INPUT_BUFFER_SIZE_DEFAULT) { + maxSize = INPUT_BUFFER_SIZE_DEFAULT; + } + return maxSize; +} + +uint32_t AudioFFMpegAacEncoderPlugin::getOutputBufferSize() const +{ + return OUTPUT_BUFFER_SIZE_DEFAULT; +} + +Format AudioFFMpegAacEncoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/encoder/audio_ffmpeg_encoder_plugin.cpp b/services/engine/codec/audio/encoder/audio_ffmpeg_encoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69f1cb34bdb341c93ccb8c956f2bbb3c777d004a --- /dev/null +++ b/services/engine/codec/audio/encoder/audio_ffmpeg_encoder_plugin.cpp @@ -0,0 +1,335 @@ +/* + * 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 "audio_ffmpeg_encoder_plugin.h" +#include "avcodec_errors.h" +#include "media_description.h" +#include "avcodec_dfx.h" +#include "avcodec_log.h" +#include "securec.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegEncoderPlugin"}; +} + +namespace OHOS { +namespace Media { +AudioFfmpegEncoderPlugin::AudioFfmpegEncoderPlugin() {} + +AudioFfmpegEncoderPlugin::~AudioFfmpegEncoderPlugin() +{ + CloseCtxLocked(); + avCodecContext_.reset(); +} + +int32_t AudioFfmpegEncoderPlugin::ProcessSendData(const std::shared_ptr &inputBuffer) +{ + int32_t ret = AVCodecServiceErrCode::AVCS_ERR_OK; + { + std::unique_lock lock(avMutext_); + if (avCodecContext_ == nullptr) { + AVCODEC_LOGE("avCodecContext_ is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_WRONG_STATE; + } + ret = sendBuffer(inputBuffer); + } + return ret; +} + +static 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); +} + +int32_t AudioFfmpegEncoderPlugin::PcmFillFrame(const std::shared_ptr &inputBuffer) +{ + auto memory = inputBuffer->GetBuffer(); + const uint8_t *ptr = memory->GetBase(); + auto bytesPerSample = av_get_bytes_per_sample(avCodecContext_->sample_fmt); + if (!av_sample_fmt_is_planar(avCodecContext_->sample_fmt)) { + auto ret = av_samples_fill_arrays(cachedFrame_->data, cachedFrame_->linesize, ptr, cachedFrame_->channels, + cachedFrame_->nb_samples, (AVSampleFormat)cachedFrame_->format, 0); + if (ret < 0) { + AVCODEC_LOGE("Samples fill arrays failed: %{public}s", AVStrError(ret).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; + } + for (int i = 0; i < cachedFrame_->nb_samples; i++) { + for (int j = 0; j < cachedFrame_->channels; j++) { + auto ret = memcpy_s((void *)(&cachedFrame_->data[j][i * bytesPerSample]), bytesPerSample, + (void *)(&ptr[i * cachedFrame_->channels * bytesPerSample + bytesPerSample * j]), + bytesPerSample); + if (ret != EOK) { + AVCODEC_LOGE("memory copy failed, errno: %{public}d", ret); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::sendBuffer(const std::shared_ptr &inputBuffer) +{ + if (!inputBuffer) { + AVCODEC_LOGE("inputBuffer is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + int ret = av_frame_make_writable(cachedFrame_.get()); + if (ret != 0) { + AVCODEC_LOGE("Frame make writable failed: %{public}s", AVStrError(ret).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + if (!inputBuffer->CheckIsEos()) { + auto errCode = PcmFillFrame(inputBuffer); + if (errCode != AVCodecServiceErrCode::AVCS_ERR_OK) { + return errCode; + } + ret = avcodec_send_frame(avCodecContext_.get(), cachedFrame_.get()); + } else { + ret = avcodec_send_frame(avCodecContext_.get(), nullptr); + } + if (ret == 0) { + return AVCodecServiceErrCode::AVCS_ERR_OK; + } else if (ret == AVERROR(EAGAIN)) { + return AVCodecServiceErrCode::AVCS_ERR_AGAIN; + } else if (ret == AVERROR_EOF) { + AVCODEC_LOGI("End of stream"); + return AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM; + } else { + AVCODEC_LOGE("Send frame unknown error: %{public}s", AVStrError(ret).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } +} + +int32_t AudioFfmpegEncoderPlugin::ProcessRecieveData(std::shared_ptr &outBuffer) +{ + if (!outBuffer) { + AVCODEC_LOGE("outBuffer is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL; + } + int32_t status; + { + std::unique_lock l(avMutext_); + if (avCodecContext_ == nullptr) { + AVCODEC_LOGE("avCodecContext_ is nullptr"); + return AVCodecServiceErrCode::AVCS_ERR_WRONG_STATE; + } + status = receiveBuffer(outBuffer); + } + return status; +} + +int32_t AudioFfmpegEncoderPlugin::receiveBuffer(std::shared_ptr &outBuffer) +{ + auto ret = avcodec_receive_packet(avCodecContext_.get(), avPacket_.get()); + int32_t status; + if (ret >= 0) { + AVCODEC_LOGD("receive one packet"); + status = ReceivePacketSucc(outBuffer); + } else if (ret == AVERROR_EOF) { + outBuffer->SetEos(true); + avcodec_flush_buffers(avCodecContext_.get()); + status = AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM; + } else if (ret == AVERROR(EAGAIN)) { + status = AVCodecServiceErrCode::AVCS_ERR_NOT_ENOUGH_DATA; + } else { + AVCODEC_LOGE("audio encoder receive unknow error: %{public}s", AVStrError(ret).c_str()); + status = AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return status; +} + +int32_t AudioFfmpegEncoderPlugin::ReceivePacketSucc(std::shared_ptr &outBuffer) +{ + uint32_t headerSize = 0; + auto memory = outBuffer->GetBuffer(); + if (headerFuncValid_) { + std::string header; + GetHeaderFunc_(header, headerSize, avCodecContext_, avPacket_->size); + if (headerSize <= 0) { + AVCODEC_LOGE("Get header failed."); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + auto len = memory->Write((uint8_t *)header.c_str(), headerSize); + if (len < headerSize) { + AVCODEC_LOGE("Write header failed, len = %{public}d", len); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + + int32_t outputSize = avPacket_->size + headerSize; + if (memory->GetSize() < outputSize) { + AVCODEC_LOGW("Output buffer capacity is not enough"); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + + auto len = memory->Write(avPacket_->data, avPacket_->size); + if (len < avPacket_->size) { + AVCODEC_LOGE("write packet data failed, len = %{public}d", len); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + + auto attr = outBuffer->GetBufferAttr(); + attr.size = avPacket_->size + headerSize; + outBuffer->SetBufferAttr(attr); + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::Reset() +{ + auto ret = CloseCtxLocked(); + avCodecContext_.reset(); + return ret; +} + +int32_t AudioFfmpegEncoderPlugin::Release() +{ + std::unique_lock lock(avMutext_); + auto ret = CloseCtxLocked(); + avCodecContext_.reset(); + return ret; +} + +int32_t AudioFfmpegEncoderPlugin::Flush() +{ + std::unique_lock lock(avMutext_); + if (avCodecContext_ != nullptr) { + avcodec_flush_buffers(avCodecContext_.get()); + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::AllocateContext(const std::string &name) +{ + { + std::unique_lock lock(avMutext_); + avCodec_ = std::shared_ptr(const_cast(avcodec_find_encoder_by_name(name.c_str())), + [](AVCodec *ptr) {}); + cachedFrame_ = std::shared_ptr(av_frame_alloc(), [](AVFrame *fp) { av_frame_free(&fp); }); + avPacket_ = std::shared_ptr(av_packet_alloc(), [](AVPacket *ptr) { av_packet_free(&ptr); }); + } + if (avCodec_ == nullptr) { + return AVCodecServiceErrCode::AVCS_ERR_UNSUPPORT_PROTOCOL_TYPE; + } + + AVCodecContext *context = nullptr; + { + std::unique_lock lock(avMutext_); + context = avcodec_alloc_context3(avCodec_.get()); + avCodecContext_ = std::shared_ptr(context, [](AVCodecContext *ptr) { + avcodec_free_context(&ptr); + avcodec_close(ptr); + }); + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::InitContext(const Format &format) +{ + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, avCodecContext_->channels); + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, avCodecContext_->sample_rate); + format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, avCodecContext_->bit_rate); + format.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize_); + + int64_t layout; + format.GetLongValue(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT, layout); + avCodecContext_->channel_layout = layout; + + int32_t sampleFormat; + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_FORMAT, sampleFormat); + avCodecContext_->sample_fmt = (AVSampleFormat)sampleFormat; + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::OpenContext() +{ + { + std::unique_lock lock(avMutext_); + auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr); + if (res != 0) { + AVCODEC_LOGE("avcodec open error %{public}s", AVStrError(res).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFfmpegEncoderPlugin::InitFrame() +{ + cachedFrame_->nb_samples = avCodecContext_->frame_size; + cachedFrame_->format = avCodecContext_->sample_fmt; + cachedFrame_->channel_layout = avCodecContext_->channel_layout; + cachedFrame_->channels = avCodecContext_->channels; + int ret = av_frame_get_buffer(cachedFrame_.get(), 0); + if (ret < 0) { + AVCODEC_LOGE("Get frame buffer failed: %{public}s", AVStrError(ret).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +Format AudioFfmpegEncoderPlugin::GetFormat() const noexcept +{ + return format_; +} + +std::shared_ptr AudioFfmpegEncoderPlugin::GetCodecContext() const +{ + return avCodecContext_; +} + +std::shared_ptr AudioFfmpegEncoderPlugin::GetCodecAVPacket() const +{ + return avPacket_; +} + +std::shared_ptr AudioFfmpegEncoderPlugin::GetCodecCacheFrame() const +{ + return cachedFrame_; +} + +std::shared_ptr AudioFfmpegEncoderPlugin::GetAVCodec() const +{ + return avCodec_; +} + +int32_t AudioFfmpegEncoderPlugin::GetMaxInputSize() const noexcept +{ + return maxInputSize_; +} + +int32_t AudioFfmpegEncoderPlugin::CloseCtxLocked() +{ + if (avCodecContext_ != nullptr) { + auto res = avcodec_close(avCodecContext_.get()); + if (res != 0) { + AVCODEC_LOGE("avcodec close failed: %{public}s", AVStrError(res).c_str()); + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +void AudioFfmpegEncoderPlugin::RegisterHeaderFunc(HeaderFunc headerFunc) +{ + GetHeaderFunc_ = headerFunc; + headerFuncValid_ = true; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/audio/encoder/audio_ffmpeg_flac_encoder_plugin.cpp b/services/engine/codec/audio/encoder/audio_ffmpeg_flac_encoder_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce21962675671c7188da508021e77537f18acc9c --- /dev/null +++ b/services/engine/codec/audio/encoder/audio_ffmpeg_flac_encoder_plugin.cpp @@ -0,0 +1,157 @@ +/* + * 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 "audio_ffmpeg_flac_encoder_plugin.h" +#include "media_description.h" +#include "avcodec_errors.h" +#include "avcodec_dfx.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-AudioFFMpegFlacEncoderPlugin"}; + constexpr int minChannel = 1; + constexpr int maxChannel = 8; + constexpr int getInputBufferSize_ = 65536; + constexpr int getOutputBufferSize_ = 65536; + static const int flac_encoder_sample_rate_table[] = { + 0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, + }; + static const int flac_encoder_bits_sample_table[] = {16, 24, 32}; +} + +namespace OHOS { +namespace Media { +AudioFFMpegFlacEncoderPlugin::AudioFFMpegFlacEncoderPlugin() + : basePlugin(std::make_unique()) +{ +} + +AudioFFMpegFlacEncoderPlugin::~AudioFFMpegFlacEncoderPlugin() +{ + basePlugin->Release(); + basePlugin.reset(); + basePlugin = nullptr; +} + +static bool isTrueSampleRate(int sample) +{ + for (auto i : flac_encoder_sample_rate_table) { + if (i == sample) { + return true; + } + } + return false; +} + +static bool isTrueBitsPerSample(int bits_per_coded_sample) +{ + for (auto i : flac_encoder_bits_sample_table) { + if (i == bits_per_coded_sample) { + return true; + } + } + return false; +} + +int32_t AudioFFMpegFlacEncoderPlugin::init(const Format &format) +{ + int32_t channels, sample_rate; + int32_t bits_per_coded_sample; + format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channels); + format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sample_rate); + format.GetIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, bits_per_coded_sample); + if (!isTrueSampleRate(sample_rate)) { + AVCODEC_LOGE("init failed, because sample rate=%{public}d not in table.", sample_rate); + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_SAMPLE_RATE; + } else if (channels < minChannel || channels > maxChannel) { + AVCODEC_LOGE("init failed, because channels=%{public}d not support.", channels); + return AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT; + } else if (!isTrueBitsPerSample(bits_per_coded_sample)) { + AVCODEC_LOGE("init failed, because bits_per_coded_sample=%{public}d not support.", bits_per_coded_sample); + return AVCodecServiceErrCode::AVCS_ERR_MISMATCH_BIT_RATE; + } + + int32_t ret = basePlugin->AllocateContext("flac"); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("init failed, because AllocateContext failed. ret=%{public}d", ret); + return ret; + } + + ret = basePlugin->InitContext(format); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("init failed, because InitContext failed. ret=%{public}d", ret); + return ret; + } + + ret = basePlugin->OpenContext(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("init failed, because OpenContext failed. ret=%{public}d", ret); + return ret; + } + + ret = basePlugin->InitFrame(); + if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { + AVCODEC_LOGE("init failed, because InitFrame failed. ret=%{public}d", ret); + return ret; + } + + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioFFMpegFlacEncoderPlugin::processSendData(const std::shared_ptr &inputBuffer) +{ + return basePlugin->ProcessSendData(inputBuffer); +} + +int32_t AudioFFMpegFlacEncoderPlugin::processRecieveData(std::shared_ptr &outBuffer) +{ + return basePlugin->ProcessRecieveData(outBuffer); +} + +int32_t AudioFFMpegFlacEncoderPlugin::reset() +{ + return basePlugin->Reset(); +} + +int32_t AudioFFMpegFlacEncoderPlugin::release() +{ + return basePlugin->Release(); +} + +int32_t AudioFFMpegFlacEncoderPlugin::flush() +{ + return basePlugin->Flush(); +} + +uint32_t AudioFFMpegFlacEncoderPlugin::getInputBufferSize() const +{ + int32_t maxSize = basePlugin->GetMaxInputSize(); + if (maxSize < 0 || maxSize > getInputBufferSize_) { + maxSize = getInputBufferSize_; + } + return maxSize; +} + +uint32_t AudioFFMpegFlacEncoderPlugin::getOutputBufferSize() const +{ + return getOutputBufferSize_; +} + +Format AudioFFMpegFlacEncoderPlugin::GetFormat() const noexcept +{ + return basePlugin->GetFormat(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_buffer_info.h b/services/engine/codec/include/audio/audio_buffer_info.h new file mode 100644 index 0000000000000000000000000000000000000000..8879709bf44dcee92ab25c023dbedf6425bceb97 --- /dev/null +++ b/services/engine/codec/include/audio/audio_buffer_info.h @@ -0,0 +1,75 @@ +/* + * 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 AV_CODEC_BUFFER_INFO_H +#define AV_CODEC_BUFFER_INFO_H + +#include +#include +#include + +#include "audio_common_info.h" +#include "avcodec_common.h" +#include "avsharedmemorybase.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AudioBufferInfo : public NoCopyable { +public: + AudioBufferInfo(const uint32_t &bufferSize, const std::string_view &name, const uint32_t &metaSize = 0, + size_t align = 1); + + ~AudioBufferInfo(); + + std::shared_ptr GetBuffer() const noexcept; + + std::shared_ptr GetMetadata() const noexcept; + + bool IsHasMetaData() const noexcept; + + bool ResetBuffer(); + + bool SetBufferOwned(); + + bool IsAvilable() const noexcept; + + BufferStatus GetStatus() const noexcept; + + bool CheckIsEos() const noexcept; + + void SetEos(bool eos); + + void SetBufferAttr(const AVCodecBufferInfo &attr); + + AVCodecBufferInfo GetBufferAttr() const noexcept; + + AVCodecBufferFlag GetFlag() const noexcept; + +private: + bool isHasMeta_; + bool isEos_; + std::atomic status_; + uint32_t bufferSize_; + uint32_t metaSize_; + std::string_view name_; + std::shared_ptr buffer_; + std::shared_ptr metadata_; + AVCodecBufferInfo info_; + AVCodecBufferFlag flag_; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_buffers_manager.h b/services/engine/codec/include/audio/audio_buffers_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..21d513bf0563343e0fbd74e5a3bf9ad10af583b4 --- /dev/null +++ b/services/engine/codec/include/audio/audio_buffers_manager.h @@ -0,0 +1,70 @@ +/* + * 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 AV_CODEC_ENGIN_BFFERS_H +#define AV_CODEC_ENGIN_BFFERS_H + +#include "audio_buffer_info.h" +#include "nocopyable.h" + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace Media { +class AudioBuffersManager : public NoCopyable { +public: + AudioBuffersManager(const uint32_t &bufferSize, const std::string_view &name, const uint32_t &metaSize = 0, + size_t align = 1); + + ~AudioBuffersManager(); + + std::shared_ptr getMemory(const uint32_t &index) const noexcept; + + bool RelaseBuffer(const uint32_t &index); + + bool SetBufferBusy(const uint32_t &index); + + bool RequestNewBuffer(uint32_t *index, std::shared_ptr &buffer); + + bool RequestAvialbaleIndex(uint32_t *index); + + void ReleaseAll(); + + void SetRunning(); + +private: + void initBuffers(); + std::shared_ptr createNewBuffer(); + +private: + std::atomic isRunning_; + std::mutex avilableMuxt_; + std::condition_variable avilableCondition_; + std::queue inBufIndexQue_; + std::mutex stateMutex_; + uint32_t bufferSize_; + uint32_t metaSize_; + size_t align_; + std::string_view name_; + std::vector> bufferInfo_; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_codec_worker.h b/services/engine/codec/include/audio/audio_codec_worker.h new file mode 100644 index 0000000000000000000000000000000000000000..b2361e7d2f008085fcbcd0abdff54542786045f7 --- /dev/null +++ b/services/engine/codec/include/audio/audio_codec_worker.h @@ -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. + */ + +#ifndef AV_CODEC_ADIO_CODEC_WORKER_H +#define AV_CODEC_ADIO_CODEC_WORKER_H + +#include "audio_buffers_manager.h" +#include "audio_ffmpeg_base_codec.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "nocopyable.h" +#include "task_thread.h" + +#include +#include +#include + +namespace OHOS { +namespace Media { +class AudioCodecWorker : public NoCopyable { +public: + AudioCodecWorker(const std::shared_ptr &codec, + const std::shared_ptr &callback); + + ~AudioCodecWorker(); + + bool PushInputData(const uint32_t &index); + + bool Configure(); + + bool Start(); + + bool Stop(); + + bool Pause(); + + bool Resume(); + + bool Release(); + + std::shared_ptr GetInputBuffer() const noexcept; + + std::shared_ptr GetOutputBuffer() const noexcept; + + std::shared_ptr GetOutputBufferInfo(const uint32_t &index) const noexcept; + + std::shared_ptr GetInputBufferInfo(const uint32_t &index) const noexcept; + +private: + void produceInputBuffer(); + void consumerOutputBuffer(); + void dispose(); + bool begin(); + +private: + std::atomic isRunning; + std::atomic isProduceInput; + std::shared_ptr codec_; + uint32_t inputBufferSize; + uint32_t outputBufferSize; + std::mutex stateMutex_; + std::mutex inputMuxt_; + std::mutex outputMuxt_; + std::condition_variable inputCondition_; + std::condition_variable outputCondition_; + + std::unique_ptr inputTask_; + std::unique_ptr outputTask_; + std::shared_ptr callback_; + std::shared_ptr inputBuffer_; + std::shared_ptr outputBuffer_; + std::queue inBufIndexQue_; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_common_info.h b/services/engine/codec/include/audio/audio_common_info.h new file mode 100644 index 0000000000000000000000000000000000000000..783260754b82ab6c08c755a6000b5688acda9932 --- /dev/null +++ b/services/engine/codec/include/audio/audio_common_info.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 AV_CODEC_AUDIO_COMMON_INFO_H +#define AV_CODEC_AUDIO_COMMON_INFO_H + +namespace OHOS { +namespace Media { +enum class BufferStatus { + IDEL, + OWNE_BY_CLIENT, +}; + +enum class CodecState { + RELEASED, + INITLIZED, + FLUSHED, + RUNNING, + + INITLIZING, // RELEASED -> INITLIZED + STARTING, // INITLIZED -> RUNNING + STOPPING, // RUNNING -> INITLIZED + FLUSHING, // RUNNING -> FLUSHED + RESUMING, // FLUSHED -> RUNNING + RRELEASING, // {ANY EXCEPT RELEASED} -> RELEASED +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_ffmpeg_adapter.h b/services/engine/codec/include/audio/audio_ffmpeg_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..07086b36a1b12a99bde6a8bd41a91974d3b49285 --- /dev/null +++ b/services/engine/codec/include/audio/audio_ffmpeg_adapter.h @@ -0,0 +1,84 @@ +/* + * 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 CODEC_EENGIN_AUDIO_FFMPEG_ADAPTER_H +#define CODEC_EENGIN_AUDIO_FFMPEG_ADAPTER_H + +#include "audio_codec_worker.h" +#include "audio_ffmpeg_base_codec.h" +#include "avcodec_common.h" +#include "codecbase.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegAdapter : public CodecBase, public NoCopyable { +public: + explicit AudioFFMpegAdapter(const std::string &name); + + ~AudioFFMpegAdapter() override; + + int32_t SetCallback(const std::shared_ptr &callback) override; + + int32_t Configure(const Format &format) override; + + int32_t Start() override; + + int32_t Stop() override; + + int32_t Flush() override; + + int32_t Reset() override; + + int32_t Release() override; + + int32_t Pause() override; + + int32_t Resume() override; + + int32_t NotifyEos() override; + + int32_t SetParameter(const Format &format) override; + + int32_t GetOutputFormat(Format &format) override; + + std::shared_ptr GetInputBuffer(size_t index) override; + + int32_t QueueInputBuffer(size_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag &flag) override; + + std::shared_ptr GetOutputBuffer(size_t index) override; + + int32_t ReleaseOutputBuffer(size_t index) override; + +private: + std::atomic state_; + const std::string name_; + std::shared_ptr callback_; + std::shared_ptr audioCodec; + std::shared_ptr worker_; + +private: + int32_t doFlush(); + int32_t doStart(); + int32_t doStop(); + int32_t doResume(); + int32_t doRelease(); + int32_t doInit(); + int32_t doConfigure(const Format &format); + std::string_view stateToString(CodecState state); +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/audio_ffmpeg_base_codec.h b/services/engine/codec/include/audio/audio_ffmpeg_base_codec.h new file mode 100644 index 0000000000000000000000000000000000000000..7e8e044ec6d7b649ae5ad2a5a8ab8dd0e5727315 --- /dev/null +++ b/services/engine/codec/include/audio/audio_ffmpeg_base_codec.h @@ -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. + */ + +#ifndef BASE_CODER_PLUGIN +#define BASE_CODER_PLUGIN + +#include + +#include "audio_buffer_info.h" +#include "av_codec_base_factory.h" +#include "format.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegBaseCodec : public AVCodecBaseFactory, public NoCopyable { +public: + AudioFFMpegBaseCodec() = default; + + virtual ~AudioFFMpegBaseCodec() = default; + + virtual int32_t init(const Format &format) = 0; + + virtual int32_t processSendData(const std::shared_ptr &inputBuffer) = 0; + + virtual int32_t processRecieveData(std::shared_ptr &outBuffer) = 0; + + virtual int32_t reset() = 0; + + virtual int32_t release() = 0; + + virtual int32_t flush() = 0; + + virtual uint32_t getInputBufferSize() const = 0; + + virtual uint32_t getOutputBufferSize() const = 0; + + virtual Format GetFormat() const noexcept = 0; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/decoder/audio_ffmpeg_aac_decoder_plugin.h b/services/engine/codec/include/audio/decoder/audio_ffmpeg_aac_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..59f9486d68b7e0fa15c69f42f939ed08d8853645 --- /dev/null +++ b/services/engine/codec/include/audio/decoder/audio_ffmpeg_aac_decoder_plugin.h @@ -0,0 +1,49 @@ +/* + * 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 AUDIO_FFMPEG_AAC_DECODER_PLUGIN_H +#define AUDIO_FFMPEG_AAC_DECODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_decoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegAacDecoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegAacDecoderPlugin(); + ~AudioFFMpegAacDecoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_DECODER_AAC_NAME_KEY); + } + +private: + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/decoder/audio_ffmpeg_decoder_plugin.h b/services/engine/codec/include/audio/decoder/audio_ffmpeg_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..7207dbc91b7f997be157977be8a3db3a384723b8 --- /dev/null +++ b/services/engine/codec/include/audio/decoder/audio_ffmpeg_decoder_plugin.h @@ -0,0 +1,94 @@ +/* + * 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 AUDIO_FFMPEG_DECODER_PLUGIN +#define AUDIO_FFMPEG_DECODER_PLUGIN + +#include +#include "audio_ffmpeg_base_codec.h" +#include "nocopyable.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +}; +#endif + +namespace OHOS { +namespace Media { +class AudioFfmpegDecoderPlugin : public NoCopyable { +public: + AudioFfmpegDecoderPlugin(); + + ~AudioFfmpegDecoderPlugin(); + + int32_t ProcessSendData(const std::shared_ptr &inputBuffer); + + int32_t ProcessRecieveData(std::shared_ptr &outBuffer); + + int32_t Reset(); + + int32_t Release(); + + int32_t Flush(); + + int32_t AllocateContext(const std::string &name); + + int32_t InitContext(const Format &format); + + int32_t OpenContext(); + + Format GetFormat() const noexcept; + + std::shared_ptr GetCodecContext() const noexcept; + + std::shared_ptr GetCodecAVPacket() const noexcept; + + std::shared_ptr GetCodecCacheFrame() const noexcept; + + int32_t CloseCtxLocked(); + + int64_t GetMaxInputSize() const noexcept; + + bool hasExtraData() const noexcept; + +private: + bool hasExtra_; + int64_t maxInputSize_; + int32_t bufferNum_; + int32_t bufferIndex_; + int64_t preBufferGroupPts_; + int64_t curBufferGroupPts_; + int64_t bufferGroupPtsDistance; + + std::shared_ptr avCodec_; + std::shared_ptr avCodecContext_; + std::shared_ptr cachedFrame_; + std::shared_ptr avPacket_; + std::mutex avMutext_; + std::mutex parameterMutex_; + Format format_; + +private: + int32_t SendBuffer(const std::shared_ptr &inputBuffer); + int32_t ReceiveBuffer(std::shared_ptr &outBuffer); + int32_t ReceiveFrameSucc(std::shared_ptr &outBuffer); +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/decoder/audio_ffmpeg_flac_decoder_plugin.h b/services/engine/codec/include/audio/decoder/audio_ffmpeg_flac_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..15d0f248639139539a292f10e3063fe4f8247cbf --- /dev/null +++ b/services/engine/codec/include/audio/decoder/audio_ffmpeg_flac_decoder_plugin.h @@ -0,0 +1,49 @@ +/* + * 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 AUDIO_FFMPEG_FLAC_DECODER_PLUGIN_H +#define AUDIO_FFMPEG_FLAC_DECODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_decoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegFlacDecoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegFlacDecoderPlugin(); + ~AudioFFMpegFlacDecoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_DECODER_FLAC_NAME_KEY); + } + +private: + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.h b/services/engine/codec/include/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..b1b23bd4f94ee3641f565e3d937ab8c1bea0f94e --- /dev/null +++ b/services/engine/codec/include/audio/decoder/audio_ffmpeg_mp3_decoder_plugin.h @@ -0,0 +1,54 @@ +/* + * 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 AUDIO_FFMPEG_MP3_DECODER_PLUGIN_H +#define AUDIO_FFMPEG_MP3_DECODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_decoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegMp3DecoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegMp3DecoderPlugin(); + ~AudioFFMpegMp3DecoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_DECODER_MP3_NAME_KEY); + } + +private: + int32_t checkinit(const Format &format); + int channels; + int sample_rate; + int64_t bit_rate; + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.h b/services/engine/codec/include/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..ba658f98ddfe53c04ee27af069b6b246dd8daa06 --- /dev/null +++ b/services/engine/codec/include/audio/decoder/audio_ffmpeg_vorbis_decoder_plugin.h @@ -0,0 +1,53 @@ +/* + * 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 AUDIO_FFMPEG_VORBIS_DECODER_PLUGIN_H +#define AUDIO_FFMPEG_VORBIS_DECODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_decoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegVorbisDecoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegVorbisDecoderPlugin(); + ~AudioFFMpegVorbisDecoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_DECODER_VORBIS_NAME_KEY); + } + +private: + std::shared_ptr GenEncodeContext(const Format &format); + int32_t AssignExtradata(std::shared_ptr &context, const Format &format); + + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/encoder/audio_ffmpeg_aac_encoder_plugin.h b/services/engine/codec/include/audio/encoder/audio_ffmpeg_aac_encoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..7e1e5c35cd4f791c854a529995e3048d282cfb60 --- /dev/null +++ b/services/engine/codec/include/audio/encoder/audio_ffmpeg_aac_encoder_plugin.h @@ -0,0 +1,51 @@ +/* + * 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 AUDIO_FFMPEG_AAC_ENCODER_PLUGIN_H +#define AUDIO_FFMPEG_AAC_ENCODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_encoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegAacEncoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegAacEncoderPlugin(); + ~AudioFFMpegAacEncoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_ENCODER_AAC_NAME_KEY); + } + +private: + bool CheckFormat(const Format &format) const; + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/encoder/audio_ffmpeg_encoder_plugin.h b/services/engine/codec/include/audio/encoder/audio_ffmpeg_encoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..9890ee3b3861690768b4bddb930f9ab2b9784404 --- /dev/null +++ b/services/engine/codec/include/audio/encoder/audio_ffmpeg_encoder_plugin.h @@ -0,0 +1,82 @@ +/* + * 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 AUDIO_FFMPEG_ENCODER_PLUGIN +#define AUDIO_FFMPEG_ENCODER_PLUGIN + +#include +#include +#include "audio_ffmpeg_base_codec.h" +#include "nocopyable.h" +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "libavcodec/avcodec.h" +#ifdef __cplusplus +}; +#endif + +namespace OHOS { +namespace Media { +class AudioFfmpegEncoderPlugin : NoCopyable { + using HeaderFunc = std::function, + uint32_t dataLength)>; + +public: + AudioFfmpegEncoderPlugin(); + ~AudioFfmpegEncoderPlugin(); + int32_t ProcessSendData(const std::shared_ptr &inputBuffer); + int32_t ProcessRecieveData(std::shared_ptr &outBuffer); + int32_t Reset(); + int32_t Release(); + int32_t Flush(); + + int32_t AllocateContext(const std::string &name); + int32_t InitContext(const Format &format); + int32_t OpenContext(); + Format GetFormat() const noexcept; + int32_t InitFrame(); + + std::shared_ptr GetCodecContext() const; + std::shared_ptr GetCodecAVPacket() const; + std::shared_ptr GetCodecCacheFrame() const; + std::shared_ptr GetAVCodec() const; + void RegisterHeaderFunc(HeaderFunc headerFunc); + int32_t CloseCtxLocked(); + int32_t GetMaxInputSize() const noexcept; + +private: + int32_t maxInputSize_; + std::shared_ptr avCodec_; + std::shared_ptr avCodecContext_; + std::shared_ptr cachedFrame_; + std::shared_ptr avPacket_; + mutable std::mutex avMutext_; + std::mutex parameterMutex_; + Format format_; + +private: + int32_t sendBuffer(const std::shared_ptr &inputBuffer); + int32_t receiveBuffer(std::shared_ptr &outBuffer); + int32_t ReceivePacketSucc(std::shared_ptr &outBuffer); + int32_t PcmFillFrame(const std::shared_ptr &inputBuffer); + HeaderFunc GetHeaderFunc_; + bool headerFuncValid_ = false; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/codec/include/audio/encoder/audio_ffmpeg_flac_encoder_plugin.h b/services/engine/codec/include/audio/encoder/audio_ffmpeg_flac_encoder_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..42520ee982e8fa9b1654af525d6e8a66709b95e8 --- /dev/null +++ b/services/engine/codec/include/audio/encoder/audio_ffmpeg_flac_encoder_plugin.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 AUDIO_FFMPEG_FLAC_ENCODER_PLUGIN_H +#define AUDIO_FFMPEG_FLAC_ENCODER_PLUGIN_H + +#include "audio_ffmpeg_base_codec.h" +#include "audio_ffmpeg_encoder_plugin.h" +#include "avcodec_audio_codec_key.h" + +namespace OHOS { +namespace Media { +class AudioFFMpegFlacEncoderPlugin : public AudioFFMpegBaseCodec::CodecRegister { +public: + AudioFFMpegFlacEncoderPlugin(); + ~AudioFFMpegFlacEncoderPlugin() override; + + int32_t init(const Format &format) override; + int32_t processSendData(const std::shared_ptr &inputBuffer) override; + int32_t processRecieveData(std::shared_ptr &outBuffer) override; + int32_t reset() override; + int32_t release() override; + int32_t flush() override; + uint32_t getInputBufferSize() const override; + uint32_t getOutputBufferSize() const override; + Format GetFormat() const noexcept override; + + const static std::string identify() + { + return std::string(AVCodecAudioCodecKey::AUDIO_ENCODER_FLAC_NAME_KEY); + } + +private: + std::unique_ptr basePlugin; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/codec/include/video/fcodec.h b/services/engine/codec/include/video/fcodec.h new file mode 100644 index 0000000000000000000000000000000000000000..31ec1ed67d3298c43c22dc1b176dd7f2074b6277 --- /dev/null +++ b/services/engine/codec/include/video/fcodec.h @@ -0,0 +1,149 @@ +/* + * 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 FCODEC_H +#define FCODEC_H + +#include +#include +#include +#include +#include +#include +#include "avcodec_common.h" // AVCodecBufferInfo & callback +#include "avcodec_errors.h" // Errorcode +#include "avcodec_info.h" +#include "codec_utils.h" +#include "codecbase.h" +#include "media_description.h" +#include "surface_memory.h" +#include "task_thread.h" +namespace OHOS { +namespace Media { +namespace Codec { +class FCodec : public CodecBase { +public: + explicit FCodec(const std::string &name); + explicit FCodec(bool isEncoder, const std::string &mime); + ~FCodec() override; + int32_t Configure(const Format &format) override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t SetParameter(const Format &format) override; + int32_t GetOutputFormat(Format &format) override; + std::shared_ptr GetInputBuffer(size_t index) override; + int32_t QueueInputBuffer(size_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag &flag) override; + std::shared_ptr GetOutputBuffer(size_t index) override; + int32_t ReleaseOutputBuffer(size_t index) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t SetOutputSurface(sptr surface) override; + int32_t RenderOutputBuffer(size_t index) override; + int32_t Pause() override; + int32_t Resume() override; + struct AVBuffer { + public: + AVBuffer() = default; + ~AVBuffer() = default; + + enum status { + OWNED_BY_CODEC, + OWNED_BY_USER, + OWNED_BY_SURFACE, + }; + + std::shared_ptr memory_; + std::atomic owner_; + AVCodecBufferInfo bufferInfo_; + AVCodecBufferFlag bufferFlag_; + }; + +private: + int32_t Init(const std::string &name); + + enum struct State : int32_t { + Uninitialized, + Initialized, + Configured, + Running, + Flushing, + Flushed, + Stopping, + Releasing, + EOS, + Error, + }; + bool IsActive() const; + void ResetContext(bool isFlush = false); + std::tuple CalculateBufferSize(); + int32_t AllocateBuffers(); + int32_t ReleaseBuffers(bool isFlush = false); + void SendFrame(); + void ReceiveFrame(); + void RenderFrame(); + void ConfigureSufrace(const Format &format, const std::string_view &formatKey, uint32_t FORMAT_TYPE); + void ConfigureBuffer(const Format &format, const std::string_view &formatKey, int32_t minVal = 0, + int32_t maxVal = INT_MAX); + int32_t ConfigureDefault(); + void FramePostProcess(std::shared_ptr frameBuffer, int32_t status, int ret); + int32_t AllocateInputBuffer(int32_t bufferCnt, int32_t inBufferSize); + int32_t AllocateOutputBuffer(int32_t bufferCnt, int32_t outBufferSize); + int32_t FillFrameBuffer(const std::shared_ptr &frameBuffer); + void SetSurfaceParameter(const Format &format, const std::string_view &formatKey, uint32_t FORMAT_TYPE); + int32_t UpdateSurfaceMemory(std::shared_ptr &surfaceMemory, int64_t pts); + int32_t FillFrameBufferImpl(const std::shared_ptr &frameBuffer, AVPixelFormat ffmpegFormat, + VideoPixelFormat outputPixelFmt); + std::string codecName_; + std::atomic state_ = State::Uninitialized; + Format format_; + int32_t width_ = 0; + int32_t height_ = 0; + // INIT + std::shared_ptr avCodec_ = nullptr; + // Config + std::shared_ptr avCodecContext_ = nullptr; + // Start + std::shared_ptr avPacket_ = nullptr; + std::shared_ptr cachedFrame_ = nullptr; + // Receive frame + uint8_t *scaleData_[AV_NUM_DATA_POINTERS]; + int32_t scaleLineSize_[AV_NUM_DATA_POINTERS]; + std::shared_ptr scale_ = nullptr; + bool isConverted_ = false; + // Running + std::vector> buffers_[2]; + std::list codecAvailBuffers_; + std::list renderBuffers_; + std::list inBufQue_; + sptr CodecSurface_ = nullptr; + std::shared_ptr sendTask_ = nullptr; + std::shared_ptr receiveTask_ = nullptr; + std::shared_ptr renderTask_ = nullptr; + std::shared_mutex inputMutex_; + std::mutex outputMutex_; + std::mutex sendMutex_; + std::mutex syncMutex_; + std::condition_variable outputCv_; + std::condition_variable sendCv_; + std::shared_ptr callback_; + std::atomic isSendWait_ = false; + std::atomic isSendEos_ = false; +}; +} // namespace Codec +} // namespace Media +} // namespace OHOS +#endif // FCODEC_H diff --git a/services/engine/codec/video/BUILD.gn b/services/engine/codec/video/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..3cec3e3dd12ffa3032351c2ec40db8364b8d29ef --- /dev/null +++ b/services/engine/codec/video/BUILD.gn @@ -0,0 +1,74 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_static_library("av_codec_video_ffmpeg_codec") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/engine/codec/include/video", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/utils/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api", + "//foundation/graphic/graphic_2d/interfaces/inner_api/common", + "//foundation/graphic/graphic_2d/utils/sync_fence/export", + "//drivers/peripheral/display/interfaces/include", + "//base/startup/init/interfaces/innerkits/include/syspara", + "//base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include", + "//third_party/ffmpeg", + + # "//commonlibrary/c_utils/base/include", + ] + + defines = [] + defines += av_codec_defines + + sources = [ "$av_codec_root_dir/services/engine/codec/video/fcodec.cpp" ] + + deps = [ + "$av_codec_root_dir/services/engine/base:av_codec_codec_base", + "$av_codec_root_dir/services/engine/common:av_codec_engine_common", + "//third_party/ffmpeg:libohosffmpeg", + ] + + public_deps = [ + "$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", + "//commonlibrary/c_utils/base:utils", + "//foundation/graphic/graphic_2d:libsurface", + "//foundation/graphic/graphic_2d/utils:sync_fence", + "//third_party/bounds_checking_function:libsec_static", + ] + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/engine/codec/video/fcodec.cpp b/services/engine/codec/video/fcodec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a74bc0fa0fc5d7175e0a2de20e8bdf15bc56a97 --- /dev/null +++ b/services/engine/codec/video/fcodec.cpp @@ -0,0 +1,984 @@ +/* + * 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 "avcodec_dfx.h" +#include "avcodec_log.h" +#include "codec_utils.h" +#include "securec.h" +#include "utils.h" +#include "fcodec.h" +namespace OHOS { +namespace Media { +namespace Codec { +static const uint32_t INDEX_INPUT = 0; +static const uint32_t INDEX_OUTPUT = 1; +static const int32_t DEFAULT_IN_BUFFER_CNT = 8; +static const int32_t DEFAULT_OUT_BUFFER_CNT = 8; +static const int32_t DEFAULT_MIN_BUFFER_CNT = 1; +static const uint32_t VIDEO_PIX_DEPTH_YUV = 3; +static const uint32_t VIDEO_PIX_DEPTH_RGBA = 4; +static const int32_t VIDEO_ALIGN_SIZE = 16; // 16字节对齐 +static const int32_t VIDEO_MAX_SIZE = 15360; // 16K的宽 +static const int32_t DEFAULT_VIDEO_WIDTH = 1920; +static const int32_t DEFAULT_VIDEO_HEIGHT = 1080; +static const uint32_t DEFAULT_TRY_DECODE_TIME = 10; +static const struct { + const char *codecName; + const char *mimeType; + const char *ffmpegCodec; + const bool isEncoder; +} SupportCodec[] = { + {"video_decoder.avc", "video/avc", "h264", false}, +}; +static const size_t numSupportCodec = sizeof(SupportCodec) / sizeof(SupportCodec[0]); +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "FCodec"}; +} +FCodec::FCodec(const std::string &name) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_LOG(!name.empty(), "Create codec failed: empty name"); + std::string fcodecName; + for (size_t i = 0; i < numSupportCodec; ++i) { + if (SupportCodec[i].codecName == name) { + fcodecName = SupportCodec[i].ffmpegCodec; + break; + } + } + CHECK_AND_RETURN_LOG(!fcodecName.empty(), "Create codec failed: not support name: %{public}s", name.c_str()); + int32_t ret = Init(fcodecName); + format_.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_NAME, name); + CHECK_AND_RETURN_LOG(ret == AVCS_ERR_OK, "Create codec failed: init codec error"); +} + +FCodec::FCodec(bool isEncoder, const std::string &mime) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_LOG(!mime.empty(), "Create codec failed: empty mime"); + std::string fcodecName; + for (size_t i = 0; i < numSupportCodec; ++i) { + if (SupportCodec[i].mimeType == mime && SupportCodec[i].isEncoder == isEncoder) { + fcodecName = SupportCodec[i].ffmpegCodec; + break; + } + } + CHECK_AND_RETURN_LOG(!fcodecName.empty(), "Create codec failed: not support mime: %{public}s", mime.c_str()); + int32_t ret = Init(fcodecName); + CHECK_AND_RETURN_LOG(ret == AVCS_ERR_OK, "Create codec failed: init codec error"); +} + +FCodec::~FCodec() +{ + callback_ = nullptr; + CodecSurface_ = nullptr; + Release(); + state_ = State::Uninitialized; +} + +int32_t FCodec::Init(const std::string &name) +{ + AVCODEC_SYNC_TRACE; + avCodec_ = + std::shared_ptr(const_cast(avcodec_find_decoder_by_name(name.c_str())), [](void *ptr) {}); + CHECK_AND_RETURN_RET_LOG(avCodec_ != nullptr, AVCS_ERR_INVALID_VAL, + "Init codec failed: cannot find codec with name %{public}s", name.c_str()); + codecName_ = name; + sendTask_ = std::make_shared("sendFrame"); + sendTask_->RegisterHandler([this] { SendFrame(); }); + receiveTask_ = std::make_shared("ReceiveFrame"); + receiveTask_->RegisterHandler([this] { ReceiveFrame(); }); + state_ = State::Initialized; + AVCODEC_LOGI("Init codec successful, state: Uninitialized -> Initialized"); + return AVCS_ERR_OK; +} + +int32_t FCodec::ConfigureDefault() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((state_ == State::Initialized), AVCS_ERR_INVALID_STATE, + "Configure codec failed: not in Initialized state"); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_VIDEO_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_VIDEO_HEIGHT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_MAX_OUTPUT_BUFFER_COUNT, DEFAULT_OUT_BUFFER_CNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_BUFFER_COUNT, DEFAULT_IN_BUFFER_CNT); + avCodecContext_ = std::shared_ptr(avcodec_alloc_context3(avCodec_.get()), [](AVCodecContext *p) { + if (p != nullptr) { + if (p->extradata) { + av_free(p->extradata); + p->extradata = nullptr; + } + avcodec_free_context(&p); + } + }); + CHECK_AND_RETURN_RET_LOG(avCodecContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "Configure codec failed: Allocate context error"); + avCodecContext_->codec_type = AVMEDIA_TYPE_VIDEO; + return AVCS_ERR_OK; +} + +void FCodec::ConfigureBuffer(const Format &format, const std::string_view &formatKey, int32_t minVal, int32_t maxVal) +{ + if (format.GetValueType(formatKey) == FORMAT_TYPE_INT32) { + int32_t val32 = 0; + if (format.GetIntValue(formatKey, val32) && val32 > minVal && val32 < maxVal) { + format_.PutIntValue(formatKey, val32); + } else { + AVCODEC_LOGW( + "Set parameter failed: %{public}.*s, which minimum threshold=%{public}d, maximum threshold=%{public}d", + formatKey.size(), formatKey.data(), minVal, maxVal); + } + } else if (format.GetValueType(formatKey) == FORMAT_TYPE_INT64) { + int64_t val64 = 0; + if (format.GetLongValue(formatKey, val64) && val64 > minVal) { + format_.PutLongValue(formatKey, val64); + } else { + AVCODEC_LOGW("Set parameter failed: %{public}.*s", formatKey.size(), formatKey.data()); + } + } else { + AVCODEC_LOGW("Unsupport type for parameter: %{public}.*s", formatKey.size(), formatKey.data()); + } +} + +void FCodec::ConfigureSufrace(const Format &format, const std::string_view &formatKey, uint32_t FORMAT_TYPE) +{ + uint8_t *addr = nullptr; + size_t size = 0; + int32_t val = 0; + if (formatKey == MediaDescriptionKey::MD_KEY_CODEC_CONFIG && FORMAT_TYPE == FORMAT_TYPE_ADDR) { + if (format.GetBuffer(formatKey, &addr, size) && size > 0) { + auto allocSize = AlignUp(size + AV_INPUT_BUFFER_PADDING_SIZE, VIDEO_ALIGN_SIZE); + avCodecContext_->extradata = static_cast(av_mallocz(allocSize)); + (void)memcpy_s(avCodecContext_->extradata, allocSize, addr, size); + avCodecContext_->extradata_size = size; + format_.PutBuffer(formatKey, avCodecContext_->extradata, avCodecContext_->extradata_size); + } + } else if (formatKey == MediaDescriptionKey::MD_KEY_PIXEL_FORMAT && FORMAT_TYPE == FORMAT_TYPE_INT32) { + if (format.GetIntValue(formatKey, val)) { + VideoPixelFormat vpf = static_cast(val); + if (vpf == VideoPixelFormat::RGBA || vpf == VideoPixelFormat::BGRA) { + format_.PutIntValue(formatKey, val); + } + } + } else if (formatKey == MediaDescriptionKey::MD_KEY_ROTATION_ANGLE && FORMAT_TYPE == FORMAT_TYPE_INT32) { + if (format.GetIntValue(formatKey, val)) { + GraphicTransformType sr = static_cast(val); + if (sr == GraphicTransformType::GRAPHIC_ROTATE_NONE || sr == GraphicTransformType::GRAPHIC_ROTATE_90 || + sr == GraphicTransformType::GRAPHIC_ROTATE_180 || sr == GraphicTransformType::GRAPHIC_ROTATE_270) { + format_.PutIntValue(formatKey, val); + } + } + } else if (formatKey == MediaDescriptionKey::MD_KEY_SCALE_TYPE && FORMAT_TYPE == FORMAT_TYPE_INT32) { + if (format.GetIntValue(formatKey, val)) { + ScalingMode scaleMode = static_cast(val); + if (scaleMode == ScalingMode::SCALING_MODE_SCALE_TO_WINDOW || + scaleMode == ScalingMode::SCALING_MODE_SCALE_CROP) { + format_.PutIntValue(formatKey, val); + } + } + } else { + AVCODEC_LOGW("Set parameter failed: %{public}.*s, please check your value", formatKey.size(), formatKey.data()); + } +} + +int32_t FCodec::Configure(const Format &format) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((state_ == State::Initialized), AVCS_ERR_INVALID_STATE, + "Configure codec failed: not in Initialized state"); + CHECK_AND_RETURN_RET_LOG((ConfigureDefault() == AVCS_ERR_OK), AVCS_ERR_UNKNOWN, + "Configure codec failed: not in Initialized state"); + for (auto &it : format.GetFormatMap()) { + if (it.first == MediaDescriptionKey::MD_KEY_MAX_OUTPUT_BUFFER_COUNT || + it.first == MediaDescriptionKey::MD_KEY_MAX_INPUT_BUFFER_COUNT) { + ConfigureBuffer(format, it.first, DEFAULT_MIN_BUFFER_CNT); + } else if (it.first == MediaDescriptionKey::MD_KEY_WIDTH || it.first == MediaDescriptionKey::MD_KEY_HEIGHT) { + ConfigureBuffer(format, it.first, 0, VIDEO_MAX_SIZE); + } else if (it.first == MediaDescriptionKey::MD_KEY_BITRATE) { + ConfigureBuffer(format, MediaDescriptionKey::MD_KEY_BITRATE); + } else if (it.first == MediaDescriptionKey::MD_KEY_CODEC_CONFIG || + it.first == MediaDescriptionKey::MD_KEY_PIXEL_FORMAT || + it.first == MediaDescriptionKey::MD_KEY_ROTATION_ANGLE || + it.first == MediaDescriptionKey::MD_KEY_SCALE_TYPE) { + ConfigureSufrace(format, it.first, it.second.type); + } else { + AVCODEC_LOGW("Set parameter failed: %{public}.*s, unsupport name", it.first.size(), it.first.data()); + } + } + format.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, avCodecContext_->bit_rate); + format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width_); + format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height_); + avCodecContext_->width = width_; + avCodecContext_->height = height_; + state_ = State::Configured; + AVCODEC_LOGI("Configured codec successful: state: Initialized -> Configured"); + return AVCS_ERR_OK; +} + +bool FCodec::IsActive() const +{ + return state_ == State::Running || state_ == State::Flushed; +} + +void FCodec::ResetContext(bool isFlush) +{ + if (avCodecContext_ == nullptr) { + return; + } + if (avCodecContext_->extradata) { + av_free(avCodecContext_->extradata); + avCodecContext_->extradata = nullptr; + } + avCodecContext_->coded_width = 0; + avCodecContext_->coded_height = 0; + avCodecContext_->extradata_size = 0; + if (!isFlush) { + avCodecContext_->width = 0; + avCodecContext_->height = 0; + avCodecContext_->get_buffer2 = nullptr; + } +} + +int32_t FCodec::Start() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(callback_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Start codec failed: callback is null"); + CHECK_AND_RETURN_RET_LOG((state_ == State::Configured || state_ == State::Flushed), AVCS_ERR_INVALID_STATE, + "Start codec failed: not in Configured or Flushed state"); + if (state_ == State::Flushed) { + for (uint32_t i = 0; i < buffers_[INDEX_INPUT].size(); i++) { + callback_->OnInputBufferAvailable(i); + } + state_ = State::Running; + receiveTask_->Start(); + sendTask_->Start(); + AVCODEC_LOGI("Codec starts successful, state: Flushed -> Running"); + return AVCS_ERR_OK; + } + cachedFrame_ = std::shared_ptr(av_frame_alloc(), [](AVFrame *p) { av_frame_free(&p); }); + avPacket_ = std::shared_ptr(av_packet_alloc(), [](AVPacket *p) { av_packet_free(&p); }); + CHECK_AND_RETURN_RET_LOG((cachedFrame_ != nullptr && avPacket_ != nullptr), AVCS_ERR_UNKNOWN, + "Start codec failed: cannot allocate frame or packet"); + for (int32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) { + scaleData_[i] = nullptr; + scaleLineSize_[i] = 0; + } + isConverted_ = false; + std::unique_lock sLock(syncMutex_); + CHECK_AND_RETURN_RET_LOG(avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr) == 0, AVCS_ERR_UNKNOWN, + "Start codec failed: cannot open avcodec"); + sLock.unlock(); + int32_t ret = AllocateBuffers(); + if (ret != AVCS_ERR_OK) { + std::unique_lock sLock(syncMutex_); + avcodec_close(avCodecContext_.get()); + AVCODEC_LOGE("Start codec failed: cannot allocate buffers"); + return ret; + } + state_ = State::Running; + receiveTask_->Start(); + sendTask_->Start(); + if (CodecSurface_) { + renderTask_->Start(); + } + AVCODEC_LOGI("Codec starts successful, state: Configured -> Running"); + return AVCS_ERR_OK; +} + +int32_t FCodec::Stop() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(state_ != State::Configured, AVCS_ERR_OK, "Stop codec successful, state: Configured"); + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), AVCS_ERR_INVALID_STATE, + "Stop codec failed: not in running or Eos state"); + AVCODEC_LOGI("Stopping codec starts"); + state_ = State::Stopping; + if (sendTask_ != nullptr) { + sendTask_->Stop(); + } + if (receiveTask_ != nullptr) { + receiveTask_->Stop(); + } + if (CodecSurface_ && renderTask_ != nullptr) { + renderTask_->Stop(); + } + AVCODEC_LOGI("Stopp codec loops"); + std::unique_lock sLock(syncMutex_); + avcodec_close(avCodecContext_.get()); + if (avCodecContext_->extradata) { + av_free(avCodecContext_->extradata); + avCodecContext_->extradata = nullptr; + } + avCodecContext_->extradata_size = 0; + sLock.unlock(); + AVCODEC_LOGI("Stopp ffmpeg codec"); + CHECK_AND_RETURN_RET_LOG(ReleaseBuffers() == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Stop codec failed: cannot release buffer"); + state_ = State::Configured; + AVCODEC_LOGI("Stop codec successful, state: Configured"); + return AVCS_ERR_OK; +} + +int32_t FCodec::Flush() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), AVCS_ERR_INVALID_STATE, + "Flush codec failed: not in running or Eos state"); + state_ = State::Flushing; + sendTask_->Pause(); + receiveTask_->Pause(); + if (CodecSurface_) { + renderTask_->Pause(); + } + std::unique_lock sLock(syncMutex_); + avcodec_flush_buffers(avCodecContext_.get()); + ResetContext(true); + sLock.unlock(); + CHECK_AND_RETURN_RET_LOG(ReleaseBuffers(true) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Flush codec failed: cannot release buffer"); + std::unique_lock oLock(outputMutex_); + for (uint32_t i = 0; i < buffers_[INDEX_OUTPUT].size(); i++) { + buffers_[INDEX_OUTPUT][i]->owner_ = AVBuffer::OWNED_BY_CODEC; + codecAvailBuffers_.emplace_back(i); + } + oLock.unlock(); + std::unique_lock iLock(inputMutex_); + for (uint32_t i = 0; i < buffers_[INDEX_INPUT].size(); i++) { + buffers_[INDEX_INPUT][i]->owner_ = AVBuffer::OWNED_BY_USER; + } + iLock.unlock(); + state_ = State::Flushed; + AVCODEC_LOGI("Flush codec successful, state: Flushed"); + return AVCS_ERR_OK; +} + +int32_t FCodec::Reset() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(Release() == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Reset codec failed: cannot release codec"); + int32_t ret = Init(codecName_); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Reset codec failed: cannot init codec"); + } + AVCODEC_LOGI("Reset codec successful, state: Initialized"); + return ret; +} + +int32_t FCodec::Release() +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(state_ != State::Uninitialized, AVCS_ERR_OK, "Release codec successful"); + state_ = State::Releasing; + if (sendTask_ != nullptr) { + sendTask_->Stop(); + } + if (receiveTask_ != nullptr) { + receiveTask_->Stop(); + } + if (CodecSurface_ && renderTask_ != nullptr) { + renderTask_->Stop(); + } + std::unique_lock sLock(syncMutex_); + avcodec_close(avCodecContext_.get()); + ResetContext(); + sLock.unlock(); + format_ = Format(); + if (CodecSurface_ != nullptr) { + CodecSurface_ = nullptr; + } + CHECK_AND_RETURN_RET_LOG(ReleaseBuffers() == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Release codec failed: cannot release buffers"); + + state_ = State::Uninitialized; + AVCODEC_LOGI("Release codec successful, state: Uninitialized"); + return AVCS_ERR_OK; +} + +void FCodec::SetSurfaceParameter(const Format &format, const std::string_view &formatKey, uint32_t FORMAT_TYPE) +{ + int32_t val = 0; + if (formatKey == MediaDescriptionKey::MD_KEY_PIXEL_FORMAT && format.GetIntValue(formatKey, val)) { + VideoPixelFormat vpf = static_cast(val); + if (vpf == VideoPixelFormat::RGBA || vpf == VideoPixelFormat::BGRA) { + format_.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, val); + PixelFormat surfacePixelFmt = TranslateSurfaceFormat(vpf); + std::lock_guard oLock(outputMutex_); + SurfaceMemory::SetConfig(width_, height_, surfacePixelFmt); + } + } else if (formatKey == MediaDescriptionKey::MD_KEY_ROTATION_ANGLE && format.GetIntValue(formatKey, val)) { + GraphicTransformType sr = static_cast(val); + if (sr == GraphicTransformType::GRAPHIC_ROTATE_NONE || sr == GraphicTransformType::GRAPHIC_ROTATE_90 || + sr == GraphicTransformType::GRAPHIC_ROTATE_180 || sr == GraphicTransformType::GRAPHIC_ROTATE_270) { + format_.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, val); + std::lock_guard oLock(outputMutex_); + CodecSurface_->SetTransform(sr); + } + } else if (formatKey == MediaDescriptionKey::MD_KEY_SCALE_TYPE && format.GetIntValue(formatKey, val)) { + ScalingMode scaleMode = static_cast(val); + if (scaleMode == ScalingMode::SCALING_MODE_SCALE_TO_WINDOW || + scaleMode == ScalingMode::SCALING_MODE_SCALE_CROP) { + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, val); + std::lock_guard oLock(outputMutex_); + SurfaceMemory::SetScaleType(scaleMode); + } + } else { + AVCODEC_LOGW("Set parameter failed: %{public}.*s", formatKey.size(), formatKey.data()); + } +} + +int32_t FCodec::SetParameter(const Format &format) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(IsActive(), AVCS_ERR_INVALID_STATE, + "Set parameter failed: not in Running or Flushed state"); + for (auto &it : format.GetFormatMap()) { + if (CodecSurface_ != nullptr) { + if (it.second.type == FORMAT_TYPE_INT32) { + if (it.first == MediaDescriptionKey::MD_KEY_PIXEL_FORMAT || + it.first == MediaDescriptionKey::MD_KEY_ROTATION_ANGLE || + it.first == MediaDescriptionKey::MD_KEY_SCALE_TYPE) { + SetSurfaceParameter(format, it.first, it.second.type); + } else { + AVCODEC_LOGW("Current Version, %{public}s is not supported", it.first.c_str()); + } + } + } else { + AVCODEC_LOGW("Current Version, SetParameter function only support Suface Mode"); + } + } + AVCODEC_LOGI("Set parameter successful"); + return AVCS_ERR_OK; +} + +int32_t FCodec::GetOutputFormat(Format &format) +{ + AVCODEC_SYNC_TRACE; + format = format_; + AVCODEC_LOGI("Get outputFormat successful"); + return AVCS_ERR_OK; +} + +std::tuple FCodec::CalculateBufferSize() +{ + int32_t stride = AlignUp(width_, VIDEO_ALIGN_SIZE); + int32_t inputBufferSize = static_cast((stride * height_) * (VIDEO_PIX_DEPTH_YUV >> 1)); + int32_t outputBufferSize = inputBufferSize; + if (CodecSurface_ != nullptr) { + outputBufferSize = static_cast(stride * height_ * VIDEO_PIX_DEPTH_RGBA); + } + AVCODEC_LOGI("Input buffer size = %{public}d, output buffer size=%{public}d", inputBufferSize, outputBufferSize); + return std::make_tuple(inputBufferSize, outputBufferSize); +} + +int32_t FCodec::AllocateInputBuffer(int32_t bufferCnt, int32_t inBufferSize) +{ + int32_t valBufferCnt = 0; + for (uint32_t i = 0; i < bufferCnt; i++) { + std::shared_ptr buf = std::make_shared(); + buf->memory_ = AVSharedMemoryBase::CreateFromLocal(inBufferSize, AVSharedMemory::FLAGS_READ_WRITE, + std::string("inBuffer") + std::to_string(i)); + if (buf->memory_ == nullptr || buf->memory_->GetBase() == nullptr) { + AVCODEC_LOGE("Allocate input buffer failed, index=%{public}d", i); + continue; + } + buf->owner_ = AVBuffer::OWNED_BY_USER; + buffers_[INDEX_INPUT].emplace_back(buf); + callback_->OnInputBufferAvailable(valBufferCnt); + valBufferCnt++; + } + if (buffers_[INDEX_INPUT].size() < DEFAULT_MIN_BUFFER_CNT) { + AVCODEC_LOGE("Allocate input buffer failed: only %{public}d buffer is allocated, no memory", + buffers_[INDEX_INPUT].size()); + buffers_[INDEX_INPUT].clear(); + return AVCS_ERR_NO_MEMORY; + } + return AVCS_ERR_OK; +} + +int32_t FCodec::AllocateOutputBuffer(int32_t bufferCnt, int32_t outBufferSize) +{ + int32_t valBufferCnt = 0; + if (CodecSurface_) { + CHECK_AND_RETURN_RET_LOG(CodecSurface_->SetQueueSize(bufferCnt) == OHOS::SurfaceError::SURFACE_ERROR_OK, + AVCS_ERR_NO_MEMORY, "Surface set QueueSize=%{public}d failed", bufferCnt); + int32_t val32 = 0; + format_.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, val32); + PixelFormat surfacePixelFmt = TranslateSurfaceFormat(static_cast(val32)); + CHECK_AND_RETURN_RET_LOG(surfacePixelFmt != PixelFormat::PIXEL_FMT_BUTT, AVCS_ERR_UNSUPPORT, + "Failed to allocate output buffer: unsupported surface format"); + SurfaceMemory::SetSurface(CodecSurface_); + SurfaceMemory::SetConfig(static_cast(width_), static_cast(height_), surfacePixelFmt); + + format_.GetIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, val32); + SurfaceMemory::SetScaleType(static_cast(val32)); + format_.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, val32); + CodecSurface_->SetTransform(static_cast(val32)); + } + for (int i = 0; i < bufferCnt; i++) { + std::shared_ptr buf = std::make_shared(); + if (CodecSurface_ == nullptr) { + buf->memory_ = AVSharedMemoryBase::CreateFromLocal(outBufferSize, AVSharedMemory::FLAGS_READ_WRITE, + std::string("outBuffer") + std::to_string(i)); + } else { + buf->memory_ = SurfaceMemory::Create(); + } + if (buf->memory_ == nullptr || buf->memory_->GetBase() == nullptr) { + AVCODEC_LOGE("Allocate output buffer failed, index=%{public}d", i); + continue; + } + buf->owner_ = AVBuffer::OWNED_BY_CODEC; + buffers_[INDEX_OUTPUT].emplace_back(buf); + codecAvailBuffers_.emplace_back(valBufferCnt); + valBufferCnt++; + } + if (buffers_[INDEX_OUTPUT].size() < DEFAULT_MIN_BUFFER_CNT) { + AVCODEC_LOGE("Allocate output buffer failed: only %{public}d buffer is allocated, no memory", + buffers_[INDEX_OUTPUT].size()); + buffers_[INDEX_INPUT].clear(); + buffers_[INDEX_OUTPUT].clear(); + return AVCS_ERR_NO_MEMORY; + } + return AVCS_ERR_OK; +} + +int32_t FCodec::AllocateBuffers() +{ + int32_t inBufferSize = 0; + int32_t outBufferSize = 0; + std::tie(inBufferSize, outBufferSize) = CalculateBufferSize(); + CHECK_AND_RETURN_RET_LOG(inBufferSize > 0 && outBufferSize > 0, AVCS_ERR_INVALID_VAL, + "Allocate buffer with input size=%{public}d, output size=%{public}d failed", inBufferSize, + outBufferSize); + int32_t InputBufferCnt = 0; + int32_t OutputBufferCnt = 0; + format_.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_BUFFER_COUNT, InputBufferCnt); + format_.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_OUTPUT_BUFFER_COUNT, OutputBufferCnt); + if (AllocateInputBuffer(InputBufferCnt, inBufferSize) == AVCS_ERR_NO_MEMORY || + AllocateOutputBuffer(OutputBufferCnt, outBufferSize) == AVCS_ERR_NO_MEMORY) { + return AVCS_ERR_NO_MEMORY; + } + AVCODEC_LOGI("Allocate buffers successful"); + return AVCS_ERR_OK; +} + +int32_t FCodec::ReleaseBuffers(bool isFlush) +{ + std::unique_lock iLock(inputMutex_); + inBufQue_.clear(); + if (!isFlush) { + buffers_[INDEX_INPUT].clear(); + } + iLock.unlock(); + std::unique_lock oLock(outputMutex_); + codecAvailBuffers_.clear(); + if (!isFlush) { + buffers_[INDEX_OUTPUT].clear(); + } + oLock.unlock(); + if (scaleData_[0] != nullptr) { + if (isConverted_) { + av_free(scaleData_[0]); + isConverted_ = false; + scale_.reset(); + } + for (int32_t i = 0; i < AV_NUM_DATA_POINTERS; i++) { + scaleData_[i] = nullptr; + scaleLineSize_[i] = 0; + } + } + if (CodecSurface_) { + CodecSurface_->CleanCache(); + } + return AVCS_ERR_OK; +} + +std::shared_ptr FCodec::GetInputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(IsActive(), nullptr, "Get input buffer failed: not in Running or Flushed state"); + std::vector> &avBuffers = buffers_[INDEX_INPUT]; + CHECK_AND_RETURN_RET_LOG(index < avBuffers.size(), nullptr, + "Get buffer failed with bad index, index=%{public}zu", index); + CHECK_AND_RETURN_RET_LOG(avBuffers[index]->owner_ == AVBuffer::OWNED_BY_USER, nullptr, + "Get buffer failed with index=%{public}zu, buffer is not available", index); + std::shared_lock iLock(inputMutex_); + return std::static_pointer_cast(avBuffers[index]->memory_); +} + +std::shared_ptr FCodec::GetOutputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), nullptr, + "Get output buffer failed: not in Running/Flushed/EOS state"); + CHECK_AND_RETURN_RET_LOG(CodecSurface_ == nullptr, nullptr, "Get output buffer failed: surface output"); + std::vector> &avBuffers = buffers_[INDEX_OUTPUT]; + CHECK_AND_RETURN_RET_LOG(index < avBuffers.size(), nullptr, + "Get buffer failed with bad index, index=%{public}zu", index); + CHECK_AND_RETURN_RET_LOG(avBuffers[index]->owner_ == AVBuffer::OWNED_BY_USER, nullptr, + "Get buffer failed with index=%{public}zu, buffer is not available", index); + + std::unique_lock oLock(outputMutex_); + return std::static_pointer_cast(avBuffers[index]->memory_); +} + +int32_t FCodec::QueueInputBuffer(size_t index, const AVCodecBufferInfo &info, AVCodecBufferFlag &flag) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG(IsActive(), AVCS_ERR_INVALID_STATE, + "Queue input buffer failed: not in Running or Flushed state"); + std::vector> &inBuffers = buffers_[INDEX_INPUT]; + CHECK_AND_RETURN_RET_LOG(index < inBuffers.size(), AVCS_ERR_INVALID_VAL, + "Queue input buffer failed with bad index, index=%{public}zu, buffer_size=%{public}zu", + index, inBuffers.size()); + CHECK_AND_RETURN_RET_LOG(inBuffers[index]->owner_ == AVBuffer::OWNED_BY_USER, AVCS_ERR_INVALID_OPERATION, + "Queue input buffer failed: buffer with index=%{public}zu is not available", index); + std::unique_lock iLock(inputMutex_); + inBufQue_.emplace_back(index); + inBuffers[index]->owner_ = AVBuffer::OWNED_BY_CODEC; + inBuffers[index]->bufferInfo_ = info; + inBuffers[index]->bufferFlag_ = flag; + return AVCS_ERR_OK; +} + +void FCodec::SendFrame() +{ + AVCODEC_SYNC_TRACE; + if (!IsActive()) { + AVCODEC_LOGD("Cannot send frame to codec: not in Running or Flushed state"); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + std::unique_lock iLock(inputMutex_); + if (inBufQue_.empty()) { + AVCODEC_LOGD("Cannot send frame to codec: empty input buffer"); + iLock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + size_t index = inBufQue_.front(); + std::shared_ptr &inputBuffer = buffers_[INDEX_INPUT][index]; + iLock.unlock(); + if (inputBuffer->bufferFlag_ != AVCODEC_BUFFER_FLAG_EOS) { + avPacket_->data = inputBuffer->memory_->GetBase(); + avPacket_->size = static_cast(inputBuffer->bufferInfo_.size); + avPacket_->pts = inputBuffer->bufferInfo_.presentationTimeUs; + } else { + avPacket_->data = nullptr; + avPacket_->size = 0; + std::unique_lock sendLock(sendMutex_); + isSendEos_ = true; + sendCv_.wait(sendLock); + } + int ret; + std::unique_lock sLock(syncMutex_); + ret = avcodec_send_packet(avCodecContext_.get(), avPacket_.get()); + av_packet_unref(avPacket_.get()); + sLock.unlock(); + if (ret == 0) { + std::unique_lock iLock(inputMutex_); + inBufQue_.pop_front(); + iLock.unlock(); + inputBuffer->owner_ = AVBuffer::OWNED_BY_USER; + callback_->OnInputBufferAvailable(index); + } else { + AVCODEC_LOGD("Cannot send frame to codec: ffmpeg ret = %{public}s", AVStrError(ret).c_str()); + std::unique_lock sendLock(sendMutex_); + isSendWait_ = true; + sendCv_.wait(sendLock); // 接收帧后唤醒 + } +} + +int32_t FCodec::FillFrameBufferImpl(const std::shared_ptr &frameBuffer, AVPixelFormat ffmpegFormat, + VideoPixelFormat outputPixelFmt) +{ + int32_t ret; + std::shared_ptr frameMomory = frameBuffer->memory_; + if (IsYuvFormat(ffmpegFormat)) { + std::shared_ptr buffer = std::static_pointer_cast(frameMomory); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_INVALID_VAL, + "Failed to dynamic cast AVSharedMemory to ShareMemory"); + buffer->ClearUsedSize(); + ret = WriteYuvData(buffer, scaleData_, scaleLineSize_, format_); + frameBuffer->bufferInfo_.size = buffer->GetUsedSize(); + } else if (IsRgbFormat(ffmpegFormat)) { + std::shared_ptr buffer = std::static_pointer_cast(frameMomory); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_INVALID_VAL, + "Failed to dynamic cast AVSharedMemory to SurfaceMemory"); + buffer->ClearUsedSize(); + ret = WriteRgbData(buffer, scaleData_, scaleLineSize_, format_); + frameBuffer->bufferInfo_.size = buffer->GetUsedSize(); + } else { + AVCODEC_LOGE("Fill frame buffer failed : unsupported pixel format: %{public}d", outputPixelFmt); + return AVCS_ERR_UNSUPPORT; + } + + frameBuffer->bufferInfo_.presentationTimeUs = cachedFrame_->pts; + AVCODEC_LOGD("Fill frame buffer successful"); + return ret; +} + +int32_t FCodec::FillFrameBuffer(const std::shared_ptr &frameBuffer) +{ + CHECK_AND_RETURN_RET_LOG((cachedFrame_->flags & AV_FRAME_FLAG_CORRUPT) == 0, AVCS_ERR_INVALID_VAL, + "Recevie frame from codec failed: decoded frame is corrupt"); + AVPixelFormat ffmpegFormat = static_cast(cachedFrame_->format); + VideoPixelFormat outputPixelFmt; + if (CodecSurface_ == nullptr) { + outputPixelFmt = ConvertPixelFormatFromFFmpeg(cachedFrame_->format); + CHECK_AND_RETURN_RET_LOG(outputPixelFmt != VideoPixelFormat::UNKNOWN, AVCS_ERR_UNSUPPORT, + "Recevie frame from codec failed: unsupported pixel fmt"); + } else { + int32_t val32; + format_.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, val32); + outputPixelFmt = static_cast(val32); + ffmpegFormat = ConvertPixelFormatToFFmpeg(outputPixelFmt); + CHECK_AND_RETURN_RET_LOG(ffmpegFormat != AVPixelFormat::AV_PIX_FMT_NONE, AVCS_ERR_UNSUPPORT, + "Recevie frame from codec failed: unsupported pixel fmt"); + } + if (CodecSurface_ == nullptr || ffmpegFormat == static_cast(cachedFrame_->format)) { + for (int32_t i = 0; cachedFrame_->linesize[i] > 0; i++) { + scaleData_[i] = cachedFrame_->data[i]; + scaleLineSize_[i] = cachedFrame_->linesize[i]; + } + format_.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(outputPixelFmt)); + } else { + int32_t ret = ConvertVideoFrame(scale_, cachedFrame_, scaleData_, scaleLineSize_, ffmpegFormat); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Scale video frame failed: %{public}d", ret); + isConverted_ = true; + } + return FillFrameBufferImpl(frameBuffer, ffmpegFormat, outputPixelFmt); +} + +void FCodec::FramePostProcess(std::shared_ptr frameBuffer, int32_t status, int ret) +{ + size_t index = codecAvailBuffers_.front(); + if (status == AVCS_ERR_OK) { + std::unique_lock oLock(outputMutex_); + codecAvailBuffers_.pop_front(); + oLock.unlock(); + frameBuffer->owner_ = AVBuffer::OWNED_BY_USER; + if (ret == AVERROR_EOF) { + callback_->OnOutputBufferAvailable(index, frameBuffer->bufferInfo_, AVCODEC_BUFFER_FLAG_EOS); + } else { + if (isSendWait_) { + std::unique_lock sLock(sendMutex_); + isSendWait_ = false; + sendCv_.notify_one(); + } + callback_->OnOutputBufferAvailable(index, frameBuffer->bufferInfo_, AVCODEC_BUFFER_FLAG_NONE); + } + } else if (status == AVCS_ERR_UNSUPPORT) { + AVCODEC_LOGE("Recevie frame from codec failed: OnError"); + callback_->OnError(AVCODEC_ERROR_EXTEND_START, status); + state_ = State::Error; + } else { + AVCODEC_LOGI("Recevie frame from codec failed"); + } +} + +void FCodec::ReceiveFrame() +{ + AVCODEC_SYNC_TRACE; + if (!IsActive()) { + AVCODEC_LOGD("Cannot recevie frame from codec: not in Running or Flushed state"); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + std::unique_lock oLock(outputMutex_); + outputCv_.wait(oLock, [this]() { return codecAvailBuffers_.size() > 0; }); + if (!IsActive()) { + oLock.unlock(); + AVCODEC_LOGD("Cannot recevie frame from codec: not in Running or Flushed state"); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + size_t index = codecAvailBuffers_.front(); + std::shared_ptr frameBuffer = buffers_[INDEX_OUTPUT][index]; + oLock.unlock(); + int ret; + std::unique_lock sLock(syncMutex_); + av_frame_unref(cachedFrame_.get()); + ret = avcodec_receive_frame(avCodecContext_.get(), cachedFrame_.get()); + sLock.unlock(); + int32_t status = AVCS_ERR_OK; + if (ret >= 0) { + status = FillFrameBuffer(frameBuffer); + } else if (ret == AVERROR_EOF) { + AVCODEC_LOGI("Receive EOS frame"); + frameBuffer->bufferFlag_ = AVCODEC_BUFFER_FLAG_EOS; + state_ = State::EOS; + std::unique_lock sLock(syncMutex_); + avcodec_flush_buffers(avCodecContext_.get()); + } else if (ret == AVERROR(EAGAIN)) { + if (isSendWait_ || isSendEos_) { + std::lock_guard sLock(sendMutex_); + sendCv_.notify_one(); + } + return; + } else { + AVCODEC_LOGE("Failed to decoder: unknow error"); + return; + } + FramePostProcess(frameBuffer, status, ret); +} + +void FCodec::RenderFrame() +{ + AVCODEC_SYNC_TRACE; + if (!IsActive()) { + AVCODEC_LOGD("Failed to render frame to codec: not in Running or Flushed state"); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + std::unique_lock oLock(outputMutex_); + if (renderBuffers_.empty()) { + AVCODEC_LOGD("Failed to render frame to codec: empty render buffer"); + oLock.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + return; + } + size_t index = renderBuffers_.front(); + std::shared_ptr outputBuffer = buffers_[INDEX_OUTPUT][index]; + oLock.unlock(); + std::shared_ptr surfaceMemory = std::static_pointer_cast(outputBuffer->memory_); + while (true) { + if (surfaceMemory->GetSurfaceBuffer() == nullptr) { + std::this_thread::sleep_for(std::chrono::milliseconds(DEFAULT_TRY_DECODE_TIME)); + } else { + AVCODEC_LOGD("render frame success, index=%{public}zu", index); + std::lock_guard oLock(outputMutex_); + codecAvailBuffers_.emplace_back(index); + renderBuffers_.pop_front(); + outputBuffer->owner_ = AVBuffer::OWNED_BY_CODEC; + if (codecAvailBuffers_.size() == 1) { + outputCv_.notify_one(); + } + break; + } + } +} + +int32_t FCodec::ReleaseOutputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), AVCS_ERR_INVALID_STATE, + "Release output buffer failed: not in Running/Flushed/EOS"); + std::unique_lock oLock(outputMutex_); + if (std::find(codecAvailBuffers_.begin(), codecAvailBuffers_.end(), index) == codecAvailBuffers_.end() && + buffers_[INDEX_OUTPUT][index]->owner_ == AVBuffer::OWNED_BY_USER) { + buffers_[INDEX_OUTPUT][index]->owner_ = AVBuffer::OWNED_BY_CODEC; + codecAvailBuffers_.emplace_back(index); + if (codecAvailBuffers_.size() == 1) { + outputCv_.notify_one(); + } + return AVCS_ERR_OK; + } else { + AVCODEC_LOGE("Release output buffer failed: check your index=%{public}zu", index); + return AVCS_ERR_INVALID_VAL; + } +} + +int32_t FCodec::UpdateSurfaceMemory(std::shared_ptr &surfaceMemory, int64_t pts) +{ + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), AVCS_ERR_INVALID_STATE, + "Failed to update surface memory: Invalid state"); + + sptr surfaceBuffer = surfaceMemory->GetSurfaceBuffer(); + CHECK_AND_RETURN_RET_LOG(surfaceBuffer != nullptr, AVCS_ERR_INVALID_VAL, + "Failed to update surface memory: surface buffer is NULL"); + OHOS::BufferFlushConfig flushConfig = {{0, 0, surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight()}, pts}; + surfaceMemory->SetNeedRender(true); + surfaceMemory->UpdateSurfaceBufferScaleMode(); + auto res = CodecSurface_->FlushBuffer(surfaceBuffer, surfaceMemory->GetFlushFence(), flushConfig); + if (res != OHOS::SurfaceError::SURFACE_ERROR_OK) { + AVCODEC_LOGW("Failed to update surface memory: %{public}d", res); + surfaceMemory->SetNeedRender(false); + return AVCS_ERR_UNKNOWN; + } + return AVCS_ERR_OK; +} + +int32_t FCodec::RenderOutputBuffer(size_t index) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((IsActive() || state_ == State::EOS), AVCS_ERR_INVALID_STATE, + "Failed to render output buffer: invalid state"); + + if (std::find(codecAvailBuffers_.begin(), codecAvailBuffers_.end(), index) == codecAvailBuffers_.end() && + buffers_[INDEX_OUTPUT][index]->owner_ == AVBuffer::OWNED_BY_USER) { + // render + std::shared_ptr outputBuffer = buffers_[INDEX_OUTPUT][index]; + std::shared_ptr surfaceMemory = std::static_pointer_cast(outputBuffer->memory_); + + int32_t ret = UpdateSurfaceMemory(surfaceMemory, outputBuffer->bufferInfo_.presentationTimeUs); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Update surface memory failed: %{public}d", static_cast(ret)); + } else { + AVCODEC_LOGD("Update surface memory successful"); + } + surfaceMemory->ReleaseSurfaceBuffer(); + std::lock_guard oLock(outputMutex_); + outputBuffer->owner_ = AVBuffer::OWNED_BY_SURFACE; + renderBuffers_.emplace_back(index); + return AVCS_ERR_OK; + } else { + AVCODEC_LOGE("Failed to render output buffer with bad index, index=%{public}zu", index); + return AVCS_ERR_INVALID_VAL; + } +} + +int32_t FCodec::SetOutputSurface(sptr CodecSurface) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((!IsActive()), AVCS_ERR_INVALID_STATE, + "Set output surface failed: not in Running/Flushed state"); + CHECK_AND_RETURN_RET_LOG(CodecSurface != nullptr, AVCS_ERR_INVALID_VAL, + "Set output surface failed: surface is NULL"); + CodecSurface_ = CodecSurface; + format_.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(VideoPixelFormat::RGBA)); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_NONE)); + if (renderTask_ == nullptr) { + renderTask_ = std::make_shared("RenderFrame"); + renderTask_->RegisterHandler([this] { (void)RenderFrame(); }); + } + return AVCS_ERR_OK; +} + +int32_t FCodec::SetCallback(const std::shared_ptr &callback) +{ + AVCODEC_SYNC_TRACE; + CHECK_AND_RETURN_RET_LOG((!IsActive()), AVCS_ERR_INVALID_STATE, + "Set callback failed: not in Running/Flushed state"); + CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_INVALID_VAL, "Set callback failed: callback is NULL"); + callback_ = callback; + return AVCS_ERR_OK; +} + +int32_t FCodec::Pause() +{ + return AVCS_ERR_OK; +} + +int32_t FCodec::Resume() +{ + return AVCS_ERR_OK; +} +} // namespace Codec +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codeclist/BUILD.gn b/services/engine/codeclist/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..60fc8a71d6fff9a5a9fe5fbfc3e740b0a7835835 --- /dev/null +++ b/services/engine/codeclist/BUILD.gn @@ -0,0 +1,74 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("av_codec_engine_codeclist_config") { + visibility = [ ":*" ] + + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + + include_dirs = [ + "./", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/utils/include/", + "//third_party/libxml2/include", + + # "$av_codec_root_dir/services/engine/base/include/", + ] +} + +ohos_static_library("av_codec_engine_codeclist") { + configs = [ ":av_codec_engine_codeclist_config" ] + + sources = [ + "codec_ability_singleton.cpp", + "codeclist_core.cpp", + "codeclist_xml_parser.cpp", + ] + + deps = [ + "$av_codec_root_dir/services/dfx:av_codec_service_dfx", + "$av_codec_root_dir/services/utils:av_codec_service_utils", + "//third_party/libxml2:xml2", + ] + + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/engine/codeclist/codec_ability_singleton.cpp b/services/engine/codeclist/codec_ability_singleton.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24dc89df8ed7b692af95d99709f1ce709bbbf8bc --- /dev/null +++ b/services/engine/codeclist/codec_ability_singleton.cpp @@ -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. + */ + +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "codeclist_xml_parser.h" +#include "codec_ability_singleton.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecAbilitySingleton"}; +} + +namespace OHOS { +namespace Media { +CodecAbilitySingleton &CodecAbilitySingleton::GetInstance() +{ + AVCODEC_LOGE("CodecAbilitySingleton entered: start getting ins"); + static CodecAbilitySingleton instance; + bool ret = instance.ParseCodecXml(); + if (!ret) { + AVCODEC_LOGE("Parse codec xml failed"); + } + return instance; +} + +bool CodecAbilitySingleton::ParseCodecXml() +{ + AVCODEC_LOGE("start parsing xml"); + std::lock_guard lock(mutex_); + if (isParsered_) { + AVCODEC_LOGE("Parse codec xml done"); + return true; + } + CodeclistXmlParser xmlParser; + bool ret = xmlParser.LoadConfiguration(); + if (!ret) { + this->isParsered_ = false; + AVCODEC_LOGE("AVCodecList LoadConfiguration failed"); + return false; + } + ret = xmlParser.Parse(); + if (!ret) { + isParsered_ = false; + AVCODEC_LOGE("AVCodecList Parse failed."); + return false; + } + std::vector data = xmlParser.GetCapabilityDataArray(); + capabilityDataArray_.insert(capabilityDataArray_.end(), data.begin(), data.end()); + isParsered_ = true; + AVCODEC_LOGE("Parse codec xml successful, num = %{public}zu", capabilityDataArray_.size()); + return true; +} + +CodecAbilitySingleton::CodecAbilitySingleton() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecAbilitySingleton::~CodecAbilitySingleton() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecAbilitySingleton::RegisterCapabilityArray(const std::vector &capaArray) +{ + std::lock_guard lock(mutex_); + capabilityDataArray_.insert(capabilityDataArray_.end(), capaArray.begin(), capaArray.end()); + AVCODEC_LOGD("RegisterCapability success"); +} + +std::vector CodecAbilitySingleton::GetCapabilityArray() +{ + std::lock_guard lock(mutex_); + return capabilityDataArray_; +} +} // namespace Media +} // namespace OHOS diff --git a/services/engine/codeclist/codec_ability_singleton.h b/services/engine/codeclist/codec_ability_singleton.h new file mode 100644 index 0000000000000000000000000000000000000000..1a3b524efc6d35ca4b8d81e2d5a9e6577b0a6543 --- /dev/null +++ b/services/engine/codeclist/codec_ability_singleton.h @@ -0,0 +1,40 @@ +/* + * 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 CODEABILITY_SINGLETON_H +#define CODEABILITY_SINGLETON_H + +#include +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) CodecAbilitySingleton : public NoCopyable { +public: + ~CodecAbilitySingleton(); + static CodecAbilitySingleton &GetInstance(); + void RegisterCapabilityArray(const std::vector &capaArray); + std::vector GetCapabilityArray(); + +private: + CodecAbilitySingleton(); + bool ParseCodecXml(); + std::vector capabilityDataArray_; + std::mutex mutex_; + bool isParsered_ {false}; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEABILITY_SINGLETON_H \ No newline at end of file diff --git a/services/engine/codeclist/codeclist_builder.cpp b/services/engine/codeclist/codeclist_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da5116b682b5aa8bc4bb2fba686c60c3f267c55f --- /dev/null +++ b/services/engine/codeclist/codeclist_builder.cpp @@ -0,0 +1,34 @@ +/* + * 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 "codeclist_builder.h" +#include "fcodec.h" + +namespace OHOS { +namespace Media { +int32_t VideoCodecList::GetCapabilityList(std::vector &caps) +{ + std::shared_ptr codec = std::make_shared(); + auto ret = codec->getCodecCapability(caps); + return ret; +} + +int32_t AudioCodecList::GetCapabilityList(std::vector &caps) +{ + (void)caps; + return 0; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codeclist/codeclist_builder.h b/services/engine/codeclist/codeclist_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..cb45089b79c48d6703253ea17b18b71b74f436c6 --- /dev/null +++ b/services/engine/codeclist/codeclist_builder.h @@ -0,0 +1,36 @@ +/* + * 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 CODECLIST_BUILDER_H +#define CODECLIST_BUILDER_H + +#include "avcodec_info.h" +#include "codeclistbase.h" + +namespace OHOS { +namespace Media { +class VideoCodecList : public CodecListBase { +public: + ~VideoCodecList() override = default; + int32_t GetCapabilityList(std::vector &caps) override; +}; +class AudioCodecList : public CodecListBase { +public: + ~AudioCodecList() override = default; + int32_t GetCapabilityList(std::vector &caps) override; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_BUILDER_H diff --git a/services/engine/codeclist/codeclist_core.cpp b/services/engine/codeclist/codeclist_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f1a607507b74b349e22975f0f486e86ee9bf6fd --- /dev/null +++ b/services/engine/codeclist/codeclist_core.cpp @@ -0,0 +1,232 @@ +/* + * 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 // fabs +#include "codec_ability_singleton.h" +#include "avcodec_log.h" +#include "codeclist_core.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListCore"}; +constexpr float EPSINON = 0.0001; +} // namespace + +namespace OHOS { +namespace Media { +CodecListCore::CodecListCore() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListCore::~CodecListCore() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +bool CodecListCore::CheckBitrate(const Format &format, const CapabilityData &data) +{ + int32_t targetBitrate; + if (!format.ContainKey("bitrate")) { + AVCODEC_LOGD("The bitrate of the format are not specified"); + return true; + } + (void)format.GetIntValue("bitrate", targetBitrate); + if (data.bitrate.minVal > targetBitrate || data.bitrate.maxVal < targetBitrate) { + return false; + } + return true; +} + +bool CodecListCore::CheckVideoResolution(const Format &format, const CapabilityData &data) +{ + int32_t targetWidth; + int32_t targetHeight; + if ((!format.ContainKey("width")) || (!format.ContainKey("height"))) { + AVCODEC_LOGD("The width and height of the format are not specified"); + return true; + } + (void)format.GetIntValue("width", targetWidth); + (void)format.GetIntValue("height", targetHeight); + if (data.width.minVal > targetWidth || data.width.maxVal < targetWidth || data.height.minVal > targetHeight || + data.height.maxVal < targetHeight) { + return false; + } + return true; +} + +bool CodecListCore::CheckVideoPixelFormat(const Format &format, const CapabilityData &data) +{ + int32_t targetPixelFormat; + if (!format.ContainKey("pixel_format")) { + AVCODEC_LOGD("The pixel_format of the format are not specified"); + return true; + } + (void)format.GetIntValue("pixel_format", targetPixelFormat); + if (find(data.pixFormat.begin(), data.pixFormat.end(), targetPixelFormat) == data.pixFormat.end()) { + return false; + } + return true; +} + +bool CodecListCore::CheckVideoFrameRate(const Format &format, const CapabilityData &data) +{ + if (!format.ContainKey("frame_rate")) { + AVCODEC_LOGD("The frame_rate of the format are not specified"); + return true; + } + + switch (format.GetValueType(std::string_view("frame_rate"))) { + case FORMAT_TYPE_INT32: { + int32_t targetFrameRateInt; + (void)format.GetIntValue("frame_rate", targetFrameRateInt); + if (data.frameRate.minVal > targetFrameRateInt || data.frameRate.maxVal < targetFrameRateInt) { + return false; + } + break; + } + case FORMAT_TYPE_DOUBLE: { + double targetFrameRateDouble; + (void)format.GetDoubleValue("frame_rate", targetFrameRateDouble); + double minValDouble {data.frameRate.minVal}; + double maxValDouble {data.frameRate.maxVal}; + if ((minValDouble > targetFrameRateDouble && fabs(minValDouble - targetFrameRateDouble) >= EPSINON) || + (maxValDouble < targetFrameRateDouble && fabs(maxValDouble - targetFrameRateDouble) >= EPSINON)) { + return false; + } + break; + } + default: + break; + } + return true; +} + +bool CodecListCore::CheckAudioChannel(const Format &format, const CapabilityData &data) +{ + int32_t targetChannel; + if (!format.ContainKey("channel_count")) { + AVCODEC_LOGD("The channel_count of the format are not specified"); + return true; + } + (void)format.GetIntValue("channel_count", targetChannel); + if (data.channels.minVal > targetChannel || data.channels.maxVal < targetChannel) { + return false; + } + return true; +} + +bool CodecListCore::CheckAudioSampleRate(const Format &format, const CapabilityData &data) +{ + int32_t targetSampleRate; + if (!format.ContainKey("samplerate")) { + AVCODEC_LOGD("The samplerate of the format are not specified"); + return true; + } + (void)format.GetIntValue("samplerate", targetSampleRate); + if (find(data.sampleRate.begin(), data.sampleRate.end(), targetSampleRate) == data.sampleRate.end()) { + return false; + } + return true; +} + +bool CodecListCore::IsVideoCapSupport(const Format &format, const CapabilityData &data) +{ + return CheckVideoResolution(format, data) && CheckVideoPixelFormat(format, data) && + CheckVideoFrameRate(format, data) && CheckBitrate(format, data); +} + +bool CodecListCore::IsAudioCapSupport(const Format &format, const CapabilityData &data) +{ + return CheckAudioChannel(format, data) && CheckAudioSampleRate(format, data) && CheckBitrate(format, data); +} + +// mime是必要参数 +std::string CodecListCore::FindCodec(const Format &format, bool isEncoder) +{ + (void)isEncoder; + + std::lock_guard lock(mutex_); + if (!format.ContainKey("codec_mime")) { + AVCODEC_LOGD("Get MimeType from format failed"); + return ""; + } + std::string targetMimeType; + (void)format.GetStringValue("codec_mime", targetMimeType); + + AVCodecType codecType = AVCODEC_TYPE_NONE; + bool isVideo = targetMimeType.find("video") != std::string::npos; + if (isVideo) { + codecType = isEncoder ? AVCODEC_TYPE_VIDEO_ENCODER : AVCODEC_TYPE_VIDEO_DECODER; + } else { + codecType = isEncoder ? AVCODEC_TYPE_AUDIO_ENCODER : AVCODEC_TYPE_AUDIO_DECODER; + } + + int isVendor = -1; + bool isVendorKey = format.ContainKey("codec_vendor_flag"); + if (isVendorKey) { + (void)format.GetIntValue("codec_vendor_flag", isVendor); + } + std::vector capabilityDataArray = CodecAbilitySingleton::GetInstance().GetCapabilityArray(); + auto iter = capabilityDataArray.begin(); + while (iter != capabilityDataArray.end()) { + if ((*iter).codecType != codecType || (*iter).mimeType != targetMimeType || + (isVendorKey && (*iter).isVendor != isVendor)) { + ++iter; + continue; + } + if (isVideo) { + if (IsVideoCapSupport(format, *iter)) { + return (*iter).codecName; + } + } else { + if (IsAudioCapSupport(format, *iter)) { + return (*iter).codecName; + } + } + ++iter; + } + return ""; +} + +std::string CodecListCore::FindEncoder(const Format &format) +{ + return FindCodec(format, true); +} + +std::string CodecListCore::FindDecoder(const Format &format) +{ + return FindCodec(format, false); +} + +CapabilityData CodecListCore::CreateCapability(std::string codecName) +{ + std::lock_guard lock(mutex_); + CapabilityData capData; + if (codecName.empty()) { + return capData; + } + std::vector capabilityDataArray = CodecAbilitySingleton::GetInstance().GetCapabilityArray(); + auto iter = capabilityDataArray.begin(); + while (iter != capabilityDataArray.end()) { + if (codecName == ((*iter).codecName)) { + capData = (*iter); + break; + } + ++iter; + } + return capData; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codeclist/codeclist_core.h b/services/engine/codeclist/codeclist_core.h new file mode 100644 index 0000000000000000000000000000000000000000..5c5b15eb09c48021e7e5f911b4d91e3573ac361e --- /dev/null +++ b/services/engine/codeclist/codeclist_core.h @@ -0,0 +1,48 @@ +/* + * 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 CODECLIST_CORE_H +#define CODECLIST_CORE_H + +#include +#include "nocopyable.h" +#include "format.h" +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) CodecListCore : public NoCopyable { +public: + CodecListCore(); + ~CodecListCore(); + std::string FindEncoder(const Format &format); + std::string FindDecoder(const Format &format); + CapabilityData CreateCapability(std::string codecName); + +private: + bool CheckBitrate(const Format &format, const CapabilityData &data); + bool CheckVideoResolution(const Format &format, const CapabilityData &data); + bool CheckVideoPixelFormat(const Format &format, const CapabilityData &data); + bool CheckVideoFrameRate(const Format &format, const CapabilityData &data); + bool CheckAudioChannel(const Format &format, const CapabilityData &data); + bool CheckAudioSampleRate(const Format &format, const CapabilityData &data); + bool IsVideoCapSupport(const Format &format, const CapabilityData &data); + bool IsAudioCapSupport(const Format &format, const CapabilityData &data); + std::string FindCodec(const Format &format, bool isEncoder); + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_CORE_H diff --git a/services/engine/codeclist/codeclist_xml_parser.cpp b/services/engine/codeclist/codeclist_xml_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..804f97972f4922ca7158d838e3f1fd5698ed7682 --- /dev/null +++ b/services/engine/codeclist/codeclist_xml_parser.cpp @@ -0,0 +1,611 @@ +/* + * 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 "avcodec_log.h" +#include "string_ex.h" +#include "codeclist_xml_parser.h" +using namespace std; +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodeclistXmlParser"}; +constexpr int32_t PAIR_LENGTH = 2; +const string AVCODEC_CAPS_FILE = "/etc/codec/avcodec_caps.xml"; +} // namespace +namespace OHOS { +namespace Media { +const std::unordered_map VIDEO_PROFILE_MAP = { + // H263 + {"H263BackwardCompatible", H263_PROFILE_BACKWARD_COMPATIBLE}, + {"H263Baseline", H263_PROFILE_BASELINE}, + {"H263H320Coding", H263_PROFILE_H320_CODING}, + {"H263HighCompression", H263_PROFILE_HIGH_COMPRESSION}, + {"H263HighLatency", H263_PROFILE_HIGH_LATENCY}, + {"H263ISWV2", H263_PROFILE_ISW_V2}, + {"H263ISWV3", H263_PROFILE_ISW_V3}, + {"H263Interlace", H263_PROFILE_INTERLACE}, + {"H263Internet", H263_PROFILE_INTERNET}, + // H264 + {"AVCBaseline", AVC_PROFILE_BASELINE}, + {"AVCHighCompression", AVC_PROFILE_CONSTRAINED_BASELINE}, + {"AVCConstrainedHigh", AVC_PROFILE_CONSTRAINED_HIGH}, + {"AVCExtended", AVC_PROFILE_EXTENDED}, + {"AVCHigh", AVC_PROFILE_HIGH}, + {"AVCHigh10", AVC_PROFILE_HIGH_10}, + {"AVCHigh422", AVC_PROFILE_HIGH_422}, + {"AVCHigh444", AVC_PROFILE_HIGH_444}, + {"AVCMain", AVC_PROFILE_MAIN}, + // H265 + {"HEVCMain", HEVC_PROFILE_MAIN}, + {"HEVCMain10", HEVC_PROFILE_MAIN_10}, + {"HEVCMainStill", HEVC_PROFILE_MAIN_STILL}, + // MPEG2 + {"MPEG2_422", MPEG2_PROFILE_422}, + {"MPEG2High", MPEG2_PROFILE_HIGH}, + {"MPEG2Main", MPEG2_PROFILE_MAIN}, + {"MPEG2SNR", MPEG2_PROFILE_SNR}, + {"MPEG2Simple", MPEG2_PROFILE_SIMPLE}, + {"MPEG2Spatial", MPEG2_PROFILE_SPATIAL}, + // MPEG4 + {"MPEG4AdvancedCoding", MPEG4_PROFILE_ADVANCED_CODING}, + {"MPEG4AdvancedCore", MPEG4_PROFILE_ADVANCED_CORE}, + {"MPEG4AdvancedRealTime", MPEG4_PROFILE_ADVANCED_REAL_TIME}, + {"MPEG4AdvancedScalable", MPEG4_PROFILE_ADVANCED_SCALABLE}, + {"MPEG4AdvancedSimple", MPEG4_PROFILE_ADVANCED_SIMPLE}, + {"MPEG4BasicAnimated", MPEG4_PROFILE_BASIC_ANIMATED}, + {"MPEG4Core", MPEG4_PROFILE_CORE}, + {"MPEG4CoreScalable", MPEG4_PROFILE_CORE_SCALABLE}, + {"MPEG4Hybrid", MPEG4_PROFILE_HYBRID}, + {"MPEG4Main", MPEG4_PROFILE_MAIN}, + {"MPEG4Nbit", MPEG4_PROFILE_NBIT}, + {"MPEG4ScalableTexture", MPEG4_PROFILE_SCALABLE_TEXTURE}, + {"MPEG4Simple", MPEG4_PROFILE_SIMPLE}, + {"MPEG4SimpleFBA", MPEG4_PROFILE_SIMPLE_FBA}, + {"MPEG4SimpleFace", MPEG4_PROFILE_SIMPLE_FACE}, + {"MPEG4SimpleScalable", MPEG4_PROFILE_SIMPLE_SCALABLE}, + // VP8 + {"VP8Main", VP8_PROFILE_MAIN}, +}; + +const std::unordered_map AUDIO_PROFILE_MAP = { + {"AAC_LC", AAC_PROFILE_LC}, {"AAC_ELD", AAC_PROFILE_ELD}, {"AAC_ERLC", AAC_PROFILE_ERLC}, + {"AAC_HE", AAC_PROFILE_HE}, {"AAC_HE_V2", AAC_PROFILE_HE_V2}, {"AAC_LD", AAC_PROFILE_LD}, + {"AAC_Main", AAC_PROFILE_MAIN}, +}; + +const std::unordered_map VIDEO_LEVEL_MAP = { + // H264 + {"AVC_LEVEL_1", AVC_LEVEL_1}, + {"AVC_LEVEL_1b", AVC_LEVEL_1b}, + {"AVC_LEVEL_11", AVC_LEVEL_11}, + {"AVC_LEVEL_12", AVC_LEVEL_12}, + {"AVC_LEVEL_13", AVC_LEVEL_13}, + {"AVC_LEVEL_2", AVC_LEVEL_2}, + {"AVC_LEVEL_21", AVC_LEVEL_21}, + {"AVC_LEVEL_22", AVC_LEVEL_22}, + {"AVC_LEVEL_3", AVC_LEVEL_3}, + {"AVC_LEVEL_31", AVC_LEVEL_31}, + {"AVC_LEVEL_32", AVC_LEVEL_32}, + {"AVC_LEVEL_4", AVC_LEVEL_4}, + {"AVC_LEVEL_41", AVC_LEVEL_41}, + {"AVC_LEVEL_42", AVC_LEVEL_42}, + {"AVC_LEVEL_5", AVC_LEVEL_5}, + {"AVC_LEVEL_51", AVC_LEVEL_51}, + // H265 + {"HEVC_LEVEL_1", HEVC_LEVEL_1}, + {"HEVC_LEVEL_2", HEVC_LEVEL_2}, + {"HEVC_LEVEL_21", HEVC_LEVEL_21}, + {"HEVC_LEVEL_3", HEVC_LEVEL_3}, + {"HEVC_LEVEL_31", HEVC_LEVEL_31}, + {"HEVC_LEVEL_4", HEVC_LEVEL_4}, + {"HEVC_LEVEL_41", HEVC_LEVEL_41}, + {"HEVC_LEVEL_5", HEVC_LEVEL_5}, + {"HEVC_LEVEL_51", HEVC_LEVEL_51}, + {"HEVC_LEVEL_52", HEVC_LEVEL_52}, + {"HEVC_LEVEL_6", HEVC_LEVEL_6}, + {"HEVC_LEVEL_61", HEVC_LEVEL_61}, + {"HEVC_LEVEL_62", HEVC_LEVEL_62}, + + {"MPEG2_LEVEL_LL", MPEG2_LEVEL_LL}, + {"MPEG2_LEVEL_ML", MPEG2_LEVEL_ML}, + {"MPEG2_LEVEL_H14", MPEG2_LEVEL_H14}, + {"MPEG2_LEVEL_HL", MPEG2_LEVEL_HL}, + + {"MPEG4_LEVEL_0", MPEG4_LEVEL_0}, + {"MPEG4_LEVEL_0B", MPEG4_LEVEL_0B}, + {"MPEG4_LEVEL_1", MPEG4_LEVEL_1}, + {"MPEG4_LEVEL_2", MPEG4_LEVEL_2}, + {"MPEG4_LEVEL_3", MPEG4_LEVEL_3}, + {"MPEG4_LEVEL_4", MPEG4_LEVEL_4}, + {"MPEG4_LEVEL_4A", MPEG4_LEVEL_4A}, + {"MPEG4_LEVEL_5", MPEG4_LEVEL_5}, +}; + +const std::unordered_map VIDEO_FORMAT_MAP = { + {"YUV420P", YUV420P}, {"NV12", NV12}, {"NV21", NV21}, {"RGBA", RGBA}, {"BGRA", BGRA}, +}; + +const std::unordered_map AUDIO_BITDEPTH_MAP = { + {"U8", SAMPLE_U8}, + {"S16LE", SAMPLE_S16LE}, + {"S24LE", SAMPLE_S24LE}, + {"S32LE", SAMPLE_S32LE}, +}; + +const std::unordered_map BITRATE_MODE_MAP = { + {"CBR", CBR}, + {"VBR", VBR}, + {"CQ", CQ}, +}; + +const std::unordered_map CODEC_TYPE_MAP = { + {"VIDEO_ENCODER", AVCODEC_TYPE_VIDEO_ENCODER}, + {"VIDEO_DECODER", AVCODEC_TYPE_VIDEO_DECODER}, + {"AUDIO_ENCODER", AVCODEC_TYPE_AUDIO_ENCODER}, + {"AUDIO_DECODER", AVCODEC_TYPE_AUDIO_DECODER}, +}; + +CodeclistXmlParser::CodeclistXmlParser() +{ + capabilityKeys_ = { + "codecName", + "codecType", + "mimeType", + "isVendor", + "maxInstance", + "bitrate", + "channels", + "complexity", + "alignment", + "width", + "height", + "frameRate", + "encodeQuality", + "blockPerFrame", + "blockPerSecond", + "blockSize", + "sampleRate", + "pixFormat", + "bitDepth", + "profiles", + "bitrateMode", + "profileLevelsMap", + "measuredFrameRate", + "supportSwapWidthHeight", + }; + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodeclistXmlParser::~CodeclistXmlParser() +{ + Destroy(); + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +bool CodeclistXmlParser::LoadConfiguration() +{ + mDoc_ = xmlReadFile(AVCODEC_CAPS_FILE.c_str(), nullptr, 0); + if (mDoc_ == nullptr) { + AVCODEC_LOGE("AVCodec xmlReadFile failed"); + return false; + } + return true; +} + +bool CodeclistXmlParser::Parse() +{ + xmlNode *root = xmlDocGetRootElement(mDoc_); + if (root == nullptr) { + AVCODEC_LOGE("AVCodec xmlDocGetRootElement failed"); + return false; + } + return ParseInternal(root); +} + +void CodeclistXmlParser::Destroy() +{ + if (mDoc_ != nullptr) { + xmlFreeDoc(mDoc_); + } + return; +} + +bool CodeclistXmlParser::ParseInternal(xmlNode *node) +{ + xmlNode *currNode = node; + for (; currNode != nullptr; currNode = currNode->next) { + if (currNode->type == XML_ELEMENT_NODE) { + switch (GetNodeNameAsInt(currNode)) { + case AUDIO_DECODER: + case AUDIO_ENCODER: + case VIDEO_DECODER: + case VIDEO_ENCODER: { + ParseData(currNode); + break; + } + default: ParseInternal(currNode->children); break; + } + } + } + return true; +} + +bool CodeclistXmlParser::TransStrAsRange(const string &str, Range &range) +{ + if (str == "null" || str == "") { + AVCODEC_LOGD("str is null"); + return false; + } + size_t pos = str.find("-"); + if (pos != str.npos && pos + 1 < str.size()) { + string head = str.substr(0, pos); + string tail = str.substr(pos + 1); + if (!StrToInt(head, range.minVal)) { + AVCODEC_LOGE("call StrToInt func false, input str is: %{public}s", head.c_str()); + return false; + } + if (!StrToInt(tail, range.maxVal)) { + AVCODEC_LOGE("call StrToInt func false, input str is: %{public}s", tail.c_str()); + return false; + } + } else { + AVCODEC_LOGE("Can not find the delimiter of \"-\" in : %{public}s", str.c_str()); + return false; + } + return true; +} + +bool CodeclistXmlParser::TransStrAsSize(const string &str, ImgSize &size) +{ + if (str == "null" || str == "") { + AVCODEC_LOGD("str is null"); + return false; + } + size_t pos = str.find("x"); + if (pos != str.npos && pos + 1 < str.size()) { + string head = str.substr(0, pos); + string tail = str.substr(pos + 1); + if (!StrToInt(head, size.width)) { + AVCODEC_LOGE("call StrToInt func false, input str is: %{public}s", head.c_str()); + return false; + } + if (!StrToInt(tail, size.height)) { + AVCODEC_LOGE("call StrToInt func false, input str is: %{public}s", tail.c_str()); + return false; + } + } else { + AVCODEC_LOGD("Can not find the delimiter of \"x\" in : %{public}s", str.c_str()); + return false; + } + return true; +} + +std::vector CodeclistXmlParser::TransStrAsIntegerArray(const std::vector &spilt) +{ + std::vector array; + for (auto iter = spilt.begin(); iter != spilt.end(); iter++) { + int32_t num = -1; + if (!StrToInt(*iter, num)) { + AVCODEC_LOGE("call StrToInt func false, input str is: %{public}s", iter->c_str()); + return array; + } + array.push_back(num); + } + return array; +} + +std::vector CodeclistXmlParser::TransMapAsIntegerArray(const std::unordered_map &capMap, + const std::vector &spilt) +{ + std::vector res; + for (auto iter = spilt.begin(); iter != spilt.end(); iter++) { + if (capMap.find(*iter) != capMap.end()) { + res.emplace_back(capMap.at(*iter)); + } else { + AVCODEC_LOGD("can not find %{public}s in capabilityMap", iter->c_str()); + } + } + return res; +} + +bool CodeclistXmlParser::SpiltKeyList(const string &str, const string &delim, std::vector &spilt) +{ + if (str == "") { + return false; + } + string strAddDelim = str; + if (str.back() != delim.back()) { + strAddDelim = str + delim; + } + size_t size = strAddDelim.size(); + for (size_t i = 0; i < size; ++i) { + size_t pos = strAddDelim.find(delim, i); + if (pos != strAddDelim.npos) { + string s = strAddDelim.substr(i, pos - i); + spilt.push_back(s); + i = pos + delim.size() - 1; + } + } + return true; +} + +bool CodeclistXmlParser::SetCapabilityStringData(std::unordered_map dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + AVCODEC_LOGE("Get %{public}s: %{public}s", capabilityKey.c_str(), capabilityValue.c_str()); + dataMap.at(capabilityKey) = capabilityValue; + return true; +} + +bool CodeclistXmlParser::SetCapabilityIntData(std::unordered_map dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + if (capabilityKey == "codecType") { + if (CODEC_TYPE_MAP.find(capabilityValue) == CODEC_TYPE_MAP.end()) { + return false; + } + dataMap.at(capabilityKey) = CODEC_TYPE_MAP.at(capabilityValue); + AVCODEC_LOGD("The value of %{public}s in the configuration file is incorrect.", capabilityValue.c_str()); + } else { + if (!StrToInt(capabilityValue, dataMap.at(capabilityKey))) { + return false; + } + } + return true; +} + +bool CodeclistXmlParser::SetCapabilityBoolData(std::unordered_map dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + if (capabilityValue == "true") { + dataMap.at(capabilityKey) = true; + } else if (capabilityValue == "false") { + dataMap.at(capabilityKey) = false; + } else { + AVCODEC_LOGD("The value of %{public}s in the configuration file is incorrect.", capabilityValue.c_str()); + return false; + } + return true; +} + +bool CodeclistXmlParser::SetCapabilityRangeData(std::unordered_map dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + Range range; + bool ret = TransStrAsRange(capabilityValue, range); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "failed:can not trans %{public}s", capabilityValue.c_str()); + dataMap.at(capabilityKey) = range; + return true; +} + +bool CodeclistXmlParser::SetCapabilitySizeData(std::unordered_map dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + ImgSize size; + bool ret = TransStrAsSize(capabilityValue, size); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "failed:can not trans %{public}s", capabilityValue.c_str()); + dataMap.at(capabilityKey) = size; + return true; +} + +bool CodeclistXmlParser::SetCapabilityHashRangeData(std::unordered_map &> dataMap, + const string &capabilityKey, + const string &capabilityValue) +{ + std::map resolutionFrameRateMap; + std::vector spilt; + bool ret = SpiltKeyList(capabilityValue, ",", spilt); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "failed:can not split %{public}s", capabilityValue.c_str()); + for (auto iter = spilt.begin(); iter != spilt.end(); iter++) { + std::vector resolutionFrameRateVector; + ImgSize resolution; + Range frameRate; + ret = SpiltKeyList(*iter, "@", resolutionFrameRateVector); + CHECK_AND_RETURN_RET_LOG(ret != false && resolutionFrameRateVector.size() == PAIR_LENGTH, false, + "failed:can not trans %{public}s", iter->c_str()); + if (!(TransStrAsSize(resolutionFrameRateVector[0], resolution) && + TransStrAsRange(resolutionFrameRateVector[1], frameRate))) { + AVCODEC_LOGD("failed:can not trans %{public}s for resolution or frame rate", iter->c_str()); + return false; + } + resolutionFrameRateMap.insert(std::make_pair(resolution, frameRate)); + } + dataMap.at(capabilityKey) = resolutionFrameRateMap; + return true; +} + +bool CodeclistXmlParser::SetCapabilityHashVectorData( + std::unordered_map> &> dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + std::map> profileLevelsMap; + std::vector spilt; + bool ret = SpiltKeyList(capabilityValue, ",", spilt); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "failed:can not split %{public}s", capabilityValue.c_str()); + for (auto iter = spilt.begin(); iter != spilt.end(); iter++) { + std::vector profileLevelsVector; + std::vector LevelValsVector; + int32_t profileKey; + std::vector array; + ret = SpiltKeyList(*iter, "@", profileLevelsVector); + CHECK_AND_RETURN_RET_LOG(ret != false && profileLevelsVector.size() == PAIR_LENGTH, false, + "failed:can not trans %{public}s", iter->c_str()); + if (VIDEO_PROFILE_MAP.find(profileLevelsVector[0]) != VIDEO_PROFILE_MAP.end()) { + profileKey = VIDEO_PROFILE_MAP.at(profileLevelsVector[0]); + } else if (AUDIO_PROFILE_MAP.find(profileLevelsVector[0]) != AUDIO_PROFILE_MAP.end()) { + profileKey = AUDIO_PROFILE_MAP.at(profileLevelsVector[0]); + } else { + return false; + } + ret = SpiltKeyList(profileLevelsVector[1], "#", LevelValsVector); + CHECK_AND_RETURN_RET_LOG(ret != false && LevelValsVector.size() > 0, false, "failed:can not trans %{public}s", + profileLevelsVector[1].c_str()); + string lev = LevelValsVector[0]; + if (VIDEO_LEVEL_MAP.find(lev) != VIDEO_LEVEL_MAP.end()) { + array = TransMapAsIntegerArray(VIDEO_LEVEL_MAP, LevelValsVector); + } + profileLevelsMap.insert(std::make_pair(profileKey, array)); + AVCODEC_LOGE("Profile: %{public}s=%{public}d, level0: %{public}s=%{public}d", profileLevelsVector[0].c_str(), + profileKey, profileLevelsVector[1].c_str(), array[0]); + } + dataMap.at(capabilityKey) = profileLevelsMap; + return true; +} + +bool CodeclistXmlParser::IsNumberArray(const std::vector &strArray) +{ + for (auto iter = strArray.begin(); iter != strArray.end(); iter++) { + for (char const &c : *iter) { + if (std::isdigit(c) == 0) { + return false; + } + } + } + return true; +} + +bool CodeclistXmlParser::SetCapabilityVectorData(std::unordered_map &> dataMap, + const string &capabilityKey, const string &capabilityValue) +{ + std::vector spilt; + std::vector array; + bool ret = SpiltKeyList(capabilityValue, ",", spilt); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "failed:can not split %{public}s", capabilityValue.c_str()); + if (spilt.size() > 0) { + string probe = spilt[0]; + if (VIDEO_PROFILE_MAP.find(probe) != VIDEO_PROFILE_MAP.end()) { + array = TransMapAsIntegerArray(VIDEO_PROFILE_MAP, spilt); + } else if (AUDIO_PROFILE_MAP.find(probe) != AUDIO_PROFILE_MAP.end()) { + array = TransMapAsIntegerArray(AUDIO_PROFILE_MAP, spilt); + } else if (VIDEO_FORMAT_MAP.find(probe) != VIDEO_FORMAT_MAP.end()) { + array = TransMapAsIntegerArray(VIDEO_FORMAT_MAP, spilt); + } else if (AUDIO_BITDEPTH_MAP.find(probe) != AUDIO_BITDEPTH_MAP.end()) { + array = TransMapAsIntegerArray(AUDIO_BITDEPTH_MAP, spilt); + } else if (BITRATE_MODE_MAP.find(probe) != BITRATE_MODE_MAP.end()) { + array = TransMapAsIntegerArray(BITRATE_MODE_MAP, spilt); + } else if (IsNumberArray(spilt)) { + array = TransStrAsIntegerArray(spilt); + } else { + AVCODEC_LOGD("The value of %{public}s in the configuration file is incorrect.", capabilityValue.c_str()); + return false; + } + dataMap.at(capabilityKey) = array; + } + return true; +} + +bool CodeclistXmlParser::SetCapabilityData(CapabilityData &data, const string &capabilityKey, + const string &capabilityValue) const +{ + std::unordered_map capabilityStringMap = { + {"codecName", data.codecName}, {"mimeType", data.mimeType}}; + std::unordered_map capIntMap = { + {"codecType", data.codecType}, {"maxInstance", data.maxInstance}}; + std::unordered_map capabilityBoolMap = { + {"isVendor", data.isVendor}, {"supportSwapWidthHeight", data.supportSwapWidthHeight}}; + std::unordered_map capSizeMap = {{"blockSize", data.blockSize}, {"alignment", data.alignment}}; + std::unordered_map &> capabilityHashRangeMap = { + {"measuredFrameRate", data.measuredFrameRate}}; + std::unordered_map capabilityRangeMap = { + {"bitrate", data.bitrate}, {"complexity", data.complexity}, {"frameRate", data.frameRate}, + {"width", data.width}, {"height", data.height}, {"blockPerFrame", data.blockPerFrame}, + {"channels", data.channels}, {"encodeQuality", data.encodeQuality}, {"blockPerSecond", data.blockPerSecond}}; + std::unordered_map &> capabilityVectorMap = { + {"sampleRate", data.sampleRate}, {"pixFormat", data.pixFormat}, {"bitDepth", data.bitDepth}, + {"profiles", data.profiles}, {"bitrateMode", data.bitrateMode}}; + std::unordered_map> &> capabilityHashVectorMap = { + {"profileLevelsMap", data.profileLevelsMap}}; + bool ret = false; + if (capabilityStringMap.find(capabilityKey) != capabilityStringMap.end()) { + ret = SetCapabilityStringData(capabilityStringMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityStringData failed"); + } else if (capIntMap.find(capabilityKey) != capIntMap.end()) { + ret = SetCapabilityIntData(capIntMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityIntData failed"); + } else if (capabilityBoolMap.find(capabilityKey) != capabilityBoolMap.end()) { + ret = SetCapabilityBoolData(capabilityBoolMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityBoolData failed"); + } else if (capSizeMap.find(capabilityKey) != capSizeMap.end()) { + ret = SetCapabilitySizeData(capSizeMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilitySizeData failed"); + } else if (capabilityHashRangeMap.find(capabilityKey) != capabilityHashRangeMap.end()) { + ret = SetCapabilityHashRangeData(capabilityHashRangeMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityHashRangeData failed"); + } else if (capabilityRangeMap.find(capabilityKey) != capabilityRangeMap.end()) { + ret = SetCapabilityRangeData(capabilityRangeMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityRangeData failed"); + } else if (capabilityVectorMap.find(capabilityKey) != capabilityVectorMap.end()) { + ret = SetCapabilityVectorData(capabilityVectorMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityVectorData failed"); + } else if (capabilityHashVectorMap.find(capabilityKey) != capabilityHashVectorMap.end()) { + ret = SetCapabilityHashVectorData(capabilityHashVectorMap, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityVectorData failed"); + } else { + CHECK_AND_RETURN_RET_LOG(ret != false, false, "can not find capabilityKey: %{public}s", capabilityKey.c_str()); + } + return true; +} + +bool CodeclistXmlParser::ParseData(xmlNode *node) +{ + xmlNode *child = node->xmlChildrenNode; + string capabilityValue; + CapabilityData capabilityData; + for (; child != nullptr; child = child->next) { + if (!xmlStrEqual(child->name, reinterpret_cast("Item"))) { + continue; + } + for (auto it = capabilityKeys_.begin(); it != capabilityKeys_.end(); it++) { + string capabilityKey = *it; + if (xmlHasProp(child, reinterpret_cast(const_cast(capabilityKey.c_str())))) { + xmlChar *pXmlProp = + xmlGetProp(child, reinterpret_cast(const_cast(capabilityKey.c_str()))); + CHECK_AND_CONTINUE_LOG(pXmlProp != nullptr, "SetCapabilityData failed"); + capabilityValue = string(reinterpret_cast(pXmlProp)); + bool ret = SetCapabilityData(capabilityData, capabilityKey, capabilityValue); + CHECK_AND_RETURN_RET_LOG(ret != false, false, "SetCapabilityData failed"); + break; + } + } + } + capabilityDataArray_.push_back(capabilityData); + return true; +} + +NodeName CodeclistXmlParser::GetNodeNameAsInt(xmlNode *node) +{ + if (xmlStrEqual(node->name, reinterpret_cast("Codecs"))) { + return CODECS; + } else if (xmlStrEqual(node->name, reinterpret_cast("AudioCodecs"))) { + return AUDIO_CODECS; + } else if (xmlStrEqual(node->name, reinterpret_cast("VideoCodecs"))) { + return VIDEO_CODECS; + } else if (xmlStrEqual(node->name, reinterpret_cast("AudioDecoder"))) { + return AUDIO_DECODER; + } else if (xmlStrEqual(node->name, reinterpret_cast("AudioEncoder"))) { + return AUDIO_ENCODER; + } else if (xmlStrEqual(node->name, reinterpret_cast("VideoDecoder"))) { + return VIDEO_DECODER; + } else if (xmlStrEqual(node->name, reinterpret_cast("VideoEncoder"))) { + return VIDEO_ENCODER; + } else { + return UNKNOWN; + } +} + +std::vector CodeclistXmlParser::GetCapabilityDataArray() const +{ + return capabilityDataArray_; +} +// #endif +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/codeclist/codeclist_xml_parser.h b/services/engine/codeclist/codeclist_xml_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c00656450d83fbd65414899266a4fdda64269ea7 --- /dev/null +++ b/services/engine/codeclist/codeclist_xml_parser.h @@ -0,0 +1,85 @@ +/* + * 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 CODECLIST_XML_PARSER_H +#define CODECLIST_XML_PARSER_H + +#include +#include +#include +#include +#include +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +enum NodeName : int32_t { + CODECS, + AUDIO_CODECS, + VIDEO_CODECS, + AUDIO_DECODER, + AUDIO_ENCODER, + VIDEO_DECODER, + VIDEO_ENCODER, + UNKNOWN +}; + +class CodeclistXmlParser { +public: + CodeclistXmlParser(); + ~CodeclistXmlParser(); + bool LoadConfiguration(); + bool Parse(); + void Destroy(); + std::vector GetCapabilityDataArray() const; + +private: + static bool IsNumberArray(const std::vector &strArray); + static bool TransStrAsRange(const std::string &str, Range &range); + static bool TransStrAsSize(const std::string &str, ImgSize &size); + static std::vector TransMapAsIntegerArray(const std::unordered_map &capMap, + const std::vector &spilt); + static std::vector TransStrAsIntegerArray(const std::vector &spilt); + static bool SpiltKeyList(const std::string &str, const std::string &delim, std::vector &spilt); + static bool SetCapabilityStringData(std::unordered_map dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool SetCapabilityIntData(std::unordered_map dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool SetCapabilityBoolData(std::unordered_map dataMap, const std::string &capabilityKey, + const std::string &capabilityValue); + static bool SetCapabilityRangeData(std::unordered_map dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool SetCapabilityVectorData(std::unordered_map &> dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool SetCapabilitySizeData(std::unordered_map dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool SetCapabilityHashRangeData(std::unordered_map &> dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + static bool + SetCapabilityHashVectorData(std::unordered_map> &> dataMap, + const std::string &capabilityKey, const std::string &capabilityValue); + + static NodeName GetNodeNameAsInt(xmlNode *node); + bool SetCapabilityData(CapabilityData &data, const std::string &capabilityKey, + const std::string &capabilityValue) const; + bool ParseInternal(xmlNode *node); + bool ParseData(xmlNode *node); + std::vector capabilityDataArray_; + xmlDoc *mDoc_ = nullptr; + std::vector capabilityKeys_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_XML_PARSER_H \ No newline at end of file diff --git a/services/engine/common/BUILD.gn b/services/engine/common/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..cf36bd899b765d33cc9ac59b620d88687bf16c44 --- /dev/null +++ b/services/engine/common/BUILD.gn @@ -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. + +import("//build/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_static_library("av_codec_engine_common") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/utils/include", + "//base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface/", + "//foundation/graphic/graphic_2d/utils/sync_fence/export", + "//drivers/peripheral/display/interfaces/include", + "//third_party/ffmpeg", + ] + + sources = [ + "$av_codec_root_dir/services/engine/common/codec_utils.cpp", + "$av_codec_root_dir/services/engine/common/surface_memory.cpp", + ] + + public_deps = [ + "$av_codec_root_dir/services/dfx:av_codec_service_dfx", + "$av_codec_root_dir/services/utils:av_codec_service_utils", + "//commonlibrary/c_utils/base:utils", + "//foundation/graphic/graphic_2d:libsurface", + "//foundation/graphic/graphic_2d/utils:sync_fence", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/ffmpeg:libohosffmpeg", + ] + + external_deps = [ + "c_utils:utils", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + ] +} diff --git a/services/engine/common/codec_utils.cpp b/services/engine/common/codec_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96f9e24a183831f09984948a24a08c0578f86f6c --- /dev/null +++ b/services/engine/common/codec_utils.cpp @@ -0,0 +1,230 @@ +/* + * 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 "avcodec_log.h" +#include "media_description.h" +#include "codec_utils.h" + +namespace OHOS { +namespace Media { +namespace Codec { +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "FCodec"}; +std::map g_pixelFormatMap = { + {VideoPixelFormat::YUV420P, AV_PIX_FMT_YUV420P}, + {VideoPixelFormat::NV12, AV_PIX_FMT_NV12}, + {VideoPixelFormat::NV21, AV_PIX_FMT_NV21}, + {VideoPixelFormat::RGBA, AV_PIX_FMT_RGBA}, + {VideoPixelFormat::BGRA, AV_PIX_FMT_BGRA}, +}; +} // namespace + +int32_t ConvertVideoFrame(std::shared_ptr scale, std::shared_ptr frame, uint8_t **dstData, + int32_t *dstLineSize, AVPixelFormat dstPixFmt) +{ + if (scale == nullptr) { + scale = std::make_shared(); + ScalePara scalePara {static_cast(frame->width), + static_cast(frame->height), + static_cast(frame->format), + static_cast(frame->width), + static_cast(frame->height), + dstPixFmt}; + CHECK_AND_RETURN_RET_LOG(scale->Init(scalePara, dstData, dstLineSize) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Scale init error"); + } + return scale->Convert(frame->data, frame->linesize, dstData, dstLineSize); +} + +int32_t WriteRgbDataStride(const std::shared_ptr &frameBuffer, uint8_t **scaleData, + int32_t *scaleLineSize, int32_t stride, const Format &format) +{ + int32_t height; + int32_t fmt; + format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height); + format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt); + VideoPixelFormat pixFmt = static_cast(fmt); + if (pixFmt == VideoPixelFormat::RGBA || pixFmt == VideoPixelFormat::BGRA) { + size_t srcPos = 0; + size_t dstPos = 0; + int32_t writeSize = scaleLineSize[0]; + for (uint32_t colNum = 0; colNum < height; colNum++) { + frameBuffer->Write(scaleData[0] + srcPos, writeSize, dstPos); + dstPos += stride; + } + } else { + return AVCS_ERR_UNSUPPORT; + } + AVCODEC_LOGD("WriteRgbDataStride success"); + return AVCS_ERR_OK; +} + +int32_t WriteYuvData(const std::shared_ptr &frameBuffer, uint8_t **scaleData, + int32_t *scaleLineSize, const Format &format) +{ + int32_t height; + int32_t fmt; + format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height); + format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt); + VideoPixelFormat pixFmt = static_cast(fmt); + size_t ySize = static_cast(scaleLineSize[0] * height); // yuv420: 411 nv21 + size_t uvSize = static_cast(scaleLineSize[1] * height / 2); // 2 + size_t frameSize = 0; + if (pixFmt == VideoPixelFormat::YUV420P) { + frameSize = ySize + (uvSize * 2); // 2 + } else if (pixFmt == VideoPixelFormat::NV21 || pixFmt == VideoPixelFormat::NV12) { + frameSize = ySize + uvSize; + } + CHECK_AND_RETURN_RET_LOG(frameBuffer->GetSize() >= frameSize, AVCS_ERR_NO_MEMORY, + "output buffer size is not enough: real[%{public}zu], need[%{public}zu]", + frameBuffer->GetSize(), frameSize); + if (pixFmt == VideoPixelFormat::YUV420P) { + frameBuffer->Write(scaleData[0], ySize); + frameBuffer->Write(scaleData[1], uvSize); + frameBuffer->Write(scaleData[2], uvSize); // 2 + } else if ((pixFmt == VideoPixelFormat::NV12) || (pixFmt == VideoPixelFormat::NV21)) { + frameBuffer->Write(scaleData[0], ySize); + frameBuffer->Write(scaleData[1], uvSize); + } else { + return AVCS_ERR_UNSUPPORT; + } + AVCODEC_LOGD("WriteYuvData success"); + return AVCS_ERR_OK; +} + +int32_t WriteRgbData(const std::shared_ptr &frameBuffer, uint8_t **scaleData, int32_t *scaleLineSize, + const Format &format) +{ + int32_t width; + int32_t height; + int32_t fmt; + format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width); + format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height); + format.GetIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, fmt); + VideoPixelFormat pixFmt = static_cast(fmt); + uint32_t stride = frameBuffer->GetSurfaceBufferStride(); + if (stride % width) { + return WriteRgbDataStride(frameBuffer, scaleData, scaleLineSize, stride, format); + } + size_t frameSize = static_cast(scaleLineSize[0] * height); + CHECK_AND_RETURN_RET_LOG(frameBuffer->GetSize() >= frameSize, AVCS_ERR_NO_MEMORY, + "output buffer size is not enough: real[%{public}zu], need[%{public}zu]", + frameBuffer->GetSize(), frameSize); + if (pixFmt == VideoPixelFormat::RGBA || pixFmt == VideoPixelFormat::BGRA) { + frameBuffer->Write(scaleData[0], frameSize); + } else { + return AVCS_ERR_UNSUPPORT; + } + AVCODEC_LOGD("WriteRgbData success"); + return AVCS_ERR_OK; +} + +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); +} + +PixelFormat TranslateSurfaceFormat(const VideoPixelFormat &surfaceFormat) +{ + switch (surfaceFormat) { + case VideoPixelFormat::YUV420P: { + return PixelFormat::PIXEL_FMT_YCBCR_420_P; + } + case VideoPixelFormat::RGBA: { + return PixelFormat::PIXEL_FMT_RGBA_8888; + } + case VideoPixelFormat::BGRA: { + return PixelFormat::PIXEL_FMT_BGRA_8888; + } + case VideoPixelFormat::NV12: { + return PixelFormat::PIXEL_FMT_YCBCR_420_SP; + } + case VideoPixelFormat::NV21: { + return PixelFormat::PIXEL_FMT_YCRCB_420_SP; + } + default: + return PixelFormat::PIXEL_FMT_BUTT; + } +} + +VideoPixelFormat ConvertPixelFormatFromFFmpeg(int32_t ffmpegPixelFormat) +{ + auto iter = std::find_if( + g_pixelFormatMap.begin(), g_pixelFormatMap.end(), + [&](const std::pair &tmp) -> bool { return tmp.second == ffmpegPixelFormat; }); + return iter == g_pixelFormatMap.end() ? VideoPixelFormat::UNKNOWN : iter->first; +} + +AVPixelFormat ConvertPixelFormatToFFmpeg(VideoPixelFormat pixelFormat) +{ + auto iter = std::find_if( + g_pixelFormatMap.begin(), g_pixelFormatMap.end(), + [&](const std::pair &tmp) -> bool { return tmp.first == pixelFormat; }); + return iter == g_pixelFormatMap.end() ? AV_PIX_FMT_NONE : iter->second; +} + +bool IsYuvFormat(AVPixelFormat format) +{ + return (format == AV_PIX_FMT_YUV420P || format == AV_PIX_FMT_NV12 || format == AV_PIX_FMT_NV21); +} + +bool IsRgbFormat(AVPixelFormat format) +{ + return (format == AV_PIX_FMT_RGBA || format == AV_PIX_FMT_BGRA); +} + +int32_t Scale::Init(const ScalePara &scalePara, uint8_t **dstData, int32_t *dstLineSize) +{ + scalePara_ = scalePara; + if (swsCtx_ != nullptr) { + return AVCS_ERR_OK; + } + auto swsContext = + sws_getContext(scalePara_.srcWidth, scalePara_.srcHeight, scalePara_.srcFfFmt, scalePara_.dstWidth, + scalePara_.dstHeight, scalePara_.dstFfFmt, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); + if (swsContext == nullptr) { + return AVCS_ERR_UNKNOWN; + } + swsCtx_ = std::shared_ptr(swsContext, [](struct SwsContext *ptr) { + if (ptr != nullptr) { + sws_freeContext(ptr); + } + }); + auto ret = av_image_alloc(dstData, dstLineSize, scalePara_.dstWidth, scalePara_.dstHeight, scalePara_.dstFfFmt, + scalePara_.align); + if (ret < 0) { + return AVCS_ERR_UNKNOWN; + } + for (int32_t i = 0; dstLineSize[i] > 0; i++) { + if (dstData[i] && !dstLineSize[i]) { + return AVCS_ERR_UNKNOWN; + } + } + return AVCS_ERR_OK; +} + +int32_t Scale::Convert(uint8_t **srcData, const int32_t *srcLineSize, uint8_t **dstData, int32_t *dstLineSize) +{ + auto res = sws_scale(swsCtx_.get(), srcData, srcLineSize, 0, scalePara_.srcHeight, dstData, dstLineSize); + if (res < 0) { + return AVCS_ERR_UNKNOWN; + } + return AVCS_ERR_OK; +} +} // namespace Codec +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/common/include/codec_utils.h b/services/engine/common/include/codec_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..3f56186f3f16f9fc9fbe316308c3ef31f0add8a0 --- /dev/null +++ b/services/engine/common/include/codec_utils.h @@ -0,0 +1,83 @@ +/* + * 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 CODEC_UTILS_H +#define CODEC_UTILS_H + +#include "surface.h" +#include "avcodec_errors.h" +#include "surface_memory.h" +#include "avsharedmemorybase.h" +#include "format.h" +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavutil/imgutils.h" +#include "libswscale/swscale.h" +}; +namespace OHOS { +namespace Media { +namespace Codec { +enum struct VideoFormat : uint8_t { + UNKNOWN = 0, + H264 = 1, + MPEG4 = 2, +}; +enum struct VideoPixelFormat : uint32_t { + UNKNOWN, + YUV420P, ///< planar YUV 4:2:0, 1 Cr & Cb sample per 2x2 Y samples + NV12, ///< semi-planar YUV 4:2:0, UVUV... + NV21, ///< semi-planar YUV 4:2:0, VUVU... + RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... +}; + +struct ScalePara { + int32_t srcWidth = 0; + int32_t srcHeight = 0; + AVPixelFormat srcFfFmt = AVPixelFormat::AV_PIX_FMT_NONE; + int32_t dstWidth = 0; + int32_t dstHeight = 0; + AVPixelFormat dstFfFmt = AVPixelFormat::AV_PIX_FMT_RGBA; + int32_t align = 16; +}; + +struct Scale { +public: + int32_t Init(const ScalePara &scalePara, uint8_t **dstData, int32_t *dstLineSize); + int32_t Convert(uint8_t **srcData, const int32_t *srcLineSize, uint8_t **dstData, int32_t *dstLineSize); + +private: + ScalePara scalePara_; + std::shared_ptr swsCtx_ = nullptr; +}; + +PixelFormat TranslateSurfaceFormat(const VideoPixelFormat &surfaceFormat); +VideoPixelFormat ConvertPixelFormatFromFFmpeg(int32_t ffmpegPixelFormat); +AVPixelFormat ConvertPixelFormatToFFmpeg(VideoPixelFormat pixelFormat); +int32_t ConvertVideoFrame(std::shared_ptr scale, std::shared_ptr frame, uint8_t **dstData, + int32_t *dstLineSize, AVPixelFormat dstPixFmt); +int32_t WriteRgbDataStride(const std::shared_ptr &frameBuffer, uint8_t **scaleData, + int32_t *scaleLineSize, int32_t stride, const Format &format); +int32_t WriteYuvData(const std::shared_ptr &frameBuffer, uint8_t **scaleData, + int32_t *scaleLineSize, const Format &format); +int32_t WriteRgbData(const std::shared_ptr &frameBuffer, uint8_t **scaleData, int32_t *scaleLineSize, + const Format &format); +std::string AVStrError(int errnum); +bool IsYuvFormat(AVPixelFormat format); +bool IsRgbFormat(AVPixelFormat format); +} // namespace Codec +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/common/include/surface_memory.h b/services/engine/common/include/surface_memory.h new file mode 100644 index 0000000000000000000000000000000000000000..9fd7dde10e7dc9b6ec1108900a5138e1d271c27e --- /dev/null +++ b/services/engine/common/include/surface_memory.h @@ -0,0 +1,70 @@ +/* + * 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 AV_CODEC_SURFACE_MEMORY_H +#define AV_CODEC_SURFACE_MEMORY_H + +#include "refbase.h" +#include "surface.h" +#include "avsharedmemory.h" +#include "sync_fence.h" + +namespace OHOS { +namespace Media { +namespace { +constexpr uint64_t USAGE = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA; +constexpr int32_t SURFACE_STRIDE_ALIGN = 8; +constexpr int32_t TIMEOUT = 0; +} // namespace + +class SurfaceMemory : public AVSharedMemory { +public: + SurfaceMemory() = default; + virtual ~SurfaceMemory() override; + static std::shared_ptr Create(); + static void SetSurface(sptr surface); + static void SetConfig(int32_t width, int32_t height, int32_t format, uint64_t usage = USAGE, + int32_t strideAlign = SURFACE_STRIDE_ALIGN, int32_t timeout = TIMEOUT); + static void SetScaleType(ScalingMode videoScaleMode); + size_t Write(const uint8_t *in, size_t writeSize, size_t position = INVALID_POSITION); + size_t Read(uint8_t *out, size_t readSize, size_t position = INVALID_POSITION); + void ClearUsedSize(); + void AllocSurfaceBuffer(); + void ReleaseSurfaceBuffer(); + sptr GetSurfaceBuffer(); + uint32_t GetSurfaceBufferStride(); + int32_t GetFlushFence(); + int32_t GetUsedSize() const; + void UpdateSurfaceBufferScaleMode(); + void SetNeedRender(bool needRender); + virtual uint8_t *GetBase() const override; + virtual int32_t GetSize() const override; + virtual uint32_t GetFlags() const final; + +private: + // Allocated memory size. + sptr surfaceBuffer_ = nullptr; + size_t size_ = 0; + int32_t fence_ = -1; + uint32_t stride_ = 0; + bool needRender_ = false; + static sptr surfaceMem_; + static BufferRequestConfig requestConfig_; + static ScalingMode scalingMode_; + static constexpr size_t INVALID_POSITION = -1; +}; +} // namespace Media +} // namespace OHOS +#endif diff --git a/services/engine/common/surface_memory.cpp b/services/engine/common/surface_memory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df3fb50c3abec573d6b6d7549cccd05041e2c9c0 --- /dev/null +++ b/services/engine/common/surface_memory.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2023-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 "avcodec_log.h" +#include "securec.h" +#include +#include "native_averrors.h" +#include "surface_memory.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-SurfaceMemory"}; +} +namespace OHOS { +namespace Media { +sptr SurfaceMemory::surfaceMem_ = nullptr; +BufferRequestConfig SurfaceMemory::requestConfig_ = {0}; +ScalingMode SurfaceMemory::scalingMode_ = {ScalingMode::SCALING_MODE_SCALE_TO_WINDOW}; + +std::shared_ptr SurfaceMemory::Create() +{ + CHECK_AND_RETURN_RET_LOG(surfaceMem_ != nullptr, nullptr, "surface is nullptr"); + CHECK_AND_RETURN_RET_LOG(requestConfig_.width != 0 && requestConfig_.height != 0, nullptr, + "surface config invalid"); + std::shared_ptr buffer = std::make_shared(); + buffer->AllocSurfaceBuffer(); + return buffer; +} + +SurfaceMemory::~SurfaceMemory() +{ + ReleaseSurfaceBuffer(); +} + +size_t SurfaceMemory::Write(const uint8_t* in, size_t writeSize, size_t position) +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, 0, "surfaceBuffer is nullptr"); + size_t start = 0; + size_t capacity = GetSize(); + if (position == INVALID_POSITION) { + start = size_; + } else { + start = std::min(position, capacity); + } + size_t length = std::min(writeSize, capacity - start); + if (memcpy_s(GetBase() + start, length, in, length) != EOK) { + return 0; + } + size_ = start + length; + return length; +} + +size_t SurfaceMemory::Read(uint8_t* out, size_t readSize, size_t position) +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, 0, "surfaceBuffer is nullptr"); + size_t start = 0; + size_t maxLength = size_; + if (position != INVALID_POSITION) { + start = std::min(position, size_); + maxLength = size_ - start; + } + size_t length = std::min(readSize, maxLength); + if (memcpy_s(out, length, GetBase() + start, length) != EOK) { + return 0; + } + return length; +} + +void SurfaceMemory::AllocSurfaceBuffer() +{ + if (surfaceMem_ == nullptr || surfaceBuffer_ != nullptr) { + AVCODEC_LOGE("surface is nullptr or surfaceBuffer is not nullptr"); + return; + } + int32_t releaseFence = -1; + auto ret = surfaceMem_->RequestBuffer(surfaceBuffer_, releaseFence, requestConfig_); + if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK || surfaceBuffer_ == nullptr) { + if (ret == OHOS::SurfaceError::SURFACE_ERROR_NO_BUFFER) { + AVCODEC_LOGE("buffer queue is no more buffers"); + } else { + AVCODEC_LOGE("surface RequestBuffer fail, ret: %{public}" PRIu64, static_cast(ret)); + } + return; + } + if (surfaceBuffer_->Map() != OHOS::SurfaceError::SURFACE_ERROR_OK) { + AVCODEC_LOGE("surface buffer Map failed"); + surfaceMem_->CancelBuffer(surfaceBuffer_); + return; + } + sptr autoFence = new(std::nothrow) SyncFence(releaseFence); + if (autoFence != nullptr) { + autoFence->Wait(100); // 100ms + } + ret = surfaceMem_->SetScalingMode(surfaceBuffer_->GetSeqNum(), scalingMode_); + if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { + AVCODEC_LOGE("surface buffer set scaling mode failed"); + surfaceMem_->CancelBuffer(surfaceBuffer_); + return; + } + + auto bufferHandle = surfaceBuffer_->GetBufferHandle(); + if (bufferHandle != nullptr) { + stride_ = bufferHandle->stride; + } + fence_ = -1; + AVCODEC_LOGD("request surface buffer success, releaseFence: %{public}d", releaseFence); +} + +void SurfaceMemory::ReleaseSurfaceBuffer() +{ + if (surfaceBuffer_ == nullptr) { + return; + } + if (!needRender_) { + auto ret = surfaceMem_->CancelBuffer(surfaceBuffer_); + if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { + AVCODEC_LOGE("surface CancelBuffer fail, ret: %{public}" PRIu64, static_cast(ret)); + } + } + surfaceBuffer_ = nullptr; +} + +sptr SurfaceMemory::GetSurfaceBuffer() +{ + if (!surfaceBuffer_) { + // request surface buffer again when old buffer flush to nullptr + AllocSurfaceBuffer(); + } + return surfaceBuffer_; +} + +uint32_t SurfaceMemory::GetSurfaceBufferStride() +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, 0, "surfaceBuffer is nullptr"); + return stride_; +} + +int32_t SurfaceMemory::GetFlushFence() +{ + return fence_; +} + +void SurfaceMemory::ClearUsedSize() +{ + size_ = 0; +} + +void SurfaceMemory::SetNeedRender(bool needRender) +{ + needRender_ = needRender; +} + +void SurfaceMemory::UpdateSurfaceBufferScaleMode() +{ + if (surfaceBuffer_ == nullptr) { + AVCODEC_LOGE("surfaceBuffer is nullptr"); + return; + } + + auto ret = surfaceMem_->SetScalingMode(surfaceBuffer_->GetSeqNum(), scalingMode_); + if (ret != OHOS::SurfaceError::SURFACE_ERROR_OK) { + AVCODEC_LOGE("update surface buffer scaling mode fail, ret: %{public}" PRIu64, static_cast(ret)); + } +} + +void SurfaceMemory::SetSurface(sptr surface) +{ + surfaceMem_ = surface; +} + +void SurfaceMemory::SetConfig(int32_t width, int32_t height, int32_t format, uint64_t usage, int32_t strideAlign, + int32_t timeout) +{ + requestConfig_ = { + .width=width, + .height=height, + .strideAlignment=strideAlign, + .format=format, + .usage=usage, + .timeout=timeout + }; +} + +void SurfaceMemory::SetScaleType(ScalingMode videoScaleMode) +{ + scalingMode_ = videoScaleMode; +} + +uint8_t* SurfaceMemory::GetBase() const +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, nullptr, "surfaceBuffer is nullptr"); + return static_cast(surfaceBuffer_->GetVirAddr()); +} + +int32_t SurfaceMemory::GetUsedSize() const +{ + return size_; +} + +int32_t SurfaceMemory::GetSize() const +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, -1, "surfaceBuffer is nullptr"); + uint32_t size = surfaceBuffer_->GetSize(); + return static_cast(size); +} + +uint32_t SurfaceMemory::GetFlags() const +{ + CHECK_AND_RETURN_RET_LOG(surfaceBuffer_ != nullptr, 0, "surfaceBuffer is nullptr"); + return FLAGS_READ_WRITE; +} +} // namespace OHOS +} // namespace Media diff --git a/services/engine/demuxer/demuxer_engine_impl.cpp b/services/engine/demuxer/demuxer_engine_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..909d61d69fa9102501b1c254aba2494310749954 --- /dev/null +++ b/services/engine/demuxer/demuxer_engine_impl.cpp @@ -0,0 +1,92 @@ +/* + * 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 "demuxer_engine_impl.h" +#include "securec.h" +#include "avcodec_log.h" +#include "demuxer_factory.h" +#include "avcodec_errors.h" +#include "iostream" +#include "avcodec_dfx.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerEngineImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr IDemuxerEngineFactory::CreateDemuxerEngine( + int32_t appUid, int32_t appPid, uintptr_t sourceAddr) +{ + AVCodecTrace trace("IDemuxerEngineFactory::CreateDemuxerEngine"); + std::shared_ptr demuxerEngineImpl = + std::make_shared(appUid, appPid, sourceAddr); + CHECK_AND_RETURN_RET_LOG(demuxerEngineImpl != nullptr, nullptr, "create MuxerEngine implementation failed"); + return demuxerEngineImpl; +} + +DemuxerEngineImpl::DemuxerEngineImpl(int32_t appUid, int32_t appPid, uintptr_t sourceAddr) + : appUid_(appUid), appPid_(appPid), sourceAddr_(sourceAddr) +{ + AVCodecTrace trace("DemuxerEngineImpl::Create"); + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + demuxer_ = Plugin::DemuxerFactory::Instance().CreatePlugin(sourceAddr_); + if (demuxer_ != nullptr) { + AVCODEC_LOGI("init demuxer engine successful"); + } else { + AVCODEC_LOGE("init demuxer engine failed"); + } +} + +DemuxerEngineImpl::~DemuxerEngineImpl() +{ + AVCODEC_LOGD("Destroy"); + appUid_ = -1; + appPid_ = -1; + demuxer_ = nullptr; + + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t DemuxerEngineImpl::SelectSourceTrackByID(uint32_t trackIndex) +{ + AVCodecTrace trace("DemuxerEngineImpl::SelectSourceTrackByID"); + AVCODEC_LOGI("SelectSourceTrackByID"); + return demuxer_->SelectSourceTrackByID(trackIndex); +} + +int32_t DemuxerEngineImpl::UnselectSourceTrackByID(uint32_t trackIndex) +{ + AVCodecTrace trace("DemuxerEngineImpl::UnselectSourceTrackByID"); + AVCODEC_LOGI("UnselectSourceTrackByID"); + return demuxer_->UnselectSourceTrackByID(trackIndex); +} + +int32_t DemuxerEngineImpl::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + AVCodecTrace trace("DemuxerEngineImpl::CopyNextSample"); + AVCODEC_LOGI("CopyNextSample"); + return demuxer_->CopyNextSample(trackIndex, buffer, bufferInfo, flag); +} + +int32_t DemuxerEngineImpl::SeekToTime(int64_t mSeconds, AVSeekMode mode) +{ + AVCodecTrace trace("DemuxerEngineImpl::SeekToTime"); + AVCODEC_LOGI("SeekToTime"); + return demuxer_->SeekToTime(mSeconds, mode); +} +} // Media +} // OHOS diff --git a/services/engine/demuxer/include/demuxer_engine_impl.h b/services/engine/demuxer/include/demuxer_engine_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..8747ffe5ffe2b3acc4007694c96171c848cdf767 --- /dev/null +++ b/services/engine/demuxer/include/demuxer_engine_impl.h @@ -0,0 +1,46 @@ +/* + * 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 DEMUXER_ENGINE_IMPL_H +#define DEMUXER_ENGINE_IMPL_H + +#include +#include +#include +#include +#include "i_demuxer_engine.h" +#include "demuxer.h" +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class DemuxerEngineImpl : public IDemuxerEngine { +public: + DemuxerEngineImpl(int32_t appUid, int32_t appPid, uintptr_t sourceAddr); + ~DemuxerEngineImpl() override; + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode) override; +private: + int32_t appUid_ = -1; + int32_t appPid_ = -1; + uintptr_t sourceAddr_; + std::shared_ptr demuxer_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // DEMUXER_ENGINE_IMPL_H \ No newline at end of file diff --git a/services/engine/demuxer/include/i_demuxer_engine.h b/services/engine/demuxer/include/i_demuxer_engine.h new file mode 100644 index 0000000000000000000000000000000000000000..0a49900533723d551a46251ef0c05ec223ece647 --- /dev/null +++ b/services/engine/demuxer/include/i_demuxer_engine.h @@ -0,0 +1,46 @@ +/* + * 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 IDEMUXER_ENGINE_H +#define IDEMUXER_ENGINE_H + +#include +#include "format.h" +#include "avcodec_common.h" +#include "avsharedmemory.h" + +namespace OHOS { +namespace Media { +class IDemuxerEngine { +public: + virtual ~IDemuxerEngine() = default; + virtual int32_t SelectSourceTrackByID(uint32_t trackIndex) = 0; + virtual int32_t UnselectSourceTrackByID(uint32_t trackIndex) = 0; + virtual int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) = 0; + virtual int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode) = 0; +}; + +class __attribute__((visibility("default"))) IDemuxerEngineFactory { +public: + static std::shared_ptr CreateDemuxerEngine(int32_t appUid, + int32_t appPid, uintptr_t sourceAddr); +private: + IDemuxerEngineFactory() = default; + ~IDemuxerEngineFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // IDEMUXER_ENGINE_H \ No newline at end of file diff --git a/services/engine/factory/av_codec_base_factory.h b/services/engine/factory/av_codec_base_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..9afa8ea0530bdaef0f11cacd8ef63f7cefcc411d --- /dev/null +++ b/services/engine/factory/av_codec_base_factory.h @@ -0,0 +1,76 @@ +/* + * 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 AV_CODEC_ENGIN_BASE_FACTORY_H +#define AV_CODEC_ENGIN_BASE_FACTORY_H + +#include + +namespace OHOS { +namespace Media { +template +class AVCodecBaseFactory { +public: + using self = AVCodecBaseFactory; + + template + static std::shared_ptr make_sharePtr(const Identity &k, TS &&...args) + { + auto it = builders().find(k); + if (it == builders().end()) + return nullptr; + return it->second(std::forward(args)...); + } + + template + struct CodecRegister : public I { + friend T; + static bool avRegister() + { + const auto r = T::identify(); + AVCodecBaseFactory::builders()[r] = [](Args &&...args) -> std::shared_ptr { + return std::make_shared(std::forward(args)...); + }; + return true; + } + static bool registered; + + private: + CodecRegister() : I() + { + (void)registered; + } + }; + +private: + friend I; + AVCodecBaseFactory() = default; + using builder = std::function(Args...)>; + + static auto &builders() + { + static std::unordered_map container; + return container; + } +}; + +template +template +bool AVCodecBaseFactory::CodecRegister::registered = + AVCodecBaseFactory::CodecRegister::avRegister(); +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/engine/factory/demuxer_factory.cpp b/services/engine/factory/demuxer_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f5bcaa0609df6b4ce3945e7f97ffe75465cee31 --- /dev/null +++ b/services/engine/factory/demuxer_factory.cpp @@ -0,0 +1,202 @@ +/* + * 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 "type_cast_ext.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "demuxer_factory.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerFactory"}; +} + +namespace OHOS { +namespace Media { +namespace Plugin { +static std::string g_libFileHead = "libav_codec_plugin_"; +static std::string g_fileSeparator = "/"; +static std::string g_fileMark = "Demuxer"; +static std::string g_libFileTail = AV_CODEC_PLUGIN_FILE_TAIL; + +DemuxerFactory::DemuxerFactory() +{ + RegisterPlugins(); +} + +DemuxerFactory::~DemuxerFactory() +{ + UnregisterAllPlugins(); +} + +std::shared_ptr DemuxerFactory::CreatePlugin(uintptr_t sourceAddr) +{ + AVCODEC_LOGD("create demuxer plugin from DemuxerFactory"); + std::string pluginName; + uint32_t maxRank = 0; + for (auto& name : registerData_->registerNames) { + std::shared_ptr regInfo = registerData_->registerTable[name]; + if (regInfo->info->pluginType == PluginType::DEMUXER) { + auto rank = regInfo->info->rank; + if (rank > maxRank) { + maxRank = rank; + pluginName = name; + } + } else { + AVCODEC_LOGW("Create demuxer plugin failed, because get plugin type: %{public}d", PluginType::DEMUXER); + } + } + + if (!pluginName.empty()) { + std::shared_ptr regInfo = registerData_->registerTable[pluginName]; + auto plugin = ReinterpretPointerCast(regInfo->creator()); + int32_t ret = plugin->Create(sourceAddr); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Create demuxer plugin failed, cannot create plugin!"); + return nullptr; + } + AVCODEC_LOGD("create demuxer plugin successful! pluginName %{public}s(maxRank %{public}d)", + pluginName.c_str(), maxRank); + return std::shared_ptr( + new Demuxer(regInfo->packageDef->pkgVersion, regInfo->info->apiVersion, plugin)); + } else { + AVCODEC_LOGW("Create demuxer plugin failed, can not find any demuxer plugins!"); + } + return nullptr; +} + +void DemuxerFactory::RegisterPlugins() +{ + RegisterDynamicPlugins(AV_CODEC_PLUGIN_PATH); +} + +void DemuxerFactory::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; + 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; + } + AVCODEC_LOGD("Regist dyanmic plugin: libName %{public}s", libName.c_str()); + + 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) { + AVCODEC_LOGI("Create pluginLoader successful: %{public}s!", libName.c_str()); + loader->FetchRegisterFunction()(std::make_shared(registerData_, loader)); + registeredLoaders_.push_back(loader); + } else { + AVCODEC_LOGE("Create pluginLoader failed!"); + } + } + closedir(libDir); + } +} + +void DemuxerFactory::UnregisterAllPlugins() +{ + for (auto& loader : registeredLoaders_) { + loader->FetchUnregisterFunction()(); + loader.reset(); + } + registeredLoaders_.clear(); + registerData_->registerNames.clear(); + registerData_->registerTable.clear(); +} + +bool DemuxerFactory::RegisterData::IsPluginExist(const std::string& name) +{ + return registerTable.find(name) != registerTable.end(); +} + +Status DemuxerFactory::RegisterImpl::AddPlugin(const PluginDefBase& def) +{ + if (!Verification(def)) { + // 插件定义参数校验不合法 + return Status::ERROR_INVALID_DATA; + } + if (!VersionMatched(def)) { + // 版本不匹配,不给注册 + return Status::ERROR_UNKNOWN; + } + if (registerData->IsPluginExist(def.name)) { + // 重复注册,且有更合适的版本存在 + return Status::ERROR_PLUGIN_ALREADY_EXISTS; + } + auto& pluginDef = (DemuxerPluginDef&)def; + std::shared_ptr regInfo = std::make_shared(); + regInfo->packageDef = packageDef; + regInfo->creator = reinterpret_cast(pluginDef.creator); + regInfo->sniffer = reinterpret_cast(pluginDef.sniffer); + + std::shared_ptr info = std::make_shared(); + info->apiVersion = pluginDef.apiVersion; + info->pluginType = pluginDef.pluginType; + info->name = pluginDef.name; + info->description = pluginDef.description; + info->rank = pluginDef.rank; + + regInfo->info = info; + regInfo->loader = std::move(pluginLoader); + + registerData->registerTable[pluginDef.name] = regInfo; + registerData->registerNames.push_back(pluginDef.name); + return Status::NO_ERROR; +} + +Status DemuxerFactory::RegisterImpl::AddPackage(const PackageDef& def) +{ + return SetPackageDef(def); +} + +Status DemuxerFactory::RegisterImpl::SetPackageDef(const PackageDef& def) +{ + packageDef = std::make_shared(def); + return Status::NO_ERROR; +} + +bool DemuxerFactory::RegisterImpl::Verification(const PluginDefBase& definition) +{ + if (definition.rank < 0 || definition.rank > 100) { // 100 + return false; + } + return (definition.pluginType != PluginType::INVALID_TYPE); +} + +bool DemuxerFactory::RegisterImpl::VersionMatched(const PluginDefBase& definition) +{ + int major = (definition.apiVersion >> 16) & 0xFFFF; // 16 + int minor = definition.apiVersion & 0xFFFF; + uint32_t version = DEMUXER_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/factory/demuxer_factory.h b/services/engine/factory/demuxer_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..6d4b86f98b507d0693159dee3c55e5b6492bad3a --- /dev/null +++ b/services/engine/factory/demuxer_factory.h @@ -0,0 +1,83 @@ +/* + * 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 DEMUXER_FACTORY_H +#define DEMUXER_FACTORY_H + +#include +#include +#include "plugin_info.h" +#include "demuxer.h" +#include "plugin_loader.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +class DemuxerFactory { +public: + DemuxerFactory(const DemuxerFactory&) = delete; + DemuxerFactory operator=(const DemuxerFactory&) = delete; + ~DemuxerFactory(); + static DemuxerFactory& Instance() + { + static DemuxerFactory impl; + return impl; + } + + std::shared_ptr CreatePlugin(uintptr_t sourceAddr); + DemuxerFactory(); +private: + void RegisterPlugins(); + void RegisterDynamicPlugins(const char* libDirPath); + void UnregisterAllPlugins(); + +private: + struct PluginRegInfo { + std::shared_ptr packageDef; + std::shared_ptr info; + DemuxerPluginCreatorFunc creator; + DemuxerPluginSnifferFunc sniffer; + std::shared_ptr loader; + }; + struct RegisterData { + std::vector registerNames; + std::map> registerTable; + bool IsPluginExist(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& definition); + bool VersionMatched(const PluginDefBase& definition); + + 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 // DEMUXER_FACTORY_H diff --git a/services/engine/muxer/muxer_engine_impl.cpp b/services/engine/muxer/muxer_engine_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50f1ee29494e77aca65f6988abe6e42b75b96a71 --- /dev/null +++ b/services/engine/muxer/muxer_engine_impl.cpp @@ -0,0 +1,452 @@ +/* + * 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 +#include +#include "securec.h" +#include "avcodec_log.h" +#include "muxer_factory.h" +#include "avcodec_dfx.h" +#include "avcodec_info.h" +#include "avcodec_errors.h" +#include "avcodec_dump_utils.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; + constexpr uint32_t DUMP_MUXER_INFO_INDEX = 0x01010000; + constexpr uint32_t DUMP_STATUS_INDEX = 0x01010100; + constexpr uint32_t DUMP_OUTPUT_FORMAT_INDEX = 0x01010200; + constexpr uint32_t DUMP_OFFSET_8 = 8; + + const std::map OutputFormatStringMap = { + { OHOS::Media::OutputFormat::OUTPUT_FORMAT_M4A, "m4a" }, + { OHOS::Media::OutputFormat::OUTPUT_FORMAT_MPEG_4, "mp4" }, + }; + + const std::vector> AUDIO_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_MIME, "Codec_Mime" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, "Channel_Count" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_BITRATE, "Bit_Rate" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_SAMPLE_RATE, "Sample_Rate" }, + }; + + const std::vector> VIDEO_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_MIME, "Codec_Mime" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_WIDTH, "Width" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_HEIGHT, "Height" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_BITRATE, "Bit_Rate" }, + }; + + const std::vector> IMAGE_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_MIME, "Codec_Mime" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_WIDTH, "Width" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_HEIGHT, "Height" }, + }; + + const std::map>> MUXER_DUMP_TABLE = { + { OHOS::Media::MuxerEngineImpl::TrackMimeType::TRACK_MIME_TYPE_AUDIO, AUDIO_DUMP_TABLE }, + { OHOS::Media::MuxerEngineImpl::TrackMimeType::TRACK_MIME_TYPE_VIDEO, VIDEO_DUMP_TABLE }, + { OHOS::Media::MuxerEngineImpl::TrackMimeType::TRACK_MIME_TYPE_IMAGE, IMAGE_DUMP_TABLE }, + }; +} + +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); + 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") +{ + format_ = (format_ == OUTPUT_FORMAT_DEFAULT) ? OUTPUT_FORMAT_MPEG_4 : format_; + 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_ = State::INITIALIZED; + AVCODEC_LOGI("state_ is INITIALIZED"); + } else { + AVCODEC_LOGE("state_ is UNINITIALIZED"); + } +} + +MuxerEngineImpl::~MuxerEngineImpl() +{ + AVCODEC_LOGD("Destroy"); + + if (state_ == 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_ == 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_ == 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_ == 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; + mediaDescMap_.emplace(trackIndex, MediaDescription(trackDesc)); + + 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_ == 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}zu", tracks_.size()); + Plugin::Status ret = muxer_->Start(); + CHECK_AND_RETURN_RET_LOG(ret == Plugin::Status::NO_ERROR, TranslatePluginStatus(ret), "Start failed"); + state_ = 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_ == 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_); + if (state_ == State::STOPPED) { + AVCODEC_LOGW("current state is STOPPED!"); + return AVCS_ERR_OK; + } + CHECK_AND_RETURN_RET_LOG(state_ == State::STARTED, AVCS_ERR_INVALID_OPERATION, + "The state is not STARTED. The current state is %{public}s", ConvertStateToString(state_).c_str()); + state_ = 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) +{ + AVCodecDumpControler dumpControler; + + dumpControler.AddInfo(DUMP_MUXER_INFO_INDEX, "Muxer_Info"); + dumpControler.AddInfo(DUMP_STATUS_INDEX, "Status", ConvertStateToString(state_)); + dumpControler.AddInfo(DUMP_OUTPUT_FORMAT_INDEX, + "Output_Format", OutputFormatStringMap.at(format_)); + + int32_t dumpTrackIndex = 3; + for (auto it = mediaDescMap_.begin(); it != mediaDescMap_.end(); ++it) { + int mediaDescIdx = 0; + auto mediaDesc = it->second; + int32_t dumpInfoIndex = 1; + std::string codecMime; + bool ret = mediaDesc.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, codecMime); + CHECK_AND_CONTINUE_LOG(ret == true, "Get codec mime from format failed."); + TrackMimeType mimeType = GetTrackMimeType(codecMime); + auto &dumpTable = MUXER_DUMP_TABLE.at(mimeType); + + dumpControler.AddInfo(DUMP_MUXER_INFO_INDEX + (dumpTrackIndex << DUMP_OFFSET_8), + std::string("Track_") + std::to_string(mediaDescIdx) + "_Info"); + for (auto iter : dumpTable) { + dumpControler.AddInfoFromFormat( + DUMP_MUXER_INFO_INDEX + (dumpTrackIndex << 8) + dumpInfoIndex, + mediaDesc, iter.first, iter.second); + dumpInfoIndex++; + } + dumpTrackIndex++; + mediaDescIdx++; + } + + std::string dumpString; + dumpControler.GetDumpString(dumpString); + CHECK_AND_RETURN_RET_LOG(fd != -1, AVCS_ERR_INVALID_VAL, "Get a invalid fd."); + 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(State state) +{ + std::string stateInfo {}; + switch (state) { + case State::UNINITIALIZED: + stateInfo = "UNINITIALIZED"; + break; + case State::INITIALIZED: + stateInfo = "INITIALIZED"; + break; + case State::STARTED: + stateInfo = "STARTED"; + break; + case State::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; +} + +MuxerEngineImpl::TrackMimeType MuxerEngineImpl::GetTrackMimeType(const std::string &mime) +{ + TrackMimeType type; + if (mime.find("audio") != mime.npos) { + type = TRACK_MIME_TYPE_AUDIO; + } else if (mime.find("video") != mime.npos) { + type = TRACK_MIME_TYPE_VIDEO; + } else { + type = TRACK_MIME_TYPE_IMAGE; + } + + return type; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/services/engine/muxer/muxer_engine_impl.h b/services/engine/muxer/muxer_engine_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..7b6cf350aad32ce766b3dbdccc3e72af27ee8e7c --- /dev/null +++ b/services/engine/muxer/muxer_engine_impl.h @@ -0,0 +1,87 @@ +/* + * 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; + + enum class State { + UNINITIALIZED, + INITIALIZED, + STARTED, + STOPPED + }; + + enum TrackMimeType { + TRACK_MIME_TYPE_AUDIO = 0, + TRACK_MIME_TYPE_VIDEO, + TRACK_MIME_TYPE_IMAGE + }; + +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(State state); + int32_t TranslatePluginStatus(Plugin::Status error); + TrackMimeType GetTrackMimeType(const std::string &mime); + + 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_ = State::UNINITIALIZED; + std::shared_ptr muxer_ = nullptr; + std::map tracks_; + std::map mediaDescMap_; + 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 new file mode 100644 index 0000000000000000000000000000000000000000..743717a005294fd7c98ee1d7662e75f96f808268 --- /dev/null +++ b/services/engine/plugin/BUILD.gn @@ -0,0 +1,34 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("plugin_presets") { + include_dirs = [ + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/engine/plugin/core", + "$av_codec_root_dir/services/engine/plugin/interface", + "$av_codec_root_dir/services/engine/source/hst_releated", + "//third_party/bounds_checking_function/include", + "//base/hiviewdfx/hilog/interfaces/native/innerkits/include", + ] +} + +group("av_codec_plugin") { + deps = [ "plugins:av_codec_plugin_store" ] +} diff --git a/services/engine/plugin/common/error_code_ext.h b/services/engine/plugin/common/error_code_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..6c1cd598a5aef72c9301b6716f3b48569b0e0877 --- /dev/null +++ b/services/engine/plugin/common/error_code_ext.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 ERROR_CODE_EXT_H +#define ERROR_CODE_EXT_H + +#include "plugin_definition.h" +#include "avcodec_errors.h" + +namespace OHOS { +namespace Media { +int32_t 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; +} +} // namespace Media +} // namespace OHOS + +#endif // ERROR_CODE_EXT_H \ No newline at end of file diff --git a/services/engine/plugin/common/type_cast_ext.h b/services/engine/plugin/common/type_cast_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..7a4a228a4e209c2a7f5a5fe8cb7e2c1a3b1b9d97 --- /dev/null +++ b/services/engine/plugin/common/type_cast_ext.h @@ -0,0 +1,58 @@ +/* + * 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 TYPE_CAST_EXT_H +#define TYPE_CAST_EXT_H + +#include + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * This function is used to compare two type_info. Besides the basic compare using operator == of type_info, + * we also consider types with the same names are the same types. + * @param t1 type + * @param t2 type + * @return true if t1 and t2 are the same type. otherwise, false. + */ +inline bool IsSameType(const std::type_info& t1, const std::type_info& t2) noexcept +{ + if (t1 == t2) { + return true; + } + auto t1Length = strlen(t1.name()); + if (t1Length == strlen(t2.name()) && strncmp(t1.name(), t2.name(), t1Length) == 0) { + return true; + } + return false; +} + +/** + * This function is used to reinterpret cast one shared_ptr into another shared_ptr. + * @tparam T type + * @tparam U type + * @param ptr pointer + * @return cast result + */ +template +inline std::shared_ptr ReinterpretPointerCast(const std::shared_ptr& ptr) noexcept +{ + return std::shared_ptr(ptr, reinterpret_cast(ptr.get())); +} +} // Plugin +} // Media +} // OHOS + +#endif // TYPE_CAST_EXT_H diff --git a/services/engine/plugin/core/demuxer.cpp b/services/engine/plugin/core/demuxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66d378bf2b9e3446e88346419f54169d9a0e7fb5 --- /dev/null +++ b/services/engine/plugin/core/demuxer.cpp @@ -0,0 +1,49 @@ +/* + * 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 "demuxer.h" +#include "avcodec_errors.h" +#include "demuxer_plugin.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +Demuxer::Demuxer (uint32_t pkgVer, uint32_t apiVer, std::shared_ptr plugin) + : pkgVersion_(pkgVer), apiVersion_(apiVer), demuxer_(std::move(plugin)) {} + +int32_t Demuxer::SelectSourceTrackByID(uint32_t trackIndex) +{ + return demuxer_->SelectSourceTrackByID(trackIndex); +} + +int32_t Demuxer::UnselectSourceTrackByID(uint32_t trackIndex) +{ + return demuxer_->UnselectSourceTrackByID(trackIndex); +} + +int32_t Demuxer::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + return demuxer_->CopyNextSample(trackIndex, buffer, bufferInfo, flag); +} + +int32_t Demuxer::SeekToTime(int64_t mSeconds, AVSeekMode mode) +{ + int32_t ret = demuxer_->SeekToTime(mSeconds, mode); + return ret; +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/plugin/core/demuxer.h b/services/engine/plugin/core/demuxer.h new file mode 100644 index 0000000000000000000000000000000000000000..3463ce2f21bf1f5dcabd97c91375e9ea4e1a588a --- /dev/null +++ b/services/engine/plugin/core/demuxer.h @@ -0,0 +1,48 @@ +/* + * 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_DEMUXER_H +#define PLUGIN_CORE_DEMUXER_H + +#include "format.h" +#include "avcodec_common.h" +#include "demuxer_plugin.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +class Demuxer { +public: + Demuxer(const Demuxer &) = delete; + Demuxer operator=(const Demuxer &) = delete; + ~Demuxer() = default; + int32_t SelectSourceTrackByID(uint32_t trackIndex); + int32_t UnselectSourceTrackByID(uint32_t trackIndex); + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag); + int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode); + +private: + friend class DemuxerFactory; + Demuxer(uint32_t pkgVer, uint32_t apiVer, std::shared_ptr plugin); + const uint32_t pkgVersion_; + const uint32_t apiVersion_; + std::shared_ptr demuxer_; + uint16_t trackLogCount = 0; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_CORE_DEMUXER_H diff --git a/services/engine/plugin/core/muxer.cpp b/services/engine/plugin/core/muxer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37890d8bc3fff971bf919e9bcca053cec6bbdc24 --- /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 0000000000000000000000000000000000000000..fe117a4376adce9095d0c80ea25acf11ce888ad2 --- /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 0000000000000000000000000000000000000000..26b7f03ce194a03ff7af390716ed3efccede9dc5 --- /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 0000000000000000000000000000000000000000..d73cc355b4b8d5677279426b2a9404f1d79f29d6 --- /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 +#include +#include "muxer.h" +#include "plugin_loader.h" + +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_info.h b/services/engine/plugin/core/plugin_info.h new file mode 100644 index 0000000000000000000000000000000000000000..bb5484f89df25155a0c97117cca4bb3314a1b2a7 --- /dev/null +++ b/services/engine/plugin/core/plugin_info.h @@ -0,0 +1,78 @@ +/* + * 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_INFO_H +#define PLUGIN_INFO_H + +#include "plugin_definition.h" +#include "format.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * PluginInfo, which describes static information for a plugin, including basic plugin information, + * such as the type, name, rank. + * + * Different types of plugins have their own extra information, + * which is described in the "extra" field in the form of key-value. + * + * Note that the type, name, rating, and extra information describes the plugin as a whole; + * + */ +struct PluginInfo { + uint32_t apiVersion; + std::string name; + PluginType pluginType; + std::string description; + uint32_t rank; + Format extra; +}; + +/** + * Extra information about the plugin. + * Describes the protocol types supported by the Source plugin for playback. + */ +#define PLUGIN_INFO_EXTRA_PROTOCOL "protocol" // NOLINT: macro constant + +/** + * Extra information about the plugin. + * Describes the input source types supported by the Source plugin for record. + */ +#define PLUGIN_INFO_EXTRA_INPUT_TYPE "inputType" // NOLINT: macro constant + +/** + * Extra information about the plugin. + * Describes the output types supported by the OutputSink plugin. + */ +#define PLUGIN_INFO_EXTRA_OUTPUT_TYPE "outputType" // NOLINT: macro constant + +/** + * Extra information about the plugin. + * Describes the extensions supported by the Demuxer plugin. + */ +#define PLUGIN_INFO_EXTRA_EXTENSIONS "extensions" // NOLINT: macro constant + +/** + * Extra information about the plugin. + * Describes the CodecMode supported by the Codec plugin. + * + * ValueType: enum Plugin::CodecMode + */ +#define PLUGIN_INFO_EXTRA_CODEC_MODE "codec_mode" // NOLINT: macro constant +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // PLUGIN_INFO_H diff --git a/services/engine/plugin/core/plugin_loader.cpp b/services/engine/plugin/core/plugin_loader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d0e2b57f4138ea281c4ed69cc10bd79012c66887 --- /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 = std::make_shared(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 0000000000000000000000000000000000000000..c1b3176a655b91496e26084b1da3a780585b19f8 --- /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(void* handler, std::string name); // NOLINT: void* + + 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: + 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/demuxer_plugin.h b/services/engine/plugin/interface/demuxer_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..ab9b79b788db98af267e4d8c9befe5e0029b87f1 --- /dev/null +++ b/services/engine/plugin/interface/demuxer_plugin.h @@ -0,0 +1,67 @@ +/* + * 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 DEDEMUXER_PLUGIN_H +#define DEDEMUXER_PLUGIN_H + +#include +#include "avcodec_common.h" +#include "plugin_base.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +struct DemuxerPlugin : public PluginBase { + explicit DemuxerPlugin() : PluginBase("Demuxer") {} + virtual int32_t Create(uintptr_t sourceAddr) = 0; + virtual int32_t CopyNextSample(uint32_t &trackIndex, uint8_t* buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) = 0; + virtual int32_t SelectSourceTrackByID(uint32_t index) = 0; + virtual int32_t UnselectSourceTrackByID(uint32_t index) = 0; + virtual int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode) = 0; + Status SetCallback(Callback* cb) + { + (void)cb; + return Status::ERROR_UNIMPLEMENTED; + }; +}; + +/// Demuxer plugin api major number. +#define DEMUXER_API_VERSION_MAJOR (1) + +/// Demuxer plugin api minor number +#define DEMUXER_API_VERSION_MINOR (0) + +/// Demuxer plugin version +#define DEMUXER_API_VERSION MAKE_VERSION(DEMUXER_API_VERSION_MAJOR, DEMUXER_API_VERSION_MINOR) + +/// Demuxer create function +using DemuxerPluginCreatorFunc = std::shared_ptr(*)(); +/// Demuxer sniff function +using DemuxerPluginSnifferFunc = int32_t (*)(const std::string& name); + +struct DemuxerPluginDef : public PluginDefBase { + DemuxerPluginCreatorFunc creator {nullptr}; ///< Demuxer plugin create function. + DemuxerPluginSnifferFunc sniffer {nullptr}; ///< Demuxer plugin sniff function. + DemuxerPluginDef() + { + apiVersion = DEMUXER_API_VERSION; ///< Demuxer plugin version. + pluginType = PluginType::DEMUXER; ///< Plugin type, MUST be DEMUXER. + } +}; +} // namepsace Plugin +} // namespace Media +} // namespace OHOS +#endif // DEDEMUXER_PLUGIN_H \ No newline at end of file diff --git a/services/engine/plugin/interface/muxer_plugin.h b/services/engine/plugin/interface/muxer_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..2896cd8431418f0af3b0443712ab3425a99961ca --- /dev/null +++ b/services/engine/plugin/interface/muxer_plugin.h @@ -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. + */ + +#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; + Status SetCallback(Callback* cb) + { + (void)cb; + return Status::ERROR_UNIMPLEMENTED; + } +}; + +/// 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/plugins/BUILD.gn b/services/engine/plugin/plugins/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..655452998ed837ae815021f15e279f44b581c849 --- /dev/null +++ b/services/engine/plugin/plugins/BUILD.gn @@ -0,0 +1,20 @@ +# 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" ] + deps += [ "demuxer/ffmpeg_demuxer:plugin_demuxer_ffmpeg" ] +} diff --git a/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/BUILD.gn b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..f6f602c3451ed42fff44c084ee384ebcc1f81536 --- /dev/null +++ b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/BUILD.gn @@ -0,0 +1,41 @@ +# 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_demuxer_ffmpeg") { + deps = [] + deps += [ ":av_codec_plugin_FFmpegDemuxer" ] +} + +# standard +import("//build/ohos.gni") +ohos_shared_library("av_codec_plugin_FFmpegDemuxer") { + sources = [ "ffmpeg_demuxer_plugin.cpp" ] + + include_dirs = [ "//third_party/ffmpeg" ] + + public_configs = + [ "$av_codec_root_dir/services/engine/plugin:plugin_presets" ] + + public_deps = [ + "$av_codec_root_dir/services/utils:av_codec_format", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/ffmpeg:libohosffmpeg", + ] + + relative_install_dir = "media/av_codec_plugins" + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.cpp b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8dcc16a58534833d827cd3a8bd9eb34f7a2d16e2 --- /dev/null +++ b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.cpp @@ -0,0 +1,431 @@ +/* + * 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 "avcodec_errors.h" +#include "native_avcodec_base.h" +#include "plugin_definition.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "ffmpeg_demuxer_plugin.h" + +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 78, 0) and LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 64, 100) +#if LIBAVFORMAT_VERSION_INT != AV_VERSION_INT(58, 76, 100) + +#endif +#endif +#define AV_CODEC_TIME_BASE (static_cast(1)) +#define AV_CODEC_NSECOND AV_CODEC_TIME_BASE +#define AV_CODEC_USECOND (static_cast(1000) * AV_CODEC_NSECOND) +#define AV_CODEC_MSECOND (static_cast(1000) * AV_CODEC_USECOND) +#define AV_CODEC_SECOND (static_cast(1000) * AV_CODEC_MSECOND) + + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "FFmpegDemuxerPlugin"}; +} + + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace FFmpeg { +namespace { +static const std::map seekModeToFFmpegSeekFlags = { + { AVSeekMode::SEEK_MODE_PREVIOUS_SYNC, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD }, + { AVSeekMode::SEEK_MODE_NEXT_SYNC, AVSEEK_FLAG_FRAME }, + { AVSeekMode::SEEK_MODE_CLOSEST_SYNC, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY } +}; + +int32_t Sniff(const std::string& pluginName) +{ + return 100; +} + +Status RegisterDemuxerPlugins(const std::shared_ptr& reg) +{ + DemuxerPluginDef def; + constexpr int32_t RankScore = 100; + def.name = "ffmpegDemuxer"; + def.description = "ffmpeg demuxer"; + def.rank = RankScore; + def.creator = []() -> std::shared_ptr { + return std::make_shared(); + }; + def.sniffer = Sniff; + return reg->AddPlugin(def); +} + +PLUGIN_DEFINITION(FFmpegDemuxer, LicenseType::GPL, RegisterDemuxerPlugins, [] {}) + +static const std::map videoBitStreamFormatStringMap = { + {"AVCC", VideoBitStreamFormat::AVCC}, + {"HVCC", VideoBitStreamFormat::HVCC}, + {"ANNEXB", VideoBitStreamFormat::ANNEXB}, +}; +} + +inline int64_t AvTime2Ms(int64_t hTime) +{ + return hTime / AV_CODEC_MSECOND; +} + +int64_t ConvertTimeToFFmpeg(int64_t timestampUs, AVRational base) +{ + int64_t result; + if (base.num == 0) { + result = AV_NOPTS_VALUE; + } else { + AVRational bq = {1, AV_CODEC_SECOND}; + result = av_rescale_q(timestampUs, bq, base); + } + return result; +} + +int64_t ConvertTimeFromFFmpeg(int64_t pts, AVRational base) +{ + int64_t out; + if (pts == AV_NOPTS_VALUE) { + out = -1; + } else { + AVRational bq = {1, AV_CODEC_SECOND}; + out = av_rescale_q(pts, base, bq); + } + return out; +} + +int64_t FFmpegDemuxerPlugin::GetTotalStreamFrames(int streamIndex) +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::GetTotalStreamFrames is called"); + return formatContext_->streams[streamIndex]->nb_frames; +} + + +AVCodecBufferFlag FFmpegDemuxerPlugin::ConvertFlagsFromFFmpeg(AVPacket* pkt, AVStream* avStream) +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::ConvertFlagsFromFFmpeg is called"); + AVCodecBufferFlag flags = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + if (pkt->flags == 0x0001) { + if (abs((int)(avStream->duration-pkt->pts)) <= (pkt->duration)) { + flags = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS; + } else { + flags = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_SYNC_FRAME; + } + } else { + flags = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + } + + return flags; +} + +int32_t FFmpegDemuxerPlugin::Create(uintptr_t sourceAddr) +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::Create is on call"); + if (std::is_object::value) { + formatContext_ = std::shared_ptr((AVFormatContext*)sourceAddr); + SetBitStreamFormat(); + AVCODEC_LOGD("create FFmpegDemuxerPlugin successful."); + } else { + formatContext_ = nullptr; + AVCODEC_LOGW("create FFmpegDemuxerPlugin failed, becasue sourceAddr is not a class address."); + return AVCS_ERR_INVALID_VAL; + } + return AVCS_ERR_OK; +} + +FFmpegDemuxerPlugin::FFmpegDemuxerPlugin() +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::FFmpegDemuxerPlugin is on call"); +} + +FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin() +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin is on call"); + formatContext_ = nullptr; + selectedTrackIds_.clear(); +} + +int32_t FFmpegDemuxerPlugin::SetBitStreamFormat() +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::SetBitStreamFormat is on call"); + uint32_t trackCount = formatContext_->nb_streams; + for (uint32_t i = 0; i < trackCount; i++) { + if (formatContext_->streams[i]->codecpar->codec_type== AVMEDIA_TYPE_VIDEO) { + AVDictionary *trackMetadata = formatContext_->streams[i]->metadata; + std::string key = std::string(AVSourceTrackFormat::VIDEO_BIT_STREAM_FORMAT); + auto tag = av_dict_get(trackMetadata, key.c_str(), nullptr, AV_DICT_IGNORE_SUFFIX); + if (tag == nullptr) { + AVCODEC_LOGW("SetBitStreamFormat failed, Output stream format will not change!"); + } else if (auto value = videoBitStreamFormatStringMap.at(tag->value)) { + videoBitStreamFormat_[i] = value; + AVCODEC_LOGD("SetBitStreamFormat successful, track %{public}d, %{public}s", i, tag->value); + } else { + AVCODEC_LOGW("SetBitStreamFormat failed, %{public}s is not supported, \ + Output stream format will not change!", tag->value); + } + } + } + std::string videoBitStreamFormatString = ""; + for (auto const& pair: videoBitStreamFormat_) { + videoBitStreamFormatString += std::to_string(pair.first) + "=" + std::to_string(pair.second) + " | "; + } + AVCODEC_LOGD("videoBitStreamFormat: %{public}s", videoBitStreamFormatString.c_str()); + return AVCS_ERR_OK; +} + +int32_t FFmpegDemuxerPlugin::SelectSourceTrackByID(uint32_t trackIndex) +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::SelectSourceTrackByID is on call"); + std::stringstream selectedTracksString; + for (const auto &index : selectedTrackIds_) { + selectedTracksString << index; + } + AVCODEC_LOGI("Total track in file: %{public}d | add track index: %{public}d", + formatContext_.get()->nb_streams, trackIndex); + AVCODEC_LOGI("Selected tracks in file: %{public}s.", selectedTracksString.str().c_str()); + + if (trackIndex < 0 || trackIndex >= static_cast(formatContext_.get()->nb_streams)) { + AVCODEC_LOGE("trackIndex is invalid! Just have %{public}d tracks in file", formatContext_.get()->nb_streams); + return AVCS_ERR_INVALID_VAL; + } + auto index = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(), + [trackIndex](uint32_t selectedId) {return trackIndex == selectedId;}); + if (index == selectedTrackIds_.end()) { + selectedTrackIds_.push_back(trackIndex); + } else { + AVCODEC_LOGW("track %{public}d is already in selected list!", trackIndex); + } + return AVCS_ERR_OK; +} + +int32_t FFmpegDemuxerPlugin::UnselectSourceTrackByID(uint32_t trackIndex) +{ + std::stringstream selectedTracksString; + for (const auto &index : selectedTrackIds_) { + selectedTracksString << index; + } + AVCODEC_LOGI("Selected track in file: %{public}s | remove track: %{public}d", + selectedTracksString.str().c_str(), trackIndex); + + auto index = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(), + [trackIndex](uint32_t selectedId) {return trackIndex == selectedId; }); + if (index != selectedTrackIds_.end()) { + selectedTrackIds_.erase(index); + } else { + AVCODEC_LOGW("Unselect track failed, track %{public}d is not in selected list!", trackIndex); + return AVCS_ERR_INVALID_VAL; + } + return AVCS_ERR_OK; +} + +std::vector FFmpegDemuxerPlugin::GetSelectedTrackIds() +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::GetSelectedTrackIds is on call"); + std::vector trackIds; + trackIds = selectedTrackIds_; + return trackIds; +} + +bool FFmpegDemuxerPlugin::IsInSelectedTrack(uint32_t trackIndex) +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::IsInSelectedTrack is on call"); + return std::any_of(selectedTrackIds_.begin(), selectedTrackIds_.end(), + [trackIndex](uint32_t id) { return id == trackIndex; }); +} + +void FFmpegDemuxerPlugin::InitBitStreamContext(const AVStream& avStream) +{ + AVCODEC_LOGI("FFmpegDemuxerPlugin::InitBitStreamContext is on call"); + const AVBitStreamFilter* avBitStreamFilter {nullptr}; + char codeTag[AV_FOURCC_MAX_STRING_SIZE] {0}; + av_fourcc_make_string(codeTag, avStream.codecpar->codec_tag); + if (strncmp(codeTag, "avc1", strlen("avc1")) == 0) { + AVCODEC_LOGD("codeTag is avc1, will convert avc1 to annexb"); + avBitStreamFilter = av_bsf_get_by_name("h264_mp4toannexb"); + } else if (strncmp(codeTag, "hevc", strlen("hevc")) == 0) { + AVCODEC_LOGD("codeTag is hevc, will convert hevc to annexb"); + avBitStreamFilter = av_bsf_get_by_name("hevc_mp4toannexb"); + } else { + AVCODEC_LOGW("Can not find valid bit stream filter for %{public}s, stream will not be converted", codeTag); + } + if (avBitStreamFilter && !avbsfContext_) { + AVBSFContext* avbsfContext {nullptr}; + (void)av_bsf_alloc(avBitStreamFilter, &avbsfContext); + (void)avcodec_parameters_copy(avbsfContext->par_in, avStream.codecpar); + av_bsf_init(avbsfContext); + avbsfContext_ = std::shared_ptr(avbsfContext, [](AVBSFContext* ptr) { + if (ptr) { + av_bsf_free(&ptr); + } + }); + } + if (avbsfContext_ == nullptr) { + AVCODEC_LOGW("the video bit stream not support %{public}s convert to annexb format, \ + stream will not be converted", codeTag); + } +} + +void FFmpegDemuxerPlugin::ConvertAvcOrHevcToAnnexb(AVPacket& pkt) +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::ConvertAvcOrHevcToAnnexb is on call"); + (void)av_bsf_send_packet(avbsfContext_.get(), &pkt); + (void)av_packet_unref(&pkt); + (void)av_bsf_receive_packet(avbsfContext_.get(), &pkt); +} + +int32_t FFmpegDemuxerPlugin::ConvertAVPacketToSample(AVStream* avStream, uint8_t* buffer, AVCodecBufferInfo &bufferInfo, + AVCodecBufferFlag &flag, AVPacket* pkt) +{ + int frameSize = 0; + bufferInfo.presentationTimeUs = AvTime2Ms(ConvertTimeFromFFmpeg(pkt->pts, avStream->time_base)); + flag = ConvertFlagsFromFFmpeg(pkt, avStream); + if (avStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + frameSize = pkt->size; + } else if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (avStream->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) { + AVCODEC_LOGE("unsupport raw video"); + return AVCS_ERR_UNSUPPORT_STREAM; + } + if (videoBitStreamFormat_[pkt->stream_index] == VideoBitStreamFormat::ANNEXB) { + if (!avbsfContext_) { + InitBitStreamContext(*avStream); + } + if (avbsfContext_) { + ConvertAvcOrHevcToAnnexb(*pkt); + } + } + frameSize = pkt->size; + } else { + AVCODEC_LOGE("unsupport stream type"); + return AVCS_ERR_UNSUPPORT_VID_PARAMS; + } + if (buffer==nullptr) { + AVCODEC_LOGW("the buffer is NULL, allocate buffer\n"); + buffer = (uint8_t*)malloc(frameSize); + } + + bufferInfo.size = frameSize; + bufferInfo.offset = 0; + memset_s(buffer, frameSize, 0, frameSize); + memcpy_s(buffer, frameSize, pkt->data, frameSize); + return AVCS_ERR_OK; +} + +int32_t FFmpegDemuxerPlugin::CopyNextSample(uint32_t &trackIndex, uint8_t* buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + AVCODEC_LOGD("FFmpegDemuxerPlugin::CopyNextSample is on call"); + int ret = -1; + AVPacket* pkt = av_packet_alloc(); + do { + ret = av_read_frame(formatContext_.get(), pkt); + } while (ret >= 0 && !selectedTrackIds_.empty() && !IsInSelectedTrack(pkt->stream_index)); + + if (ret >= 0) { + trackIndex = pkt->stream_index; + AVStream* avStream = formatContext_->streams[pkt->stream_index]; + if (!sampleIndex_.count(pkt->stream_index)) { + sampleIndex_[pkt->stream_index]=1; + } else { + sampleIndex_[pkt->stream_index]++; + } + ret = ConvertAVPacketToSample(avStream, buffer, bufferInfo, flag, pkt); + } else { + AVCODEC_LOGE("read frame failed, ffmpeg error: %{public}d", ret); + ret = AVCS_ERR_DEMUXER_FAILED; + } + av_packet_free(&pkt); + return ret; +} + +int64_t FFmpegDemuxerPlugin::CalculateTimeByFrameIndex(AVStream* avStream, int keyFrameIdx) +{ +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 78, 0) + return avformat_index_get_entry(avStream, keyFrameIdx)->timestamp; +#elif LIBAVFORMAT_VERSION_INT == AV_VERSION_INT(58, 76, 100) + return avStream->index_entries[keyFrameIdx].timestamp; +#elif LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(58, 64, 100) + return avStream->internal->index_entries[keyFrameIdx].timestamp; +#else + return avStream->index_entries[keyFrameIdx].timestamp; +#endif +} + +int32_t FFmpegDemuxerPlugin::SeekToTime(int64_t mSeconds, AVSeekMode mode) +{ + if (!seekModeToFFmpegSeekFlags.count(mode)) { + AVCODEC_LOGE("unsupported seek mode: %{public}d", static_cast(mode)); + return AVCS_ERR_SEEK_FAILED; + } + int flags = seekModeToFFmpegSeekFlags.at(mode); + std::vector trackVec; + if (selectedTrackIds_.empty()) { + for (uint32_t trackIndex = 0; trackIndex < formatContext_.get()->nb_streams; trackIndex++) { + trackVec.push_back(trackIndex); + } + } else { + trackVec = selectedTrackIds_; + } + + for (size_t i = 0; i < trackVec.size(); i++) { + int trackIndex = trackVec[i]; + auto avStream = formatContext_->streams[trackIndex]; + int64_t ffTime = ConvertTimeToFFmpeg(mSeconds*1000*1000, avStream->time_base); + if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (ffTime > avStream->duration) { + AVCODEC_LOGE("ERROR: Seek to timestamp = %{public}" PRId64 " failed, max = %{public}" PRId64, + ffTime, avStream->duration); + return AVCS_ERR_SEEK_FAILED; + } + if (AvTime2Ms(ConvertTimeFromFFmpeg(avStream->duration, avStream->time_base) - mSeconds) <= 100 + && mode == AVSeekMode::SEEK_MODE_NEXT_SYNC) { + flags = seekModeToFFmpegSeekFlags.at(AVSeekMode::SEEK_MODE_PREVIOUS_SYNC); + } + if (ffTime < 0) { + AVCODEC_LOGW("invalid ffmpeg time: %{public}" PRId64 " ms, will be set to 0", ffTime); + ffTime = 0; + } + int keyFrameIdx = av_index_search_timestamp(avStream, ffTime, flags); + if (keyFrameIdx < 0) { + flags = seekModeToFFmpegSeekFlags.at(AVSeekMode::SEEK_MODE_CLOSEST_SYNC); + keyFrameIdx = av_index_search_timestamp(avStream, ffTime, flags); + } + if (keyFrameIdx >= 0) { + ffTime = CalculateTimeByFrameIndex(avStream, keyFrameIdx); + } + } + int64_t realSeekTime = ConvertTimeFromFFmpeg(ffTime, avStream->time_base); + AVCODEC_LOGD("realSeekTime: %{public}" PRId64, realSeekTime); + AVCODEC_LOGD("seek param: trackIndex=%{public}d, ffTime=%{public}" PRId64 ", \ + realSeekTime=%{public}" PRId64 ", flags=%{public}d", + trackIndex, ffTime, realSeekTime, flags); + + auto rtv = av_seek_frame(formatContext_.get(), trackIndex, ffTime, flags); + if (rtv < 0) { + AVCODEC_LOGE("seek failed, return value: %{public}d", rtv); + return AVCS_ERR_SEEK_FAILED; + } + } + return AVCS_ERR_OK; +} +} // FFmpeg +} // Plugin +} // Media +} // OHOS diff --git a/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.h b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..4524c386b6c537babc75aea9375ab04416b95a23 --- /dev/null +++ b/services/engine/plugin/plugins/demuxer/ffmpeg_demuxer/ffmpeg_demuxer_plugin.h @@ -0,0 +1,75 @@ +/* + * 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_DEMUXER_PLUGIN_H +#define FFMPEG_DEMUXER_PLUGIN_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +#include "libavutil/dict.h" + +#ifdef __cplusplus +} +#endif + +#include "demuxer_plugin.h" +#include "avcodec_common.h" +#include "avsharedmemory.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace FFmpeg { +class FFmpegDemuxerPlugin : public DemuxerPlugin { +public: + FFmpegDemuxerPlugin(); + ~FFmpegDemuxerPlugin(); + int32_t Create(uintptr_t sourceAddr) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t* buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t SeekToTime(int64_t mSeconds, AVSeekMode mode) override; + std::vector GetSelectedTrackIds(); +private: + bool IsInSelectedTrack(uint32_t trackIndex); + AVCodecBufferFlag ConvertFlagsFromFFmpeg(AVPacket* pkt, AVStream* avStream); + int64_t GetTotalStreamFrames(int streamIndex); + int32_t SetBitStreamFormat(); + int32_t ConvertAVPacketToSample(AVStream* avStream, uint8_t* buffer, AVCodecBufferInfo &bufferInfo, + AVCodecBufferFlag &flag, AVPacket* pkt); + void ConvertAvcOrHevcToAnnexb(AVPacket& pkt); + void InitBitStreamContext(const AVStream& avStream); + int64_t CalculateTimeByFrameIndex(AVStream* avStream, int keyFrameIdx); + std::vector selectedTrackIds_; + std::shared_ptr formatContext_; + std::shared_ptr avbsfContext_ {nullptr}; + std::map videoBitStreamFormat_; + std::map sampleIndex_; +}; +} // namespace FFmpeg +} // namespace Plugin +} // namespace AVCodec +} // namespace OH +#endif // FFMPEG_DEMUXER_PLUGIN_H \ 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 0000000000000000000000000000000000000000..a98a7ee93c2bdf28e751a8c39b6a8af57a33069b --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/BUILD.gn @@ -0,0 +1,44 @@ +# 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 = + [ "$av_codec_root_dir/services/engine/plugin:plugin_presets" ] + + public_deps = [ + "$av_codec_root_dir/services/utils:av_codec_format", + "//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/ffmpeg:libohosffmpeg", + ] + + relative_install_dir = "media/av_codec_plugins" + subsystem_name = "multimedia" + part_name = "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 0000000000000000000000000000000000000000..7068db03faed8fdeade28ba46b9f640dfa8878e5 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_muxer_plugin.cpp @@ -0,0 +1,426 @@ +/* + * 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) +{ + constexpr int32_t ffmpegConfidence = 60; + 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 = ffmpegConfidence; + } + + 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) +{ + constexpr int32_t mimeTypeLen = 5; + 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, mimeTypeLen, "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, mimeTypeLen, "video") || !mimeType.compare(0, mimeTypeLen, "image")) { + if (!mimeType.compare(0, mimeTypeLen, "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()); + } + + if (trackDesc.ContainKey(MediaDescriptionKey::MD_KEY_BITRATE)) { + trackDesc.GetLongValue(MediaDescriptionKey::MD_KEY_BITRATE, par->bit_rate); // bit rate + } + if (trackDesc.ContainKey(MediaDescriptionKey::MD_KEY_CODEC_CONFIG) && + 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 0000000000000000000000000000000000000000..69014e1ac146940c5701d9e6f3c95cae3f475db4 --- /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 0000000000000000000000000000000000000000..cc424671af4ac0df39b75b7acfcdc47748b2a3fd --- /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 0000000000000000000000000000000000000000..1548208e0a7f4d8dc1067536a3a4d7f81627dd46 --- /dev/null +++ b/services/engine/plugin/plugins/muxer/ffmpeg_muxer/ffmpeg_utils.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 FFMPEG_UTILS_H +#define FFMPEG_UTILS_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavcodec/avcodec.h" +#include "libavutil/error.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/engine/source/hst_releated/media_source.cpp b/services/engine/source/hst_releated/media_source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42fb4c3794743db5a4d307529edfbf23c4a2429f --- /dev/null +++ b/services/engine/source/hst_releated/media_source.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021-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 "media_source.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +MediaSource::MediaSource(std::string uri) + : uri_(std::move(uri)), type_(SourceType::SOURCE_TYPE_URI) +{ +} + +SourceType MediaSource::GetSourceType() const +{ + return type_; +} + +const std::string &MediaSource::GetSourceUri() const +{ + return uri_; +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS + diff --git a/services/engine/source/hst_releated/media_source.h b/services/engine/source/hst_releated/media_source.h new file mode 100644 index 0000000000000000000000000000000000000000..a1629e07dcd7352508b4654e70b75a1ff5eef9c2 --- /dev/null +++ b/services/engine/source/hst_releated/media_source.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_MEDIA_SOURCE_H +#define HISTREAMER_PLUGIN_MEDIA_SOURCE_H + +#include +#include +#include + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @brief Unified enumerates media source types. + * + * @since 1.0 + * @version 1.0 + */ +enum class SourceType : int32_t { + /** Local file path or network address */ + SOURCE_TYPE_URI = 0, + /** Local file descriptor */ + SOURCE_TYPE_FD, + /** Stream data */ + SOURCE_TYPE_STREAM, +}; + +class MediaSource { +public: + /// Construct an a specified URI. + explicit MediaSource(std::string uri); + + /// Destructor + virtual ~MediaSource() = default; + + /// Obtains the source type. + SourceType GetSourceType() const; + + /// Obtains the media source URI. + const std::string &GetSourceUri() const; + +private: + std::string uri_ {}; + SourceType type_ {}; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/engine/source/hst_releated/plugin_base.h b/services/engine/source/hst_releated/plugin_base.h new file mode 100644 index 0000000000000000000000000000000000000000..eadcd261c07207593b2d55c8591d59458892384d --- /dev/null +++ b/services/engine/source/hst_releated/plugin_base.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_INTF_PLUGIN_BASE_H +#define HISTREAMER_PLUGIN_INTF_PLUGIN_BASE_H + +#include +#include "plugin_tags.h" +#include "plugin_buffer.h" +#include "plugin_definition.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +enum class ErrorType { + PLUGIN_ERROR, + ALGO_ERROR, + CLIENT_ERROR, + SERVER_ERROR, +}; + +/** + * @brief Plugin status callback interface. + * @since 1.0 + * @version 1.0 + */ +struct Callback { + virtual ~Callback() = default; +}; + +/** + * @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 1.0 + * @version 1.0 + */ +struct PluginBase { + explicit PluginBase(std::string name): pluginName_(std::move(name)) {} + virtual ~PluginBase() = default; + + /** + * @brief Get plugin name + * @return plugin name + */ + std::string GetName() const + { + return pluginName_; + } + + /** + * @brief Plugin initialization, which is used to load external resources or plugin common resources. + * The function is valid only in the CREATED state. If the initialization is successful, + * the plugin enters the INITIALIZED state. + * @return Execution status return + * @retval OK: Plugin Init succeeded. + * @retval ERROR_NO_MEMORY: Memory allocation or external resource loading error caused by insufficient memory. + */ + virtual Status Init() + { + return Status::OK; + } + + /** + * @brief Plugin deinitialize to release resources. + * This function can be invoked in any state. + * After the function is invoked, the plugin will no longer be available. + * @return Execution status return + * @retval OK: Plugin Deinit succeeded. + */ + virtual Status Deinit() + { + return Status::OK; + } + + /** + * @brief Preparing parameters required or allocate the memory for plugin running. + * The function is valid only in the INITIALIZED state. If the prepare is successful, + * the plugin enters the PREPARED state. + * @return Execution status return + * @retval OK: Plugin Prepare succeeded. + * @retval ERROR_NO_MEMORY: Memory allocation error caused by insufficient memory. + */ + virtual Status Prepare() + { + return Status::OK; + } + + /** + * @brief Reset the plugin, reset the plugin running status and parameters before Prepare. + * The function is valid only in the PREPARED/RUNNING/PAUSED state. If the reset is successful, + * the plugin enters the INITIALIZED state. + * @return Execution status return + * @retval OK: Plugin Reset succeeded. + * @retval ERROR_UNIMPLEMENTED: This method is not implemented and cannot respond to reset. + */ + virtual Status Reset() + { + return Status::OK; + } + + /** + * @brief The plugin enters the running state and can process data. + * The function is valid only in the PREPARED state. If the start is successful, + * the plugin enters the RUNNING state. If an error occurs during the running, + * the plu-in status can be changed through asynchronous callback. + * @return Execution status return + * @retval OK: Plugin Start succeeded. + */ + virtual Status Start() + { + return Status::OK; + } + + /** + * @brief The plugin enters the stopped state and stops processing data. + * The function is valid only in the RUNNING state. If the stop is successful, + * the plugin enters the PREPARED state. Temporary data generated during the operation will be cleared. + * @return Execution status return + * @retval OK: Plugin Stop succeeded. + */ + virtual Status Stop() + { + return Status::OK; + } + + /** + * @brief Get the value of a specified parameter. + * This function can be called in any state except DESTROYED and INVALID. + * @param tag Plugin parameter type, which is described by tag. + * @param value Plugin parameter value. which is described by Any type. Need check the real type in tag. + * @return Execution status return + * @retval OK: Plugin GetParameter succeeded. + * @retval ERROR_INVALID_PARAMETER: The plugin does not support this parameter. + */ + virtual Status GetParameter(Tag tag, ValueType &value) + { + (void)tag; + (void)value; + return Status::ERROR_UNIMPLEMENTED; + } + + /** + * @brief Set the specified parameter. The value must be within the valid range of the parameter. + * This function can be called in any state except DESTROYED and INVALID. + * @param tag Plugin parameter type, which is described by tag. + * @param value Plugin parameter value. which is described by Any type. Need check the real type in tag. + * @return Execution status return + * @retval OK: Plugin SetParameter succeeded. + * @retval ERROR_INVALID_PARAMETER: The plugin does not support this parameter. + * @retval ERROR_INVALID_DATA: The value is not in the valid range. + * @retval ERROR_MISMATCHED_TYPE: The data type is mismatched. + */ + virtual Status SetParameter(Tag tag, const ValueType &value) + { + (void)tag; + (void)value; + return Status::ERROR_UNIMPLEMENTED; + } + + /** + * @brief Get the allocator specified by the plugin. + * The allocator can allocate memory types that meet the plugin requirements. + * @return Obtains the allocator object or NULL if the plugin does not have requirements for memory. + */ + virtual std::shared_ptr GetAllocator() + { + return nullptr; + } + + /** + * @brief Sets the plugin callback message to notify the plugin user. + * This function can be called in any state except DESTROYED and INVALID. + * @param cb Message callback, NULL callback listening is canceled. + * @return Execution status return + * @retval OK: Plugin SetCallback succeeded. + */ + virtual Status SetCallback(Callback* cb) = 0; + +protected: + const std::string pluginName_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_INTF_PLUGIN_BASE_H diff --git a/services/engine/source/hst_releated/plugin_buffer.cpp b/services/engine/source/hst_releated/plugin_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3801466b9b93b3ce023244dfb6e5b01243420b02 --- /dev/null +++ b/services/engine/source/hst_releated/plugin_buffer.cpp @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021-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 "plugin_buffer.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +Memory::Memory(size_t capacity, std::shared_ptr bufData, size_t align, MemoryType type) + : memoryType(type), capacity(capacity), alignment(align), + offset(0), size(0), allocator(nullptr), addr(std::move(bufData)) +{ +} + +Memory::Memory(size_t capacity, std::shared_ptr allocator, size_t align, MemoryType type, bool allocMem) + : memoryType(type), capacity(capacity), alignment(align), offset(0), + size(0), allocator(std::move(allocator)), addr(nullptr) +{ + if (!allocMem) { + return; + } + size_t allocSize = align ? (capacity + align - 1) : capacity; + if (this->allocator) { + addr = std::shared_ptr(static_cast(this->allocator->Alloc(allocSize)), + [this](uint8_t* ptr) { this->allocator->Free(static_cast(ptr)); }); + } else { + addr = std::shared_ptr(new uint8_t[allocSize], std::default_delete()); + } + offset = static_cast(AlignUp(reinterpret_cast(addr.get()), static_cast(align)) - + reinterpret_cast(addr.get())); +} + +size_t Memory::GetCapacity() +{ + return capacity; +} + +void Memory::Reset() +{ + this->size = 0; +} + +size_t Memory::Write(const uint8_t* in, size_t writeSize, size_t position) +{ + size_t start = 0; + if (position == INVALID_POSITION) { + start = size; + } else { + start = std::min(position, capacity); + } + size_t length = std::min(writeSize, capacity - start); + if (memcpy_s(GetRealAddr() + start, length, in, length) != EOK) { + return 0; + } + size = start + length; + return length; +} + +size_t Memory::Read(uint8_t* out, size_t readSize, size_t position) +{ + size_t start = 0; + size_t maxLength = size; + if (position != INVALID_POSITION) { + start = std::min(position, size); + maxLength = size - start; + } + size_t length = std::min(readSize, maxLength); + if (memcpy_s(out, length, GetRealAddr() + start, length) != EOK) { + return 0; + } + return length; +} + +const uint8_t* Memory::GetReadOnlyData(size_t position) +{ + if (position > capacity) { + return nullptr; + } + return GetRealAddr() + position; +} + +uint8_t* Memory::GetWritableAddr(size_t estimatedWriteSize, size_t position) +{ + if (position + estimatedWriteSize > capacity) { + return nullptr; + } + uint8_t* ptr = GetRealAddr() + position; + size = (estimatedWriteSize + position); + return ptr; +} + +void Memory::UpdateDataSize(size_t realWriteSize, size_t position) +{ + if (position + realWriteSize > capacity) { + return; + } + size = (realWriteSize + position); +} + +size_t Memory::GetSize() +{ + return size; +} + +uint8_t* Memory::GetRealAddr() const +{ + return addr.get() + offset; +} + +MemoryType Memory::GetMemoryType() +{ + return memoryType; +} + +Buffer::Buffer(BufferMetaType type) : trackID(0), pts(0), dts(0), duration(0), flag (0) +{ + (void)type; +} + +std::shared_ptr Buffer::CreateDefaultBuffer(BufferMetaType type, size_t capacity, + std::shared_ptr allocator, size_t align) +{ + auto buffer = std::make_shared(type); + std::shared_ptr memory = std::shared_ptr(new Memory(capacity, allocator, align)); + buffer->data.push_back(memory); + return buffer; +} + +std::shared_ptr Buffer::WrapMemory(uint8_t* dataptr, size_t capacity, size_t size) +{ + auto memory = std::shared_ptr( + new Memory(capacity, std::shared_ptr(dataptr, [](void* ptr) {(void)ptr;}))); + memory->size = size; + this->data.push_back(memory); + return memory; +} + +std::shared_ptr Buffer::WrapMemoryPtr(std::shared_ptr dataptr, size_t capacity, size_t size) +{ + auto memory = std::shared_ptr(new Memory(capacity, dataptr)); + memory->size = size; + this->data.push_back(memory); + return memory; +} + +std::shared_ptr Buffer::AllocMemory(std::shared_ptr allocator, size_t capacity, size_t align) +{ + auto type = (allocator != nullptr) ? allocator->GetMemoryType() : MemoryType::VIRTUAL_ADDR; + std::shared_ptr memory = nullptr; + switch (type) { + case MemoryType::VIRTUAL_ADDR: { + memory = std::shared_ptr(new Memory(capacity, allocator, align)); + break; + } + default: + break; + } + if (memory == nullptr) { + return nullptr; + } + data.push_back(memory); + return memory; +} + +uint32_t Buffer::GetMemoryCount() +{ + return data.size(); +} + +std::shared_ptr Buffer::GetMemory(uint32_t index) +{ + if (data.size() <= index) { + return nullptr; + } + return data[index]; +} + + +bool Buffer::IsEmpty() +{ + return data.empty(); +} + +void Buffer::Reset() +{ + data[0]->Reset(); + trackID = 0; + pts = 0; + dts = 0; + duration = 0; + flag = 0; +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS diff --git a/services/engine/source/hst_releated/plugin_buffer.h b/services/engine/source/hst_releated/plugin_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..7a65bef3a3707c51471fa7d6d44d24c3e4cbae27 --- /dev/null +++ b/services/engine/source/hst_releated/plugin_buffer.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_COMMON_BUFFER_H +#define HISTREAMER_PLUGIN_COMMON_BUFFER_H + +#include +#include +#include + +#include "plugin_memory.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +/// End of Stream Buffer Flag +#define BUFFER_FLAG_EOS 0x00000001 +/// Video Key Frame Flag +#define BUFFER_FLAG_KEY_FRAME 0x00000002 + +// Align value template +template +using MakeUnsigned = typename std::make_unsigned::type; + +template +constexpr T AlignUp(T num, U alignment) +{ + return (alignment > 0) ? (static_cast((num + static_cast>(alignment) - 1)) & + static_cast((~(static_cast>(alignment) - 1)))) : + num; +} + +/** + * @enum Buffer Meta Type + * + * @since 1.0 + * @version 1.0 + */ +enum struct BufferMetaType : uint32_t { + AUDIO, ///< Meta used to describe audio data + VIDEO, ///< Meta used to describe video data +}; + + +/** +* @brief Buffer base class. +* Contains the data storage and metadata information of the buffer (buffer description information). +* +* @since 1.0 +* @version 1.0 +*/ +class Buffer { +public: + /// Construct an empty buffer. + explicit Buffer(BufferMetaType type = BufferMetaType::AUDIO); + + /// Destructor + ~Buffer() = default; + + static std::shared_ptr CreateDefaultBuffer(BufferMetaType type, size_t capacity, + std::shared_ptr allocator = nullptr, + size_t align = 1); + + std::shared_ptr WrapMemory(uint8_t* dataptr, size_t capacity, size_t size); + + std::shared_ptr WrapMemoryPtr(std::shared_ptr dataptr, size_t capacity, size_t size); + + std::shared_ptr AllocMemory(std::shared_ptr allocator, size_t capacity, size_t align = 1); + + uint32_t GetMemoryCount(); + + std::shared_ptr GetMemory(uint32_t index = 0); + + void Reset(); + + /// no memory in the buffer. + bool IsEmpty(); + + /// track index. + uint32_t trackID; + + /// presentation timestamp of the buffer based on {@link HST_TIME_BASE}. + int64_t pts; + + /// decoding timestamp of the buffer based on {@link HST_TIME_BASE}. + int64_t dts; + + /// duration in time of the buffer data based on {@link HST_TIME_BASE}. + int64_t duration; + + /// flag of the buffer, which is used to record extra information. + /// @see BUFFER_FLAG_EOS + uint64_t flag; + +private: + /// Data described by this buffer. + std::vector> data {}; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_COMMON_BUFFER_H diff --git a/services/engine/source/hst_releated/plugin_caps.h b/services/engine/source/hst_releated/plugin_caps.h new file mode 100644 index 0000000000000000000000000000000000000000..d38ee1e81364f1d037ef18b74ab86a75fffddbda --- /dev/null +++ b/services/engine/source/hst_releated/plugin_caps.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_COMMON_CAPS_H +#define HISTREAMER_PLUGIN_COMMON_CAPS_H + +#include // NOLINT: used it +#include "plugin_tags.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +/// Indicates that the available capability type is an fixed value. +template using FixedCapability = T; + +/// Indicates that the available capability type is an interval value. +template using IntervalCapability = std::pair; + +/// Indicates that the available capability types are discrete values. +template using DiscreteCapability = std::vector; + +/** + * @brief The Capability describes the input and output capabilities of the plugin. + * + * It is basically a set of tags attached to the mime-type in order to + * describe the mime-type more closely. + * + * @since 1.0 + * @version 1.0 + */ +struct Capability { + /** + * @enum Capability ID is used to describe plugin capabilities or support capability matching. + * All Capability ID must come from Tag. + * + * For details about the definition and usage, to see enum Tag in file plugin_tags.h. + * + * @since 1.0 + * @version 1.0 + */ + enum struct Key : uint32_t { + MEDIA_BITRATE = static_cast(Tag::MEDIA_BITRATE), + AUDIO_SAMPLE_RATE = static_cast(Tag::AUDIO_SAMPLE_RATE), + AUDIO_CHANNELS = static_cast(Tag::AUDIO_CHANNELS), + AUDIO_CHANNEL_LAYOUT = static_cast(Tag::AUDIO_CHANNEL_LAYOUT), + AUDIO_SAMPLE_FORMAT = static_cast(Tag::AUDIO_SAMPLE_FORMAT), + AUDIO_MPEG_VERSION = static_cast(Tag::AUDIO_MPEG_VERSION), + AUDIO_MPEG_LAYER = static_cast(Tag::AUDIO_MPEG_LAYER), + AUDIO_AAC_PROFILE = static_cast(Tag::AUDIO_AAC_PROFILE), + AUDIO_AAC_LEVEL = static_cast(Tag::AUDIO_AAC_LEVEL), + AUDIO_AAC_STREAM_FORMAT = static_cast(Tag::AUDIO_AAC_STREAM_FORMAT), + VIDEO_PIXEL_FORMAT = static_cast(Tag::VIDEO_PIXEL_FORMAT), + VIDEO_BIT_STREAM_FORMAT = static_cast(Tag::VIDEO_BIT_STREAM_FORMAT), + }; + + /// Used to store the capability in the key-value format. + using KeyMap = std::map; + + /// default constructor + Capability() = default; + + /** + * @brief constructor one capability with mime of m + * + * @param m mime string + */ + explicit Capability(std::string m):mime(std::move(m)) {} + + /** + * @brief Append one fix key into KeyMap + * + * @tparam T type of value + * @param key Capability::Key + * @param val value + * @return reference of object + */ + template + Capability& AppendFixedKey(Key key, const T& val) + { + keys[key] = val; + return *this; + } + + /** + * @brief Append one interval key i.e. [rangeStart, rangeEnd] into KeyMap + * + * @tparam T type of value + * @param key Capability::Key + * @param rangeStart range start + * @param rangeEnd rang end + * @return reference of object + */ + template + Capability& AppendIntervalKey(Key key, const T& rangeStart, const T& rangeEnd) + { + keys[key] = std::make_pair(rangeStart, rangeEnd); + return *this; + } + + /** + * @brief Append one discrete key i.e. {val1, val2, ....} into KeyMap + * + * @tparam T type of value + * @param key Capability::Key + * @param discreteValues values + * @return reference of object + */ + template + Capability& AppendDiscreteKeys(Key key, DiscreteCapability discreteValues) + { + keys[key] = std::move(discreteValues); + return *this; + } + + /** + * @brief set mime of this capability + * + * @param val mime value + * @return reference of object + */ + Capability& SetMime(std::string val) + { + mime = std::move(val); + return *this; + } + + /// mime of capability. For details, see {@link constants.h} + std::string mime; + + /// Store the parameters(Capability::Key, value pairs), which should be negotiated + KeyMap keys; +}; + +/// A collection of multiple capabilities +using CapabilitySet = std::vector; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_COMMON_CAPS_H diff --git a/services/engine/source/hst_releated/plugin_definition.h b/services/engine/source/hst_releated/plugin_definition.h new file mode 100644 index 0000000000000000000000000000000000000000..c442fe013bbfad1e6f953d8314ef6f55673d5ea8 --- /dev/null +++ b/services/engine/source/hst_releated/plugin_definition.h @@ -0,0 +1,238 @@ +/* + * 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 "plugin_types.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @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 +}; + +/** + * @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. +}; + +/// Plugin create function. All plugins must implement this function. +template +using PluginCreatorFunc = std::shared_ptr(*)(const std::string& name); + +/** + * @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 CSERR_PLUGIN_ALREADY_EXISTS: The plugin already exists in plugin registered. + * @retval CSERR_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 CSERR_PLUGIN_ALREADY_EXISTS: The package or plugins already exists. + * @retval CSERR_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 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/source/hst_releated/plugin_memory.h b/services/engine/source/hst_releated/plugin_memory.h new file mode 100644 index 0000000000000000000000000000000000000000..7f3af7f576739c6ded043efb23462d3c057fa8ec --- /dev/null +++ b/services/engine/source/hst_releated/plugin_memory.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022-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. + */ + +#ifndef HISTREAMER_PLUGIN_MEMORY_H +#define HISTREAMER_PLUGIN_MEMORY_H + +#include +#include + +namespace OHOS { +namespace Media { +namespace Plugin { +constexpr size_t INVALID_POSITION = -1; +/** + * @enum MemoryType + * + * @since 1.0 + * @version 1.0 + */ +enum struct MemoryType : uint8_t { + VIRTUAL_ADDR = 0, ///< Virtual address + SURFACE_BUFFER, ///< Surface + SHARE_MEMORY, ///< Share Memory fd +}; + +/** +* @brief Memory allocator, which is provided by the plugin implementer. +* +* @since 1.0 +* @version 1.0 +*/ +struct Allocator { + explicit Allocator(MemoryType type = MemoryType::VIRTUAL_ADDR) : memoryType(type) {} + virtual ~Allocator() = default; + /** + * @brief Allocates a buffer using the specified size + * . + * @param size Allocation parameters. + * @return Pointer of the allocated buffer. + */ + virtual void* Alloc(size_t size) = 0; + + /** + * @brief Frees a buffer. + * Buffer handles returned by Alloc() must be freed with this function when no longer needed. + * + * @param ptr Pointer of the allocated buffer. + */ + virtual void Free(void* ptr) = 0; // NOLINT: intentionally using void* here + + MemoryType GetMemoryType() + { + return memoryType; + } + +private: + MemoryType memoryType; +}; + +/** +* @brief Memory description. Only manager the basic memory information. +* +* here is the memory layout. +* | capacity | +* |------------------------------------------| +* | buffer size | +* |-------------------------| +* addr offset buffer end +* +---------+-------------------------+----------------+ +* |*********| used buffer | unused buffer | +* +---------+-------------------------+----------------+ +* +* operate position: +* position +* +----------------+ +* +* @since 1.0 +* @version 1.0 +*/ +class Memory { +public: + /// Destructor + virtual ~Memory() = default; + + virtual size_t GetCapacity(); + + size_t GetSize(); + + const uint8_t* GetReadOnlyData(size_t position = 0); + + uint8_t *GetWritableAddr(size_t estimatedWriteSize, size_t position = 0); + + // If estimatedWriteSize doesn't equal to realWriteSize, should call UpdateDataSize + void UpdateDataSize(size_t realWriteSize, size_t position = 0); + + virtual size_t Write(const uint8_t* in, size_t writeSize, size_t position = INVALID_POSITION); + + virtual size_t Read(uint8_t* out, size_t readSize, size_t position = INVALID_POSITION); + + void Reset(); + + MemoryType GetMemoryType(); + +protected: + /** + * Allocates memory by the specified allocator. + * Allocation and release are the responsibility of the external allocator. + * + * @param capacity Allocated memory size. + * @param allocator External allocator. + * @param align The alignment of the memory. + */ + explicit Memory(size_t capacity, std::shared_ptr allocator = nullptr, + size_t align = 1, MemoryType type = MemoryType::VIRTUAL_ADDR, bool allocMem = true); + + /** + * Get real memory address, it is addr + offset, the offset is calculated according to alignment. + */ + virtual uint8_t *GetRealAddr() const; + + /// Memory type + MemoryType memoryType; + + /// Allocated memory size. + size_t capacity; + + /// The alignment of the memory. +#if (defined(__GNUC__) || defined(__clang__)) && (!defined(WIN32)) + __attribute__((unused)) +#endif + size_t alignment; + + /// Offset of the buffer address to make sure access according to alignment. + size_t offset {0}; + + /// Valid data size + size_t size; + + /// Externally specified allocator, optional. + std::shared_ptr allocator; + +private: + /** + * Create objects based on the external memory, use shared pointers, + * the allocation and release of memory are managed externally. + * + * @param capacity Allocated memory size. + * @param bufData External memory. + * @param align The alignment of the memory. + */ + Memory(size_t capacity, std::shared_ptr bufData, + size_t align = 1, MemoryType type = MemoryType::VIRTUAL_ADDR); + + /// Allocated virtual memory address. + std::shared_ptr addr; + + friend class Buffer; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_MEMORY_H diff --git a/services/engine/source/hst_releated/plugin_tags.h b/services/engine/source/hst_releated/plugin_tags.h new file mode 100644 index 0000000000000000000000000000000000000000..c3ae65d59b188d8ab8daedca9956d82751d3b411 --- /dev/null +++ b/services/engine/source/hst_releated/plugin_tags.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_COMMON_TAGS_H +#define HISTREAMER_PLUGIN_COMMON_TAGS_H + +#include // NOLINT +#include +#include // NOLINT + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @enum source input type. + * + * @since 1.0 + * @version 1.0 + */ +enum struct SrcInputType : uint32_t { + UNKNOWN, ///< Unknown audio input type + AUD_MIC, ///< Audio source input type of Microphone PCM data + AUD_ES, ///< Audio source input type of Raw encoded data + VID_SURFACE_YUV, ///< Video source input type of YUV video data + VID_SURFACE_RGB, ///< Video source input type of RGB video data + VID_SURFACE_ES, ///< Video source input type of Raw encoded data +}; + +enum struct TagSection : uint8_t { + REGULAR = 1, + MEDIA = 2, + AUDIO_UNIVERSAL = 3, + AUDIO_SPECIFIC = 4, + VIDEO_UNIVERSAL = 5, + VIDEO_SPECIFIC = 6, + MAX_SECTION = 64 +}; + +enum struct AudioFormat : uint8_t { + MPEG = 1, + AAC, +}; + +enum struct VideoFormat : uint8_t { + UNKNOWN = 0, + H264 = 1, + MPEG4 = 2, +}; + +enum class MediaType : uint32_t { + UNKNOWN = 0, ///< Usually treated as DATA + AUDIO, + VIDEO, + SUBTITLE, + ATTACHMENT, ///< Opaque data information usually sparse + DATA ///< Opaque data information usually continuous +}; + +#define MAKE_AUDIO_SPECIFIC_START(format) (SECTION_AUDIO_SPECIFIC_START | (static_cast(format) << 8U)) + +#define MAKE_VIDEO_SPECIFIC_START(format) (SECTION_VIDEO_SPECIFIC_START | (static_cast(format) << 8U)) + +/** + * @brief Tag is a key-value pair used to settings or transfer information. + * + * The "key" member:An uint32_t index, defined as an enumerated type. + * Tag Index consisting of the following fragments: + * - reserved field + * - vendor extensions + * - section (regular, audio, video ...) + * - addition index + * + * layout: + * +----------+---------+--------+----------------+ + * | reserved | section | vendor | addition index | + * +----------+---------+--------+----------------+ + * bit: 31 ... 22 21 ... 16 15 14 ............ 0 + * + * The "value" member: Different tag have different value types, + * which is defined in the plug-in interface. + * + * @since 1.0 + * @version 1.0 + */ +enum struct Tag : uint32_t { + INVALID = 0, + SECTION_REGULAR_START = static_cast(TagSection::REGULAR) << 16U, // regular tag + SECTION_MEDIA_START = static_cast(TagSection::MEDIA) << 16U, // media tag + SECTION_AUDIO_UNIVERSAL_START = static_cast(TagSection::AUDIO_UNIVERSAL) << 16U, // audio universal tag + SECTION_AUDIO_SPECIFIC_START = static_cast(TagSection::AUDIO_SPECIFIC) << 16U, // audio specific tag + SECTION_VIDEO_UNIVERSAL_START = static_cast(TagSection::VIDEO_UNIVERSAL) << 16U, // video universal tag + SECTION_VIDEO_SPECIFIC_START = static_cast(TagSection::VIDEO_SPECIFIC) << 16U, // video specific tag + + /* -------------------- regular tag -------------------- */ + MIME = SECTION_REGULAR_START + 1, ///< std::string + TRACK_ID, ///< uint32_t, track id + REQUIRED_OUT_BUFFER_CNT, ///< uint32_t, required buffer count of plugin; read only tag + REQUIRED_OUT_BUFFER_SIZE, ///< uint32_t, required buffer size of plugin; read only tag + BUFFER_ALLOCATOR, ///< Allocator, allocator to alloc buffers + BUFFERING_SIZE, ///< uint32_t, download buffer size + WATERLINE_HIGH, ///< uint32_t, high waterline + WATERLINE_LOW, ///< uint32_t, low waterline + SRC_INPUT_TYPE, ///< @see SrcInputType + BITS_PER_CODED_SAMPLE, ///< uint32_t, bits per coded sample + APP_TOKEN_ID, ///< uint32_t, app token id + APP_UID, ///< int32_t, app uid + APP_PID, ///< int32_t, app pid + AUDIO_RENDER_INFO, ///< AudioRenderInfo, audio render info + AUDIO_INTERRUPT_MODE, ///< AudioInterruptMode, audio interrupt mode + VIDEO_SCALE_TYPE, ///< VideoScaleType, video scale type + + /* -------------------- media tag -------------------- */ + MEDIA_TITLE = SECTION_MEDIA_START + 1, ///< string + MEDIA_ARTIST, ///< std::string, artist + MEDIA_LYRICIST, ///< std::string, lyricist + MEDIA_ALBUM, ///< std::string, album + MEDIA_ALBUM_ARTIST, ///< std::string, album artist + MEDIA_DATE, ///< std::string, media date, format:YYYY-MM-DD + MEDIA_COMMENT, ///< std::string, comment + MEDIA_GENRE, ///< std::string, genre + MEDIA_COPYRIGHT, ///< std::string, copyright + MEDIA_LANGUAGE, ///< std::string, language + MEDIA_DESCRIPTION, ///< std::string, description + MEDIA_LYRICS, ///< std::string, cyrics + MEDIA_DURATION, ///< int64_t, duration based on {@link HST_TIME_BASE} + MEDIA_FILE_SIZE, ///< uint64_t, file size + MEDIA_BITRATE, ///< int64_t, bite rate + MEDIA_FILE_URI, ///< std::string, file uri + MEDIA_CODEC_CONFIG, ///< std::vector, codec config. e.g. AudioSpecificConfig for mp4 + MEDIA_POSITION, ///< uint64_t : The byte position within media stream/file + MEDIA_START_TIME, ///< int64_t: The start time of one track + MEDIA_SEEKABLE, ///< enum Seekable: Seekable status of the media + MEDIA_PLAYBACK_SPEED, ///< double, playback speed + MEDIA_TYPE, ///< enum MediaType: Auido Video Subtitle... + + /* -------------------- audio universal tag -------------------- */ + AUDIO_CHANNELS = SECTION_AUDIO_UNIVERSAL_START + 1, ///< uint32_t, stream channel num + AUDIO_CHANNEL_LAYOUT, ///< @see AudioChannelLayout, stream channel layout + AUDIO_SAMPLE_RATE, ///< uint32_t, sample rate + AUDIO_SAMPLE_FORMAT, ///< @see AudioSampleFormat + AUDIO_SAMPLE_PER_FRAME, ///< uint32_t, sample per frame + AUDIO_OUTPUT_CHANNELS, ///< uint32_t, sink output channel num + AUDIO_OUTPUT_CHANNEL_LAYOUT, ///< @see AudioChannelLayout, sink output channel layout + + /* -------------------- audio specific tag -------------------- */ + AUDIO_SPECIFIC_MPEG_START = MAKE_AUDIO_SPECIFIC_START(AudioFormat::MPEG), + AUDIO_MPEG_VERSION, ///< uint32_t, mpeg version + AUDIO_MPEG_LAYER, ///< uint32_t, mpeg layer + + AUDIO_SPECIFIC_AAC_START = MAKE_AUDIO_SPECIFIC_START(AudioFormat::AAC), + AUDIO_AAC_PROFILE, ///< @see AudioAacProfile + AUDIO_AAC_LEVEL, ///< uint32_t, acc level + AUDIO_AAC_STREAM_FORMAT, ///< @see AudioAacStreamFormat + + /* -------------------- video universal tag -------------------- */ + VIDEO_WIDTH = SECTION_VIDEO_UNIVERSAL_START + 1, ///< uint32_t, video width + VIDEO_HEIGHT, ///< uint32_t, video height + VIDEO_PIXEL_FORMAT, ///< @see VideoPixelFormat + VIDEO_FRAME_RATE, ///< uint32_t, video frame rate + VIDEO_SURFACE, ///< @see class Surface + VIDEO_MAX_SURFACE_NUM, ///< uint32_t, max video surface num + VIDEO_CAPTURE_RATE, ///< double, video capture rate + VIDEO_BIT_STREAM_FORMAT, ///< @see VideoBitStreamFormat + + /* -------------------- video specific tag -------------------- */ + VIDEO_SPECIFIC_H264_START = MAKE_VIDEO_SPECIFIC_START(VideoFormat::H264), + VIDEO_H264_PROFILE, ///< @see VideoH264Profile + VIDEO_H264_LEVEL, ///< uint32_t, h264 level +}; +/** + * @enum Media protocol type. + * + * @since 1.0 + * @version 1.0 + */ +enum struct ProtocolType : uint32_t { + UNKNOWN, ///< Unknown protocol + FILE, ///< File protocol, uri prefix: "file://" + FD, ///< File descriptor protocol, uri prefix: "fd://" + STREAM, ///< Stream protocol, uri prefix: "stream://" + HTTP, ///< Http protocol, uri prefix: "http://" + HTTPS, ///< Https protocol, uri prefix: "https://" + HLS, ///< Http live streaming protocol, uri prefix: "https://" or "https://" or "file://", suffix: ".m3u8" + DASH, ///< Dynamic adaptive streaming over Http protocol, uri prefix: "https://" or "https://", suffix: ".mpd" + RTSP, ///< Real time streaming protocol, uri prefix: "rtsp://" + RTP, ///< Real-time transport protocol, uri prefix: "rtp://" + RTMP, ///< RTMP protocol, uri prefix: "rtmp://" + FTP, ///< FTP protocol, uri prefix: "ftp://" + UDP, ///< User datagram protocol, uri prefix: "udp://" +}; + +class Any final {}; +using ValueType = Any; + +/** + * The tag content is stored in key-value format. + */ +using CodecConfig = std::vector; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_COMMON_TAGS_H diff --git a/services/engine/source/hst_releated/plugin_types.h b/services/engine/source/hst_releated/plugin_types.h new file mode 100644 index 0000000000000000000000000000000000000000..816721dbf2ffcf98e10fb8b9aa80c1524b157d49 --- /dev/null +++ b/services/engine/source/hst_releated/plugin_types.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_TYPES_H +#define HISTREAMER_PLUGIN_TYPES_H + +#include // NOLINT: using int32_t in this file + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @enum Plugin running state. + * + * @since 1.0 + * @version 1.0 + */ +enum struct State : int32_t { + CREATED = 0, ///< Indicates the status of the plugin when it is constructed. + ///< The plug-in will not be restored in the entire life cycle. + INITIALIZED = 1, ///< Plugin global resource initialization completion status. + PREPARED = 2, ///< Status of parameters required for plugin running. + RUNNING = 3, ///< The system enters the running state after call start(). + PAUSED = 4, ///< Plugin temporarily stops processing data. This state is optional. + DESTROYED = -1, ///< Plugin destruction state. In this state, all resources are released. + INVALID = -2, ///< An error occurs in any state and the plugin enters the invalid state. +}; + +/** + * @enum Enumerates types of Seek Mode. + * + * @brief Seek modes, Options that SeekTo() behaviour. + * + * @since 1.0 + * @version 1.0 + */ +enum struct SeekMode : uint32_t { + SEEK_NEXT_SYNC = 0, ///> sync to keyframes after the time point. + SEEK_PREVIOUS_SYNC, ///> sync to keyframes before the time point. + SEEK_CLOSEST_SYNC, ///> sync to closest keyframes. + SEEK_CLOSEST, ///> seek to frames closest the time point. +}; + +/** + * @enum Seekable Status. + * + * @since 1.0 + * @version 1.0 + */ +enum class Seekable : int32_t { + INVALID = -1, + UNSEEKABLE = 0, + SEEKABLE = 1 +}; + +enum struct CodecMode { + HARDWARE, ///< HARDWARE CODEC + SOFTWARE, ///< SOFTWARE CODEC +}; + +/** + * @enum Plugin Type. + * + * @since 1.0 + * @version 1.0 + */ +enum struct PluginType : int32_t { + INVALID_TYPE = -1, ///< Invalid plugin + SOURCE = 1, ///< reference SourcePlugin + DEMUXER, ///< reference DemuxerPlugin + AUDIO_DECODER, ///< reference CodecPlugin + AUDIO_ENCODER, ///< reference CodecPlugin + VIDEO_DECODER, ///< reference CodecPlugin + VIDEO_ENCODER, ///< reference CodecPlugin + AUDIO_SINK, ///< reference AudioSinkPlugin + VIDEO_SINK, ///< reference VideoSinkPlugin + MUXER, ///< reference MuxerPlugin + OUTPUT_SINK, ///< reference OutputSinkPlugin +}; + +/* + * @brief Audio RenderInfo, default ContentType::CONTENT_TYPE_UNKNOWN(0) and StreamUsage::STREAM_USAGE_UNKNOWN(0) + * combined into AudioStreamType::STREAM_MUSIC. + */ +struct AudioRenderInfo { + int32_t contentType {0}; + int32_t streamUsage {0}; + int32_t rendererFlags {0}; +}; + +enum class AudioInterruptMode { + SHARE_MODE, + INDEPENDENT_MODE +}; + +enum class VideoScaleType { + VIDEO_SCALE_TYPE_FIT, + VIDEO_SCALE_TYPE_FIT_CROP, +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_TYPES_H diff --git a/services/engine/source/hst_releated/source_plugin.h b/services/engine/source/hst_releated/source_plugin.h new file mode 100644 index 0000000000000000000000000000000000000000..73da148413a1a2bba4543349c210870f364f2e73 --- /dev/null +++ b/services/engine/source/hst_releated/source_plugin.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021-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 HISTREAMER_PLUGIN_INTF_SOURCE_PLUGIN_H +#define HISTREAMER_PLUGIN_INTF_SOURCE_PLUGIN_H + +#include +#include +#include "media_source.h" +#include "plugin_caps.h" +#include "plugin_base.h" +#include "plugin_definition.h" + + +namespace OHOS { +namespace Media { +namespace Plugin { +/** + * @brief Source Plugin Interface. + * + * The data source may be network push or active read. + * + * @since 1.0 + * @version 1.0 + */ +struct SourcePlugin : public PluginBase { + /// constructor + explicit SourcePlugin(std::string name): PluginBase(std::move(name)) {} + /** + * @brief Set the data source to source plugin. + * + * The function is valid only in the CREATED state. + * + * @param source data source, uri or stream source + * @return Execution status return + * @retval OK: Plugin SetSource succeeded. + * @retval ERROR_WRONG_STATE: Call this function in non wrong state + * @retval ERROR_NOT_EXISTED: Uri is not existed. + * @retval ERROR_UNSUPPORTED_FORMAT: Uri is not supported. + * @retval ERROR_INVALID_PARAMETER: Uri is invalid. + */ + virtual OHOS::Media::Plugin::Status SetSource(std::shared_ptr source) = 0; + + /** + * @brief Read data from data source. + * + * The function is valid only after RUNNING state. + * + * @param buffer Buffer to store the data, it can be nullptr or empty to get the buffer from plugin. + * @param expectedLen Expected data size to be read + * @return Execution status return + * @retval OK: Plugin Read succeeded. + * @retval ERROR_NOT_ENOUGH_DATA: Data not enough + * @retval END_OF_STREAM: End of stream + */ + virtual Status Read(std::shared_ptr& buffer, size_t expectedLen) = 0; + + /** + * @brief Get data source size. + * + * The function is valid only after INITIALIZED state. + * + * @param size data source size. + * @return Execution status return. + * @retval OK: Plugin GetSize succeeded. + */ + virtual Status GetSize(size_t& size) = 0; + + /** + * @brief Indicates that the current source can be seek. + * + * The function is valid only after INITIALIZED state. + * + * @return Execution status return + * @retval OK: Plugin GetSeekable succeeded. + */ + virtual Seekable GetSeekable() = 0; + + /** + * @brief Seeks for a specified position for the source. + * + * After being started, the source seeks for a specified position to read data frames. + * + * The function is valid only after RUNNING state. + * + * @param offset position to read data frames + * @return Execution status return + * @retval OK: Plugin SeekTo succeeded. + * @retval ERROR_INVALID_DATA: The offset is invalid. + */ + virtual Status SeekTo(uint64_t offset) = 0; +}; + +/// Source plugin api major number. +#define SOURCE_API_VERSION_MAJOR (1) + +/// Source plugin api minor number +#define SOURCE_API_VERSION_MINOR (0) + +/// Source plugin version +#define SOURCE_API_VERSION MAKE_VERSION(SOURCE_API_VERSION_MAJOR, SOURCE_API_VERSION_MINOR) + +/** + * @brief Describes the source plugin information. + * + * @since 1.0 + * @version 1.0 + */ +struct SourcePluginDef : public PluginDefBase { + std::vector protocol; ///< Protocols supported by playback source + SrcInputType inputType; ///< Input type supported by record source + CapabilitySet outCaps; ///< Plug-in output capability, For details, @see Capability. + PluginCreatorFunc creator {nullptr}; ///< Source plugin create function. + SourcePluginDef() + { + apiVersion = SOURCE_API_VERSION; ///< Source plugin version. + pluginType = PluginType::SOURCE; ///< Plugin type, MUST be SOURCE. + } +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // HISTREAMER_PLUGIN_INTF_SOURCE_PLUGIN_H diff --git a/services/engine/source/include/i_source_engine.h b/services/engine/source/include/i_source_engine.h new file mode 100644 index 0000000000000000000000000000000000000000..84de5910ec0d18ccdf213e60c2a8ebb02aaabb2c --- /dev/null +++ b/services/engine/source/include/i_source_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 ISOURCE_ENGINE_H +#define ISOURCE_ENGINE_H + +#include +#include "format.h" +#include "avcodec_common.h" +#include "avsharedmemory.h" +#include "i_source_engine.h" + +namespace OHOS { +namespace Media { +class ISourceEngine { +public: + virtual ~ISourceEngine() = default; + virtual int32_t Create() = 0; + virtual int32_t GetTrackCount(uint32_t &trackCount) = 0; + virtual int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetSourceFormat(Format &format) = 0; + virtual int32_t GetTrackFormat(Format &format, uint32_t trackIndex) = 0; + virtual uintptr_t GetSourceAddr() = 0; +}; + +class __attribute__((visibility("default"))) ISourceEngineFactory { +public: + static std::shared_ptr CreateSourceEngine(int32_t appUid, int32_t appPid, const std::string& uri); +private: + ISourceEngineFactory() = default; + ~ISourceEngineFactory() = default; +}; +} // namespace Media +} // namespace OHOS +#endif // ISOURCE_ENGINE_H \ No newline at end of file diff --git a/services/engine/source/include/source_engine_impl.h b/services/engine/source/include/source_engine_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..6b623dec83fdda9c696a3ca5eecd1264d2c191ec --- /dev/null +++ b/services/engine/source/include/source_engine_impl.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 SOURCE_ENGINE_IMPL_H +#define SOURCE_ENGINE_IMPL_H + +#include +#include +#include +#include +#include "i_source_engine.h" +#include "plugin_definition.h" +#include "source.h" +#include "block_queue.h" +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class SourceEngineImpl : public ISourceEngine { +public: + SourceEngineImpl(int32_t appUid, int32_t appPid, const std::string& uri); + ~SourceEngineImpl() override; + int32_t Create() override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + uintptr_t GetSourceAddr() override; + +private: + int32_t appUid_ = -1; + int32_t appPid_ = -1; + std::string uri_; + std::shared_ptr source_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCE_ENGINE_IMPL_H \ No newline at end of file diff --git a/services/engine/source/source.cpp b/services/engine/source/source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e5d9cf6ef62ff4f66aafd0fce110228cb0e0edc --- /dev/null +++ b/services/engine/source/source.cpp @@ -0,0 +1,613 @@ +/* + * 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 "source.h" +#include +#include +#include +#include +#include +#include "avcodec_errors.h" +#include "avcodec_dfx.h" +#include "avcodec_log.h" +#include "avcodec_common.h" +#include "media_source.h" +#include "format.h" + +static std::string g_libFileHead = "libhistreamer_plugin_"; +static std::string g_fileSeparator = "/"; +static std::string g_libFileTail = ".z.so"; + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "Source"}; + + inline bool FileIsExists (const char* name) + { + struct stat buffer; + return (stat(name, &buffer) == 0); + } + + static std::map pluginMap = { + {"http", "libhistreamer_plugin_HttpSource.z.so"}, + {"https", "libhistreamer_plugin_HttpSource.z.so"}, + {"fd", "libhistreamer_plugin_FileFdSource.z.so"}, + {"file", "libhistreamer_plugin_FileSource.z.so"} + }; + + std::map> g_pluginInputFormat; + + std::string GetUriSuffix(const std::string& uri) + { + AVCODEC_LOGD("GetUriSuffix, input: uri=%{public}s", uri.c_str()); + std::string suffix; + auto const pos = uri.find_last_of('.'); + if (pos != std::string::npos) { + suffix = uri.substr(pos + 1); + } + AVCODEC_LOGD("suffix: %{public}s", suffix.c_str()); + return suffix; + } + + int32_t ParseProtocol(const std::string& uri, std::string& protocol) + { + AVCODEC_LOGD("ParseProtocol, input: uri=%{public}s, protocol=%{public}s", uri.c_str(), protocol.c_str()); + int32_t ret; + auto const pos = uri.find("://"); + if (pos != std::string::npos) { + auto prefix = uri.substr(0, pos); + protocol.append(prefix); + ret = AVCS_ERR_OK; + } else { + protocol.append("file"); + } + + if (protocol.empty()) { + AVCODEC_LOGE("ERROR:Invalid protocol: %{public}s", protocol.c_str()); + ret = AVCS_ERR_INVALID_OPERATION; + } + return ret; + } + + RegisterFunc OpenFilePlugin(const std::string& path, const std::string& name) + { + AVCODEC_LOGD("OpenFilePlugin, input: path=%{public}s, name=%{public}s", path.c_str(), name.c_str()); + void *handler = nullptr; + auto pathStr = path.c_str(); + if (FileIsExists(pathStr)) { + handler = ::dlopen(pathStr, RTLD_NOW); + if (handler == nullptr) { + AVCODEC_LOGE("dlopen failed due to %{public}s", ::dlerror()); + } + } + if (handler) { + std::string registerFuncName = "register_" + name; + RegisterFunc registerFunc = nullptr; + registerFunc = (RegisterFunc)(::dlsym(handler, registerFuncName.c_str())); + if (registerFunc) { + return registerFunc; + } else { + AVCODEC_LOGE("register is not found in %{public}s", registerFuncName.c_str()); + } + } else { + AVCODEC_LOGE("dlopen failed: %{public}s", pathStr); + } + return {}; + } + + bool IsInputFormatSupported(const char* name) + { + if (!strcmp(name, "audio_device") || !strncmp(name, "image", 5) || + !strcmp(name, "mjpeg") || !strcmp(name, "redir") || !strncmp(name, "u8", 2) || + !strncmp(name, "u16", 3) || !strncmp(name, "u24", 3) || + !strncmp(name, "u32", 3) || + !strncmp(name, "s8", 2) || !strncmp(name, "s16", 3) || + !strncmp(name, "s24", 3) || + !strncmp(name, "s32", 3) || !strncmp(name, "f32", 3) || + !strncmp(name, "f64", 3) || + !strcmp(name, "mulaw") || !strcmp(name, "alaw")) { + return false; + } + if (!strcmp(name, "sdp") || !strcmp(name, "rtsp") || !strcmp(name, "applehttp")) { + return false; + } + return true; + } + + 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; + } + } + }; +} + +Status FfmpegRegister::AddPlugin(const PluginDefBase& def) +{ + auto& tmpDef = (SourcePluginDef&) def; + sourcePlugin = (tmpDef.creator)(def.name); + return Status::OK; +} + +Status FfmpegRegister::AddPackage(const PackageDef& def) +{ + packageDef = std::make_shared(def); + return Status::OK; +} +constexpr size_t DEFAULT_READ_SIZE = 4096; + +Source::Source() + :formatContext_(nullptr), inputFormat_(nullptr) +{ + AVCODEC_LOGI("Source::Source is on call"); + register_ = std::make_shared(); +} + +Source::~Source() +{ + formatContext_ = nullptr; + inputFormat_ = nullptr; + sourcePlugin_ = nullptr; + register_ = nullptr; + avioContext_ = nullptr; + AVCODEC_LOGI("Source::~Source is on call"); +} + +int32_t Source::GetTrackCount(uint32_t &trackCount) +{ + CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "call getTrackcount failed, because create source failed!"); + trackCount = static_cast(formatContext_->nb_streams); + return AVCS_ERR_OK; +} + +int32_t Source::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + AVCODEC_LOGI("Source::SetTrackFormat is on call"); + AVCODEC_LOGI("set track: %{public}d, format: %{public}s", trackIndex, format.Stringify().c_str()); + if (trackIndex < 0 || trackIndex >= static_cast(formatContext_->nb_streams)) { + AVCODEC_LOGE("trackIndex is invalid!"); + return AVCS_ERR_INVALID_VAL; + } + AVStream *stream = formatContext_->streams[trackIndex]; + CHECK_AND_RETURN_RET_LOG(stream != nullptr, AVCS_ERR_INVALID_OPERATION, + "streams %{public}d is nullptr!", trackIndex); + Format::FormatDataMap formatMap = format.GetFormatMap(); + AVDictionary *streamMetadata = stream->metadata; + for (auto iter = formatMap.rbegin(); iter != formatMap.rend(); iter++) { + if (iter->first == AVSourceTrackFormat::VIDEO_BIT_STREAM_FORMAT) { + if (stream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { + AVCODEC_LOGE("track is not video, set VIDEO_BIT_STREAM_FORMAT failed!"); + return AVCS_ERR_INVALID_OPERATION; + } + int32_t streamFormat = iter->second.val.int32Val; + AVCODEC_LOGD("SetTrackFormat format: streamFormat: %{public}d, codec_id: %{public}d", + streamFormat, stream->codecpar->codec_id); + if ((streamFormat == VideoBitStreamFormat::AVCC && stream->codecpar->codec_id != AV_CODEC_ID_H264) || + (streamFormat == VideoBitStreamFormat::HVCC && stream->codecpar->codec_id != AV_CODEC_ID_HEVC)) { + return AVCS_ERR_INVALID_OPERATION; + }; + av_dict_set(&streamMetadata, iter->first.c_str(), (std::to_string(streamFormat)).c_str(), 0); + } + } + av_dict_copy(&stream->metadata, streamMetadata, 0); + return AVCS_ERR_OK; +} + +void Source::GetStringFormatFromMetadata(std::string key, std::string_view formatName, Format &format) +{ + int32_t ret; + AVDictionaryEntry *valPtr = nullptr; + valPtr = av_dict_get(formatContext_->metadata, key.c_str(), nullptr, AV_DICT_IGNORE_SUFFIX); + if (valPtr == nullptr) { + AVCODEC_LOGW("Put track info failed: miss %{public}s info in file", key.c_str()); + } else { + ret = format.PutStringValue(formatName, valPtr->value); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Put track info failed: miss %{public}s info in file", key.c_str()); + } + } +} + +int32_t Source::GetSourceFormat(Format &format) +{ + AVCODEC_LOGI("Source::GetFormat is on call"); + CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, "formatContext_ is nullptr!"); + Format::FormatDataMap formatMap = format.GetFormatMap(); + + GetStringFormatFromMetadata("title", AVSourceFormat::SOURCE_TITLE, format); + GetStringFormatFromMetadata("artist", AVSourceFormat::SOURCE_ARTIST, format); + GetStringFormatFromMetadata("album", AVSourceFormat::SOURCE_ALBUM, format); + GetStringFormatFromMetadata("album_artist", AVSourceFormat::SOURCE_ALBUM_ARTIST, format); + GetStringFormatFromMetadata("date", AVSourceFormat::SOURCE_DATE, format); + GetStringFormatFromMetadata("comment", AVSourceFormat::SOURCE_COMMENT, format); + GetStringFormatFromMetadata("genre", AVSourceFormat::SOURCE_GENRE, format); + GetStringFormatFromMetadata("copyright", AVSourceFormat::SOURCE_COPYRIGHT, format); + GetStringFormatFromMetadata("language", AVSourceFormat::SOURCE_LANGUAGE, format); + GetStringFormatFromMetadata("description", AVSourceFormat::SOURCE_DESCRIPTION, format); + GetStringFormatFromMetadata("media_type", AVSourceFormat::SOURCE_TYPE, format); + GetStringFormatFromMetadata("lyrics", AVSourceFormat::SOURCE_LYRICS, format); + + auto ret = format.PutLongValue(AVSourceFormat::SOURCE_DURATION, formatContext_->duration); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Put track info failed: miss album_artist info in file"); + } + return AVCS_ERR_OK; +} + + +int32_t Source::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + AVCODEC_LOGI("Source::GetTrackFormat is on call"); + int ret = -1; + CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "GetTrackFormat failed, formatContext_ is nullptr!"); + if (trackIndex < 0 || trackIndex >= static_cast(formatContext_->nb_streams)) { + AVCODEC_LOGE("trackIndex is invalid!"); + return AVCS_ERR_INVALID_VAL; + } + auto stream = formatContext_->streams[trackIndex]; + ret = format.PutIntValue(AVSourceTrackFormat::TRACK_INDEX, trackIndex); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss index info in track %{public}d", trackIndex); + } + ret = format.PutLongValue(AVSourceTrackFormat::TRACK_SAMPLE_COUNT, stream->nb_frames); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss sample cout info in track %{public}d", trackIndex); + } + ret = format.PutStringValue(AVSourceTrackFormat::TRACK_TYPE, + av_get_media_type_string(stream->codecpar->codec_type)); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss type info in track %{public}d", trackIndex); + } + ret = format.PutLongValue(AVSourceTrackFormat::TRACK_DURATION, stream->duration); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss duration info in track %{public}d", trackIndex); + } + ret = format.PutIntValue(AVSourceTrackFormat::VIDEO_TRACK_WIDTH, stream->codecpar->width); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss width info in track %{public}d", trackIndex); + } + ret = format.PutIntValue(AVSourceTrackFormat::VIDEO_TRACK_HEIGHT, stream->codecpar->height); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss height info in track %{public}d", trackIndex); + } + AVDictionaryEntry *pair = av_dict_get(stream->metadata, "rotate", nullptr, 0); + if (pair!=nullptr) { + ret = format.PutIntValue(AVSourceTrackFormat::VIDEO_TRACK_ROTATION, std::atoi(pair->value)); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGW("Get track info failed: miss rotate info in track %{public}d", trackIndex); + } + } else { + AVCODEC_LOGW("Get track info failed: miss rotate info in track %{public}d", trackIndex); + } + return AVCS_ERR_OK; +} + + +uintptr_t Source::GetSourceAddr() +{ + CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "GetSourceAddr failed, formatContext_ is nullptr!"); + return (uintptr_t)(formatContext_.get()); +} + + +int32_t Source::Create(std::string& uri) +{ + AVCODEC_LOGI("Source::Create is called"); + int32_t ret = LoadDynamicPlugin(uri); + CHECK_AND_RETURN_RET_LOG(ret != AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when load source plugin!"); + std::shared_ptr mediaSource = std::make_shared(uri); + AVCODEC_LOGD("mediaSource Init: %{public}s", mediaSource->GetSourceUri().c_str()); + if (sourcePlugin_ == nullptr) { + AVCODEC_LOGE("load sourcePlugin_ fail !"); + return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED; + } + Status pluginRet = sourcePlugin_->SetSource(mediaSource); + CHECK_AND_RETURN_RET_LOG(pluginRet == Status::OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when set data source for plugin!"); + ret = LoadDemuxerList(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when load demuxerlist!"); + ret = SniffInputFormat(uri); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when find input format!"); + CHECK_AND_RETURN_RET_LOG(inputFormat_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when find input format, cannnot match any input format!"); + + ret = InitAVFormatContext(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when parse source info!"); + CHECK_AND_RETURN_RET_LOG(formatContext_ != nullptr, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source failed when init AVFormatContext!"); + return AVCS_ERR_OK; +} + + +int32_t Source::LoadDemuxerList() +{ + const AVInputFormat* plugin = nullptr; + constexpr size_t strMax = 4; + void* i = nullptr; + while ((plugin = av_demuxer_iterate(&i))) { + if (plugin->long_name != nullptr) { + if (!strncmp(plugin->long_name, "pcm ", strMax)) { + continue; + } + } + if (!IsInputFormatSupported(plugin->name)) { + continue; + } + std::string pluginName = "avdemux_" + std::string(plugin->name); + ReplaceDelimiter(".,|-<> ", '_', pluginName); + g_pluginInputFormat[pluginName] = + std::shared_ptr(const_cast(plugin), [](void*) {}); + } + if (g_pluginInputFormat.empty()) { + AVCODEC_LOGW("cannot load any format demuxer"); + return AVCS_ERR_INVALID_OPERATION; + } + return AVCS_ERR_OK; +} + + +int32_t Source::LoadDynamicPlugin(const std::string& path) +{ + AVCODEC_LOGI("LoadDynamicPlugin: %{public}s", path.c_str()); + std::string protocol; + if (!ParseProtocol(path, protocol)) { + AVCODEC_LOGE("Couldn't find valid protocol for %{public}s", path.c_str()); + return AVCS_ERR_INVALID_OPERATION; + } + if (pluginMap.count(protocol) == 0) { + AVCODEC_LOGE("Unsupport protocol: %{public}s", protocol.c_str()); + return AVCS_ERR_INVALID_OPERATION; + } + std::string libFileName = pluginMap[protocol]; + std::string filePluginPath = OH_FILE_PLUGIN_PATH + g_fileSeparator + libFileName; + std::string pluginName = + libFileName.substr(g_libFileHead.size(), libFileName.size() - g_libFileHead.size() - g_libFileTail.size()); + std::string registerFuncName = "register_" + pluginName; + RegisterFunc registerFunc = OpenFilePlugin(filePluginPath, pluginName); + if (registerFunc) { + register_ = std::make_shared(); + registerFunc(register_); + sourcePlugin_ = register_->sourcePlugin; + AVCODEC_LOGD("regist source plugin successful"); + return AVCS_ERR_OK; + } else { + AVCODEC_LOGD("regist source plugin failed, sourcePlugin path: %{public}s", filePluginPath.c_str()); + return AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED; + } +} + +int32_t Source::GuessInputFormat(const std::string& uri, std::shared_ptr &bestInputFormat) +{ + std::string uriSuffix = GetUriSuffix(uri); + if (uriSuffix.empty()) { + AVCODEC_LOGW("can't found suffix ,please check the file %{public}s's suffix", uri.c_str()); + return AVCS_ERR_INVALID_OPERATION; + } + std::map>::iterator iter; + for (iter = g_pluginInputFormat.begin(); iter != g_pluginInputFormat.end(); iter++) { + std::shared_ptr inputFormat = iter->second; + if (uriSuffix == inputFormat->name) { + bestInputFormat = inputFormat; + AVCODEC_LOGD("find input fromat successful: %{public}s", inputFormat->name); + break; + } + } + return AVCS_ERR_OK; +} + +int32_t Source::SniffInputFormat(const std::string& uri) +{ + size_t bufferSize = DEFAULT_READ_SIZE; + size_t fileSize = 0; + if (!static_cast(sourcePlugin_->GetSize(fileSize))) { + bufferSize = (bufferSize < fileSize) ? bufferSize : fileSize; + } + std::vector buff(bufferSize); + auto bufferInfo = std::make_shared(); + auto bufferMemory = bufferInfo->WrapMemory(buff.data(), bufferSize, 0); + if (bufferMemory==nullptr) { + return AVCS_ERR_NO_MEMORY; + } + auto ret = static_cast(sourcePlugin_->Read(bufferInfo, bufferSize)); + CHECK_AND_RETURN_RET_LOG(ret >= 0, AVCS_ERR_CREATE_SOURCE_SUB_SERVICE_FAILED, + "create source service failed when probe source format!"); + AVProbeData probeData = {"", buff.data(), static_cast(bufferSize), ""}; + constexpr int probThresh = 50; + int maxProb = 0; + std::map>::iterator iter; + for (iter = g_pluginInputFormat.begin(); iter != g_pluginInputFormat.end(); iter++) { + std::string vtype = iter->first; + std::shared_ptr inputFormat = iter -> second; + if (inputFormat->read_probe) { + auto prob = inputFormat->read_probe(&probeData); + if (prob > probThresh) { + inputFormat_ = inputFormat; + break; + } + if (prob > maxProb) { + maxProb = prob; + inputFormat_ = inputFormat; + } + } + } + if (inputFormat_ == nullptr) { + AVCODEC_LOGW("sniff input format failed, will guess one!"); + return GuessInputFormat(uri, inputFormat_); + } + return AVCS_ERR_OK; +} + +void Source::InitAVIOContext(int flags) +{ + constexpr int bufferSize = 4096; + customIOContext_.sourcePlugin = sourcePlugin_.get(); + Status pluginRet = sourcePlugin_->GetSize(customIOContext_.fileSize); + if (pluginRet != Status::OK) { + AVCODEC_LOGE("get file size failed when set data source for plugin!"); + return; + } + pluginRet = sourcePlugin_->SeekTo(0); + if (pluginRet != Status::OK) { + AVCODEC_LOGE("seek to 0 failed when set data source for plugin!"); + return; + } + customIOContext_.offset=0; + customIOContext_.eof=false; + auto buffer = static_cast(av_malloc(bufferSize)); + auto bufferVector = std::make_shared(); + customIOContext_.bufMemory = bufferVector; + auto bufMemory = bufferVector->WrapMemory(buffer, bufferSize, 0); + if (buffer == nullptr) { + AVCODEC_LOGE("AllocAVIOContext failed to av_malloc..."); + return; + } + avioContext_ = avio_alloc_context(buffer, bufferSize, flags & AVIO_FLAG_WRITE, + (void*)(&customIOContext_), AVReadPacket, NULL, AVSeek); + customIOContext_.avioContext = avioContext_; + if (avioContext_ == nullptr) { + AVCODEC_LOGE("AllocAVIOContext failed to avio_alloc_context..."); + av_free(buffer); + return; + } + Seekable seekable = sourcePlugin_->GetSeekable(); + AVCODEC_LOGD("seekable_ is %{public}d", (int)seekable); + avioContext_->seekable = (seekable == Seekable::SEEKABLE) ? AVIO_SEEKABLE_NORMAL : 0; + if (!(static_cast(flags) & static_cast(AVIO_FLAG_WRITE))) { + avioContext_->buf_ptr = avioContext_->buf_end; + avioContext_->write_flag = 0; + } +} + +int64_t Source::AVSeek(void *opaque, int64_t offset, int whence) +{ + auto customIOContext = static_cast(opaque); + uint64_t newPos = 0; + switch (whence) { + case SEEK_SET: + newPos = static_cast(offset); + customIOContext->offset = newPos; + break; + case SEEK_CUR: + newPos = customIOContext->offset + offset; + break; + case SEEK_END: + case AVSEEK_SIZE: { + size_t mediaDataSize = 0; + customIOContext->sourcePlugin->GetSize(mediaDataSize); + if (mediaDataSize > 0) { + newPos = mediaDataSize + offset; + } + break; + } + default: + AVCODEC_LOGW("AVSeek unexpected whence: %{oublic}d", whence); + break; + } + if (whence != AVSEEK_SIZE) { + customIOContext->offset = newPos; + } + return newPos; +} + +int Source::AVReadPacket(void *opaque, uint8_t *buf, int bufSize) +{ + int rtv = -1; + auto readSize = bufSize; + auto customIOContext = static_cast(opaque); + auto bufferVector = customIOContext->bufMemory; + if ((customIOContext->avioContext->seekable == (int) Seekable::SEEKABLE)&&(customIOContext->fileSize!=0)) { + if (customIOContext->offset > customIOContext->fileSize) { + AVCODEC_LOGW("ERROR: offset: %{public}zu is larger than totalSize: %{public}zu", + customIOContext->offset, customIOContext->fileSize); + return AVCS_ERR_SEEK_FAILED; + } + if (static_cast(customIOContext->offset+bufSize) > customIOContext->fileSize) { + readSize = customIOContext->fileSize - customIOContext->offset; + } + if (buf!=nullptr && bufferVector->GetMemory()!=nullptr) { + auto memSize = static_cast(bufferVector->GetMemory()->GetCapacity()); + readSize = (readSize > memSize) ? memSize : readSize; + } + if (customIOContext->position != customIOContext->offset) { + int32_t err = static_cast(customIOContext->sourcePlugin->SeekTo(customIOContext->offset)); + if (err < 0) { + AVCODEC_LOGD("ERROR: Seek to %{public}zu fail,err=%{public}d\n", customIOContext->offset, err); + return AVCS_ERR_SEEK_FAILED; + } + customIOContext->position = customIOContext->offset; + } + int32_t result = static_cast( + customIOContext->sourcePlugin->Read(bufferVector, static_cast(readSize))); + AVCODEC_LOGD("AVReadPacket read data size = %{public}d", + static_cast(bufferVector->GetMemory()->GetSize())); + if (result == 0) { + rtv = bufferVector->GetMemory()->GetSize(); + customIOContext->offset += rtv; + customIOContext->position += rtv; + } else if (static_cast(result) == 1) { + customIOContext->eof=true; + rtv = AVERROR_EOF; + } else { + AVCODEC_LOGE("AVReadPacket failed with rtv = %{public}d", static_cast(result)); + } + } + return rtv; +} + +int32_t Source::InitAVFormatContext() +{ + AVFormatContext *formatContext = avformat_alloc_context(); + if (formatContext == nullptr) { + AVCODEC_LOGE("InitAVFormatContext failed, because alloc AVFormatContext failed."); + return AVCS_ERR_INVALID_OPERATION; + } + InitAVIOContext(AVIO_FLAG_READ); + if (avioContext_ == nullptr) { + AVCODEC_LOGE("InitAVFormatContext failed, because init AVIOContext failed."); + return AVCS_ERR_INVALID_OPERATION; + } + formatContext->pb = avioContext_; + formatContext->flags |= AVFMT_FLAG_CUSTOM_IO; + int32_t ret = -1; + ret = static_cast(avformat_open_input(&formatContext, nullptr, inputFormat_.get(), nullptr)); + if (ret == 0) { + formatContext_ = std::shared_ptr(formatContext, [](AVFormatContext* ptr) { + if (ptr) { + auto ctx = ptr->pb; + if (ctx) { + av_freep(&ctx->buffer); + av_free(ctx); + } + } + }); + } else { + AVCODEC_LOGE("avformat_open_input failed by %{public}s", inputFormat_->name); + return AVCS_ERR_INVALID_OPERATION; + } + return AVCS_ERR_OK; +} +} // namespace Plugin +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/engine/source/source.h b/services/engine/source/source.h new file mode 100644 index 0000000000000000000000000000000000000000..3d2ba02c2c5c24b8902ece984274cfebd5905028 --- /dev/null +++ b/services/engine/source/source.h @@ -0,0 +1,96 @@ +/* + * 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 SOURCE_H +#define SOURCE_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavformat/avformat.h" +#include "libavutil/opt.h" +#ifdef __cplusplus +} +#endif + +#include +#include "avcodec_errors.h" +#include "source_plugin.h" +#include "plugin_types.h" +#include "plugin_buffer.h" +#include "plugin_definition.h" +#include "sourcebase.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +struct FfmpegRegister : PackageRegister { +public: + std::string name = "custom register"; + Status AddPlugin(const PluginDefBase& def) override; + Status AddPackage(const PackageDef& def) override; + std::shared_ptr sourcePlugin {nullptr}; +private: + std::shared_ptr packageDef; +}; + +class Source : public SourceBase { +public: + Source(); + ~Source(); + + int32_t Create(std::string& uri) override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + uintptr_t GetSourceAddr() override; + std::shared_ptr GetSourcePlugin() + { + return sourcePlugin_; + } + +private: + struct CustomIOContext { + SourcePlugin* sourcePlugin = nullptr; + size_t offset = 0; + size_t position = 0; + bool eof = false; + size_t fileSize = 0; + AVIOContext* avioContext = nullptr; + std::shared_ptr bufMemory; + }; + + std::shared_ptr formatContext_; + std::map trackParam_; + std::shared_ptr inputFormat_; + std::shared_ptr sourcePlugin_; + std::shared_ptr register_; + CustomIOContext customIOContext_; + AVIOContext* avioContext_ = nullptr; + int32_t LoadDemuxerList(); + int32_t LoadDynamicPlugin(const std::string& path); + int32_t GuessInputFormat(const std::string& uri, std::shared_ptr& bestInputFormat); + int32_t SniffInputFormat(const std::string& uri); + static int AVReadPacket(void* opaque, uint8_t* buf, int bufSize); + static int64_t AVSeek(void* opaque, int64_t offset, int whence); + void InitAVIOContext(int flags); + int32_t InitAVFormatContext(); + void GetStringFormatFromMetadata(std::string key, std::string_view formatName, Format &format); +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS +#endif // AVSOURCE_H \ No newline at end of file diff --git a/services/engine/source/source_engine_impl.cpp b/services/engine/source/source_engine_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40b10de9715c3beec80ff1024a47b583370d940e --- /dev/null +++ b/services/engine/source/source_engine_impl.cpp @@ -0,0 +1,106 @@ +/* + * 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 "source_engine_impl.h" +#include +#include +#include +#include "securec.h" +#include "source.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SourceEngineImpl"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr ISourceEngineFactory::CreateSourceEngine(int32_t appUid, int32_t appPid, + const std::string& uri) +{ + AVCodecTrace trace("ISourceEngineFactory::CreateSourceEngine"); + std::shared_ptr sourceEngineImpl = std::make_shared(appUid, appPid, uri); + CHECK_AND_RETURN_RET_LOG(sourceEngineImpl != nullptr, nullptr, "create SourceEngine implementation failed"); + return sourceEngineImpl; +} + +int32_t SourceEngineImpl::Create() +{ + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + if (source_ != nullptr) { + AVCODEC_LOGI("state_ is INITIALIZED"); + } else { + AVCODEC_LOGE("state_ is UNINITIALIZED"); + } + return source_->Create(uri_); +} + +SourceEngineImpl::SourceEngineImpl(int32_t appUid, int32_t appPid, const std::string& uri) + : appUid_(appUid), appPid_(appPid), uri_(uri) +{ + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + source_ = std::make_shared(); + if (source_ == nullptr) { + AVCODEC_LOGE("create demuxer engine failed"); + } +} + +SourceEngineImpl::~SourceEngineImpl() +{ + AVCODEC_LOGD("Destroy"); + appUid_ = -1; + appPid_ = -1; + source_ = nullptr; + AVCODEC_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t SourceEngineImpl::GetTrackCount(uint32_t &trackCount) +{ + AVCodecTrace trace("SourceEngineImpl::GetTrackCount"); + AVCODEC_LOGI("GetTrackCount"); + return source_->GetTrackCount(trackCount); +} + +int32_t SourceEngineImpl::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + AVCodecTrace trace("SourceEngineImpl::SetTrackFormat"); + AVCODEC_LOGI("SetTrackFormat"); + return source_->SetTrackFormat(format, trackIndex); +} + +int32_t SourceEngineImpl::GetSourceFormat(Format &format) +{ + AVCodecTrace trace("SourceEngineImpl::GetSourceFormat"); + AVCODEC_LOGI("GetSourceFormat"); + return source_->GetSourceFormat(format); +} + +int32_t SourceEngineImpl::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + AVCodecTrace trace("SourceEngineImpl::GetTrackFormat"); + AVCODEC_LOGI("GetTrackFormat"); + return source_->GetTrackFormat(format, trackIndex); +} + +uintptr_t SourceEngineImpl::GetSourceAddr() +{ + AVCodecTrace trace("SourceEngineImpl::GetSourceAddr"); + AVCODEC_LOGI("GetSourceAddr"); + return source_->GetSourceAddr(); +} +} // Media +} // OHOS diff --git a/services/etc/BUILD.gn b/services/etc/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..13b84339724e5cd50118347f155a5de32ead92c0 --- /dev/null +++ b/services/etc/BUILD.gn @@ -0,0 +1,21 @@ +# 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. + +import("//build/ohos.gni") + +ohos_prebuilt_etc("av_codec_service.cfg") { + source = "av_codec_service.cfg" + relative_install_dir = "init" + part_name = "av_codec" + subsystem_name = "multimedia" +} diff --git a/services/etc/av_codec_service.cfg b/services/etc/av_codec_service.cfg new file mode 100644 index 0000000000000000000000000000000000000000..2abd2ba0a11c4eda58061bc6aa3223d761476995 --- /dev/null +++ b/services/etc/av_codec_service.cfg @@ -0,0 +1,10 @@ +{ + "services" : [{ + "name" : "av_codec_service", + "path" : ["/system/bin/sa_main", "/system/profile/av_codec_service.xml"], + "uid" : "media", + "gid" : ["av_codec_rw", "system"], + "secon" : "u:r:media_service:s0" + } + ] +} diff --git a/services/etc/avcodec_caps.xml b/services/etc/avcodec_caps.xml new file mode 100644 index 0000000000000000000000000000000000000000..db38b9114b66bc199079f506377b9fa6dbe69d28 --- /dev/null +++ b/services/etc/avcodec_caps.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/services/include/i_avcodec_service.h b/services/include/i_avcodec_service.h new file mode 100644 index 0000000000000000000000000000000000000000..a95e65799adba32c36040d1ca204cabe9f713adb --- /dev/null +++ b/services/include/i_avcodec_service.h @@ -0,0 +1,150 @@ +/* + * 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_AVCODEC_SERVICE_H +#define I_AVCODEC_SERVICE_H + +#include + +#ifdef SUPPORT_CODEC +#include "i_codec_service.h" +#endif + +#ifdef SUPPORT_CODECLIST +#include "i_codeclist_service.h" +#endif + +#ifdef SUPPORT_DEMUXER +#include "i_demuxer_service.h" +#endif + +#ifdef SUPPORT_MUXER +#include "i_muxer_service.h" +#endif + +#ifdef SUPPORT_SOURCE +#include "i_source_service.h" +#endif + +namespace OHOS { +namespace Media { +class IAVCodecService { +public: + virtual ~IAVCodecService() = default; + +#ifdef SUPPORT_CODECLIST + /** + * @brief Create a codeclist service. + * + * All player functions must be created and obtained first. + * + * @return Returns a valid pointer if the setting is successful; + * @since 4.0 + * @version 4.0 + */ + virtual std::shared_ptr CreateCodecListService() = 0; + + /** + * @brief Destroy a codeclist service. + * + * call the API to destroy the codeclist service. + * + * @param pointer to the codeclist service. + * @return Returns a valid pointer if the setting is successful; + * @since 4.0 + * @version 4.0 + */ + virtual int32_t DestroyCodecListService(std::shared_ptr avCodecList) = 0; +#endif + +#ifdef SUPPORT_CODEC + /** + * @brief Create an avcodec service. + * + * All player functions must be created and obtained first. + * + * @return Returns a valid pointer if the setting is successful; + * @since 4.0 + * @version 4.0 + */ + virtual std::shared_ptr CreateCodecService() = 0; + + /** + * @brief Destroy a avcodec service. + * + * call the API to destroy the avcodec service. + * + * @param pointer to the avcodec service. + * @return Returns a valid pointer if the setting is successful; + * @since 4.0 + * @version 4.0 + */ + virtual int32_t DestroyCodecService(std::shared_ptr codec) = 0; +#endif +#ifdef SUPPORT_DEMUXER + virtual std::shared_ptr CreateDemuxerService() = 0; + virtual int32_t DestroyDemuxerService(std::shared_ptr demuxer) = 0; +#endif + +#ifdef SUPPORT_MUXER + /** + * @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 + virtual std::shared_ptr CreateSourceService() = 0; + virtual int32_t DestroySourceService(std::shared_ptr source) = 0; +#endif +}; + +class __attribute__((visibility("default"))) AVCodecServiceFactory { +public: + /** + * @brief IAVCodecService singleton + * + * Create Muxer and Demuxer Service Through the AVCodec Service. + * + * @return Returns IAVCodecService singleton; + * @since 4.0 + * @version 4.0 + */ + static IAVCodecService &GetInstance(); +private: + AVCodecServiceFactory() = delete; + ~AVCodecServiceFactory() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // I_AVCODEC_SERVICE_H diff --git a/services/include/i_codec_service.h b/services/include/i_codec_service.h new file mode 100644 index 0000000000000000000000000000000000000000..acb3fc7529bf4d3157235947f44607ee1fe9ec29 --- /dev/null +++ b/services/include/i_codec_service.h @@ -0,0 +1,52 @@ +/* + * 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_CODEC_SERVICE_H +#define I_CODEC_SERVICE_H + +#include +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "refbase.h" +#include "surface.h" + +namespace OHOS { +namespace Media { +class ICodecService { +public: + virtual ~ICodecService() = default; + + virtual int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) = 0; + virtual int32_t Configure(const Format &format) = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t NotifyEos() = 0; + virtual sptr CreateInputSurface() = 0; + virtual int32_t SetOutputSurface(sptr surface) = 0; + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + virtual int32_t GetOutputFormat(Format &format) = 0; + virtual int32_t ReleaseOutputBuffer(uint32_t index, bool render = false) = 0; + virtual int32_t SetParameter(const Format &format) = 0; + virtual int32_t SetCallback(const std::shared_ptr &callback) = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // I_CODEC_SERVICE_H \ No newline at end of file diff --git a/services/include/i_codeclist_service.h b/services/include/i_codeclist_service.h new file mode 100644 index 0000000000000000000000000000000000000000..b1d01d7c839049d9efb2887353cfc3660996a468 --- /dev/null +++ b/services/include/i_codeclist_service.h @@ -0,0 +1,32 @@ +/* + * 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_CODECLIST_SERVICE_H +#define I_CODECLIST_SERVICE_H + +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class ICodecListService { +public: + virtual ~ICodecListService() = default; + virtual std::string FindDecoder(const Format &format) = 0; + virtual std::string FindEncoder(const Format &format) = 0; + virtual CapabilityData CreateCapability(const std::string codecName) = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // I_CODECLIST_SERVICE_H \ No newline at end of file diff --git a/services/include/i_demuxer_service.h b/services/include/i_demuxer_service.h new file mode 100644 index 0000000000000000000000000000000000000000..77103d6da058af62bb9c7fd64e6bcec853770721 --- /dev/null +++ b/services/include/i_demuxer_service.h @@ -0,0 +1,37 @@ +/* + * 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_DEMUXER_SERVICE_H +#define I_DEMUXER_SERVICE_H + +#include +#include +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class IDemuxerService { +public: + virtual ~IDemuxerService() = default; + + virtual int32_t Init(uintptr_t sourceAddr) = 0; + virtual int32_t SelectSourceTrackByID(uint32_t index) = 0; + virtual int32_t UnselectSourceTrackByID(uint32_t index) = 0; + virtual int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) = 0; + virtual int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // I_DEMUXER_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 0000000000000000000000000000000000000000..ec1efd54bc1b5a86ad01980e12964ada038fe42a --- /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/include/i_source_service.h b/services/include/i_source_service.h new file mode 100644 index 0000000000000000000000000000000000000000..7ae1ae01c97c0484f36f40fcee891bc68e7283a0 --- /dev/null +++ b/services/include/i_source_service.h @@ -0,0 +1,39 @@ +/* + * 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_SOURCE_SERVICE_H +#define I_SOURCE_SERVICE_H + +#include +#include +#include "format.h" + +namespace OHOS { +namespace Media { +class ISourceService { +public: + virtual ~ISourceService() = default; + + // 业务 + virtual int32_t Init(const std::string &uri) = 0; + virtual int32_t GetTrackCount(uint32_t &trackCount) = 0; + virtual int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetTrackFormat(Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetSourceFormat(Format &format) = 0; + virtual uint64_t GetSourceAddr() = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // I_SOURCE_SERVICE_H diff --git a/services/services/BUILD.gn b/services/services/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5194a19582bbd51e1e2b7b5bbf9cedea491e8e1f --- /dev/null +++ b/services/services/BUILD.gn @@ -0,0 +1,209 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +config("av_codec_service_config") { + visibility = [ ":*" ] + + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/engine/codec/include/audio", + "$av_codec_root_dir/services/engine/codec/include/video", + "$av_codec_root_dir/services/engine/codeclist", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/demuxer/include", + "$av_codec_root_dir/services/engine/factory", + "$av_codec_root_dir/services/engine/muxer", + "$av_codec_root_dir/services/engine/plugin/common", + "$av_codec_root_dir/services/engine/plugin/core", + "$av_codec_root_dir/services/engine/plugin/interface", + "$av_codec_root_dir/services/engine/source", + "$av_codec_root_dir/services/engine/source/hst_releated", + "$av_codec_root_dir/services/engine/source/include", + "$av_codec_root_dir/services/include", + "$av_codec_root_dir/services/services/codec/ipc", + "$av_codec_root_dir/services/services/codec/server", + "$av_codec_root_dir/services/services/codeclist/ipc", + "$av_codec_root_dir/services/services/codeclist/server", + "$av_codec_root_dir/services/services/common", + "$av_codec_root_dir/services/services/demuxer/ipc", + "$av_codec_root_dir/services/services/demuxer/server", + "$av_codec_root_dir/services/services/factory", + "$av_codec_root_dir/services/services/muxer/ipc", + "$av_codec_root_dir/services/services/muxer/server", + "$av_codec_root_dir/services/services/sa_avcodec/ipc", + "$av_codec_root_dir/services/services/sa_avcodec/server/include", + "$av_codec_root_dir/services/services/source/ipc", + "$av_codec_root_dir/services/services/source/server", + "$av_codec_root_dir/services/utils/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api", + "//third_party/ffmpeg", + ] + + 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 = [] + defines += av_codec_defines + defines += [ + "AV_CODEC_PLUGIN_PATH=${av_codec_plugin_path}", + "AV_CODEC_PLUGIN_FILE_TAIL=\".z.so\"", + "OH_FILE_PLUGIN_PATH=\".\"", + ] + + 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") { + install_enable = true + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = true + } + + configs = [ + ":av_codec_service_config", + "$av_codec_root_dir/services/dfx:av_codec_service_log_dfx_public_config", + ] + + sources = [ + "$av_codec_root_dir/frameworks/native/common/avcodec_errors.cpp", + "$av_codec_root_dir/services/engine/muxer/muxer_engine_impl.cpp", + "$av_codec_root_dir/services/engine/plugin/core/muxer.cpp", + "$av_codec_root_dir/services/engine/plugin/core/muxer_factory.cpp", + "$av_codec_root_dir/services/engine/plugin/core/plugin_loader.cpp", + "common/avsharedmemory_ipc.cpp", + "sa_avcodec/ipc/avcodec_listener_proxy.cpp", + "sa_avcodec/ipc/avcodec_parcel.cpp", + "sa_avcodec/ipc/avcodec_service_stub.cpp", + "sa_avcodec/server/avcodec_server.cpp", + "sa_avcodec/server/avcodec_server_manager.cpp", + ] + + if (multimedia_av_codec_support_codec) { + sources += [ + "codec/ipc/codec_listener_proxy.cpp", + "codec/ipc/codec_service_stub.cpp", + "codec/server/codec_factory.cpp", + "codec/server/codec_server.cpp", + ] + } + if (multimedia_av_codec_support_codeclist) { + sources += [ + "codeclist/ipc/codeclist_service_stub.cpp", + "codeclist/server/codeclist_server.cpp", + "sa_avcodec/ipc/codeclist_parcel.cpp", + ] + } + if (multimedia_av_codec_support_muxer) { + sources += [ + "muxer/ipc/muxer_service_stub.cpp", + "muxer/server/muxer_server.cpp", + ] + } + if (multimedia_av_codec_support_demuxer) { + sources += [ + "$av_codec_root_dir/services/engine/demuxer/demuxer_engine_impl.cpp", + "$av_codec_root_dir/services/engine/factory/demuxer_factory.cpp", + "$av_codec_root_dir/services/engine/plugin/core/demuxer.cpp", + "demuxer/ipc/demuxer_service_stub.cpp", + "demuxer/server/demuxer_server.cpp", + + # "$av_codec_root_dir/services/engine/plugin/core/plugin_loader.cpp", + ] + } + if (multimedia_av_codec_support_source) { + sources += [ + "$av_codec_root_dir/services/engine/source/hst_releated/media_source.cpp", + "$av_codec_root_dir/services/engine/source/hst_releated/plugin_buffer.cpp", + "$av_codec_root_dir/services/engine/source/source.cpp", + "$av_codec_root_dir/services/engine/source/source_engine_impl.cpp", + "source/ipc/source_service_stub.cpp", + "source/server/source_server.cpp", + ] + } + + deps = [ + "$av_codec_root_dir/services/dfx:av_codec_service_dfx", + "$av_codec_root_dir/services/engine:av_codec_engine_package", + "$av_codec_root_dir/services/engine/base:av_codec_codec_base", + "$av_codec_root_dir/services/engine/codec/audio:av_codec_audio_ffmpeg_codec", + "$av_codec_root_dir/services/engine/codec/video:av_codec_video_ffmpeg_codec", + "$av_codec_root_dir/services/utils:av_codec_format", + "$av_codec_root_dir/services/utils:av_codec_service_utils", + "//third_party/ffmpeg:libohosffmpeg", + ] + + if (multimedia_av_codec_support_codeclist) { + deps += [ + "$av_codec_root_dir/services/engine/codeclist:av_codec_engine_codeclist", + ] + } + + external_deps = [ + "c_utils:utils", + "graphic_standard:surface", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_single", + "safwk:system_ability_fwk", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/services/codec/client/codec_client.cpp b/services/services/codec/client/codec_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80f3830b25bcbb59eee0648fa1b9ab3e9c95cb93 --- /dev/null +++ b/services/services/codec/client/codec_client.cpp @@ -0,0 +1,242 @@ +/* + * 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 "codec_client.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecClient"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr CodecClient::Create(const sptr &ipcProxy) +{ + CHECK_AND_RETURN_RET_LOG(ipcProxy != nullptr, nullptr, "Ipc proxy is nullptr."); + + std::shared_ptr codec = std::make_shared(ipcProxy); + + int32_t ret = codec->CreateListenerObject(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Codec client create failed"); + + return codec; +} + +CodecClient::CodecClient(const sptr &ipcProxy) + : codecProxy_(ipcProxy) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecClient::~CodecClient() +{ + std::lock_guard lock(mutex_); + + if (codecProxy_ != nullptr) { + (void)codecProxy_->DestroyStub(); + } else { + AVCODEC_LOGD("Codec proxy is nullptr"); + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecClient::AVCodecServerDied() +{ + std::lock_guard lock(mutex_); + codecProxy_ = nullptr; + listenerStub_ = nullptr; + + if (callback_ != nullptr) { + callback_->OnError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_SERVICE_DIED); + } else { + AVCODEC_LOGD("Callback is callback"); + } +} + +int32_t CodecClient::CreateListenerObject() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + listenerStub_ = new(std::nothrow) CodecListenerStub(); + CHECK_AND_RETURN_RET_LOG(listenerStub_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec listener stub create failed"); + + sptr object = listenerStub_->AsObject(); + CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_NO_MEMORY, "Listener object is nullptr."); + + AVCODEC_LOGD("SetListenerObject"); + return codecProxy_->SetListenerObject(object); +} + +int32_t CodecClient::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Init"); + return codecProxy_->Init(type, isMimeType, name); +} + +int32_t CodecClient::Configure(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Configure"); + return codecProxy_->Configure(format); +} + +int32_t CodecClient::Start() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Start"); + return codecProxy_->Start(); +} + +int32_t CodecClient::Stop() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Stop"); + return codecProxy_->Stop(); +} + +int32_t CodecClient::Flush() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Flush"); + return codecProxy_->Flush(); +} + +int32_t CodecClient::NotifyEos() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("NotifyEos"); + return codecProxy_->NotifyEos(); +} + +int32_t CodecClient::Reset() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Reset"); + return codecProxy_->Reset(); +} + +int32_t CodecClient::Release() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("Release"); + int32_t ret = codecProxy_->Release(); + (void)codecProxy_->DestroyStub(); + codecProxy_ = nullptr; + return ret; +} + +sptr CodecClient::CreateInputSurface() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, nullptr, "Codec service does not exist."); + + AVCODEC_LOGD("CreateInputSurface"); + return codecProxy_->CreateInputSurface(); +} + +int32_t CodecClient::SetOutputSurface(sptr surface) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("SetOutputSurface"); + return codecProxy_->SetOutputSurface(surface); +} + +std::shared_ptr CodecClient::GetInputBuffer(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, nullptr, "Codec service does not exist."); + + AVCODEC_LOGD("GetInputBuffer"); + return codecProxy_->GetInputBuffer(index); +} + +int32_t CodecClient::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("QueueInputBuffer"); + return codecProxy_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr CodecClient::GetOutputBuffer(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, nullptr, "Codec service does not exist."); + + AVCODEC_LOGD("GetOutputBuffer"); + return codecProxy_->GetOutputBuffer(index); +} + +int32_t CodecClient::GetOutputFormat(Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("GetOutputFormat"); + return codecProxy_->GetOutputFormat(format); +} + +int32_t CodecClient::ReleaseOutputBuffer(uint32_t index, bool render) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("ReleaseOutputBuffer"); + return codecProxy_->ReleaseOutputBuffer(index, render); +} + +int32_t CodecClient::SetParameter(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec service does not exist."); + + AVCODEC_LOGD("SetParameter"); + return codecProxy_->SetParameter(format); +} + +int32_t CodecClient::SetCallback(const std::shared_ptr &callback) +{ + CHECK_AND_RETURN_RET_LOG(callback != nullptr, AVCS_ERR_NO_MEMORY, "Callback is nullptr."); + CHECK_AND_RETURN_RET_LOG(listenerStub_ != nullptr, AVCS_ERR_NO_MEMORY, "Listener stub is nullptr."); + + callback_ = callback; + AVCODEC_LOGD("SetCallback"); + listenerStub_->SetCallback(callback); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/client/codec_client.h b/services/services/codec/client/codec_client.h new file mode 100644 index 0000000000000000000000000000000000000000..e0a8b78d782b4e8e278e6fe89c7bdaeb4a13fcb9 --- /dev/null +++ b/services/services/codec/client/codec_client.h @@ -0,0 +1,61 @@ +/* + * 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 CODEC_CLIENT_H +#define CODEC_CLIENT_H + +#include "i_codec_service.h" +#include "i_standard_codec_service.h" +#include "codec_listener_stub.h" + +namespace OHOS { +namespace Media { +class CodecClient : public ICodecService { +public: + static std::shared_ptr Create(const sptr &ipcProxy); + explicit CodecClient(const sptr &ipcProxy); + ~CodecClient(); + // 业务 + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) override; + int32_t Configure(const Format &format) override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + sptr CreateInputSurface() override; + int32_t SetOutputSurface(sptr surface) override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index, bool render) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + + void AVCodecServerDied(); + +private: + int32_t CreateListenerObject(); + + sptr codecProxy_ = nullptr; + sptr listenerStub_ = nullptr; + std::shared_ptr callback_ = nullptr; + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_CLIENT_H diff --git a/services/services/codec/ipc/codec_listener_proxy.cpp b/services/services/codec/ipc/codec_listener_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5b91e354a2ac6b3f4ed4b72b888693a494fa341 --- /dev/null +++ b/services/services/codec/ipc/codec_listener_proxy.cpp @@ -0,0 +1,134 @@ +/* + * 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 "codec_listener_proxy.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_parcel.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListenerProxy"}; +} + +namespace OHOS { +namespace Media { +CodecListenerProxy::CodecListenerProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListenerProxy::~CodecListenerProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecListenerProxy::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor()); + CHECK_AND_RETURN_LOG(token, "Write descriptor failed!"); + + data.WriteInt32(static_cast(errorType)); + data.WriteInt32(errorCode); + int error = Remote()->SendRequest(CodecListenerMsg::ON_ERROR, data, reply, option); + CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed"); +} + +void CodecListenerProxy::OnOutputFormatChanged(const Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor()); + CHECK_AND_RETURN_LOG(token, "Write descriptor failed!"); + + (void)AVCodecParcel::Marshalling(data, format); + int error = Remote()->SendRequest(CodecListenerMsg::ON_OUTPUT_FORMAT_CHANGED, data, reply, option); + CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed"); +} + +void CodecListenerProxy::OnInputBufferAvailable(uint32_t index) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor()); + CHECK_AND_RETURN_LOG(token, "Write descriptor failed!"); + + data.WriteUint32(index); + int error = Remote()->SendRequest(CodecListenerMsg::ON_INPUT_BUFFER_AVAILABLE, data, reply, option); + CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed"); +} + +void CodecListenerProxy::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + bool token = data.WriteInterfaceToken(CodecListenerProxy::GetDescriptor()); + CHECK_AND_RETURN_LOG(token, "Write descriptor failed!"); + + data.WriteUint32(index); + data.WriteInt64(info.presentationTimeUs); + data.WriteInt32(info.size); + data.WriteInt32(info.offset); + data.WriteInt32(static_cast(flag)); + int error = Remote()->SendRequest(CodecListenerMsg::ON_OUTPUT_BUFFER_AVAILABLE, data, reply, option); + CHECK_AND_RETURN_LOG(error == AVCS_ERR_OK, "Send request failed"); +} + +CodecListenerCallback::CodecListenerCallback(const sptr &listener) + : listener_(listener) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListenerCallback::~CodecListenerCallback() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecListenerCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + if (listener_ != nullptr) { + listener_->OnError(errorType, errorCode); + } +} + +void CodecListenerCallback::OnOutputFormatChanged(const Format &format) +{ + if (listener_ != nullptr) { + listener_->OnOutputFormatChanged(format); + } +} + +void CodecListenerCallback::OnInputBufferAvailable(uint32_t index) +{ + if (listener_ != nullptr) { + listener_->OnInputBufferAvailable(index); + } +} + +void CodecListenerCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + if (listener_ != nullptr) { + listener_->OnOutputBufferAvailable(index, info, flag); + } +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/ipc/codec_listener_proxy.h b/services/services/codec/ipc/codec_listener_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..dfba694e0a55a868b97f7283ac7816b214563758 --- /dev/null +++ b/services/services/codec/ipc/codec_listener_proxy.h @@ -0,0 +1,54 @@ +/* + * 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 CODEC_LISTENER_PROXY_H +#define CODEC_LISTENER_PROXY_H + +#include "i_standard_codec_listener.h" +#include "avcodec_death_recipient.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class CodecListenerCallback : public AVCodecCallback, public NoCopyable { +public: + explicit CodecListenerCallback(const sptr &listener); + virtual ~CodecListenerCallback(); + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + sptr listener_ = nullptr; +}; + +class CodecListenerProxy : public IRemoteProxy, public NoCopyable { +public: + explicit CodecListenerProxy(const sptr &impl); + virtual ~CodecListenerProxy(); + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_LISTENER_PROXY_H diff --git a/services/services/codec/ipc/codec_listener_stub.cpp b/services/services/codec/ipc/codec_listener_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..167b2dc9879e34677fadee3d87521cdf55ec5720 --- /dev/null +++ b/services/services/codec/ipc/codec_listener_stub.cpp @@ -0,0 +1,114 @@ +/* + * 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 "codec_listener_stub.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_parcel.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListenerStub"}; +} + +namespace OHOS { +namespace Media { +CodecListenerStub::CodecListenerStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListenerStub::~CodecListenerStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int CodecListenerStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + auto remoteDescriptor = data.ReadInterfaceToken(); + if (CodecListenerStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + switch (code) { + case CodecListenerMsg::ON_ERROR: { + int32_t errorType = data.ReadInt32(); + int32_t errorCode = data.ReadInt32(); + OnError(static_cast(errorType), errorCode); + return AVCS_ERR_OK; + } + case CodecListenerMsg::ON_OUTPUT_FORMAT_CHANGED: { + Format format; + (void)AVCodecParcel::Unmarshalling(data, format); + OnOutputFormatChanged(format); + return AVCS_ERR_OK; + } + case CodecListenerMsg::ON_INPUT_BUFFER_AVAILABLE: { + uint32_t index = data.ReadUint32(); + OnInputBufferAvailable(index); + return AVCS_ERR_OK; + } + case CodecListenerMsg::ON_OUTPUT_BUFFER_AVAILABLE: { + uint32_t index = data.ReadUint32(); + AVCodecBufferInfo info; + info.presentationTimeUs = data.ReadInt64(); + info.size = data.ReadInt32(); + info.offset = data.ReadInt32(); + AVCodecBufferFlag flag = static_cast(data.ReadInt32()); + OnOutputBufferAvailable(index, info, flag); + return AVCS_ERR_OK; + } + default: { + AVCODEC_LOGE("Default case, please check codec listener stub"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } +} + +void CodecListenerStub::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + if (callback_ != nullptr) { + callback_->OnError(errorType, errorCode); + } +} + +void CodecListenerStub::OnOutputFormatChanged(const Format &format) +{ + if (callback_ != nullptr) { + callback_->OnOutputFormatChanged(format); + } +} + +void CodecListenerStub::OnInputBufferAvailable(uint32_t index) +{ + if (callback_ != nullptr) { + callback_->OnInputBufferAvailable(index); + } +} + +void CodecListenerStub::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + if (callback_ != nullptr) { + callback_->OnOutputBufferAvailable(index, info, flag); + } +} + +void CodecListenerStub::SetCallback(const std::shared_ptr &callback) +{ + callback_ = callback; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/ipc/codec_listener_stub.h b/services/services/codec/ipc/codec_listener_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..0cc12f1bb2e9e9b66addec67bf1aa13d63b25954 --- /dev/null +++ b/services/services/codec/ipc/codec_listener_stub.h @@ -0,0 +1,40 @@ +/* + * 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 CODEC_LISTENER_STUB_H +#define CODEC_LISTENER_STUB_H + +#include "i_standard_codec_listener.h" +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class CodecListenerStub : public IRemoteStub { +public: + CodecListenerStub(); + virtual ~CodecListenerStub(); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + void SetCallback(const std::shared_ptr &callback); + +private: + std::shared_ptr callback_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_LISTENER_STUB_H diff --git a/services/services/codec/ipc/codec_service_proxy.cpp b/services/services/codec/ipc/codec_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73627d084abc65d5701a5fee76ab54604e47e96f --- /dev/null +++ b/services/services/codec/ipc/codec_service_proxy.cpp @@ -0,0 +1,444 @@ +/* + * 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 "codec_service_proxy.h" +#include "codec_listener_stub.h" +#include "avsharedmemory_ipc.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_parcel.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecServiceProxy"}; +} + +namespace OHOS { +namespace Media { +class CodecServiceProxy::CodecBufferCache : public NoCopyable { +public: + CodecBufferCache() = default; + ~CodecBufferCache() = default; + + int32_t ReadFromParcel(uint32_t index, MessageParcel &parcel, std::shared_ptr &memory) + { + auto iter = caches_.find(index); + CacheFlag flag = static_cast(parcel.ReadUint8()); + if (flag == CacheFlag::HIT_CACHE) { + if (iter == caches_.end()) { + AVCODEC_LOGE("Mark hit cache, but can find the index's cache, index: %{public}u", index); + return AVCS_ERR_INVALID_VAL; + } + memory = iter->second; + return AVCS_ERR_OK; + } + + if (flag == CacheFlag::UPDATE_CACHE) { + memory = ReadAVSharedMemoryFromParcel(parcel); + CHECK_AND_RETURN_RET_LOG(memory != nullptr, AVCS_ERR_INVALID_VAL, "Read memory from parcel failed"); + + if (iter == caches_.end()) { + AVCODEC_LOGI("Add cache, index: %{public}u", index); + caches_.emplace(index, memory); + } else { + iter->second = memory; + AVCODEC_LOGI("Update cache, index: %{public}u", index); + } + return AVCS_ERR_OK; + } + + // invalidate cache flag + if (iter != caches_.end()) { + iter->second = nullptr; + caches_.erase(iter); + } + memory = nullptr; + AVCODEC_LOGE("Invalidate cache for index: %{public}u, flag: %{public}hhu", index, flag); + return AVCS_ERR_INVALID_VAL; + } + +private: + enum CacheFlag : uint8_t { + HIT_CACHE = 1, + UPDATE_CACHE, + INVALIDATE_CACHE, + }; + + std::unordered_map> caches_; +}; + +CodecServiceProxy::CodecServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecServiceProxy::~CodecServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t CodecServiceProxy::SetListenerObject(const sptr &object) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + (void)data.WriteRemoteObject(object); + int32_t ret = Remote()->SendRequest(SET_LISTENER_OBJ, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + data.WriteInt32(static_cast(type)); + data.WriteBool(isMimeType); + data.WriteString(name); + int32_t ret = Remote()->SendRequest(INIT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Configure(const Format &format) +{ + if (inputBufferCache_ == nullptr) { + inputBufferCache_ = std::make_unique(); + } + + if (outputBufferCache_ == nullptr) { + outputBufferCache_ = std::make_unique(); + } + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + (void)AVCodecParcel::Marshalling(data, format); + int32_t ret = Remote()->SendRequest(CONFIGURE, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Start() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::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, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Stop() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::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, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Flush() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(FLUSH, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::NotifyEos() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(NOTIFY_EOS, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Reset() +{ + inputBufferCache_ = nullptr; + outputBufferCache_ = nullptr; + + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(RESET, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::Release() +{ + inputBufferCache_ = nullptr; + outputBufferCache_ = nullptr; + + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(RELEASE, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +sptr CodecServiceProxy::CreateInputSurface() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, nullptr, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(CREATE_INPUT_SURFACE, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, + "Send request failed"); + + sptr object = reply.ReadRemoteObject(); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "Read surface object failed"); + + sptr producer = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(producer != nullptr, nullptr, "Convert object to producer failed"); + + return OHOS::Surface::CreateSurfaceAsProducer(producer); +} + +int32_t CodecServiceProxy::SetOutputSurface(sptr surface) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + CHECK_AND_RETURN_RET_LOG(surface != nullptr, AVCS_ERR_NO_MEMORY, "Surface is nullptr"); + sptr producer = surface->GetProducer(); + CHECK_AND_RETURN_RET_LOG(producer != nullptr, AVCS_ERR_NO_MEMORY, "Producer is nullptr"); + + sptr object = producer->AsObject(); + CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_NO_MEMORY, "Object is nullptr"); + + const std::string surfaceFormat = "SURFACE_FORMAT"; + std::string format = surface->GetUserData(surfaceFormat); + AVCODEC_LOGI("Surface format is %{public}s!", format.c_str()); + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + (void)data.WriteRemoteObject(object); + data.WriteString(format); + int32_t ret = Remote()->SendRequest(SET_OUTPUT_SURFACE, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +std::shared_ptr CodecServiceProxy::GetInputBuffer(uint32_t index) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, nullptr, "Write descriptor failed!"); + + data.WriteUint32(index); + int32_t ret = Remote()->SendRequest(GET_INPUT_BUFFER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, + "Send request failed"); + + std::shared_ptr memory = nullptr; + if (inputBufferCache_ != nullptr) { + ret = inputBufferCache_->ReadFromParcel(index, reply, memory); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Read from parcel failed"); + } + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "Get input buffer failed"); + return memory; +} + +int32_t CodecServiceProxy::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + data.WriteUint32(index); + data.WriteInt64(info.presentationTimeUs); + data.WriteInt32(info.size); + data.WriteInt32(info.offset); + data.WriteInt32(static_cast(flag)); + int32_t ret = Remote()->SendRequest(QUEUE_INPUT_BUFFER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +std::shared_ptr CodecServiceProxy::GetOutputBuffer(uint32_t index) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, nullptr, "Write descriptor failed!"); + + data.WriteUint32(index); + int32_t ret = Remote()->SendRequest(GET_OUTPUT_BUFFER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, + "Send request failed"); + + std::shared_ptr memory = nullptr; + if (outputBufferCache_ != nullptr) { + ret = outputBufferCache_->ReadFromParcel(index, reply, memory); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Read from parcel failed"); + } + CHECK_AND_RETURN_RET_LOG(memory != nullptr, nullptr, "Get output buffer failed"); + return memory; +} + +int32_t CodecServiceProxy::GetOutputFormat(Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(GET_OUTPUT_FORMAT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + (void)AVCodecParcel::Unmarshalling(reply, format); + return AVCS_ERR_OK; +} + +int32_t CodecServiceProxy::ReleaseOutputBuffer(uint32_t index, bool render) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + data.WriteUint32(index); + data.WriteBool(render); + int32_t ret = Remote()->SendRequest(RELEASE_OUTPUT_BUFFER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + +int32_t CodecServiceProxy::SetParameter(const Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + (void)AVCodecParcel::Marshalling(data, format); + int32_t ret = Remote()->SendRequest(SET_PARAMETER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} + + +int32_t CodecServiceProxy::DestroyStub() +{ + inputBufferCache_ = nullptr; + outputBufferCache_ = nullptr; + + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Write descriptor failed!"); + + int32_t ret = Remote()->SendRequest(DESTROY_STUB, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, + "Send request failed"); + + return reply.ReadInt32(); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/ipc/codec_service_proxy.h b/services/services/codec/ipc/codec_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..ed6cf6a50ee4e25cfe44cfe94b4e7fdbd62ca4d6 --- /dev/null +++ b/services/services/codec/ipc/codec_service_proxy.h @@ -0,0 +1,60 @@ +/* + * 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 CODEC_SERVICE_PROXY_H +#define CODEC_SERVICE_PROXY_H + +#include "i_standard_codec_service.h" +#include "nocopyable.h" + + +namespace OHOS { +namespace Media { +class CodecServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit CodecServiceProxy(const sptr &impl); + virtual ~CodecServiceProxy(); + + int32_t SetListenerObject(const sptr &object) override; + + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) override; + int32_t Configure(const Format &format) override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + sptr CreateInputSurface() override; + int32_t SetOutputSurface(sptr surface) override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index, bool render) override; + int32_t SetParameter(const Format &format) override; + + int32_t DestroyStub() override; + +private: + static inline BrokerDelegator delegator_; + + class CodecBufferCache; + std::unique_ptr inputBufferCache_; + std::unique_ptr outputBufferCache_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_SERVICE_PROXY_H diff --git a/services/services/codec/ipc/codec_service_stub.cpp b/services/services/codec/ipc/codec_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d09c196441d0f2ef1bffa3432530c096caded3ab --- /dev/null +++ b/services/services/codec/ipc/codec_service_stub.cpp @@ -0,0 +1,515 @@ +/* + * 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 "codec_service_stub.h" +#include +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_parcel.h" +#include "avcodec_server_manager.h" +#include "avsharedmemory_ipc.h" +#include "codec_listener_proxy.h" +#include "avcodec_xcollie.h" +#include "avcodec_dfx.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecServiceStub"}; +} + +namespace OHOS { +namespace Media { +class CodecServiceStub::CodecBufferCache : public NoCopyable { +public: + CodecBufferCache() = default; + ~CodecBufferCache() = default; + + int32_t WriteToParcel(uint32_t index, const std::shared_ptr &memory, MessageParcel &parcel) + { + CacheFlag flag = CacheFlag::UPDATE_CACHE; + + if (memory == nullptr || memory->GetBase() == nullptr) { + AVCODEC_LOGE("Invalid memory for index: %{public}u", index); + flag = CacheFlag::INVALIDATE_CACHE; + parcel.WriteUint8(flag); + auto iter = caches_.find(index); + if (iter != caches_.end()) { + iter->second = nullptr; + caches_.erase(iter); + } + return AVCS_ERR_OK; + } + + auto iter = caches_.find(index); + if (iter != caches_.end() && iter->second == memory.get()) { + flag = CacheFlag::HIT_CACHE; + parcel.WriteUint8(flag); + return AVCS_ERR_OK; + } + + if (iter == caches_.end()) { + AVCODEC_LOGI("Add cached codec buffer, index: %{public}u", index); + caches_.emplace(index, memory.get()); + } else { + AVCODEC_LOGI("Update cached codec buffer, index: %{public}u", index); + iter->second = memory.get(); + } + + parcel.WriteUint8(flag); + + return WriteAVSharedMemoryToParcel(memory, parcel); + } + +private: + enum CacheFlag : uint8_t { + HIT_CACHE = 1, + UPDATE_CACHE, + INVALIDATE_CACHE, + }; + + std::unordered_map caches_; +}; + +sptr CodecServiceStub::Create() +{ + sptr codecStub = new(std::nothrow) CodecServiceStub(); + CHECK_AND_RETURN_RET_LOG(codecStub != nullptr, nullptr, "Codec service stub create failed"); + + int32_t ret = codecStub->InitStub(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Codec stub init failed"); + return codecStub; +} + +CodecServiceStub::CodecServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecServiceStub::~CodecServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t CodecServiceStub::InitStub() +{ + AVCODEC_SYNC_TRACE; + + codecServer_ = CodecServer::Create(); + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server create failed"); + + recFuncs_[SET_LISTENER_OBJ] = &CodecServiceStub::SetListenerObject; + + recFuncs_[INIT] = &CodecServiceStub::Init; + recFuncs_[CONFIGURE] = &CodecServiceStub::Configure; + recFuncs_[START] = &CodecServiceStub::Start; + recFuncs_[STOP] = &CodecServiceStub::Stop; + recFuncs_[FLUSH] = &CodecServiceStub::Flush; + recFuncs_[RESET] = &CodecServiceStub::Reset; + recFuncs_[RELEASE] = &CodecServiceStub::Release; + recFuncs_[NOTIFY_EOS] = &CodecServiceStub::NotifyEos; + recFuncs_[CREATE_INPUT_SURFACE] = &CodecServiceStub::CreateInputSurface; + recFuncs_[SET_OUTPUT_SURFACE] = &CodecServiceStub::SetOutputSurface; + recFuncs_[GET_INPUT_BUFFER] = &CodecServiceStub::GetInputBuffer; + recFuncs_[QUEUE_INPUT_BUFFER] = &CodecServiceStub::QueueInputBuffer; + recFuncs_[GET_OUTPUT_BUFFER] = &CodecServiceStub::GetOutputBuffer; + recFuncs_[RELEASE_OUTPUT_BUFFER] = &CodecServiceStub::ReleaseOutputBuffer; + recFuncs_[GET_OUTPUT_FORMAT] = &CodecServiceStub::GetOutputFormat; + recFuncs_[SET_PARAMETER] = &CodecServiceStub::SetParameter; + + recFuncs_[DESTROY_STUB] = &CodecServiceStub::DestroyStub; + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::DestroyStub() +{ + codecServer_ = nullptr; + outputBufferCache_ = nullptr; + inputBufferCache_ = nullptr; + + AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::CODEC, AsObject()); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::DumpInfo(int32_t fd) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return std::static_pointer_cast(codecServer_)->DumpInfo(fd); +} + +int CodecServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + auto remoteDescriptor = data.ReadInterfaceToken(); + if (CodecServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = recFuncs_.find(code); + if (itFunc != recFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = -1; + COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), + "CodecServiceStub::OnRemoteRequest"); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Calling member func failed."); + } + return AVCS_ERR_OK; + } + } + + AVCODEC_LOGW("No member func supporting, applying default process"); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +int32_t CodecServiceStub::SetListenerObject(const sptr &object) +{ + CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_NO_MEMORY, "Object is nullptr"); + + sptr listener = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(listener != nullptr, AVCS_ERR_NO_MEMORY, "Listener is nullptr"); + + std::shared_ptr callback = std::make_shared(listener); + + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + (void)codecServer_->SetCallback(callback); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->Init(type, isMimeType, name); +} + +int32_t CodecServiceStub::Configure(const Format &format) +{ + if (inputBufferCache_ == nullptr) { + inputBufferCache_ = std::make_unique(); + } + + if (outputBufferCache_ == nullptr) { + outputBufferCache_ = std::make_unique(); + } + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->Configure(format); +} + +int32_t CodecServiceStub::Start() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->Start(); +} + +int32_t CodecServiceStub::Stop() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->Stop(); +} + +int32_t CodecServiceStub::Flush() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->Flush(); +} + +int32_t CodecServiceStub::Reset() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + inputBufferCache_ = nullptr; + outputBufferCache_ = nullptr; + return codecServer_->Reset(); +} + +int32_t CodecServiceStub::Release() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + inputBufferCache_ = nullptr; + outputBufferCache_ = nullptr; + return codecServer_->Release(); +} + +int32_t CodecServiceStub::NotifyEos() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->NotifyEos(); +} + +sptr CodecServiceStub::CreateInputSurface() +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, nullptr, "Codec server is nullptr"); + return codecServer_->CreateInputSurface(); +} + +int32_t CodecServiceStub::SetOutputSurface(sptr surface) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->SetOutputSurface(surface); +} + +std::shared_ptr CodecServiceStub::GetInputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, nullptr, "Codec server is nullptr"); + return codecServer_->GetInputBuffer(index); +} + +int32_t CodecServiceStub::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->QueueInputBuffer(index, info, flag); +} + +std::shared_ptr CodecServiceStub::GetOutputBuffer(uint32_t index) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, nullptr, "Codec server is nullptr"); + return codecServer_->GetOutputBuffer(index); +} + +int32_t CodecServiceStub::GetOutputFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->GetOutputFormat(format); +} + +int32_t CodecServiceStub::ReleaseOutputBuffer(uint32_t index, bool render) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->ReleaseOutputBuffer(index, render); +} + +int32_t CodecServiceStub::SetParameter(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Codec server is nullptr"); + return codecServer_->SetParameter(format); +} + +int32_t CodecServiceStub::DestroyStub(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(DestroyStub()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::SetListenerObject(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + sptr object = data.ReadRemoteObject(); + + bool ret = reply.WriteInt32(SetListenerObject(object)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Init(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + AVCodecType type = static_cast(data.ReadInt32()); + bool isMimeType = data.ReadBool(); + std::string name = data.ReadString(); + + bool ret = reply.WriteInt32(Init(type, isMimeType, name)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Configure(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + Format format; + (void)AVCodecParcel::Unmarshalling(data, format); + + bool ret = reply.WriteInt32(Configure(format)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + + +int32_t CodecServiceStub::Start(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(Start()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Stop(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(Stop()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Flush(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(Flush()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Reset(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(Reset()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::Release(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(Release()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::NotifyEos(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + + bool ret = reply.WriteInt32(NotifyEos()); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::CreateInputSurface(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + (void)data; + sptr surface = CreateInputSurface(); + + if (surface != nullptr && surface->GetProducer() != nullptr) { + sptr object = surface->GetProducer()->AsObject(); + bool ret = reply.WriteRemoteObject(object); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + } + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::SetOutputSurface(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + + sptr object = data.ReadRemoteObject(); + CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_NO_MEMORY, "Object is nullptr"); + + sptr producer = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(producer != nullptr, AVCS_ERR_NO_MEMORY, "Producer is nullptr"); + + sptr surface = OHOS::Surface::CreateSurfaceAsProducer(producer); + CHECK_AND_RETURN_RET_LOG(surface != nullptr, AVCS_ERR_NO_MEMORY, "Surface create failed"); + + std::string format = data.ReadString(); + AVCODEC_LOGI("Surface format is %{public}s!", format.c_str()); + const std::string surfaceFormat = "SURFACE_FORMAT"; + (void)surface->SetUserData(surfaceFormat, format); + + bool ret = reply.WriteInt32(SetOutputSurface(surface)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::GetInputBuffer(MessageParcel &data, MessageParcel &reply) +{ + CHECK_AND_RETURN_RET_LOG(inputBufferCache_ != nullptr, AVCS_ERR_NO_MEMORY, "Input buffer cache is nullptr"); + AVCODEC_SYNC_TRACE; + + uint32_t index = data.ReadUint32(); + auto buffer = GetInputBuffer(index); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_NO_MEMORY, "Buffer is nullptr"); + + return inputBufferCache_->WriteToParcel(index, buffer, reply); +} + +int32_t CodecServiceStub::QueueInputBuffer(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + + uint32_t index = data.ReadUint32(); + AVCodecBufferInfo info; + info.presentationTimeUs = data.ReadInt64(); + info.size = data.ReadInt32(); + info.offset = data.ReadInt32(); + AVCodecBufferFlag flag = static_cast(data.ReadInt32()); + + bool ret = reply.WriteInt32(QueueInputBuffer(index, info, flag)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::GetOutputBuffer(MessageParcel &data, MessageParcel &reply) +{ + CHECK_AND_RETURN_RET_LOG(outputBufferCache_ != nullptr, AVCS_ERR_INVALID_OPERATION, + "Output buffer cache is nullptr"); + AVCODEC_SYNC_TRACE; + + uint32_t index = data.ReadUint32(); + auto buffer = GetOutputBuffer(index); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCS_ERR_NO_MEMORY, "Buffer is nullptr"); + + return outputBufferCache_->WriteToParcel(index, buffer, reply); +} + +int32_t CodecServiceStub::GetOutputFormat(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + + (void)data; + Format format; + (void)GetOutputFormat(format); + (void)AVCodecParcel::Marshalling(reply, format); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::ReleaseOutputBuffer(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + + uint32_t index = data.ReadUint32(); + bool render = data.ReadBool(); + + bool ret = reply.WriteInt32(ReleaseOutputBuffer(index, render)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} + +int32_t CodecServiceStub::SetParameter(MessageParcel &data, MessageParcel &reply) +{ + AVCODEC_SYNC_TRACE; + + Format format; + (void)AVCodecParcel::Unmarshalling(data, format); + + bool ret = reply.WriteInt32(SetParameter(format)); + CHECK_AND_RETURN_RET_LOG(ret == true, AVCS_ERR_INVALID_OPERATION, "Reply write failed"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/ipc/codec_service_stub.h b/services/services/codec/ipc/codec_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..5c9a42c6dcc54b5d0a054034ce49fa577593c452 --- /dev/null +++ b/services/services/codec/ipc/codec_service_stub.h @@ -0,0 +1,91 @@ +/* + * 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 CODEC_SERVICE_STUB_H +#define CODEC_SERVICE_STUB_H + +#include +#include "i_standard_codec_listener.h" +#include "i_standard_codec_service.h" +#include "codec_server.h" +#include "avcodec_death_recipient.h" +#include "nocopyable.h" + + +namespace OHOS { +namespace Media { +class CodecServiceStub : public IRemoteStub, public NoCopyable { +public: + static sptr Create(); + virtual ~CodecServiceStub(); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + using CodecStubFunc = int32_t(CodecServiceStub::*)(MessageParcel &data, MessageParcel &reply); + int32_t SetListenerObject(const sptr &object) override; + + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) override; + int32_t Configure(const Format &format) override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + sptr CreateInputSurface() override; + int32_t SetOutputSurface(sptr surface) override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index, bool render) override; + int32_t SetParameter(const Format &format) override; + + int32_t DestroyStub() override; + + int32_t DumpInfo(int32_t fd); + +private: + CodecServiceStub(); + int32_t InitStub(); + int32_t SetListenerObject(MessageParcel &data, MessageParcel &reply); + int32_t Init(MessageParcel &data, MessageParcel &reply); + int32_t Configure(MessageParcel &data, MessageParcel &reply); + int32_t Start(MessageParcel &data, MessageParcel &reply); + int32_t Stop(MessageParcel &data, MessageParcel &reply); + int32_t Flush(MessageParcel &data, MessageParcel &reply); + int32_t Reset(MessageParcel &data, MessageParcel &reply); + int32_t Release(MessageParcel &data, MessageParcel &reply); + int32_t NotifyEos(MessageParcel &data, MessageParcel &reply); + int32_t CreateInputSurface(MessageParcel &data, MessageParcel &reply); + int32_t SetOutputSurface(MessageParcel &data, MessageParcel &reply); + int32_t GetInputBuffer(MessageParcel &data, MessageParcel &reply); + int32_t QueueInputBuffer(MessageParcel &data, MessageParcel &reply); + int32_t GetOutputBuffer(MessageParcel &data, MessageParcel &reply); + int32_t GetOutputFormat(MessageParcel &data, MessageParcel &reply); + int32_t ReleaseOutputBuffer(MessageParcel &data, MessageParcel &reply); + int32_t SetParameter(MessageParcel &data, MessageParcel &reply); + int32_t DestroyStub(MessageParcel &data, MessageParcel &reply); + + std::shared_ptr codecServer_ = nullptr; + std::map recFuncs_; + std::mutex mutex_; + + class CodecBufferCache; + std::unique_ptr inputBufferCache_; + std::unique_ptr outputBufferCache_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_SERVICE_STUB_H diff --git a/services/services/codec/ipc/i_standard_codec_listener.h b/services/services/codec/ipc/i_standard_codec_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..a150794240dd01d3261af5e2418e4a67384c75bd --- /dev/null +++ b/services/services/codec/ipc/i_standard_codec_listener.h @@ -0,0 +1,49 @@ +/* + * 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_CODEC_LISTENER_H +#define I_STANDARD_CODEC_LISTENER_H + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class IStandardCodecListener : public IRemoteBroker { +public: + virtual ~IStandardCodecListener() = default; + virtual void OnError(AVCodecErrorType errorType, int32_t errorCode) = 0; + virtual void OnOutputFormatChanged(const Format &format) = 0; + virtual void OnInputBufferAvailable(uint32_t index) = 0; + virtual void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + + /** + * IPC code ID + */ + enum CodecListenerMsg { + ON_ERROR = 0, + ON_OUTPUT_FORMAT_CHANGED, + ON_INPUT_BUFFER_AVAILABLE, + ON_OUTPUT_BUFFER_AVAILABLE + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardCodecListener"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_CODEC_LISTENER_H diff --git a/services/services/codec/ipc/i_standard_codec_service.h b/services/services/codec/ipc/i_standard_codec_service.h new file mode 100644 index 0000000000000000000000000000000000000000..ba51661c2b62c86247c80e3425a5e11c6b844ba4 --- /dev/null +++ b/services/services/codec/ipc/i_standard_codec_service.h @@ -0,0 +1,87 @@ +/* + * 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_CODEC_SERVICE_H +#define I_STANDARD_CODEC_SERVICE_H + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "avcodec_common.h" +#include "avcodec_info.h" +#include "avsharedmemory.h" +#include "surface.h" + +namespace OHOS { +namespace Media { +class IStandardCodecService : public IRemoteBroker { +public: + virtual ~IStandardCodecService() = default; + + virtual int32_t SetListenerObject(const sptr &object) = 0; + + virtual int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) = 0; + virtual int32_t Configure(const Format &format) = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t NotifyEos() = 0; + virtual sptr CreateInputSurface() = 0; + virtual int32_t SetOutputSurface(sptr surface) = 0; + virtual std::shared_ptr GetInputBuffer(uint32_t index) = 0; + virtual int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) = 0; + virtual std::shared_ptr GetOutputBuffer(uint32_t index) = 0; + virtual int32_t GetOutputFormat(Format &format) = 0; + virtual int32_t ReleaseOutputBuffer(uint32_t index, bool render) = 0; + virtual int32_t SetParameter(const Format &format) = 0; + + virtual int32_t DestroyStub() = 0; + + /** + * IPC code ID + */ + enum CodecServiceMsg { + SET_LISTENER_OBJ = 0, + INIT, + CONFIGURE, + START, + STOP, + FLUSH, + RESET, + RELEASE, + NOTIFY_EOS, + CREATE_INPUT_SURFACE, + SET_OUTPUT_SURFACE, + GET_INPUT_BUFFER, + QUEUE_INPUT_BUFFER, + GET_OUTPUT_BUFFER, + GET_OUTPUT_FORMAT, + RELEASE_OUTPUT_BUFFER, + SET_PARAMETER, + SET_INPUT_SURFACE, + DEQUEUE_INPUT_BUFFER, + DEQUEUE_OUTPUT_BUFFER, + + DESTROY_STUB + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardCodecService"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_CODEC_SERVICE_H diff --git a/services/services/codec/server/codec_factory.cpp b/services/services/codec/server/codec_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df69b865f0e2b4c0be9653294c58cb1d92fd496c --- /dev/null +++ b/services/services/codec/server/codec_factory.cpp @@ -0,0 +1,74 @@ +/* + * 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 "codec_factory.h" +#include +#include +#include +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "audio_ffmpeg_adapter.h" +#include "fcodec.h" +#include "codeclist_core.h" +#include "format.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecFactory"}; +} + +namespace OHOS { +namespace Media { +const std::string VIDEOMIMETYPE = "video/avc"; +const std::string VIDEOCODECNAME = "video_decoder.avc"; + +CodecFactory &CodecFactory::Instance() +{ + static CodecFactory inst; + return inst; +} + +CodecFactory::~CodecFactory() +{ +} + +std::shared_ptr CodecFactory::CreateCodecByMime(bool isEncoder, const std::string &mime) +{ + std::shared_ptr codecListCore = std::make_shared(); + std::string codecname; + Format format; + format.PutStringValue("codec_mime", mime); + if (isEncoder) { + codecname = codecListCore->FindEncoder(format); + } else { + codecname = codecListCore->FindDecoder(format); + } + std::shared_ptr codec = CreateCodecByName(codecname); + AVCODEC_LOGD("CreateCodecByMime is successful"); + return codec; +} + +std::shared_ptr CodecFactory::CreateCodecByName(const std::string &name) +{ + std::shared_ptr codec = nullptr; + if (name == VIDEOCODECNAME) { + codec = std::make_shared(name); + } else { + codec = std::make_shared(name); + } + AVCODEC_LOGD("Create %{public}s", name.c_str()); + return codec; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codec/server/codec_factory.h b/services/services/codec/server/codec_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..a3e4e051c73d9466bc9af0b54fc344a78656ca81 --- /dev/null +++ b/services/services/codec/server/codec_factory.h @@ -0,0 +1,36 @@ +/* + * 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 CODEC_FACTORY_H +#define CODEC_FACTORY_H + +#include +#include "codecbase.h" + +namespace OHOS { +namespace Media { +class CodecFactory { +public: + static CodecFactory &Instance(); + std::shared_ptr CreateCodecByMime(bool isEncoder, const std::string &mime); + std::shared_ptr CreateCodecByName(const std::string &name); + +private: + CodecFactory() = default; + ~CodecFactory(); +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_FACTORY_H diff --git a/services/services/codec/server/codec_server.cpp b/services/services/codec/server/codec_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f231f560fb91c768e6ce426095acc84fe5d8a303 --- /dev/null +++ b/services/services/codec/server/codec_server.cpp @@ -0,0 +1,487 @@ +/* + * 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 "codec_server.h" +#include +#include +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "codec_factory.h" +#include "avcodec_dump_utils.h" +#include "media_description.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecServer"}; + constexpr uint32_t DUMP_CODEC_INFO_INDEX = 0x01010000; + constexpr uint32_t DUMP_STATUS_INDEX = 0x01010100; + constexpr uint32_t DUMP_LAST_ERROR_INDEX = 0x01010200; + constexpr uint32_t DUMP_OFFSET_8 = 8; + + const std::map CODEC_STATE_MAP = { + {OHOS::Media::CodecServer::UNINITIALIZED, "uninitialized"}, + {OHOS::Media::CodecServer::INITIALIZED, "initialized"}, + {OHOS::Media::CodecServer::CONFIGURED, "configured"}, + {OHOS::Media::CodecServer::RUNNING, "running"}, + {OHOS::Media::CodecServer::FLUSHED, "flushed"}, + {OHOS::Media::CodecServer::END_OF_STREAM, "end of stream"}, + {OHOS::Media::CodecServer::ERROR, "error"}, + }; + + const std::vector> DEFAULT_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_NAME, "Codec_Name" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_BITRATE, "Bit_Rate" }, + }; + + const std::vector> VIDEO_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_NAME, "Codec_Name" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_WIDTH, "Width" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_HEIGHT, "Height" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_FRAME_RATE, "Frame_Rate" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_BITRATE, "Bit_Rate" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, "Pixel_Format" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_SCALE_TYPE, "Scale_Type" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, "Rotation_Angle" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, "Max_Input_Size" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_MAX_INPUT_BUFFER_COUNT, "Max_Input_Buffer_Count" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_MAX_OUTPUT_BUFFER_COUNT, "Max_Output_Buffer_Count" }, + }; + + const std::vector> AUDIO_DUMP_TABLE = { + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_NAME, "Codec_Name" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, "Channel_Count" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_BITRATE, "Bit_Rate" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_SAMPLE_RATE, "Sample_Rate" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_CODEC_CONFIG, "Codec_Config" }, + { OHOS::Media::MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, "Max_Input_Size" }, + }; + + const std::map>> CODEC_DUMP_TABLE = { + { OHOS::Media::CodecServer::CodecType::CODEC_TYPE_DEFAULT, DEFAULT_DUMP_TABLE }, + { OHOS::Media::CodecServer::CodecType::CODEC_TYPE_VIDEO, VIDEO_DUMP_TABLE }, + { OHOS::Media::CodecServer::CodecType::CODEC_TYPE_AUDIO, AUDIO_DUMP_TABLE }, + }; +} + +namespace OHOS { +namespace Media { +std::shared_ptr CodecServer::Create() +{ + std::shared_ptr server = std::make_shared(); + + int32_t ret = server->InitServer(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Codec server init failed!"); + return server; +} + +CodecServer::CodecServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecServer::~CodecServer() +{ + std::unique_ptr thread = std::make_unique(&CodecServer::ExitProcessor, this); + if (thread != nullptr && thread->joinable()) { + thread->join(); + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecServer::ExitProcessor() +{ + codecBase_ = nullptr; +} + +int32_t CodecServer::InitServer() +{ + return AVCS_ERR_OK; +} + +int32_t CodecServer::Init(AVCodecType type, bool isMimeType, const std::string &name) +{ + std::lock_guard lock(mutex_); + if (isMimeType) { + bool isEncoder = (type == AVCODEC_TYPE_VIDEO_ENCODER) || (type == AVCODEC_TYPE_AUDIO_ENCODER); + codecBase_ = CodecFactory::Instance().CreateCodecByMime(isEncoder, name); + } else { + codecBase_ = CodecFactory::Instance().CreateCodecByName(name); + } + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "CodecBase is nullptr"); + codecName_ = name; + std::shared_ptr callback = std::make_shared(shared_from_this()); + int32_t ret = codecBase_->SetCallback(callback); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, "CodecBase SetCallback failed"); + status_ = INITIALIZED; + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + return AVCS_ERR_OK; +} + +int32_t CodecServer::Configure(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == INITIALIZED, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + config_ = format; + int32_t ret = codecBase_->Configure(format); + + status_ = (ret == AVCS_ERR_OK ? CONFIGURED : ERROR); + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + return ret; +} + +int32_t CodecServer::Start() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == FLUSHED || status_ == CONFIGURED, + AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->Start(); + if (codecCb_) { + status_ = (ret == AVCS_ERR_OK ? RUNNING : ERROR); + } else { + status_ = (ret == AVCS_ERR_OK ? FLUSHED : ERROR); + } + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + return ret; +} + +int32_t CodecServer::Stop() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING || status_ == END_OF_STREAM || + status_ == FLUSHED, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->Stop(); + status_ = (ret == AVCS_ERR_OK ? CONFIGURED : ERROR); + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + return ret; +} + +int32_t CodecServer::Flush() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING || status_ == END_OF_STREAM, + AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->Flush(); + status_ = (ret == AVCS_ERR_OK ? FLUSHED : ERROR); + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + return ret; +} + +int32_t CodecServer::NotifyEos() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->NotifyEos(); + if (ret == AVCS_ERR_OK) { + status_ = END_OF_STREAM; + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + AVCODEC_LOGI("EOS state"); + } + return ret; +} + +int32_t CodecServer::Reset() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->Reset(); + status_ = (ret == AVCS_ERR_OK ? INITIALIZED : ERROR); + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + lastErrMsg_.clear(); + return ret; +} + +int32_t CodecServer::Release() +{ + std::lock_guard lock(mutex_); + std::unique_ptr thread = std::make_unique(&CodecServer::ExitProcessor, this); + if (thread != nullptr && thread->joinable()) { + thread->join(); + } + return AVCS_ERR_OK; +} + +sptr CodecServer::CreateInputSurface() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == CONFIGURED, nullptr, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, nullptr, "Codecbase is nullptr"); + sptr surface = codecBase_->CreateInputSurface(); + firstFrameTraceId_ = FAKE_POINTER(surface.GetRefPtr()); + return surface; +} + +int32_t CodecServer::SetOutputSurface(sptr surface) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == CONFIGURED, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + return codecBase_->SetOutputSurface(surface); +} + +std::shared_ptr CodecServer::GetInputBuffer(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING, nullptr, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, nullptr, "Codec base is nullptr"); + return codecBase_->GetInputBuffer(index); +} + +int32_t CodecServer::QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + std::lock_guard lock(mutex_); + firstFrameTraceId_ = FAKE_POINTER(this); + if (isFirstFrameIn_) { + AVCodecTrace::TraceBegin("CodecServer::FirstFrame", firstFrameTraceId_); + isFirstFrameIn_ = false; + } + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + int32_t ret = codecBase_->QueueInputBuffer(index, info, flag); + if (flag & AVCODEC_BUFFER_FLAG_EOS) { + if (ret == AVCS_ERR_OK) { + status_ = END_OF_STREAM; + AVCODEC_LOGI("Codec server in %{public}s status", GetStatusDescription(status_).data()); + } + } + return ret; +} + +std::shared_ptr CodecServer::GetOutputBuffer(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING || status_ == END_OF_STREAM, + nullptr, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, nullptr, "Codecbase is nullptr"); + return codecBase_->GetOutputBuffer(index); +} + +int32_t CodecServer::GetOutputFormat(Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ != UNINITIALIZED, AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + return codecBase_->GetOutputFormat(format); +} + +int32_t CodecServer::ReleaseOutputBuffer(uint32_t index, bool render) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ == RUNNING || status_ == END_OF_STREAM, + AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + + int32_t ret; + if (render) { + ret = codecBase_->RenderOutputBuffer(index); + } else { + ret = codecBase_->ReleaseOutputBuffer(index); + } + return ret; +} + +int32_t CodecServer::SetParameter(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(status_ != INITIALIZED && status_ != CONFIGURED, + AVCS_ERR_INVALID_STATE, "In invalid state"); + CHECK_AND_RETURN_RET_LOG(codecBase_ != nullptr, AVCS_ERR_NO_MEMORY, "Codecbase is nullptr"); + return codecBase_->SetParameter(format); +} + +int32_t CodecServer::SetCallback(const std::shared_ptr &callback) +{ + std::lock_guard lock(mutex_); + { + std::lock_guard cbLock(cbMutex_); + codecCb_ = callback; + } + + return AVCS_ERR_OK; +} + +int32_t CodecServer::DumpInfo(int32_t fd) +{ + Format codecFormat; + int32_t ret = codecBase_->GetOutputFormat(codecFormat); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Get codec format failed."); + CodecType codecType = GetCodecType(); + auto it = CODEC_DUMP_TABLE.find(codecType); + auto &dumpTable = it != CODEC_DUMP_TABLE.end() ? it->second : DEFAULT_DUMP_TABLE; + AVCodecDumpControler dumpControler; + std::string codecInfo; + + switch (codecType) { + case CODEC_TYPE_VIDEO: + codecInfo = "Video_Codec_Info"; + break; + case CODEC_TYPE_DEFAULT: + codecInfo = "Codec_Info"; + break; + default: + codecInfo = "Audio_Codec_Info"; + break; + } + + dumpControler.AddInfo(DUMP_CODEC_INFO_INDEX, codecInfo); + dumpControler.AddInfo(DUMP_STATUS_INDEX, + "Status", CODEC_STATE_MAP.find(status_)->second); + dumpControler.AddInfo(DUMP_LAST_ERROR_INDEX, + "Last_Error", lastErrMsg_.size() ? lastErrMsg_ : "Null"); + + int32_t dumpIndex = 3; + for (auto iter : dumpTable) { + dumpControler.AddInfoFromFormat( + DUMP_CODEC_INFO_INDEX + (dumpIndex << DUMP_OFFSET_8), + codecFormat, iter.first, iter.second); + dumpIndex++; + } + + std::string dumpString; + dumpControler.GetDumpString(dumpString); + write(fd, dumpString.c_str(), dumpString.size()); + return AVCS_ERR_OK; +} + +const std::string &CodecServer::GetStatusDescription(OHOS::Media::CodecServer::CodecStatus status) +{ + static const std::string ILLEGAL_STATE = "CODEC_STATUS_ILLEGAL"; + if (status < OHOS::Media::CodecServer::UNINITIALIZED || + status > OHOS::Media::CodecServer::ERROR) { + return ILLEGAL_STATE; + } + + return CODEC_STATE_MAP.find(status)->second; +} + +void CodecServer::OnError(int32_t errorType, int32_t errorCode) +{ + std::lock_guard lock(cbMutex_); + lastErrMsg_ = AVCSErrorToOHAVErrCodeString(static_cast(errorCode)); + FaultEventWrite(errorCode, lastErrMsg_, "Codec"); + if (codecCb_ == nullptr) { + return; + } + codecCb_->OnError(static_cast(errorType), errorCode); +} + +void CodecServer::OnOutputFormatChanged(const Format &format) +{ + std::lock_guard lock(cbMutex_); + if (codecCb_ == nullptr) { + return; + } + codecCb_->OnOutputFormatChanged(format); +} + +void CodecServer::OnInputBufferAvailable(uint32_t index) +{ + std::lock_guard lock(cbMutex_); + if (codecCb_ == nullptr) { + return; + } + codecCb_->OnInputBufferAvailable(index); +} + +void CodecServer::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + std::lock_guard lock(cbMutex_); + if (isFirstFrameOut_) { + AVCodecTrace::TraceEnd("CodecServer::FirstFrame", firstFrameTraceId_); + isFirstFrameOut_ = false; + } else { + AVCodecTrace::TraceEnd("CodecServer::Frame", FAKE_POINTER(this)); + } + + if (flag == AVCODEC_BUFFER_FLAG_EOS) { + ResetTrace(); + } else { + AVCodecTrace::TraceBegin("CodecServer::Frame", FAKE_POINTER(this)); + } + + if (codecCb_ == nullptr) { + return; + } + codecCb_->OnOutputBufferAvailable(index, info, flag); +} + +void CodecServer::ResetTrace() +{ + isFirstFrameIn_ = true; + isFirstFrameOut_ = true; + AVCodecTrace::TraceEnd("CodecServer::Frame", FAKE_POINTER(this)); + AVCodecTrace::TraceEnd("CodecServer::FirstFrame", firstFrameTraceId_); +} + +CodecBaseCallback::CodecBaseCallback(const std::shared_ptr &codec) + : codec_(codec) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecBaseCallback::~CodecBaseCallback() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecBaseCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + if (codec_ != nullptr) { + codec_->OnError(errorType, errorCode); + } +} + +void CodecBaseCallback::OnOutputFormatChanged(const Format &format) +{ + if (codec_ != nullptr) { + codec_->OnOutputFormatChanged(format); + } +} + +void CodecBaseCallback::OnInputBufferAvailable(uint32_t index) +{ + if (codec_ != nullptr) { + codec_->OnInputBufferAvailable(index); + } +} + +void CodecBaseCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + if (codec_ != nullptr) { + codec_->OnOutputBufferAvailable(index, info, flag); + } +} + +CodecServer::CodecType CodecServer::GetCodecType() +{ + CodecType codecType; + + if (codecName_.find("video") != codecName_.npos) { + codecType = CodecType::CODEC_TYPE_VIDEO; + } else if (codecName_.find("audio") != codecName_.npos) { + codecType = CodecType::CODEC_TYPE_AUDIO; + } else { + codecType = CodecType::CODEC_TYPE_DEFAULT; + } + + return codecType; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/codec/server/codec_server.h b/services/services/codec/server/codec_server.h new file mode 100644 index 0000000000000000000000000000000000000000..35ce20b63cc0ebf2685bbfcb964b2fca97b2088d --- /dev/null +++ b/services/services/codec/server/codec_server.h @@ -0,0 +1,108 @@ +/* + * 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 CODEC_SERVER_H +#define CODEC_SERVER_H + +#include "codecbase.h" +#include "i_codec_service.h" +#include "nocopyable.h" + + +namespace OHOS { +namespace Media { +class CodecServer : public std::enable_shared_from_this, public ICodecService, public NoCopyable { +public: + static std::shared_ptr Create(); + CodecServer(); + virtual ~CodecServer(); + + enum CodecStatus { + UNINITIALIZED = 0, + INITIALIZED, + CONFIGURED, + RUNNING, + FLUSHED, + END_OF_STREAM, + ERROR, + }; + + enum CodecType { + CODEC_TYPE_DEFAULT = 0, + CODEC_TYPE_VIDEO, + CODEC_TYPE_AUDIO + }; + + int32_t Init(AVCodecType type, bool isMimeType, const std::string &name) override; + int32_t Configure(const Format &format) override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + sptr CreateInputSurface() override; + int32_t SetOutputSurface(sptr surface) override; + std::shared_ptr GetInputBuffer(uint32_t index) override; + int32_t QueueInputBuffer(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + std::shared_ptr GetOutputBuffer(uint32_t index) override; + int32_t GetOutputFormat(Format &format) override; + int32_t ReleaseOutputBuffer(uint32_t index, bool render) override; + int32_t SetParameter(const Format &format) override; + int32_t SetCallback(const std::shared_ptr &callback) override; + int32_t DumpInfo(int32_t fd); + + void OnError(int32_t errorType, int32_t errorCode); + void OnOutputFormatChanged(const Format &format); + void OnInputBufferAvailable(uint32_t index); + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag); + void ResetTrace(); + +private: + int32_t InitServer(); + void ExitProcessor(); + const std::string &GetStatusDescription(OHOS::Media::CodecServer::CodecStatus status); + CodecType GetCodecType(); + + CodecStatus status_ = UNINITIALIZED; + + // std::unique_ptr codecEngine_; + std::shared_ptr codecBase_; + std::shared_ptr codecCb_; + std::mutex mutex_; + std::mutex cbMutex_; + Format config_; + std::string lastErrMsg_; + std::string codecName_; + int32_t firstFrameTraceId_ = 0; + bool isFirstFrameIn_ = true; + bool isFirstFrameOut_ = true; +}; + +class CodecBaseCallback : public AVCodecCallback, public NoCopyable { +public: + explicit CodecBaseCallback(const std::shared_ptr &codec); + virtual ~CodecBaseCallback(); + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; +private: + std::shared_ptr codec_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // CODEC_SERVER_H \ No newline at end of file diff --git a/services/services/codeclist/client/codeclist_client.cpp b/services/services/codeclist/client/codeclist_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca840e35615f9a0b60aa33f6743d38f91d1bed9d --- /dev/null +++ b/services/services/codeclist/client/codeclist_client.cpp @@ -0,0 +1,78 @@ +/* + * 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 "codeclist_client.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListClient"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr CodecListClient::Create(const sptr &ipcProxy) +{ + CHECK_AND_RETURN_RET_LOG(ipcProxy != nullptr, nullptr, "ipcProxy is nullptr.."); + + std::shared_ptr codecList = std::make_shared(ipcProxy); + + return codecList; +} + +CodecListClient::CodecListClient(const sptr &ipcProxy) + : codecListProxy_(ipcProxy) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListClient::~CodecListClient() +{ + std::lock_guard lock(mutex_); + if (codecListProxy_ != nullptr) { + (void)codecListProxy_->DestroyStub(); + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void CodecListClient::AVCodecServerDied() +{ + std::lock_guard lock(mutex_); + codecListProxy_ = nullptr; +} + +std::string CodecListClient::FindDecoder(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecListProxy_ != nullptr, "", "codeclist service does not exist."); + return codecListProxy_->FindDecoder(format); +} + +std::string CodecListClient::FindEncoder(const Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecListProxy_ != nullptr, "", "codeclist service does not exist."); + return codecListProxy_->FindEncoder(format); +} + +CapabilityData CodecListClient::CreateCapability(std::string codecName) +{ + std::lock_guard lock(mutex_); + CapabilityData capData; + CHECK_AND_RETURN_RET_LOG(codecListProxy_ != nullptr, capData, + "codeclist service does not exist."); + return codecListProxy_->CreateCapability(codecName); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codeclist/client/codeclist_client.h b/services/services/codeclist/client/codeclist_client.h new file mode 100644 index 0000000000000000000000000000000000000000..ef2d8892025b194e74df426f7cd3c7e958e4a557 --- /dev/null +++ b/services/services/codeclist/client/codeclist_client.h @@ -0,0 +1,43 @@ +/* + * 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 CODECLIST_CLIENT_H +#define CODECLIST_CLIENT_H + +#include +#include "i_codeclist_service.h" +#include "i_standard_codeclist_service.h" + +namespace OHOS { +namespace Media { +class CodecListClient : public ICodecListService { +public: + static std::shared_ptr Create(const sptr &ipcProxy); + explicit CodecListClient(const sptr &ipcProxy); + ~CodecListClient(); + void MediaServerDied(); + // ICodecListService override + std::string FindDecoder(const Format &format) override; + std::string FindEncoder(const Format &format) override; + CapabilityData CreateCapability(std::string codecName) override; + + void AVCodecServerDied(); +private: + sptr codecListProxy_ = nullptr; + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_CLIENT_H diff --git a/services/services/codeclist/ipc/codeclist_service_proxy.cpp b/services/services/codeclist/ipc/codeclist_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f993ec405552334311c1b610992bfadff8d88d6 --- /dev/null +++ b/services/services/codeclist/ipc/codeclist_service_proxy.cpp @@ -0,0 +1,106 @@ +/* + * 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 "codeclist_service_proxy.h" +#include "avcodec_parcel.h" +#include "codeclist_parcel.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListServiceProxy"}; +} + +namespace OHOS { +namespace Media { +CodecListServiceProxy::CodecListServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListServiceProxy::~CodecListServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +std::string CodecListServiceProxy::FindDecoder(const Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecListServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, "", "Failed to write descriptor!"); + + (void)AVCodecParcel::Marshalling(data, format); + int32_t ret = Remote()->SendRequest(FIND_DECODER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, "", "FindDecoder failed"); + + return reply.ReadString(); +} + +std::string CodecListServiceProxy::FindEncoder(const Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecListServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, "", "Failed to write descriptor!"); + + (void)AVCodecParcel::Marshalling(data, format); + int32_t ret = Remote()->SendRequest(FIND_ENCODER, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, "", "FindEncoder failed"); + + return reply.ReadString(); +} + +CapabilityData CodecListServiceProxy::CreateCapability(std::string codecName) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + Format profileFormat; + CapabilityData capabilityData; + + bool token = data.WriteInterfaceToken(CodecListServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, capabilityData, "Failed to write descriptor!"); + + (void)data.WriteString(codecName); + int32_t ret = Remote()->SendRequest(CREATE_CAPABILITY, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, capabilityData, "GetCodecCapabilityInfos failed, error: %{public}d", + ret); + (void)CodecListParcel::Unmarshalling(reply, capabilityData); + + return capabilityData; +} + +int32_t CodecListServiceProxy::DestroyStub() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(CodecListServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int32_t ret = Remote()->SendRequest(DESTROY, data, reply, option); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_OPERATION, "DestroyStub failed, error: %{public}d", + ret); + return reply.ReadInt32(); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codeclist/ipc/codeclist_service_proxy.h b/services/services/codeclist/ipc/codeclist_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..4f7a3a58fa78045e36ea9b4c1d4e449a8d91b887 --- /dev/null +++ b/services/services/codeclist/ipc/codeclist_service_proxy.h @@ -0,0 +1,39 @@ +/* + * 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 CODECLIST_SERVICE_PROXY_H +#define CODECLIST_SERVICE_PROXY_H + +#include "i_standard_codeclist_service.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class CodecListServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit CodecListServiceProxy(const sptr &impl); + virtual ~CodecListServiceProxy(); + + std::string FindDecoder(const Format &format) override; + std::string FindEncoder(const Format &format) override; + CapabilityData CreateCapability(std::string codecName) override; + int32_t DestroyStub() override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_SERVICE_PROXY_H diff --git a/services/services/codeclist/ipc/codeclist_service_stub.cpp b/services/services/codeclist/ipc/codeclist_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4364b07d1f4c35047fa5b112329943e72b3fd739 --- /dev/null +++ b/services/services/codeclist/ipc/codeclist_service_stub.cpp @@ -0,0 +1,148 @@ +/* + * 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 "avsharedmemory_ipc.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_server_manager.h" +#include "avcodec_xcollie.h" +#include "codeclist_service_stub.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListServiceStub"}; +} + +namespace OHOS { +namespace Media { +sptr CodecListServiceStub::Create() +{ + sptr codecListStub = new (std::nothrow) CodecListServiceStub(); + CHECK_AND_RETURN_RET_LOG(codecListStub != nullptr, nullptr, "failed to new CodecListServiceStub"); + + int32_t ret = codecListStub->Init(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed to codeclist stub init"); + return codecListStub; +} + +CodecListServiceStub::CodecListServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListServiceStub::~CodecListServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t CodecListServiceStub::Init() +{ + codecListServer_ = CodecListServer::Create(); + CHECK_AND_RETURN_RET_LOG(codecListServer_ != nullptr, AVCS_ERR_NO_MEMORY, "failed to create CodecListServer"); + codecListFuncs_[FIND_DECODER] = &CodecListServiceStub::DoFindDecoder; + codecListFuncs_[FIND_ENCODER] = &CodecListServiceStub::DoFindEncoder; + codecListFuncs_[CREATE_CAPABILITY] = &CodecListServiceStub::DoCreateCapability; + codecListFuncs_[DESTROY] = &CodecListServiceStub::DoDestroyStub; + return AVCS_ERR_OK; +} + +int32_t CodecListServiceStub::DestroyStub() +{ + codecListServer_ = nullptr; + AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::CODECLIST, AsObject()); + return AVCS_ERR_OK; +} + +int CodecListServiceStub::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 (CodecListServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = codecListFuncs_.find(code); + if (itFunc != codecListFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = -1; + COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), "CodecListServiceStub::OnRemoteRequest"); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("calling memberFunc is failed."); + } + return AVCS_ERR_OK; + } + } + AVCODEC_LOGW("CodecListServiceStub: no member func supporting, applying default process"); + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +std::string CodecListServiceStub::FindDecoder(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecListServer_ != nullptr, "", "avcodeclist server is nullptr"); + return codecListServer_->FindDecoder(format); +} + +std::string CodecListServiceStub::FindEncoder(const Format &format) +{ + CHECK_AND_RETURN_RET_LOG(codecListServer_ != nullptr, "", "avcodeclist server is nullptr"); + return codecListServer_->FindEncoder(format); +} + +CapabilityData CodecListServiceStub::CreateCapability(const std::string codecName) +{ + CapabilityData capabilityData; + CHECK_AND_RETURN_RET_LOG(codecListServer_ != nullptr, capabilityData, "avcodeclist server is nullptr"); + return codecListServer_->CreateCapability(codecName); +} + +int32_t CodecListServiceStub::DoFindDecoder(MessageParcel &data, MessageParcel &reply) +{ + Format format; + (void)AVCodecParcel::Unmarshalling(data, format); + reply.WriteString(FindDecoder(format)); + return AVCS_ERR_OK; +} + +int32_t CodecListServiceStub::DoFindEncoder(MessageParcel &data, MessageParcel &reply) +{ + Format format; + (void)AVCodecParcel::Unmarshalling(data, format); + reply.WriteString(FindEncoder(format)); + return AVCS_ERR_OK; +} + +int32_t CodecListServiceStub::DoCreateCapability(MessageParcel &data, MessageParcel &reply) +{ + std::string codecName = data.ReadString(); + CapabilityData capabilityData = CreateCapability(codecName); + + (void)CodecListParcel::Marshalling(reply, capabilityData); + + return AVCS_ERR_OK; +} + +int32_t CodecListServiceStub::DoDestroyStub(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + reply.WriteInt32(DestroyStub()); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codeclist/ipc/codeclist_service_stub.h b/services/services/codeclist/ipc/codeclist_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..ef2b45ebc4f5f56ab321fd92f30afd01863cdd07 --- /dev/null +++ b/services/services/codeclist/ipc/codeclist_service_stub.h @@ -0,0 +1,54 @@ +/* + * 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 CODECLIST_SERVICE_STUB_H +#define CODECLIST_SERVICE_STUB_H + +#include +#include "i_standard_codeclist_service.h" +#include "avcodec_death_recipient.h" +#include "codeclist_server.h" +#include "nocopyable.h" +#include "avcodec_parcel.h" +#include "codeclist_parcel.h" + +namespace OHOS { +namespace Media { +class CodecListServiceStub : public IRemoteStub, public NoCopyable { +public: + static sptr Create(); + virtual ~CodecListServiceStub(); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + std::string FindDecoder(const Format &format) override; + std::string FindEncoder(const Format &format) override; + CapabilityData CreateCapability(std::string codecName) override; + int32_t DestroyStub() override; + +private: + CodecListServiceStub(); + int32_t Init(); + int32_t DoFindDecoder(MessageParcel &data, MessageParcel &reply); + int32_t DoFindEncoder(MessageParcel &data, MessageParcel &reply); + int32_t DoCreateCapability(MessageParcel &data, MessageParcel &reply); + int32_t DoDestroyStub(MessageParcel &data, MessageParcel &reply); + std::shared_ptr codecListServer_ = nullptr; + using CodecListStubFunc = int32_t(CodecListServiceStub::*)(MessageParcel &data, MessageParcel &reply); + std::map codecListFuncs_; + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_SERVICE_STUB_H diff --git a/services/services/codeclist/ipc/i_standard_codeclist_service.h b/services/services/codeclist/ipc/i_standard_codeclist_service.h new file mode 100644 index 0000000000000000000000000000000000000000..53f1905971496205affb30fd2f0321047f6c9a03 --- /dev/null +++ b/services/services/codeclist/ipc/i_standard_codeclist_service.h @@ -0,0 +1,44 @@ +/* + * 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_CODECLIST_SERVICE_H +#define I_STANDARD_CODECLIST_SERVICE_H + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class IStandardCodecListService : public IRemoteBroker { +public: + virtual ~IStandardCodecListService() = default; + virtual std::string FindDecoder(const Format &format) = 0; + virtual std::string FindEncoder(const Format &format) = 0; + virtual CapabilityData CreateCapability(std::string codecName) = 0; + virtual int32_t DestroyStub() = 0; + + /** + * IPC code ID + */ + enum AVCodecListServiceMsg { FIND_DECODER = 0, FIND_ENCODER, CREATE_CAPABILITY, DESTROY }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardCodecListService"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_CODECLIST_SERVICE_H diff --git a/services/services/codeclist/server/codeclist_server.cpp b/services/services/codeclist/server/codeclist_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c8ecbebefbc08517fc49f8bd07e2800243bd47d --- /dev/null +++ b/services/services/codeclist/server/codeclist_server.cpp @@ -0,0 +1,66 @@ +/* + * 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 "codeclist_server.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListServer"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr CodecListServer::Create() +{ + std::shared_ptr server = std::make_shared(); + if (!server->Init()) { + AVCODEC_LOGE("failed to init CodecListServer"); + return nullptr; + } + return server; +} + +CodecListServer::CodecListServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +CodecListServer::~CodecListServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +bool CodecListServer::Init() +{ + codecListCore_ = std::make_shared(); + return true; +} + +std::string CodecListServer::FindDecoder(const Format &format) +{ + return codecListCore_->FindDecoder(format); +} + +std::string CodecListServer::FindEncoder(const Format &format) +{ + return codecListCore_->FindEncoder(format); +} + +CapabilityData CodecListServer::CreateCapability(const std::string codecName) +{ + return codecListCore_->CreateCapability(codecName); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/codeclist/server/codeclist_server.h b/services/services/codeclist/server/codeclist_server.h new file mode 100644 index 0000000000000000000000000000000000000000..f242f985181e148a5824eeb867242cf02eb40a4d --- /dev/null +++ b/services/services/codeclist/server/codeclist_server.h @@ -0,0 +1,41 @@ +/* + * 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 CODECLIST_SERVER_H +#define CODECLIST_SERVER_H + +#include "i_codeclist_service.h" +#include "codeclist_core.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class CodecListServer : public ICodecListService, public NoCopyable { +public: + static std::shared_ptr Create(); + CodecListServer(); + virtual ~CodecListServer(); + + std::string FindDecoder(const Format &format) override; + std::string FindEncoder(const Format &format) override; + CapabilityData CreateCapability(const std::string codecName) override; + +private: + bool Init(); + std::shared_ptr codecListCore_; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_SERVER_H \ No newline at end of file diff --git a/services/services/common/avsharedmemory_ipc.cpp b/services/services/common/avsharedmemory_ipc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98f426bdde3b071b441485d6f6d713f05feb6d00 --- /dev/null +++ b/services/services/common/avsharedmemory_ipc.cpp @@ -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. + */ + +#include "avsharedmemory_ipc.h" +#include +#include "avsharedmemorybase.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVSharedMemoryIPC"}; +} + +namespace OHOS { +namespace Media { +int32_t WriteAVSharedMemoryToParcel(const std::shared_ptr &memory, MessageParcel &parcel) +{ + std::shared_ptr baseMem = std::static_pointer_cast(memory); + if (baseMem == nullptr) { + AVCODEC_LOGE("invalid pointer"); + return AVCS_ERR_INVALID_VAL; + } + + int32_t fd = baseMem->GetFd(); + int32_t size = baseMem->GetSize(); + + (void)parcel.WriteFileDescriptor(fd); + parcel.WriteInt32(size); + parcel.WriteUint32(baseMem->GetFlags()); + parcel.WriteString(baseMem->GetName()); + + return AVCS_ERR_OK; +} + +std::shared_ptr ReadAVSharedMemoryFromParcel(MessageParcel &parcel) +{ + int32_t fd = parcel.ReadFileDescriptor(); + int32_t size = parcel.ReadInt32(); + uint32_t flags = parcel.ReadUint32(); + std::string name = parcel.ReadString(); + + std::shared_ptr memory = AVSharedMemoryBase::CreateFromRemote(fd, size, flags, name); + if (memory == nullptr || memory->GetBase() == nullptr) { + AVCODEC_LOGE("create remote AVSharedMemoryBase failed"); + memory = nullptr; + } + + (void)::close(fd); + return memory; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/common/avsharedmemory_ipc.h b/services/services/common/avsharedmemory_ipc.h new file mode 100644 index 0000000000000000000000000000000000000000..d46599879f3c49fd652bfdfdc2a12e448b00aa82 --- /dev/null +++ b/services/services/common/avsharedmemory_ipc.h @@ -0,0 +1,29 @@ +/* + * 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 AVSHAREDMEMORY_IPC_H +#define AVSHAREDMEMORY_IPC_H + +#include +#include "avsharedmemory.h" + +namespace OHOS { +namespace Media { +[[maybe_unused]] int32_t WriteAVSharedMemoryToParcel(const std::shared_ptr &memory, + MessageParcel &parcel); +[[maybe_unused]] std::shared_ptr ReadAVSharedMemoryFromParcel(MessageParcel &parcel); +} // namespace Media +} // namespace OHOS +#endif diff --git a/services/services/demuxer/client/demuxer_client.cpp b/services/services/demuxer/client/demuxer_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ab0e7ccca378657f6ad9b0ac161b565766364f6 --- /dev/null +++ b/services/services/demuxer/client/demuxer_client.cpp @@ -0,0 +1,96 @@ +/* + * 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 "demuxer_client.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerClient"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr DemuxerClient::Create(const sptr &ipcProxy) +{ + std::shared_ptr demuxer = std::make_shared(ipcProxy); + CHECK_AND_RETURN_RET_LOG(demuxer != nullptr, nullptr, "Failed to create demuxer client"); + return demuxer; +} + +DemuxerClient::DemuxerClient(const sptr &ipcProxy) + : demuxerProxy_(ipcProxy) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +DemuxerClient::~DemuxerClient() +{ + std::lock_guard lock(mutex_); + if (demuxerProxy_ != nullptr) { + (void)demuxerProxy_->DestroyStub(); + demuxerProxy_ = nullptr; + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t DemuxerClient::Init(uintptr_t sourceAddr) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("demuxer client call Init"); + return demuxerProxy_->Init(sourceAddr); +} + +void DemuxerClient::DemuxerClient::AVCodecServerDied() +{ + std::lock_guard lock(mutex_); + demuxerProxy_ = nullptr; +} + + +int32_t DemuxerClient::SelectSourceTrackByID(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service does not exist."); + + AVCODEC_LOGD("demuxer client call SelectSourceTrackByID"); + return demuxerProxy_->SelectSourceTrackByID(index); +} +int32_t DemuxerClient::UnselectSourceTrackByID(uint32_t index) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service does not exist."); + + AVCODEC_LOGD("demuxer client call UnselectSourceTrackByID"); + return demuxerProxy_->UnselectSourceTrackByID(index); +} +int32_t DemuxerClient::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service does not exist."); + AVCODEC_LOGD("demuxer client call CopyNextSample"); + return demuxerProxy_->CopyNextSample(trackIndex, buffer, bufferInfo, flag); +} +int32_t DemuxerClient::SeekToTime(int64_t mSeconds, const AVSeekMode mode) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service does not exist."); + AVCODEC_LOGD("demuxer client call SeekToTime"); + return demuxerProxy_->SeekToTime(mSeconds, mode); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/demuxer/client/demuxer_client.h b/services/services/demuxer/client/demuxer_client.h new file mode 100644 index 0000000000000000000000000000000000000000..f6a1752c2c5304762a60a0668755da841a235650 --- /dev/null +++ b/services/services/demuxer/client/demuxer_client.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 DEMUXER_CLIENT_H +#define DEMUXER_CLIENT_H + +#include "i_demuxer_service.h" +#include "i_standard_demuxer_service.h" + +namespace OHOS { +namespace Media { +class DemuxerClient : public IDemuxerService, public NoCopyable { +public: + static std::shared_ptr Create(const sptr &ipcProxy); + explicit DemuxerClient(const sptr &ipcProxy); + ~DemuxerClient(); + + int32_t Init(uintptr_t sourceAddr) override; + int32_t SelectSourceTrackByID(uint32_t index) override; + int32_t UnselectSourceTrackByID(uint32_t index) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) override; + void AVCodecServerDied(); +private: + std::mutex mutex_; + sptr demuxerProxy_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // DEMUXER_CLIENT_H \ No newline at end of file diff --git a/services/services/demuxer/ipc/demuxer_service_proxy.cpp b/services/services/demuxer/ipc/demuxer_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8116bc58459040443e4e81e4ebb69fc0d0cdd56f --- /dev/null +++ b/services/services/demuxer/ipc/demuxer_service_proxy.cpp @@ -0,0 +1,122 @@ +/* + * 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 "demuxer_service_proxy.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "avsharedmemory_ipc.h" +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerServiceProxy"}; +} + +namespace OHOS { +namespace Media { +DemuxerServiceProxy::DemuxerServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +DemuxerServiceProxy::~DemuxerServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t DemuxerServiceProxy::DestroyStub() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int error = Remote()->SendRequest(DESTROY_STUB, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call DestroyStub, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t DemuxerServiceProxy::Init(uint64_t sourceAddr) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + data.WriteUint64(sourceAddr); + int32_t error = Remote()->SendRequest(INIT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call Init, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t DemuxerServiceProxy::SelectSourceTrackByID(uint32_t trackIndex) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int32_t error = Remote()->SendRequest(SELECT_SOURCE_TRACK_BY_ID, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, + "Failed to call SelectSourceTrackByID, error: %{public}d", error); + return reply.ReadInt32(); +} +int32_t DemuxerServiceProxy::UnselectSourceTrackByID(uint32_t trackIndex) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int32_t error = Remote()->SendRequest(UNSELECT_SOURCE_TRACK_BY_ID, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, + "Failed to call UnselectSourceTrackByID, error: %{public}d", error); + return reply.ReadInt32(); +} +int32_t DemuxerServiceProxy::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int32_t error = Remote()->SendRequest(COPY_NEXT_SAMPLE, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call CopyNextSample, error: %{public}d", error); + + trackIndex = reply.ReadUint32(); + bufferInfo.presentationTimeUs = reply.ReadInt64(); + bufferInfo.size = reply.ReadInt32(); + bufferInfo.offset = reply.ReadInt32(); + flag = static_cast(reply.ReadUint32()); + return reply.ReadInt32(); +} +int32_t DemuxerServiceProxy::SeekToTime(int64_t mSeconds, const AVSeekMode mode) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + bool token = data.WriteInterfaceToken(DemuxerServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int32_t error = Remote()->SendRequest(SEEK_TO_TIME, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call SeekToTime, error: %{public}d", error); + return reply.ReadInt32(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/demuxer/ipc/demuxer_service_proxy.h b/services/services/demuxer/ipc/demuxer_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..0584920a21c8a50038f85a30f738721b514680c5 --- /dev/null +++ b/services/services/demuxer/ipc/demuxer_service_proxy.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 DEMUXER_SERVICE_PROXY_H +#define DEMUXER_SERVICE_PROXY_H + +#include "i_standard_demuxer_service.h" + +namespace OHOS { +namespace Media { +class DemuxerServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit DemuxerServiceProxy(const sptr &impl); + virtual ~DemuxerServiceProxy(); + int32_t Init(uint64_t sourceAddr) override; + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) override; + int32_t DestroyStub() override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // DEMUXER_SERVICE_PROXY_H \ No newline at end of file diff --git a/services/services/demuxer/ipc/demuxer_service_stub.cpp b/services/services/demuxer/ipc/demuxer_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..032e4b812430085b50acbee28f051d28eeb5b1cf --- /dev/null +++ b/services/services/demuxer/ipc/demuxer_service_stub.cpp @@ -0,0 +1,210 @@ +/* + * 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 "demuxer_service_stub.h" +#include +#include "avcodec_server_manager.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avsharedmemory_ipc.h" +#include "avcodec_xcollie.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerServiceStub"}; +} + +namespace OHOS { +namespace Media { +sptr DemuxerServiceStub::Create() +{ + sptr demuxerStub = new(std::nothrow) DemuxerServiceStub(); + CHECK_AND_RETURN_RET_LOG(demuxerStub != nullptr, nullptr, "Failed to create demuxer service stub"); + + int32_t ret = demuxerStub->InitStub(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init DemuxerServiceStub"); + return demuxerStub; +} + +DemuxerServiceStub::DemuxerServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +DemuxerServiceStub::~DemuxerServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t DemuxerServiceStub::InitStub() +{ + demuxerServer_ = DemuxerServer::Create(); + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Failed to create muxer server"); + + demuxerFuncs_[INIT] = &DemuxerServiceStub::Init; + demuxerFuncs_[SELECT_SOURCE_TRACK_BY_ID] = &DemuxerServiceStub::SelectSourceTrackByID; + demuxerFuncs_[UNSELECT_SOURCE_TRACK_BY_ID] = &DemuxerServiceStub::UnselectSourceTrackByID; + demuxerFuncs_[COPY_NEXT_SAMPLE] = &DemuxerServiceStub::CopyNextSample; + demuxerFuncs_[SEEK_TO_TIME] = &DemuxerServiceStub::SeekToTime; + + demuxerFuncs_[DESTROY_STUB] = &DemuxerServiceStub::DestroyStub; + + return AVCS_ERR_OK; +} + +int DemuxerServiceStub::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 (DemuxerServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = demuxerFuncs_.find(code); + if (itFunc != demuxerFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = -1; + COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), + "DemuxerServiceStub::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 DemuxerServiceStub::DestroyStub() +{ + demuxerServer_ = nullptr; + AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::DEMUXER, AsObject()); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::Init(uint64_t sourceAddr) +{ + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service is nullptr"); + return demuxerServer_->Init(sourceAddr); +} + +int32_t DemuxerServiceStub::SelectSourceTrackByID(uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service is nullptr"); + return demuxerServer_->SelectSourceTrackByID(trackIndex); +} + +int32_t DemuxerServiceStub::UnselectSourceTrackByID(uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service is nullptr"); + return demuxerServer_->UnselectSourceTrackByID(trackIndex); +} + +int32_t DemuxerServiceStub::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service is nullptr"); + return demuxerServer_->CopyNextSample(trackIndex, buffer, bufferInfo, flag); +} + +int32_t DemuxerServiceStub::SeekToTime(int64_t mSeconds, const AVSeekMode mode) +{ + CHECK_AND_RETURN_RET_LOG(demuxerServer_ != nullptr, AVCS_ERR_NO_MEMORY, "demuxer service is nullptr"); + return demuxerServer_->SeekToTime(mSeconds, mode); +} + +int32_t DemuxerServiceStub::DumpInfo(int32_t fd) +{ + std::string dumpInfo; + dumpInfo += "# DemuxerServiceStub \n"; + 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 DemuxerServiceStub::Init(MessageParcel &data, MessageParcel &reply) +{ + uint64_t sourceAddr = data.ReadUint64(); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Init(sourceAddr)), AVCS_ERR_UNKNOWN, "Reply Init failed!"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::SelectSourceTrackByID(MessageParcel &data, MessageParcel &reply) +{ + uint32_t trackIndex = data.ReadUint32(); + + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SelectSourceTrackByID(trackIndex)), AVCS_ERR_UNKNOWN, + "Reply SelectSourceTrackByID failed!"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::UnselectSourceTrackByID(MessageParcel &data, MessageParcel &reply) +{ + uint32_t trackIndex = data.ReadUint32(); + + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(UnselectSourceTrackByID(trackIndex)), AVCS_ERR_UNKNOWN, + "Reply UnselectSourceTrackByID failed!"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::CopyNextSample(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + uint32_t trackIndex; + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + uint8_t *buffer = nullptr; + + int32_t ret = CopyNextSample(trackIndex, buffer, info, flag); + + CHECK_AND_RETURN_RET_LOG(reply.WriteUint32(trackIndex), AVCS_ERR_UNKNOWN, "Reply CopyNextSample failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt64(info.presentationTimeUs), AVCS_ERR_UNKNOWN, + "Reply CopyNextSample failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(info.size), AVCS_ERR_UNKNOWN, "Reply CopyNextSample failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(info.offset), AVCS_ERR_UNKNOWN, "Reply CopyNextSample failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteUint32(static_cast(flag)), AVCS_ERR_UNKNOWN, + "Reply CopyNextSample failed!"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply CopyNextSample failed!"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::SeekToTime(MessageParcel &data, MessageParcel &reply) +{ + int64_t mSeconds = data.ReadInt64(); + AVSeekMode seekMode = static_cast(data.ReadInt32()); + + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SeekToTime(mSeconds, seekMode)), + AVCS_ERR_UNKNOWN, "Reply SeekToTime failed!"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServiceStub::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; +} + +int32_t DemuxerServiceStub::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/demuxer/ipc/demuxer_service_stub.h b/services/services/demuxer/ipc/demuxer_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..bb76330e5b345f3f7f5b24da319c8fa3d4024fc4 --- /dev/null +++ b/services/services/demuxer/ipc/demuxer_service_stub.h @@ -0,0 +1,62 @@ +/* + * 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 DEMUXER_SERVICE_STUB_H +#define DEMUXER_SERVICE_STUB_H + +#include +#include +#include "i_standard_demuxer_service.h" +#include "demuxer_server.h" +#include "iremote_stub.h" +#include "avcodec_common.h" + +namespace OHOS { +namespace Media { +class DemuxerServiceStub : public IRemoteStub, public NoCopyable { +public: + static sptr Create(); + virtual ~DemuxerServiceStub(); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + using DemuxerStubFunc = int32_t(DemuxerServiceStub::*)(MessageParcel &data, MessageParcel &reply); + + // 业务 + int32_t Init(uint64_t sourceAddr) override; + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) override; + + int32_t DumpInfo(int32_t fd); + int32_t DestroyStub() override; +private: + DemuxerServiceStub(); + int32_t InitStub(); + + int32_t Init(MessageParcel &data, MessageParcel &reply); + int32_t SelectSourceTrackByID(MessageParcel &data, MessageParcel &reply); + int32_t UnselectSourceTrackByID(MessageParcel &data, MessageParcel &reply); + int32_t CopyNextSample(MessageParcel &data, MessageParcel &reply); + int32_t SeekToTime(MessageParcel &data, MessageParcel &reply); + int32_t GetDumpInfo(std::string& dumpInfo); + int32_t DestroyStub(MessageParcel &data, MessageParcel &reply); + + std::mutex mutex_; + std::shared_ptr demuxerServer_ = nullptr; + std::map demuxerFuncs_; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/services/demuxer/ipc/i_standard_demuxer_service.h b/services/services/demuxer/ipc/i_standard_demuxer_service.h new file mode 100644 index 0000000000000000000000000000000000000000..31bb55d6063921e9aaa8015e830b2dc4ce5dbde6 --- /dev/null +++ b/services/services/demuxer/ipc/i_standard_demuxer_service.h @@ -0,0 +1,52 @@ +/* + * 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_DEMUXER_SERVICE_H +#define I_STANDARD_DEMUXER_SERVICE_H + +#include "avcodec_common.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace Media { +class IStandardDemuxerService : public IRemoteBroker { +public: + virtual ~IStandardDemuxerService() = default; + + // 业务 + virtual int32_t Init(uint64_t sourceAddr) = 0; + virtual int32_t SelectSourceTrackByID(uint32_t trackIndex) = 0; + virtual int32_t UnselectSourceTrackByID(uint32_t trackIndex) = 0; + virtual int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) = 0; + virtual int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) = 0; + + virtual int32_t DestroyStub() = 0; + + enum DemuxerServiceMsg { + INIT, + SELECT_SOURCE_TRACK_BY_ID, + UNSELECT_SOURCE_TRACK_BY_ID, + COPY_NEXT_SAMPLE, + SEEK_TO_TIME, + + DESTROY_STUB, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardDemuxerService"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_DEMUXER_SERVICE_H \ No newline at end of file diff --git a/services/services/demuxer/server/demuxer_server.cpp b/services/services/demuxer/server/demuxer_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1515c212b393f7551f64254d3b141760d293a238 --- /dev/null +++ b/services/services/demuxer/server/demuxer_server.cpp @@ -0,0 +1,88 @@ +/* + * 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 "demuxer_server.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "ipc_skeleton.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "DemuxerServer"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr DemuxerServer::Create() +{ + std::shared_ptr server = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(server != nullptr, nullptr, "Demuxer Service does not exist"); + return server; +} + +DemuxerServer::DemuxerServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + appUid_ = IPCSkeleton::GetCallingUid(); + appPid_ = IPCSkeleton::GetCallingPid(); +} + +DemuxerServer::~DemuxerServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); + demuxerEngine_ = nullptr; +} + +int32_t DemuxerServer::Init(uintptr_t sourceAddr) +{ + demuxerEngine_ = IDemuxerEngineFactory::CreateDemuxerEngine(appUid_, appPid_, sourceAddr); + CHECK_AND_RETURN_RET_LOG(demuxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine create failed"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServer::SelectSourceTrackByID(uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = demuxerEngine_->SelectSourceTrackByID(trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServer::UnselectSourceTrackByID(uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(demuxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = demuxerEngine_->UnselectSourceTrackByID(trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + // return index; // only for test + return AVCS_ERR_OK; +} + +int32_t DemuxerServer::CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) +{ + CHECK_AND_RETURN_RET_LOG(demuxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = demuxerEngine_->CopyNextSample(trackIndex, buffer, bufferInfo, flag); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t DemuxerServer::SeekToTime(int64_t mSeconds, const AVSeekMode mode) +{ + CHECK_AND_RETURN_RET_LOG(demuxerEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = demuxerEngine_->SeekToTime(mSeconds, mode); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/demuxer/server/demuxer_server.h b/services/services/demuxer/server/demuxer_server.h new file mode 100644 index 0000000000000000000000000000000000000000..868a99fcaae0e0d549da1257626a6cbd80db3347 --- /dev/null +++ b/services/services/demuxer/server/demuxer_server.h @@ -0,0 +1,45 @@ +/* + * 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 DEMUXER_SERVER_H +#define DEMUXER_SERVER_H + +#include "i_demuxer_service.h" +#include "nocopyable.h" +#include "i_demuxer_engine.h" + +namespace OHOS { +namespace Media { +class DemuxerServer : public std::enable_shared_from_this, public IDemuxerService, public NoCopyable { +public: + static std::shared_ptr Create(); + DemuxerServer(); + ~DemuxerServer(); + + // 业务 + int32_t Init(uintptr_t sourceAddr) override; + int32_t SelectSourceTrackByID(uint32_t trackIndex) override; + int32_t UnselectSourceTrackByID(uint32_t trackIndex) override; + int32_t CopyNextSample(uint32_t &trackIndex, uint8_t *buffer, + AVCodecBufferInfo &bufferInfo, AVCodecBufferFlag &flag) override; + int32_t SeekToTime(int64_t mSeconds, const AVSeekMode mode) override; + +private: + std::shared_ptr demuxerEngine_ = nullptr; + int32_t appUid_ = 0; + int32_t appPid_ = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // DEMUXER_SERVER_H \ No newline at end of file diff --git a/services/services/factory/i_muxer_engine.h b/services/services/factory/i_muxer_engine.h new file mode 100644 index 0000000000000000000000000000000000000000..ce2a1c35dbbffd4c2d4b1469c64d7d18a9da177e --- /dev/null +++ b/services/services/factory/i_muxer_engine.h @@ -0,0 +1,48 @@ +/* + * 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/muxer_client.cpp b/services/services/muxer/client/muxer_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f21f465d7022e3ce9bb594188af89f783091d2ee --- /dev/null +++ b/services/services/muxer/client/muxer_client.cpp @@ -0,0 +1,111 @@ +/* + * 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_client.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MuxerClient"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr MuxerClient::Create(const sptr &ipcProxy) +{ + std::shared_ptr muxerClient = std::make_shared(ipcProxy); + return muxerClient; +} + +MuxerClient::MuxerClient(const sptr &ipcProxy) + : muxerProxy_(ipcProxy) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +MuxerClient::~MuxerClient() +{ + std::lock_guard lock(mutex_); + if (muxerProxy_ != nullptr) { + (void)muxerProxy_->DestroyStub(); + muxerProxy_ = nullptr; + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void MuxerClient::AVCodecServerDied() +{ + std::lock_guard lock(mutex_); + muxerProxy_ = nullptr; +} + +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_->InitParameter(fd, format); +} + +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 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 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, trackDesc); +} + +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 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(muxerProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "Muxer Service does not exist"); + return muxerProxy_->WriteSampleBuffer(sampleBuffer, info); +} + +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/muxer_client.h b/services/services/muxer/client/muxer_client.h new file mode 100644 index 0000000000000000000000000000000000000000..251751fca328d98ef0c6a8f167681f23eae0a9b2 --- /dev/null +++ b/services/services/muxer/client/muxer_client.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 MUXER_CLIENT_H +#define MUXER_CLIENT_H + +#include +#include "i_muxer_service.h" +#include "i_standard_muxer_service.h" + +namespace OHOS { +namespace Media { +class MuxerClient : public IMuxerService, public NoCopyable { +public: + static std::shared_ptr Create(const sptr &ipcProxy); + explicit MuxerClient(const sptr &ipcProxy); + ~MuxerClient(); + + 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 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; + void Release() override; + + void AVCodecServerDied(); +private: + std::mutex mutex_; + sptr muxerProxy_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // MUXER_CLIENT_H \ No newline at end of file diff --git a/services/services/muxer/ipc/i_standard_muxer_service.h b/services/services/muxer/ipc/i_standard_muxer_service.h new file mode 100644 index 0000000000000000000000000000000000000000..41c7e112890b33b3bfb8c5697137de40f8d83b51 --- /dev/null +++ b/services/services/muxer/ipc/i_standard_muxer_service.h @@ -0,0 +1,53 @@ +/* + * 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_MUXER_SERVICE_H +#define I_STANDARD_MUXER_SERVICE_H + +#include "i_muxer_service.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace Media { +class IStandardMuxerService : public IRemoteBroker { +public: + 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 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; + virtual int32_t DestroyStub() = 0; + + enum MuxerServiceMsg { + INIT_PARAMETER = 0, + SET_LOCATION, + SET_ROTATION, + ADD_TRACK, + START, + WRITE_SAMPLE_BUFFER, + STOP, + RELEASE, + DESTROY, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardMuxerServiceq1a"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_MUXER_SERVICE_H \ No newline at end of file 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 0000000000000000000000000000000000000000..b238ecb17a083872b27522877e30587f28e18b0b --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_proxy.cpp @@ -0,0 +1,181 @@ +/* + * 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_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/muxer_service_proxy.h b/services/services/muxer/ipc/muxer_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..47e39e4a31018d913004db41dad353b37892244d --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_proxy.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 MUXER_SERVICE_PROXY_H +#define MUXER_SERVICE_PROXY_H + +#include "i_standard_muxer_service.h" + +namespace OHOS { +namespace Media { +class MuxerServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit MuxerServiceProxy(const sptr &impl); + virtual ~MuxerServiceProxy(); + + 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 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; + void Release() override; + int32_t DestroyStub() override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // MUXER_SERVICE_PROXY_H \ No newline at end of file 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 0000000000000000000000000000000000000000..97dbe0300df0db31724a7faa75e9ae95c53e19a2 --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_stub.cpp @@ -0,0 +1,228 @@ +/* + * 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_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/muxer_service_stub.h b/services/services/muxer/ipc/muxer_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..ddb5ac24a63be1f482146fc96ead85c9586408e6 --- /dev/null +++ b/services/services/muxer/ipc/muxer_service_stub.h @@ -0,0 +1,61 @@ +/* + * 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_SERVICE_STUB_H +#define MUXER_SERVICE_STUB_H + +#include "i_standard_muxer_service.h" +#include "muxer_server.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace Media { +class MuxerServiceStub : public IRemoteStub, public NoCopyable { +public: + static sptr Create(); + virtual ~MuxerServiceStub(); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + using MuxerStubFunc = int32_t(MuxerServiceStub::*)(MessageParcel &data, MessageParcel &reply); + + 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 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; + void Release() override; + int32_t DestroyStub() override; + int32_t DumpInfo(int32_t fd); + +private: + 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 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 Release(MessageParcel &data, MessageParcel &reply); + int32_t DestroyStub(MessageParcel &data, MessageParcel &reply); + + std::shared_ptr muxerServer_ {nullptr}; + std::map muxerFuncs_; +}; +} // namespace Media +} // namespace OHOS +#endif // MUXER_SERVICE_STUB_H \ 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 0000000000000000000000000000000000000000..3efac2818a3d67b7abacb4308901c4f13037e843 --- /dev/null +++ b/services/services/muxer/server/muxer_server.cpp @@ -0,0 +1,117 @@ +/* + * 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_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(); + 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/muxer_server.h b/services/services/muxer/server/muxer_server.h new file mode 100644 index 0000000000000000000000000000000000000000..6289e99864d09a723ac4f284091ae5c2f5998589 --- /dev/null +++ b/services/services/muxer/server/muxer_server.h @@ -0,0 +1,49 @@ +/* + * 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_SERVER_H +#define MUXER_SERVER_H + +#include +#include "i_muxer_service.h" +#include "i_muxer_engine.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class MuxerServer : public IMuxerService, public NoCopyable { +public: + static std::shared_ptr Create(); + MuxerServer(); + ~MuxerServer(); + + 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 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; + void Release() override; + int32_t DumpInfo(int32_t fd); + +private: + std::shared_ptr muxerEngine_ = nullptr; + int32_t appUid_ = 0; + int32_t appPid_ = 0; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/services/sa_avcodec/client/avcodec_client.cpp b/services/services/sa_avcodec/client/avcodec_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57b8b4f68d7110b295ca74967a84ad69a193bacc --- /dev/null +++ b/services/services/sa_avcodec/client/avcodec_client.cpp @@ -0,0 +1,317 @@ +/* + * 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 "avcodec_client.h" +#include "avcodec_xcollie.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#ifdef SUPPORT_DEMUXER +#include "i_standard_demuxer_service.h" +#endif +#ifdef SUPPORT_CODEC +#include "i_standard_codec_service.h" +#endif +#ifdef SUPPORT_CODECLIST +#include "i_standard_codeclist_service.h" +#endif + +#ifdef SUPPORT_SOURCE +#include "i_standard_source_service.h" +#endif + +#include "avcodec_errors.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecClient"}; +} + +namespace OHOS { +namespace Media { +static AVCodecClient avCodecClientInstance; +IAVCodecService &AVCodecServiceFactory::GetInstance() +{ + return avCodecClientInstance; +} + +AVCodecClient::AVCodecClient() noexcept +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecClient::~AVCodecClient() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +bool AVCodecClient::IsAlived() +{ + if (avCodecProxy_ == nullptr) { + avCodecProxy_ = GetAVCodecProxy(); + } + + return avCodecProxy_ != nullptr; +} +#ifdef SUPPORT_CODEC +std::shared_ptr AVCodecClient::CreateCodecService() +{ + std::lock_guard lock(mutex_); + if (!IsAlived()) { + AVCODEC_LOGE("av_codec service does not exist."); + return nullptr; + } + + sptr object = avCodecProxy_->GetSubSystemAbility( + IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_CODEC, listenerStub_->AsObject()); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "codec proxy object is nullptr."); + + sptr codecProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(codecProxy != nullptr, nullptr, "codec proxy is nullptr."); + + std::shared_ptr codecClient = CodecClient::Create(codecProxy); + CHECK_AND_RETURN_RET_LOG(codecClient != nullptr, nullptr, "failed to create codec client."); + + codecClientList_.push_back(codecClient); + return codecClient; +} + +int32_t AVCodecClient::DestroyCodecService(std::shared_ptr codecClient) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecClient != nullptr, AVCS_ERR_NO_MEMORY, "codec client is nullptr."); + codecClientList_.remove(codecClient); + return AVCS_ERR_OK; +} +#endif +#ifdef SUPPORT_CODECLIST +std::shared_ptr AVCodecClient::CreateCodecListService() +{ + std::lock_guard lock(mutex_); + if (!IsAlived()) { + AVCODEC_LOGE("av_codec service does not exist."); + return nullptr; + } + + sptr object = avCodecProxy_->GetSubSystemAbility( + IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_CODECLIST, listenerStub_->AsObject()); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "codeclist proxy object is nullptr."); + + sptr codecListProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(codecListProxy != nullptr, nullptr, "codeclist proxy is nullptr."); + + std::shared_ptr codecListClient = CodecListClient::Create(codecListProxy); + CHECK_AND_RETURN_RET_LOG(codecListClient != nullptr, nullptr, "failed to create codeclist client."); + + codecListClientList_.push_back(codecListClient); + return codecListClient; +} + +int32_t AVCodecClient::DestroyCodecListService(std::shared_ptr codecListClient) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(codecListClient != nullptr, AVCS_ERR_NO_MEMORY, "codeclist client is nullptr."); + codecListClientList_.remove(codecListClient); + return AVCS_ERR_OK; +} +#endif + +#ifdef SUPPORT_DEMUXER +std::shared_ptr AVCodecClient::CreateDemuxerService() +{ + std::lock_guard lock(mutex_); + if (!IsAlived()) { + AVCODEC_LOGE("av_codec service does not exist."); + return nullptr; + } + + sptr object = avCodecProxy_->GetSubSystemAbility( + IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_DEMUXER, listenerStub_->AsObject()); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "demuxer proxy object is nullptr."); + + sptr demuxerProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(demuxerProxy != nullptr, nullptr, "demuxer proxy is nullptr."); + + std::shared_ptr demuxerClient = DemuxerClient::Create(demuxerProxy); + CHECK_AND_RETURN_RET_LOG(demuxerClient != nullptr, nullptr, "failed to create demuxer client."); + + demuxerClientList_.push_back(demuxerClient); + return demuxerClient; +} + +int32_t AVCodecClient::DestroyDemuxerService(std::shared_ptr demuxerClient) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(demuxerClient != nullptr, AVCS_ERR_NO_MEMORY, "demuxer client is nullptr."); + demuxerClientList_.remove(demuxerClient); + return AVCS_ERR_OK; +} +#endif + +#ifdef SUPPORT_MUXER +std::shared_ptr AVCodecClient::CreateMuxerService() +{ + std::lock_guard lock(mutex_); + if (!IsAlived()) { + 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."); + + sptr muxerProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(muxerProxy != nullptr, nullptr, "muxer proxy is nullptr."); + + std::shared_ptr muxer = MuxerClient::Create(muxerProxy); + CHECK_AND_RETURN_RET_LOG(muxer != nullptr, nullptr, "failed to create muxer client."); + + muxerClientList_.push_back(muxer); + return muxer; +} + +int32_t AVCodecClient::DestroyMuxerService(std::shared_ptr muxer) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(muxer != nullptr, AVCS_ERR_NO_MEMORY, "input muxer is nullptr."); + muxerClientList_.remove(muxer); + return AVCS_ERR_OK; +} +#endif + +#ifdef SUPPORT_SOURCE +std::shared_ptr AVCodecClient::CreateSourceService() +{ + std::lock_guard lock(mutex_); + if (!IsAlived()) { + AVCODEC_LOGE("av_codec service does not exist."); + return nullptr; + } + + sptr object = avCodecProxy_->GetSubSystemAbility( + IStandardAVCodecService::AVCodecSystemAbility::AVCODEC_SOURCE, listenerStub_->AsObject()); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "source proxy object is nullptr."); + + sptr sourceProxy = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(sourceProxy != nullptr, nullptr, "source proxy is nullptr."); + + std::shared_ptr sourceClient = SourceClient::Create(sourceProxy); + CHECK_AND_RETURN_RET_LOG(sourceClient != nullptr, nullptr, "failed to create source client."); + + sourceClientList_.push_back(sourceClient); + return sourceClient; +} + +int32_t AVCodecClient::DestroySourceService(std::shared_ptr sourceClient) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceClient != nullptr, AVCS_ERR_NO_MEMORY, "source client is nullptr."); + sourceClientList_.remove(sourceClient); + return AVCS_ERR_OK; +} +#endif + +sptr AVCodecClient::GetAVCodecProxy() +{ + AVCODEC_LOGD("enter"); + sptr samgr = nullptr; + COLLIE_LISTEN(samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(), + "AVCodecClient::GetAVCodecProxy"); + CHECK_AND_RETURN_RET_LOG(samgr != nullptr, nullptr, "system ability manager is nullptr."); + + sptr object = nullptr; + COLLIE_LISTEN(object = samgr->GetSystemAbility(OHOS::AV_CODEC_SERVICE_ID), "AVCodecClient::GetAVCodecProxy"); + CHECK_AND_RETURN_RET_LOG(object != nullptr, nullptr, "avcodec object is nullptr."); + + avCodecProxy_ = iface_cast(object); + + CHECK_AND_RETURN_RET_LOG(avCodecProxy_ != nullptr, nullptr, "avcodec proxy is nullptr."); + + pid_t pid = 0; + deathRecipient_ = new (std::nothrow) AVCodecDeathRecipient(pid); + CHECK_AND_RETURN_RET_LOG(deathRecipient_ != nullptr, nullptr, "failed to new AVCodecDeathRecipient."); + + deathRecipient_->SetNotifyCb(std::bind(&AVCodecClient::AVCodecServerDied, std::placeholders::_1)); + bool result = object->AddDeathRecipient(deathRecipient_); + if (!result) { + AVCODEC_LOGE("failed to add deathRecipient"); + return nullptr; + } + + listenerStub_ = new (std::nothrow) AVCodecListenerStub(); + CHECK_AND_RETURN_RET_LOG(listenerStub_ != nullptr, nullptr, "failed to new AVCodecListenerStub"); + return avCodecProxy_; +} + +void AVCodecClient::AVCodecServerDied(pid_t pid) +{ + AVCODEC_LOGE("av_codec server is died, pid:%{public}d!", pid); + avCodecClientInstance.DoAVCodecServerDied(); +} + +void AVCodecClient::DoAVCodecServerDied() +{ + std::lock_guard lock(mutex_); + if (avCodecProxy_ != nullptr) { + (void)avCodecProxy_->AsObject()->RemoveDeathRecipient(deathRecipient_); + avCodecProxy_ = nullptr; + } + listenerStub_ = nullptr; + deathRecipient_ = nullptr; + +#ifdef SUPPORT_DEMUXER + for (auto &it : demuxerClientList_) { + auto demuxerClient = std::static_pointer_cast(it); + if (demuxerClient != nullptr) { + demuxerClient->AVCodecServerDied(); + } + } +#endif +#ifdef SUPPORT_CODEC + for (auto &it : codecClientList_) { + auto codecClient = std::static_pointer_cast(it); + if (codecClient != nullptr) { + codecClient->AVCodecServerDied(); + } + } +#endif +#ifdef SUPPORT_CODECLIST + for (auto &it : codecListClientList_) { + auto codecListClient = std::static_pointer_cast(it); + if (codecListClient != nullptr) { + codecListClient->AVCodecServerDied(); + } + } +#endif +#ifdef SUPPORT_MUXER + for (auto &it : muxerClientList_) { + auto muxer = std::static_pointer_cast(it); + if (muxer != nullptr) { + muxer->AVCodecServerDied(); + } + } +#endif +#ifdef SUPPORT_SOURCE + for (auto &it : sourceClientList_) { + auto sourceClient = std::static_pointer_cast(it); + if (sourceClient != nullptr) { + sourceClient->AVCodecServerDied(); + } + } +#endif +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/client/avcodec_client.h b/services/services/sa_avcodec/client/avcodec_client.h new file mode 100644 index 0000000000000000000000000000000000000000..ca22c9fcfeb00e4c986967ed6118f663cc0e5951 --- /dev/null +++ b/services/services/sa_avcodec/client/avcodec_client.h @@ -0,0 +1,106 @@ +/* + * 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 AVCODEC_CLIENT_H +#define AVCODEC_CLIENT_H + +#include "i_avcodec_service.h" +#include "avcodec_death_recipient.h" +#include "avcodec_listener_stub.h" +#include "i_standard_avcodec_service.h" +#ifdef SUPPORT_DEMUXER +#include "demuxer_client.h" +#endif + +#ifdef SUPPORT_MUXER +#include "muxer_client.h" +#endif + +#ifdef SUPPORT_CODEC +#include "codec_client.h" +#endif + +#ifdef SUPPORT_CODECLIST +#include "codeclist_client.h" +#endif + +#ifdef SUPPORT_SOURCE +#include "source_client.h" +#endif + +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecClient : public IAVCodecService, public NoCopyable { +public: + AVCodecClient() noexcept; + ~AVCodecClient(); + +#ifdef SUPPORT_DEMUXER + std::shared_ptr CreateDemuxerService() override; + int32_t DestroyDemuxerService(std::shared_ptr demuxer) override; +#endif + +#ifdef SUPPORT_MUXER + std::shared_ptr CreateMuxerService() override; + int32_t DestroyMuxerService(std::shared_ptr muxer) override; +#endif + +#ifdef SUPPORT_CODEC + std::shared_ptr CreateCodecService() override; + int32_t DestroyCodecService(std::shared_ptr codecClient) override; +#endif + +#ifdef SUPPORT_CODECLIST + std::shared_ptr CreateCodecListService() override; + int32_t DestroyCodecListService(std::shared_ptr codecListClient) override; +#endif + +#ifdef SUPPORT_SOURCE + std::shared_ptr CreateSourceService() override; + int32_t DestroySourceService(std::shared_ptr source) override; +#endif + +private: + sptr GetAVCodecProxy(); + bool IsAlived(); + static void AVCodecServerDied(pid_t pid); + void DoAVCodecServerDied(); + + sptr avCodecProxy_ = nullptr; + sptr listenerStub_ = nullptr; + sptr deathRecipient_ = nullptr; + +#ifdef SUPPORT_DEMUXER + std::list> demuxerClientList_; +#endif +#ifdef SUPPORT_MUXER + std::list> muxerClientList_; +#endif +#ifdef SUPPORT_CODEC + std::list> codecClientList_; +#endif +#ifdef SUPPORT_CODECLIST + std::list> codecListClientList_; +#endif +#ifdef SUPPORT_SOURCE + std::list> sourceClientList_; +#endif + + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_CLIENT_H diff --git a/services/services/sa_avcodec/client/avcodec_local.cpp b/services/services/sa_avcodec/client/avcodec_local.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8557c724770a921c6ef41c60d3c6476a3c617078 --- /dev/null +++ b/services/services/sa_avcodec/client/avcodec_local.cpp @@ -0,0 +1,39 @@ +/* + * 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 "avcodec_local.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "demuxer_server.h" + +namespace OHOS { +namespace Media { +IAVCodecService &AVCodecServiceFactory::GetInstance() +{ + static AVCodecLocal instance; + return instance; +} + +std::shared_ptr AVCodecLocal::CreateDemuxerService() +{ + return AVDemuxerServer::Create(); +} + +int32_t AVCodecLocal::DestroyDemuxerService(std::shared_ptr demuxer) +{ + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/client/avcodec_local.h b/services/services/sa_avcodec/client/avcodec_local.h new file mode 100644 index 0000000000000000000000000000000000000000..3dc83b4bacda6779e07007ecbde69351a8330fb6 --- /dev/null +++ b/services/services/sa_avcodec/client/avcodec_local.h @@ -0,0 +1,34 @@ +/* + * 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 AVCODEC_LOCAL_H +#define AVCODEC_LOCAL_H + +#include "i_avcodec_service.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecLocal : public IAVCodecService, public NoCopyable { +public: + AVCodecLocal() = default; + ~AVCodecLocal() = default; + + std::shared_ptr CreateDemuxerService() override; + int32_t DestroyDemuxerService(std::shared_ptr demuxer) override; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LOCAL_H diff --git a/services/services/sa_avcodec/ipc/avcodec_death_recipient.h b/services/services/sa_avcodec/ipc/avcodec_death_recipient.h new file mode 100644 index 0000000000000000000000000000000000000000..9491ef66ca96517e28f91eb89d3d9bf439d09732 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_death_recipient.h @@ -0,0 +1,48 @@ +/* + * 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 AVCODEC_DEATH_RECIPIENT_H +#define AVCODEC_DEATH_RECIPIENT_H + +#include "iremote_object.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecDeathRecipient : public IRemoteObject::DeathRecipient, public NoCopyable { +public: + explicit AVCodecDeathRecipient(pid_t pid) : pid_(pid) {} + virtual ~AVCodecDeathRecipient() = default; + + void OnRemoteDied(const wptr &remote) override + { + (void)remote; + if (diedCb_ != nullptr) { + diedCb_(pid_); + } + } + using NotifyCbFunc = std::function; + void SetNotifyCb(NotifyCbFunc func) + { + diedCb_ = func; + } + +private: + pid_t pid_ = 0; + NotifyCbFunc diedCb_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_DEATH_RECIPIENT_H diff --git a/services/services/sa_avcodec/ipc/avcodec_listener_proxy.cpp b/services/services/sa_avcodec/ipc/avcodec_listener_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7c5c01099aa6894b09697ad6181d6707752f5fe --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_listener_proxy.cpp @@ -0,0 +1,35 @@ +/* + * 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 "avcodec_listener_proxy.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecListenerProxy"}; +} + +namespace OHOS { +namespace Media { +AVCodecListenerProxy::AVCodecListenerProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} +AVCodecListenerProxy::~AVCodecListenerProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/avcodec_listener_proxy.h b/services/services/sa_avcodec/ipc/avcodec_listener_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..cbbf83ea1ad44044d14f8a5640172b88e7bea0c4 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_listener_proxy.h @@ -0,0 +1,34 @@ +/* + * 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 AVCODEC_LISTENER_PROXY_H +#define AVCODEC_LISTENER_PROXY_H + +#include "i_standard_avcodec_listener.h" +#include "avcodec_death_recipient.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecListenerProxy : public IRemoteProxy, public NoCopyable { +public: + explicit AVCodecListenerProxy(const sptr &impl); + virtual ~AVCodecListenerProxy(); + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LISTENER_PROXY_H diff --git a/services/services/sa_avcodec/ipc/avcodec_listener_stub.cpp b/services/services/sa_avcodec/ipc/avcodec_listener_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a86cf18efc679704a4c042853b6e5c459f38b08b --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_listener_stub.cpp @@ -0,0 +1,35 @@ +/* + * 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 "avcodec_listener_stub.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecListenerStub"}; +} + +namespace OHOS { +namespace Media { +AVCodecListenerStub::AVCodecListenerStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecListenerStub::~AVCodecListenerStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/avcodec_listener_stub.h b/services/services/sa_avcodec/ipc/avcodec_listener_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..e40e875d7a5d89e71826fe04c110d3e971ce92c5 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_listener_stub.h @@ -0,0 +1,30 @@ +/* + * 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 AVCODEC_LISTENER_STUB_H +#define AVCODEC_LISTENER_STUB_H + +#include "i_standard_avcodec_listener.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecListenerStub : public IRemoteStub, public NoCopyable { +public: + AVCodecListenerStub(); + virtual ~AVCodecListenerStub(); +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_LISTENER_STUB_H diff --git a/services/services/sa_avcodec/ipc/avcodec_parcel.cpp b/services/services/sa_avcodec/ipc/avcodec_parcel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07270ae76292d1031904fae3fb702f0bef803af0 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_parcel.cpp @@ -0,0 +1,104 @@ +/* + * 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 "avcodec_parcel.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecParcel"}; +} + +namespace OHOS { +namespace Media { +bool AVCodecParcel::Marshalling(MessageParcel &parcel, const Format &format) +{ + auto dataMap = format.GetFormatMap(); + (void)parcel.WriteUint32(dataMap.size()); + for (auto it = dataMap.begin(); it != dataMap.end(); ++it) { + (void)parcel.WriteString(it->first); + (void)parcel.WriteUint32(it->second.type); + switch (it->second.type) { + case FORMAT_TYPE_INT32: + (void)parcel.WriteInt32(it->second.val.int32Val); + break; + case FORMAT_TYPE_INT64: + (void)parcel.WriteInt64(it->second.val.int64Val); + break; + case FORMAT_TYPE_FLOAT: + (void)parcel.WriteFloat(it->second.val.floatVal); + break; + case FORMAT_TYPE_DOUBLE: + (void)parcel.WriteDouble(it->second.val.doubleVal); + break; + case FORMAT_TYPE_STRING: + (void)parcel.WriteString(it->second.stringVal); + break; + case FORMAT_TYPE_ADDR: + (void)parcel.WriteInt32(static_cast(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()); + return false; + } + AVCODEC_LOGD("success to Marshalling Key: %{public}s", it->first.c_str()); + } + + return true; +} + +bool AVCodecParcel::Unmarshalling(MessageParcel &parcel, Format &format) +{ + uint32_t size = parcel.ReadUint32(); + for (uint32_t index = 0; index < size; index++) { + std::string key = parcel.ReadString(); + uint32_t valType = parcel.ReadUint32(); + switch (valType) { + case FORMAT_TYPE_INT32: + (void)format.PutIntValue(key, parcel.ReadInt32()); + break; + case FORMAT_TYPE_INT64: + (void)format.PutLongValue(key, parcel.ReadInt64()); + break; + case FORMAT_TYPE_FLOAT: + (void)format.PutFloatValue(key, parcel.ReadFloat()); + break; + case FORMAT_TYPE_DOUBLE: + (void)format.PutDoubleValue(key, parcel.ReadDouble()); + break; + case FORMAT_TYPE_STRING: + (void)format.PutStringValue(key, parcel.ReadString()); + break; + case FORMAT_TYPE_ADDR: { + auto addrSize = parcel.ReadInt32(); + auto addr = parcel.ReadUnpadBuffer(static_cast(addrSize)); + if (addr == nullptr) { + AVCODEC_LOGE("fail to ReadBuffer Key: %{public}s", key.c_str()); + return false; + } + (void)format.PutBuffer(key, addr, static_cast(addrSize)); + break; + } + default: + AVCODEC_LOGE("fail to Unmarshalling Key: %{public}s", key.c_str()); + return false; + } + AVCODEC_LOGD("success to Unmarshalling Key: %{public}s", key.c_str()); + } + + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/avcodec_parcel.h b/services/services/sa_avcodec/ipc/avcodec_parcel.h new file mode 100644 index 0000000000000000000000000000000000000000..d70a0b2a9f5e34de0d8cac4b5bee3e46c3adbf8d --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_parcel.h @@ -0,0 +1,33 @@ +/* + * 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 AVCODEC_PARCEL_H +#define AVCODEC_PARCEL_H + +#include "format.h" +#include "message_parcel.h" + +namespace OHOS { +namespace Media { +class AVCodecParcel { +public: + AVCodecParcel() = delete; + ~AVCodecParcel() = delete; + static bool Marshalling(MessageParcel &parcel, const Format &format); + static bool Unmarshalling(MessageParcel &parcel, Format &format); +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_PARCEL_H diff --git a/services/services/sa_avcodec/ipc/avcodec_service_proxy.cpp b/services/services/sa_avcodec/ipc/avcodec_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa2c38e3e29606967ae0a8338b23e8181ab6a1ba --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_service_proxy.cpp @@ -0,0 +1,63 @@ +/* + * 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 "avcodec_service_proxy.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecServiceProxy"}; +} + +namespace OHOS { +namespace Media { +AVCodecServiceProxy::AVCodecServiceProxy(const sptr &impl) : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecServiceProxy::~AVCodecServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +sptr AVCodecServiceProxy::GetSubSystemAbility(IStandardAVCodecService::AVCodecSystemAbility subSystemId, + const sptr &listener) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (listener == nullptr) { + AVCODEC_LOGE("listener is nullptr"); + return nullptr; + } + + if (!data.WriteInterfaceToken(AVCodecServiceProxy::GetDescriptor())) { + AVCODEC_LOGE("Failed to write descriptor"); + return nullptr; + } + + (void)data.WriteInt32(static_cast(subSystemId)); + (void)data.WriteRemoteObject(listener); + int error = Remote()->SendRequest(AVCodecServiceMsg::GET_SUBSYSTEM, data, reply, option); + if (error != AVCS_ERR_OK) { + AVCODEC_LOGE("Create av_codec proxy failed, error: %{public}d", error); + return nullptr; + } + + return reply.ReadRemoteObject(); +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/avcodec_service_proxy.h b/services/services/sa_avcodec/ipc/avcodec_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..42c32a847b30d96186462e49bb9e607839bfec55 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_service_proxy.h @@ -0,0 +1,36 @@ +/* + * 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 AVCODEC_SERVICE_PROXY_H +#define AVCODEC_SERVICE_PROXY_H + +#include "i_standard_avcodec_service.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit AVCodecServiceProxy(const sptr &impl); + virtual ~AVCodecServiceProxy(); + + sptr GetSubSystemAbility(IStandardAVCodecService::AVCodecSystemAbility subSystemId, + const sptr &listener) override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_SERVICE_PROXY_H diff --git a/services/services/sa_avcodec/ipc/avcodec_service_stub.cpp b/services/services/sa_avcodec/ipc/avcodec_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b64699039d3422ecaad7d908af62fcd29f87771 --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_service_stub.cpp @@ -0,0 +1,149 @@ +/* + * 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 "avcodec_service_stub.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" +#include "avcodec_server_manager.h" +#include "avcodec_xcollie.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecServiceStub"}; +} + +namespace OHOS { +namespace Media { +AVCodecServiceStub::AVCodecServiceStub() +{ + deathRecipientMap_.clear(); + avCodecListenerMap_.clear(); + InitStub(); + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecServiceStub::~AVCodecServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void AVCodecServiceStub::InitStub() +{ + avCodecFuncs_[GET_SUBSYSTEM] = &AVCodecServiceStub::GetSystemAbility; +} + +int32_t AVCodecServiceStub::DestroyStubForPid(pid_t pid) +{ + { + std::lock_guard lock(mutex_); + sptr deathRecipient = nullptr; + sptr avCodecListener = nullptr; + + auto itDeath = deathRecipientMap_.find(pid); + if (itDeath != deathRecipientMap_.end()) { + deathRecipient = itDeath->second; + + if (deathRecipient != nullptr) { + deathRecipient->SetNotifyCb(nullptr); + } + + (void)deathRecipientMap_.erase(itDeath); + } + + auto itListener = avCodecListenerMap_.find(pid); + if (itListener != avCodecListenerMap_.end()) { + avCodecListener = itListener->second; + + if (avCodecListener != nullptr && avCodecListener->AsObject() != nullptr && deathRecipient != nullptr) { + (void)avCodecListener->AsObject()->RemoveDeathRecipient(deathRecipient); + } + + (void)avCodecListenerMap_.erase(itListener); + } + } + + AVCodecServerManager::GetInstance().DestroyStubObjectForPid(pid); + return AVCS_ERR_OK; +} + +int AVCodecServiceStub::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 (AVCodecServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = avCodecFuncs_.find(code); + if (itFunc != avCodecFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = -1; + COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), + "AVCodecServiceStub::OnRemoteRequest"); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Calling memberFunc is failed."); + } + return AVCS_ERR_OK; + } + } + AVCODEC_LOGW("avCodecFuncs_: no member func supporting, applying default process"); + + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} + +void AVCodecServiceStub::ClientDied(pid_t pid) +{ + AVCODEC_LOGE("client is dead, pid:%{public}d", pid); + (void)DestroyStubForPid(pid); +} + +int32_t AVCodecServiceStub::SetDeathListener(const sptr &object) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(object != nullptr, AVCS_ERR_NO_MEMORY, "set listener object is nullptr"); + + sptr avCodecListener = iface_cast(object); + CHECK_AND_RETURN_RET_LOG(avCodecListener != nullptr, AVCS_ERR_NO_MEMORY, + "failed to convert IStandardAVCodecListener"); + + pid_t pid = IPCSkeleton::GetCallingPid(); + sptr deathRecipient = new(std::nothrow) AVCodecDeathRecipient(pid); + CHECK_AND_RETURN_RET_LOG(deathRecipient != nullptr, AVCS_ERR_NO_MEMORY, "failed to new AVCodecDeathRecipient"); + + deathRecipient->SetNotifyCb(std::bind(&AVCodecServiceStub::ClientDied, this, std::placeholders::_1)); + + if (avCodecListener->AsObject() != nullptr) { + (void)avCodecListener->AsObject()->AddDeathRecipient(deathRecipient); + } + + AVCODEC_LOGD("client pid pid:%{public}d", pid); + avCodecListenerMap_[pid] = avCodecListener; + deathRecipientMap_[pid] = deathRecipient; + return AVCS_ERR_OK; +} + +int32_t AVCodecServiceStub::GetSystemAbility(MessageParcel &data, MessageParcel &reply) +{ + AVCodecSystemAbility id = static_cast(data.ReadInt32()); + sptr listenerObj = data.ReadRemoteObject(); + + COLLIE_LISTEN((void)reply.WriteRemoteObject(GetSubSystemAbility(id, listenerObj)), + "AVCodecServiceStub::GetSystemAbility"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/avcodec_service_stub.h b/services/services/sa_avcodec/ipc/avcodec_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..d97f4572d504f891f7c6e4d5d7e0ba3c2fe34e2d --- /dev/null +++ b/services/services/sa_avcodec/ipc/avcodec_service_stub.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 AVCODEC_SERVICE_STUB_H +#define AVCODEC_SERVICE_STUB_H + +#include +#include "i_standard_avcodec_service.h" +#include "i_standard_avcodec_listener.h" +#include "avcodec_death_recipient.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecServiceStub : public IRemoteStub, public NoCopyable { +public: + AVCodecServiceStub(); + virtual ~AVCodecServiceStub(); + + using AVCodecStubFunc = int32_t(AVCodecServiceStub::*)(MessageParcel &data, MessageParcel &reply); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +protected: + int32_t SetDeathListener(const sptr &object); + +private: + void InitStub(); + int32_t GetSystemAbility(MessageParcel &data, MessageParcel &reply); + void ClientDied(pid_t pid); + int32_t DestroyStubForPid(pid_t pid); + + std::map> deathRecipientMap_; + std::map> avCodecListenerMap_; + std::map avCodecFuncs_; + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_SERVICE_STUB_H diff --git a/services/services/sa_avcodec/ipc/codeclist_parcel.cpp b/services/services/sa_avcodec/ipc/codeclist_parcel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef795d710fdf3242fec99de301ce722ef133324b --- /dev/null +++ b/services/services/sa_avcodec/ipc/codeclist_parcel.cpp @@ -0,0 +1,157 @@ +/* + * 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 "codeclist_parcel.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "CodecListParcel"}; +} + +namespace OHOS { +namespace Media { +bool CodecListParcel::Marshalling(MessageParcel &parcel, CapabilityData &capabilityData) +{ + (void)parcel.WriteString(capabilityData.codecName); + (void)parcel.WriteString(capabilityData.mimeType); + (void)parcel.WriteBool(capabilityData.isVendor); + (void)parcel.WriteInt32(capabilityData.codecType); + (void)parcel.WriteInt32(capabilityData.maxInstance); + (void)parcel.WriteInt32(capabilityData.bitrate.minVal); + (void)parcel.WriteInt32(capabilityData.bitrate.maxVal); + (void)parcel.WriteInt32(capabilityData.channels.minVal); + (void)parcel.WriteInt32(capabilityData.channels.maxVal); + (void)parcel.WriteInt32(capabilityData.complexity.minVal); + (void)parcel.WriteInt32(capabilityData.complexity.maxVal); + (void)parcel.WriteInt32(capabilityData.alignment.width); + (void)parcel.WriteInt32(capabilityData.alignment.height); + (void)parcel.WriteInt32(capabilityData.width.minVal); + (void)parcel.WriteInt32(capabilityData.width.maxVal); + (void)parcel.WriteInt32(capabilityData.height.minVal); + (void)parcel.WriteInt32(capabilityData.height.maxVal); + (void)parcel.WriteInt32(capabilityData.frameRate.minVal); + (void)parcel.WriteInt32(capabilityData.frameRate.maxVal); + (void)parcel.WriteInt32(capabilityData.encodeQuality.minVal); + (void)parcel.WriteInt32(capabilityData.encodeQuality.maxVal); + (void)parcel.WriteInt32(capabilityData.blockPerFrame.minVal); + (void)parcel.WriteInt32(capabilityData.blockPerFrame.maxVal); + (void)parcel.WriteInt32(capabilityData.blockPerSecond.minVal); + (void)parcel.WriteInt32(capabilityData.blockPerSecond.maxVal); + (void)parcel.WriteInt32(capabilityData.blockSize.width); + (void)parcel.WriteInt32(capabilityData.blockSize.height); + (void)parcel.WriteInt32Vector(capabilityData.sampleRate); + (void)parcel.WriteInt32Vector(capabilityData.pixFormat); + (void)parcel.WriteInt32Vector(capabilityData.bitDepth); + (void)parcel.WriteInt32Vector(capabilityData.profiles); + (void)parcel.WriteInt32Vector(capabilityData.bitrateMode); + (void)Marshalling(parcel, capabilityData.measuredFrameRate); + (void)Marshalling(parcel, capabilityData.profileLevelsMap); + AVCODEC_LOGD("success to Marshalling capabilityDataArray"); + + return true; +} + +bool CodecListParcel::Marshalling(MessageParcel &parcel, const std::map &mapSizeToRange) +{ + parcel.WriteUint32(mapSizeToRange.size()); + for (auto it = mapSizeToRange.begin(); it != mapSizeToRange.end(); it++) { + (void)parcel.WriteInt32(it->first.width); + (void)parcel.WriteInt32(it->first.height); + (void)parcel.WriteInt32(it->second.minVal); + (void)parcel.WriteInt32(it->second.maxVal); + } + return true; +} + +bool CodecListParcel::Marshalling(MessageParcel &parcel, const std::map> &mapIntToVec) +{ + parcel.WriteUint32(mapIntToVec.size()); + for (auto it = mapIntToVec.begin(); it != mapIntToVec.end(); it++) { + (void)parcel.WriteInt32(it->first); + (void)parcel.WriteInt32Vector(it->second); + } + return true; +} + +bool CodecListParcel::Unmarshalling(MessageParcel &parcel, CapabilityData &capabilityData) +{ + capabilityData.codecName = parcel.ReadString(); + capabilityData.mimeType = parcel.ReadString(); + capabilityData.isVendor = parcel.ReadBool(); + capabilityData.codecType = parcel.ReadInt32(); + capabilityData.maxInstance = parcel.ReadInt32(); + capabilityData.bitrate.minVal = parcel.ReadInt32(); + capabilityData.bitrate.maxVal = parcel.ReadInt32(); + capabilityData.channels.minVal = parcel.ReadInt32(); + capabilityData.channels.maxVal = parcel.ReadInt32(); + capabilityData.complexity.minVal = parcel.ReadInt32(); + capabilityData.complexity.maxVal = parcel.ReadInt32(); + capabilityData.alignment.width = parcel.ReadInt32(); + capabilityData.alignment.height = parcel.ReadInt32(); + capabilityData.width.minVal = parcel.ReadInt32(); + capabilityData.width.maxVal = parcel.ReadInt32(); + capabilityData.height.minVal = parcel.ReadInt32(); + capabilityData.height.maxVal = parcel.ReadInt32(); + capabilityData.frameRate.minVal = parcel.ReadInt32(); + capabilityData.frameRate.maxVal = parcel.ReadInt32(); + capabilityData.encodeQuality.minVal = parcel.ReadInt32(); + capabilityData.encodeQuality.maxVal = parcel.ReadInt32(); + capabilityData.blockPerFrame.minVal = parcel.ReadInt32(); + capabilityData.blockPerFrame.maxVal = parcel.ReadInt32(); + capabilityData.blockPerSecond.minVal = parcel.ReadInt32(); + capabilityData.blockPerSecond.maxVal = parcel.ReadInt32(); + capabilityData.blockSize.width = parcel.ReadInt32(); + capabilityData.blockSize.height = parcel.ReadInt32(); + parcel.ReadInt32Vector(&capabilityData.sampleRate); + parcel.ReadInt32Vector(&capabilityData.pixFormat); + parcel.ReadInt32Vector(&capabilityData.bitDepth); + parcel.ReadInt32Vector(&capabilityData.profiles); + parcel.ReadInt32Vector(&capabilityData.bitrateMode); + Unmarshalling(parcel, capabilityData.measuredFrameRate); + Unmarshalling(parcel, capabilityData.profileLevelsMap); + AVCODEC_LOGD("success to Unmarshalling capabilityDataArray"); + + return true; +} + +bool CodecListParcel::Unmarshalling(MessageParcel &parcel, std::map &mapSizeToRange) +{ + uint32_t size = parcel.ReadUint32(); + for (uint32_t index = 0; index < size; index++) { + ImgSize key; + Range values; + key.width = parcel.ReadInt32(); + key.height = parcel.ReadInt32(); + values.minVal = parcel.ReadInt32(); + values.maxVal = parcel.ReadInt32(); + mapSizeToRange.insert(std::make_pair(key, values)); + } + return true; +} + +bool CodecListParcel::Unmarshalling(MessageParcel &parcel, std::map> &mapIntToVec) +{ + uint32_t size = parcel.ReadUint32(); + for (uint32_t index = 0; index < size; index++) { + int32_t key; + std::vector values; + key = parcel.ReadInt32(); + parcel.ReadInt32Vector(&values); + mapIntToVec.insert(std::make_pair(key, values)); + } + return true; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/ipc/codeclist_parcel.h b/services/services/sa_avcodec/ipc/codeclist_parcel.h new file mode 100644 index 0000000000000000000000000000000000000000..d2905a4cfd3f2ddc4067786a67bc5ab47ab85907 --- /dev/null +++ b/services/services/sa_avcodec/ipc/codeclist_parcel.h @@ -0,0 +1,40 @@ +/* + * 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 AVCODECLIST_PARCEL_H +#define AVCODECLIST_PARCEL_H + +#include +#include "message_parcel.h" +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +class CodecListParcel { +public: + CodecListParcel() = delete; + ~CodecListParcel() = delete; + + static bool Marshalling(MessageParcel &parcel, CapabilityData &capabilityData); + static bool Marshalling(MessageParcel &parcel, const std::map &mapSizeToRange); + static bool Marshalling(MessageParcel &parcel, const std::map> &mapIntToVec); + + static bool Unmarshalling(MessageParcel &parcel, CapabilityData &capabilityData); + static bool Unmarshalling(MessageParcel &parcel, std::map &mapSizeToRange); + static bool Unmarshalling(MessageParcel &parcel, std::map> &mapIntToVec); +}; +} // namespace Media +} // namespace OHOS +#endif // MEDIA_PARCEL_H diff --git a/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h b/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h new file mode 100644 index 0000000000000000000000000000000000000000..4368b6404124ee5b136253e0f25106330cb884cf --- /dev/null +++ b/services/services/sa_avcodec/ipc/i_standard_avcodec_listener.h @@ -0,0 +1,33 @@ +/* + * 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 + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace Media { +class IStandardAVCodecListener : public IRemoteBroker { +public: + virtual ~IStandardAVCodecListener() = default; + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardAVCodecListener"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_AVCODEC_LISTENER_H diff --git a/services/services/sa_avcodec/ipc/i_standard_avcodec_service.h b/services/services/sa_avcodec/ipc/i_standard_avcodec_service.h new file mode 100644 index 0000000000000000000000000000000000000000..a7a80c6d2e93103648f4295966a3452ae09e7135 --- /dev/null +++ b/services/services/sa_avcodec/ipc/i_standard_avcodec_service.h @@ -0,0 +1,52 @@ +/* + * 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_SERVICE_H +#define I_STANDARD_AVCODEC_SERVICE_H + +#include "ipc_types.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace Media { +class IStandardAVCodecService : public IRemoteBroker { +public: + /** + * sub system ability ID + */ + enum AVCodecSystemAbility : int32_t { + AVCODEC_DEMUXER = 0, + AVCODEC_MUXER, + AVCODEC_CODECLIST, + AVCODEC_CODEC, + AVCODEC_SOURCE + }; + + virtual sptr GetSubSystemAbility(IStandardAVCodecService::AVCodecSystemAbility subSystemId, + const sptr &listener) = 0; + + /** + * IPC code ID + */ + enum AVCodecServiceMsg : int32_t { + GET_SUBSYSTEM = 0, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardAVCodecService"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_STANDARD_AVCODEC_SERVICE_H diff --git a/services/services/sa_avcodec/server/avcodec_server.cpp b/services/services/sa_avcodec/server/avcodec_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..add45442ee1d8219a1e081d304bd9973e8726091 --- /dev/null +++ b/services/services/sa_avcodec/server/avcodec_server.cpp @@ -0,0 +1,112 @@ +/* + * 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 "avcodec_server.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_server_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecServer"}; +} + +namespace OHOS { +namespace Media { +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)); +} + +AVCodecServer::~AVCodecServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void AVCodecServer::OnDump() +{ + AVCODEC_LOGD("AVCodecServer OnDump"); +} + +void AVCodecServer::OnStart() +{ + AVCODEC_LOGD("AVCodecServer OnStart"); + bool res = Publish(this); + if (res) { + AVCODEC_LOGD("AVCodecServer OnStart res=%{public}d", res); + } +} + +void AVCodecServer::OnStop() +{ + AVCODEC_LOGD("AVCodecServer OnStop"); +} + +sptr AVCodecServer::GetSubSystemAbility(IStandardAVCodecService::AVCodecSystemAbility subSystemId, + const sptr &listener) +{ + int32_t ret = AVCodecServiceStub::SetDeathListener(listener); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "failed set death listener"); + + switch (subSystemId) { +#ifdef SUPPORT_CODECLIST + case AVCodecSystemAbility::AVCODEC_CODECLIST: { + return AVCodecServerManager::GetInstance().CreateStubObject(AVCodecServerManager::CODECLIST); + } +#endif +#ifdef SUPPORT_CODEC + case AVCodecSystemAbility::AVCODEC_CODEC: { + return AVCodecServerManager::GetInstance().CreateStubObject(AVCodecServerManager::CODEC); + } +#endif +#ifdef SUPPORT_MUXER + case AVCodecSystemAbility::AVCODEC_MUXER: { + return AVCodecServerManager::GetInstance().CreateStubObject(AVCodecServerManager::MUXER); + } +#endif +#ifdef SUPPORT_DEMUXER + case AVCodecSystemAbility::AVCODEC_DEMUXER: { + return AVCodecServerManager::GetInstance().CreateStubObject(AVCodecServerManager::DEMUXER); + } +#endif +#ifdef SUPPORT_SOURCE + case AVCodecSystemAbility::AVCODEC_SOURCE: { + return AVCodecServerManager::GetInstance().CreateStubObject(AVCodecServerManager::SOURCE); + } +#endif + default: { + AVCODEC_LOGE("subSystemId is invalid"); + return nullptr; + } + } +} + +int32_t AVCodecServer::Dump(int32_t fd, const std::vector &args) +{ + if (fd <= 0) { + AVCODEC_LOGW("Failed to check fd"); + return OHOS::INVALID_OPERATION; + } + if (AVCodecServerManager::GetInstance().Dump(fd, args) != OHOS::NO_ERROR) { + AVCODEC_LOGW("Failed to call AVCodecServerManager::Dump"); + return OHOS::INVALID_OPERATION; + } + + return OHOS::NO_ERROR; +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/server/avcodec_server_manager.cpp b/services/services/sa_avcodec/server/avcodec_server_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..58026981b92ed29ca9c983dcb2209e56a69d2238 --- /dev/null +++ b/services/services/sa_avcodec/server/avcodec_server_manager.cpp @@ -0,0 +1,561 @@ +/* + * 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 "avcodec_server_manager.h" +#include +#include +#include +#include "avcodec_dfx.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_log_dump.h" +#include "avcodec_xcollie.h" +#include "avcodec_dump_utils.h" +#ifdef SUPPORT_CODEC +#include "codec_service_stub.h" +#endif +#ifdef SUPPORT_CODECLIST +#include "codeclist_service_stub.h" +#endif +#ifdef SUPPORT_DEMUXER +#include "demuxer_service_stub.h" +#endif +#ifdef SUPPORT_MUXER +#include "muxer_service_stub.h" +#endif +#ifdef SUPPORT_SOURCE +#include "source_service_stub.h" +#endif + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecServerManager"}; + constexpr uint32_t DUMP_MENU_INDEX = 0x01000000; + constexpr uint32_t DUMP_INSTANCE_INDEX = 0x01010000; + constexpr uint32_t DUMP_PID_INDEX = 0x01010100; + constexpr uint32_t DUMP_UID_INDEX = 0x01010200; + constexpr uint32_t DUMP_OFFSET_8 = 8; + + const std::vector SA_DUMP_MENU_DUMP_TABLE = { + "all", + "codec", + "muxer", + "demuxer", + "source", + }; +} + + +namespace OHOS { +namespace Media { +constexpr uint32_t SERVER_MAX_NUMBER = 16; +AVCodecServerManager &AVCodecServerManager::GetInstance() +{ + static AVCodecServerManager instance; + return instance; +} + +int32_t WriteInfo(int32_t fd, std::string &dumpString, std::vector dumpers, bool needDetail) +{ + int32_t i = 0; + for (auto iter : dumpers) { + AVCodecDumpControler dumpControler; + dumpControler.AddInfo(DUMP_INSTANCE_INDEX, std::string("Instance_") + std::to_string(i++) + "_Info"); + dumpControler.AddInfo(DUMP_PID_INDEX, "PID", std::to_string(iter.pid_)); + dumpControler.AddInfo(DUMP_UID_INDEX, "UID", std::to_string(iter.uid_)); + dumpControler.GetDumpString(dumpString); + if (fd != -1) { + write(fd, dumpString.c_str(), dumpString.size()); + dumpString.clear(); + } + + if (needDetail && iter.entry_(fd) != AVCS_ERR_OK) { + return OHOS::INVALID_OPERATION; + } else if (fd != -1) { + write(fd, "\n", 1); + } + } + if (fd != -1) { + write(fd, dumpString.c_str(), dumpString.size()); + } + dumpString.clear(); + return OHOS::NO_ERROR; +} + +int32_t AVCodecServerManager::Dump(int32_t fd, const std::vector &args) +{ + std::string dumpString; + std::unordered_set argSets; + for (decltype(args.size()) index = 0; index < args.size(); ++index) { + argSets.insert(args[index]); + } + bool dumpAllFlag = argSets.find(u"all") != argSets.end(); + int32_t ret = OHOS::NO_ERROR; + +#ifdef SUPPORT_CODEC + dumpString += "[Codec_Server]\n"; + bool dumpCodecFlag = (argSets.find(u"codec") != argSets.end()) | dumpAllFlag; + ret = WriteInfo(fd, dumpString, dumperTbl_[StubType::CODEC], dumpCodecFlag); + CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION, + "Failed to write codec server information"); +#endif + +#ifdef SUPPORT_MUXER + dumpString += "[Muxer_Server]\n"; + bool dumpMuxerFlag = (argSets.find(u"muxer") != argSets.end()) | dumpAllFlag; + ret = WriteInfo(fd, dumpString, dumperTbl_[StubType::MUXER], dumpMuxerFlag); + CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION, + "Failed to write muxer server information"); +#endif + +#ifdef SUPPORT_DEMUXER + dumpString += "[Demuxer_Server]\n"; + bool dumpDemuxerFlag = (argSets.find(u"demuxer") != argSets.end()) | dumpAllFlag; + ret = WriteInfo(fd, dumpString, dumperTbl_[StubType::DEMUXER], dumpDemuxerFlag); + CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION, + "Failed to write demuxer server information"); +#endif + +#ifdef SUPPORT_SOURCE + dumpString += "[Source_Server]\n"; + bool dumpSourceFlag = (argSets.find(u"source") != argSets.end()) | dumpAllFlag; + ret = WriteInfo(fd, dumpString, dumperTbl_[StubType::SOURCE], dumpSourceFlag); + CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION, + "Failed to write source server information"); +#endif + + ret = AVCodecXCollie::GetInstance().Dump(fd) != OHOS::NO_ERROR; + CHECK_AND_RETURN_RET_LOG(ret == OHOS::NO_ERROR, OHOS::INVALID_OPERATION, + "Failed to write xcollie dump information"); + + if (argSets.empty() || + argSets.find(u"h") != argSets.end() || + argSets.find(u"help") != argSets.end()) { + PrintDumpMenu(fd); + } + + return OHOS::NO_ERROR; +} + +AVCodecServerManager::AVCodecServerManager() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +AVCodecServerManager::~AVCodecServerManager() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +sptr AVCodecServerManager::CreateStubObject(StubType type) +{ + std::lock_guard lock(mutex_); + switch (type) { +#ifdef SUPPORT_CODECLIST + case CODECLIST: { + return CreateCodecListStubObject(); + } +#endif +#ifdef SUPPORT_CODEC + case CODEC: { + return CreateCodecStubObject(); + } +#endif +#ifdef SUPPORT_MUXER + case MUXER: { + return CreateMuxerStubObject(); + } +#endif +#ifdef SUPPORT_DEMUXER + case DEMUXER: { + return CreateDemuxerStubObject(); + } +#endif +#ifdef SUPPORT_SOURCE + case SOURCE: { + return CreateSourceStubObject(); + } +#endif + default: { + AVCODEC_LOGE("default case, av_codec server manager failed"); + return nullptr; + } + } +} + +#ifdef SUPPORT_CODECLIST +sptr AVCodecServerManager::CreateCodecListStubObject() +{ + if (codecListStubMap_.size() >= SERVER_MAX_NUMBER) { + AVCODEC_LOGE("The number of codeclist services(%{public}zu) has reached the upper limit." + "Please release the applied resources.", codecListStubMap_.size()); + return nullptr; + } + sptr stub = CodecListServiceStub::Create(); + if (stub == nullptr) { + AVCODEC_LOGE("failed to create AVCodecListServiceStub"); + return nullptr; + } + sptr object = stub->AsObject(); + if (object != nullptr) { + pid_t pid = IPCSkeleton::GetCallingPid(); + codecListStubMap_[object] = pid; + AVCODEC_LOGD("The number of codeclist services(%{public}zu).", codecListStubMap_.size()); + } + return object; +} +#endif +#ifdef SUPPORT_CODEC +sptr AVCodecServerManager::CreateCodecStubObject() +{ + if (codecStubMap_.size() >= SERVER_MAX_NUMBER) { + AVCODEC_LOGE("The number of codec services(%{public}zu) has reached the upper limit." + "Please release the applied resources.", codecStubMap_.size()); + return nullptr; + } + sptr stub = CodecServiceStub::Create(); + if (stub == nullptr) { + AVCODEC_LOGE("failed to create CodecServiceStub"); + return nullptr; + } + sptr object = stub->AsObject(); + if (object != nullptr) { + pid_t pid = IPCSkeleton::GetCallingPid(); + codecStubMap_[object] = pid; + + Dumper dumper; + dumper.entry_ = [stub](int32_t fd) -> int32_t { + return stub->DumpInfo(fd); + }; + dumper.pid_ = pid; + dumper.uid_ = IPCSkeleton::GetCallingUid(); + dumper.remoteObject_ = object; + dumperTbl_[StubType::CODEC].emplace_back(dumper); + AVCODEC_LOGD("The number of codec services(%{public}zu).", codecStubMap_.size()); + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("failed to call InstanceDump"); + } + } + return object; +} +#endif + +#ifdef SUPPORT_DEMUXER +sptr AVCodecServerManager::CreateDemuxerStubObject() +{ + if (demuxerStubMap_.size() >= SERVER_MAX_NUMBER) { + AVCODEC_LOGE("The number of demuxer services(%{public}zu) has reached the upper limit." + "Please release the applied resources.", demuxerStubMap_.size()); + return nullptr; + } + sptr stub = DemuxerServiceStub::Create(); + if (stub == nullptr) { + AVCODEC_LOGE("failed to create DemuxerServiceStub"); + return nullptr; + } + sptr object = stub->AsObject(); + if (object != nullptr) { + pid_t pid = IPCSkeleton::GetCallingPid(); + demuxerStubMap_[object] = pid; + + Dumper dumper; + dumper.entry_ = [stub](int32_t fd) -> int32_t { + return stub->DumpInfo(fd); + }; + dumper.pid_ = pid; + dumper.uid_ = IPCSkeleton::GetCallingUid(); + dumper.remoteObject_ = object; + dumperTbl_[StubType::DEMUXER].emplace_back(dumper); + AVCODEC_LOGD("The number of demuxer services(%{public}zu).", demuxerStubMap_.size()); + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("failed to call InstanceDump"); + } + } + return object; +} +#endif + +#ifdef SUPPORT_MUXER +sptr AVCodecServerManager::CreateMuxerStubObject() +{ + if (muxerStubMap_.size() >= SERVER_MAX_NUMBER) { + AVCODEC_LOGE("The number of muxer services(%{public}zu) has reached the upper limit." + "Please release the applied resources.", muxerStubMap_.size()); + return nullptr; + } + sptr muxerStub = MuxerServiceStub::Create(); + if (muxerStub == nullptr) { + AVCODEC_LOGE("Create MuxerServiceStub failed"); + return nullptr; + } + sptr object = muxerStub->AsObject(); + if (object != nullptr) { + pid_t pid = IPCSkeleton::GetCallingPid(); + muxerStubMap_[object] = pid; + + Dumper dumper; + dumper.entry_ = [muxer = muxerStub](int32_t fd) -> int32_t { + return muxer->DumpInfo(fd); + }; + dumper.pid_ = pid; + dumper.uid_ = IPCSkeleton::GetCallingUid(); + dumper.remoteObject_ = object; + dumperTbl_[StubType::MUXER].emplace_back(dumper); + AVCODEC_LOGD("The number of muxer services(%{public}zu).", muxerStubMap_.size()); + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("Failed to call InstanceDump"); + } + } + return object; +} +#endif + +#ifdef SUPPORT_SOURCE +sptr AVCodecServerManager::CreateSourceStubObject() +{ + if (sourceStubMap_.size() >= SERVER_MAX_NUMBER) { + AVCODEC_LOGE("The number of source services(%{public}zu) has reached the upper limit." + "Please release the applied resources.", sourceStubMap_.size()); + return nullptr; + } + sptr stub = SourceServiceStub::Create(); + if (stub == nullptr) { + AVCODEC_LOGE("failed to create SourceServiceStub"); + return nullptr; + } + sptr object = stub->AsObject(); + if (object != nullptr) { + pid_t pid = IPCSkeleton::GetCallingPid(); + sourceStubMap_[object] = pid; + + Dumper dumper; + dumper.entry_ = [stub](int32_t fd) -> int32_t { + return stub->DumpInfo(fd); + }; + dumper.pid_ = pid; + dumper.uid_ = IPCSkeleton::GetCallingUid(); + dumper.remoteObject_ = object; + dumperTbl_[StubType::SOURCE].emplace_back(dumper); + AVCODEC_LOGD("The number of source services(%{public}zu).", sourceStubMap_.size()); + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("failed to call InstanceDump"); + } + } + return object; +} +#endif + +void AVCodecServerManager::DestroyStubObject(StubType type, sptr object) +{ + std::lock_guard lock(mutex_); + pid_t pid = IPCSkeleton::GetCallingPid(); + DestroyDumper(type, object); + + auto compare_func = [object](std::pair, pid_t> objectPair) -> + bool { return objectPair.first == object; }; + switch (type) { + case CODEC: { + auto it = find_if(codecStubMap_.begin(), codecStubMap_.end(), compare_func); + if (it != codecStubMap_.end()) { + AVCODEC_LOGD("destroy codec stub services(%{public}zu) pid(%{public}d).", codecStubMap_.size(), pid); + (void)codecStubMap_.erase(it); + return; + } + AVCODEC_LOGE("find codec object failed, pid(%{public}d).", pid); + break; + } + case CODECLIST: { + auto it = find_if(codecListStubMap_.begin(), codecListStubMap_.end(), compare_func); + if (it != codecListStubMap_.end()) { + AVCODEC_LOGD("destroy codeclist stub services(%{public}zu) pid(%{public}d).", + codecListStubMap_.size(), pid); + (void)codecListStubMap_.erase(it); + return; + } + AVCODEC_LOGE("find codeclist object failed, pid(%{public}d).", pid); + break; + } + 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); + (void)muxerStubMap_.erase(it); + return; + } + AVCODEC_LOGE("find muxer object failed, pid(%{public}d).", pid); + break; + } + case DEMUXER: { + auto it = find_if(demuxerStubMap_.begin(), demuxerStubMap_.end(), compare_func); + if (it != demuxerStubMap_.end()) { + AVCODEC_LOGD("destroy demuxer stub services(%{public}zu) pid(%{public}d).", + demuxerStubMap_.size(), pid); + (void)demuxerStubMap_.erase(it); + return; + } + AVCODEC_LOGE("find demuxer object failed, pid(%{public}d).", pid); + break; + } + case SOURCE: { + auto it = find_if(sourceStubMap_.begin(), sourceStubMap_.end(), compare_func); + if (it != sourceStubMap_.end()) { + AVCODEC_LOGD("destroy source stub services(%{public}zu) pid(%{public}d).", sourceStubMap_.size(), pid); + (void)sourceStubMap_.erase(it); + return; + } + AVCODEC_LOGE("find demuxer object failed, pid(%{public}d).", pid); + break; + } + default: { + AVCODEC_LOGE("default case, av_codec server manager failed, pid(%{public}d).", pid); + break; + } + } +} + +void AVCodecServerManager::DestroyStubObjectForPid(pid_t pid) +{ + std::lock_guard lock(mutex_); + AVCODEC_LOGD("codec stub services(%{public}zu) pid(%{public}d).", codecStubMap_.size(), pid); + for (auto it = codecStubMap_.begin(); it != codecStubMap_.end();) { + if (it->second == pid) { + executor_.Commit(it->first); + it = codecStubMap_.erase(it); + } else { + it++; + } + } + AVCODEC_LOGD("codec stub services(%{public}zu).", codecStubMap_.size()); + + AVCODEC_LOGD("codeclist stub services(%{public}zu) pid(%{public}d).", codecListStubMap_.size(), pid); + for (auto it = codecListStubMap_.begin(); it != codecListStubMap_.end();) { + if (it->second == pid) { + executor_.Commit(it->first); + it = codecListStubMap_.erase(it); + } else { + it++; + } + } + AVCODEC_LOGD("codeclist stub services(%{public}zu).", codecListStubMap_.size()); + + AVCODEC_LOGD("muxer stub services(%{public}zu) pid(%{public}d).", muxerStubMap_.size(), pid); + for (auto it = muxerStubMap_.begin(); it != muxerStubMap_.end();) { + if (it->second == pid) { + executor_.Commit(it->first); + it = muxerStubMap_.erase(it); + } else { + it++; + } + } + AVCODEC_LOGD("muxer stub services(%{public}zu).", muxerStubMap_.size()); + + AVCODEC_LOGD("demuxer stub services(%{public}zu) pid(%{public}d).", demuxerStubMap_.size(), pid); + for (auto it = demuxerStubMap_.begin(); it != demuxerStubMap_.end();) { + if (it->second == pid) { + executor_.Commit(it->first); + it = demuxerStubMap_.erase(it); + } else { + it++; + } + } + AVCODEC_LOGD("demuxer stub services(%{public}zu).", demuxerStubMap_.size()); + + AVCODEC_LOGD("source stub services(%{public}zu) pid(%{public}d).", sourceStubMap_.size(), pid); + for (auto it = sourceStubMap_.begin(); it != sourceStubMap_.end();) { + if (it->second == pid) { + executor_.Commit(it->first); + it = sourceStubMap_.erase(it); + } else { + it++; + } + } + AVCODEC_LOGD("source stub services(%{public}zu).", sourceStubMap_.size()); + + executor_.Clear(); +} + +void AVCodecServerManager::DestroyDumper(StubType type, sptr object) +{ + for (auto it = dumperTbl_[type].begin(); it != dumperTbl_[type].end(); it++) { + if (it->remoteObject_ == object) { + (void)dumperTbl_[type].erase(it); + AVCODEC_LOGD("AVCodecServerManager::DestroyDumper"); + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("failed to call InstanceDump"); + } + return; + } + } +} + +void AVCodecServerManager::DestroyDumperForPid(pid_t pid) +{ + for (auto &dumpers : dumperTbl_) { + for (auto it = dumpers.second.begin(); it != dumpers.second.end();) { + if (it->pid_ == pid) { + it = dumpers.second.erase(it); + AVCODEC_LOGD("AVCodecServerManager::DestroyDumperForPid"); + } else { + it++; + } + } + } + if (Dump(-1, std::vector()) != OHOS::NO_ERROR) { + AVCODEC_LOGW("failed to call InstanceDump"); + } +} + +void AVCodecServerManager::AsyncExecutor::Commit(sptr obj) +{ + std::lock_guard lock(listMutex_); + freeList_.push_back(obj); +} + +void AVCodecServerManager::AsyncExecutor::Clear() +{ + std::thread(&AVCodecServerManager::AsyncExecutor::HandleAsyncExecution, this).detach(); +} + +void AVCodecServerManager::AsyncExecutor::HandleAsyncExecution() +{ + std::list> tempList; + { + std::lock_guard lock(listMutex_); + freeList_.swap(tempList); + } + tempList.clear(); +} + +void AVCodecServerManager::PrintDumpMenu(int32_t fd) +{ + AVCodecDumpControler dumpControler; + dumpControler.AddInfo(DUMP_MENU_INDEX, "[AVCodec Dump Menu]"); + uint32_t index = 1; + for (auto iter : SA_DUMP_MENU_DUMP_TABLE) { + dumpControler.AddInfo(DUMP_MENU_INDEX + (index << DUMP_OFFSET_8), iter); + } + + std::string dumpString; + dumpControler.GetDumpString(dumpString); + dumpString += "\n"; + dumpString += "Add args to get more infomation about avcodec components.\n"; + dumpString += "Example: hidumper -s AVCodecService -a \"all\"\n"; + + if (fd != -1) { + write(fd, dumpString.c_str(), dumpString.size()); + } +} +} // namespace Media +} // namespace OHOS diff --git a/services/services/sa_avcodec/server/include/avcodec_server.h b/services/services/sa_avcodec/server/include/avcodec_server.h new file mode 100644 index 0000000000000000000000000000000000000000..82e55a8ed55d1c6e30815f8df112ad64eefa4aea --- /dev/null +++ b/services/services/sa_avcodec/server/include/avcodec_server.h @@ -0,0 +1,44 @@ +/* + * 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 AVCODEC_SERVER_H +#define AVCODEC_SERVER_H + +#include "avcodec_service_stub.h" +#include "system_ability.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVCodecServer : public SystemAbility, public AVCodecServiceStub { + DECLARE_SYSTEM_ABILITY(AVCodecServer); +public: + explicit AVCodecServer(int32_t systemAbilityId, bool runOnCreate = true); + ~AVCodecServer(); + + // IStandardAVCodecService override + sptr GetSubSystemAbility(IStandardAVCodecService::AVCodecSystemAbility subSystemId, + const sptr &listener) override; + +protected: + // SystemAbility override + void OnDump() override; + void OnStart() override; + void OnStop() override; + int32_t Dump(int32_t fd, const std::vector& args) override; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_SERVER_H \ No newline at end of file diff --git a/services/services/sa_avcodec/server/include/avcodec_server_manager.h b/services/services/sa_avcodec/server/include/avcodec_server_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..9d863c19a7747b84bbd3999770492532b23ddb03 --- /dev/null +++ b/services/services/sa_avcodec/server/include/avcodec_server_manager.h @@ -0,0 +1,103 @@ +/* + * 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 AVCODEC_SERVER_MANAGER_H +#define AVCODEC_SERVER_MANAGER_H + +#include +#include +#include +#include +#include "iremote_object.h" +#include "ipc_skeleton.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +using DumperEntry = std::function; +struct Dumper { + pid_t pid_; + pid_t uid_; + DumperEntry entry_; + sptr remoteObject_; +}; + +class AVCodecServerManager : public NoCopyable { +public: + static AVCodecServerManager &GetInstance(); + ~AVCodecServerManager(); + + enum StubType { + CODECLIST, + CODEC, + MUXER, + DEMUXER, + SOURCE + }; + sptr CreateStubObject(StubType type); + void DestroyStubObject(StubType type, sptr object); + void DestroyStubObjectForPid(pid_t pid); + int32_t Dump(int32_t fd, const std::vector &args); + void DestroyDumper(StubType type, sptr object); + void DestroyDumperForPid(pid_t pid); + +private: + AVCodecServerManager(); + void PrintDumpMenu(int32_t fd); + +#ifdef SUPPORT_DEMUXER + sptr CreateDemuxerStubObject(); +#endif + +#ifdef SUPPORT_MUXER + sptr CreateMuxerStubObject(); +#endif + +#ifdef SUPPORT_CODEC + sptr CreateCodecStubObject(); +#endif +#ifdef SUPPORT_CODECLIST + sptr CreateCodecListStubObject(); +#endif + +#ifdef SUPPORT_SOURCE + sptr CreateSourceStubObject(); +#endif + + class AsyncExecutor { + public: + AsyncExecutor() = default; + virtual ~AsyncExecutor() = default; + void Commit(sptr obj); + void Clear(); + private: + void HandleAsyncExecution(); + std::list> freeList_; + std::mutex listMutex_; + }; + + std::map, pid_t> demuxerStubMap_; + std::map, pid_t> muxerStubMap_; + std::map, pid_t> codecStubMap_; + std::map, pid_t> codecListStubMap_; + std::map, pid_t> sourceStubMap_; + std::map> dumperTbl_; + AsyncExecutor executor_; + + std::mutex mutex_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_SERVER_MANAGER_H \ No newline at end of file diff --git a/services/services/source/client/source_client.cpp b/services/services/source/client/source_client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0a5480781107c8af95d5b33ddd2028a6c9fcc49 --- /dev/null +++ b/services/services/source/client/source_client.cpp @@ -0,0 +1,109 @@ +/* + * 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 "source_client.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SourceClient"}; +} + +namespace OHOS { +namespace Media { +std::shared_ptr SourceClient::Create(const sptr &ipcProxy) +{ + std::shared_ptr source = std::make_shared(ipcProxy); + CHECK_AND_RETURN_RET_LOG(source != nullptr, nullptr, "Failed to create source client"); + return source; +} + +SourceClient::SourceClient(const sptr &ipcProxy) + : sourceProxy_(ipcProxy) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +SourceClient::~SourceClient() +{ + std::lock_guard lock(mutex_); + if (sourceProxy_ != nullptr) { + (void)sourceProxy_->DestroyStub(); + sourceProxy_ = nullptr; + } + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +void SourceClient::AVCodecServerDied() +{ + std::lock_guard lock(mutex_); + sourceProxy_ = nullptr; +} + +int32_t SourceClient::Init(const std::string &uri) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call Init"); + return sourceProxy_->Init(uri); +} + +int32_t SourceClient::GetTrackCount(uint32_t &trackCount) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call GetTrackCount"); + return sourceProxy_->GetTrackCount(trackCount); +} + +int32_t SourceClient::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call SetTrackFormat"); + return sourceProxy_->SetTrackFormat(format, trackIndex); +} + +int32_t SourceClient::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call GetTrackFormat"); + return sourceProxy_->GetTrackFormat(format, trackIndex); +} + +int32_t SourceClient::GetSourceFormat(Format &format) +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call GetSourceFormat"); + return sourceProxy_->GetSourceFormat(format); +} + +uint64_t SourceClient::GetSourceAddr() +{ + std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(sourceProxy_ != nullptr, AVCS_ERR_NO_MEMORY, "source service does not exist."); + + AVCODEC_LOGD("source client call GetSourceAddr"); + return sourceProxy_->GetSourceAddr(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/source/client/source_client.h b/services/services/source/client/source_client.h new file mode 100644 index 0000000000000000000000000000000000000000..9b6a50c25586591c11c2fad4f52a783f53be157c --- /dev/null +++ b/services/services/source/client/source_client.h @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#ifndef SOURCE_CLIENT_H +#define SOURCE_CLIENT_H + +#include "i_source_service.h" +#include "i_standard_source_service.h" + +namespace OHOS { +namespace Media { +class SourceClient : public ISourceService, public NoCopyable { +public: + static std::shared_ptr Create(const sptr &ipcProxy); + explicit SourceClient(const sptr &ipcProxy); + ~SourceClient(); + + int32_t Init(const std::string &uri) override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + uint64_t GetSourceAddr() override; + + void AVCodecServerDied(); +private: + std::mutex mutex_; + sptr sourceProxy_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCE_CLIENT_H \ No newline at end of file diff --git a/services/services/source/ipc/i_standard_source_service.h b/services/services/source/ipc/i_standard_source_service.h new file mode 100644 index 0000000000000000000000000000000000000000..e6aebec2539740befaf779ffd82007afd7c3494e --- /dev/null +++ b/services/services/source/ipc/i_standard_source_service.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef I_STANDARD_SOURCE_SERVICE_H +#define I_STANDARD_SOURCE_SERVICE_H + +#include "iremote_proxy.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class IStandardSourceService : public IRemoteBroker { +public: + virtual ~IStandardSourceService() = default; + + virtual int32_t Init(const std::string &uri) = 0; + virtual int32_t GetTrackCount(uint32_t &trackCount) = 0; + virtual int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetTrackFormat(Format &format, uint32_t trackIndex) = 0; + virtual int32_t GetSourceFormat(Format &format) = 0; + virtual uint64_t GetSourceAddr() = 0; + + virtual int32_t DestroyStub() = 0; + enum SourceServiceMsg { + INIT, + GET_TRACK_COUNT, + DESTROY, + SET_TRACK_FORMAT, + GET_TRACK_FORMAT, + GET_SOURCE_FORMAT, + GET_SOURCE_ADDR, + DESTROY_STUB, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"IStandardSourceService"); +}; +} // namespace Media +} // namespace OHOS +#endif // I_AVSOURCE_SERVICE_H \ No newline at end of file diff --git a/services/services/source/ipc/source_service_proxy.cpp b/services/services/source/ipc/source_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e666e3b4ff7ca6e2c6b5543926b46ea45aa9063 --- /dev/null +++ b/services/services/source/ipc/source_service_proxy.cpp @@ -0,0 +1,146 @@ +/* + * 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 "source_service_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, "SourceServiceProxy"}; +} + +namespace OHOS { +namespace Media { +SourceServiceProxy::SourceServiceProxy(const sptr &impl) + : IRemoteProxy(impl) +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +SourceServiceProxy::~SourceServiceProxy() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t SourceServiceProxy::DestroyStub() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int error = Remote()->SendRequest(DESTROY_STUB, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call DestroyStub, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t SourceServiceProxy::Init(const std::string &uri) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + data.WriteString(uri); + int error = Remote()->SendRequest(INIT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call Init, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t SourceServiceProxy::GetTrackCount(uint32_t &trackCount) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + data.WriteUint32(trackCount); + int error = Remote()->SendRequest(GET_TRACK_COUNT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call GetTrackCount, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t SourceServiceProxy::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + AVCodecParcel::Marshalling(data, format); + data.WriteUint32(trackIndex); + int error = Remote()->SendRequest(SET_TRACK_FORMAT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call SetTrackFormat, error: %{public}d", error); + return reply.ReadInt32(); +} + +int32_t SourceServiceProxy::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + data.WriteUint32(trackIndex); + int error = Remote()->SendRequest(GET_TRACK_FORMAT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call GetTrackFormat, error: %{public}d", error); + + AVCodecParcel::Unmarshalling(reply, format); + return reply.ReadInt32(); +} + +int32_t SourceServiceProxy::GetSourceFormat(Format &format) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int error = Remote()->SendRequest(GET_SOURCE_FORMAT, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call GetTrackFormat, error: %{public}d", error); + + AVCodecParcel::Unmarshalling(reply, format); + return reply.ReadInt32(); +} + +uint64_t SourceServiceProxy::GetSourceAddr() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + bool token = data.WriteInterfaceToken(SourceServiceProxy::GetDescriptor()); + CHECK_AND_RETURN_RET_LOG(token, AVCS_ERR_INVALID_OPERATION, "Failed to write descriptor!"); + + int error = Remote()->SendRequest(GET_SOURCE_ADDR, data, reply, option); + CHECK_AND_RETURN_RET_LOG(error == AVCS_ERR_OK, error, "Failed to call GetSourceAddr, error: %{public}d", error); + return reply.ReadUint64(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/source/ipc/source_service_proxy.h b/services/services/source/ipc/source_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..736e8529a499e3b0f1e12a2aa696e0fcaff44a1c --- /dev/null +++ b/services/services/source/ipc/source_service_proxy.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef SOURCE_SERVICE_PROXY_H +#define SOURCE_SERVICE_PROXY_H + +#include "i_standard_source_service.h" + +namespace OHOS { +namespace Media { +class SourceServiceProxy : public IRemoteProxy, public NoCopyable { +public: + explicit SourceServiceProxy(const sptr &impl); + virtual ~SourceServiceProxy(); + + int32_t Init(const std::string &uri) override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + uint64_t GetSourceAddr() override; + + int32_t DestroyStub() override; +private: + static inline BrokerDelegator delegator_; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCE_SERVICE_PROXY_H \ No newline at end of file diff --git a/services/services/source/ipc/source_service_stub.cpp b/services/services/source/ipc/source_service_stub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b0a604eca2094fa9f87cd15d156ed6cbb067909 --- /dev/null +++ b/services/services/source/ipc/source_service_stub.cpp @@ -0,0 +1,203 @@ +/* + * 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 "source_service_stub.h" +#include "avcodec_server_manager.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_dfx.h" +#include "avsharedmemory_ipc.h" +#include "avcodec_parcel.h" +#include "avcodec_xcollie.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SourceAVServiceStub"}; +} + +namespace OHOS { +namespace Media { +sptr SourceServiceStub::Create() +{ + sptr sourceStub = new(std::nothrow) SourceServiceStub(); + CHECK_AND_RETURN_RET_LOG(sourceStub != nullptr, nullptr, "Failed to create source service stub"); + + int32_t ret = sourceStub->InitStub(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, nullptr, "Failed to init SourceServiceStub"); + return sourceStub; +} + +SourceServiceStub::SourceServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); +} + +SourceServiceStub::~SourceServiceStub() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); +} + +int32_t SourceServiceStub::InitStub() +{ + sourceServer_ = SourceServer::Create(); + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "Failed to create source server"); + + sourceFuncs_[INIT] = &SourceServiceStub::Init; + sourceFuncs_[GET_TRACK_COUNT] = &SourceServiceStub::GetTrackCount; + sourceFuncs_[SET_TRACK_FORMAT] = &SourceServiceStub::SetTrackFormat; + sourceFuncs_[GET_TRACK_FORMAT] = &SourceServiceStub::GetTrackFormat; + sourceFuncs_[GET_SOURCE_FORMAT] = &SourceServiceStub::GetSourceFormat; + sourceFuncs_[GET_SOURCE_ADDR] = &SourceServiceStub::GetSourceAddr; + sourceFuncs_[DESTROY_STUB] = &SourceServiceStub::DestroyStub; + return AVCS_ERR_OK; +} + +int SourceServiceStub::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 (SourceServiceStub::GetDescriptor() != remoteDescriptor) { + AVCODEC_LOGE("Invalid descriptor"); + return AVCS_ERR_INVALID_OPERATION; + } + + auto itFunc = sourceFuncs_.find(code); + if (itFunc != sourceFuncs_.end()) { + auto memberFunc = itFunc->second; + if (memberFunc != nullptr) { + int32_t ret = -1; + COLLIE_LISTEN(ret = (this->*memberFunc)(data, reply), + "SourceServiceStub::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 SourceServiceStub::DestroyStub() +{ + sourceServer_ = nullptr; + AVCodecServerManager::GetInstance().DestroyStubObject(AVCodecServerManager::SOURCE, AsObject()); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::Init(const std::string &uri) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->Init(uri); +} + +int32_t SourceServiceStub::GetTrackCount(uint32_t &trackCount) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->GetTrackCount(trackCount); +} + +int32_t SourceServiceStub::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->SetTrackFormat(format, trackIndex); +} + +int32_t SourceServiceStub::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->GetTrackFormat(format, trackIndex); +} + +int32_t SourceServiceStub::GetSourceFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->GetSourceFormat(format); +} + +uint64_t SourceServiceStub::GetSourceAddr() +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return sourceServer_->GetSourceAddr(); +} + +int32_t SourceServiceStub::DumpInfo(int32_t fd) +{ + CHECK_AND_RETURN_RET_LOG(sourceServer_ != nullptr, AVCS_ERR_NO_MEMORY, "source server is nullptr"); + return std::static_pointer_cast(sourceServer_)->DumpInfo(fd); +} + +int32_t SourceServiceStub::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; +} + +int32_t SourceServiceStub::Init(MessageParcel &data, MessageParcel &reply) +{ + std::string uri = data.ReadString(); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(Init(uri)), AVCS_ERR_UNKNOWN, "Reply Init failed"); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::GetTrackCount(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + uint32_t trackCount; + int32_t ret = GetTrackCount(trackCount); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(trackCount), AVCS_ERR_UNKNOWN, "Reply GetTrackCount failed"); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply GetTrackCount failed"); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::SetTrackFormat(MessageParcel &data, MessageParcel &reply) +{ + Format param; + (void)AVCodecParcel::Unmarshalling(data, param); + uint32_t trackIndex = data.ReadUint32(); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(SetTrackFormat(param, trackIndex)), AVCS_ERR_UNKNOWN, + "Reply SetTrackFormat failed"); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::GetTrackFormat(MessageParcel &data, MessageParcel &reply) +{ + uint32_t trackIndex = data.ReadUint32(); + Format format; + int32_t ret = GetTrackFormat(format, trackIndex); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply GetTrackFormat failed"); + AVCodecParcel::Marshalling(reply, format); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::GetSourceFormat(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + + Format format; + int32_t ret = GetSourceFormat(format); + AVCodecParcel::Marshalling(reply, format); + CHECK_AND_RETURN_RET_LOG(reply.WriteInt32(ret), AVCS_ERR_UNKNOWN, "Reply GetSourceAddr failed"); + return AVCS_ERR_OK; +} + +int32_t SourceServiceStub::GetSourceAddr(MessageParcel &data, MessageParcel &reply) +{ + (void)data; + + CHECK_AND_RETURN_RET_LOG(reply.WriteUint64(GetSourceAddr()), AVCS_ERR_UNKNOWN, "Reply GetSourceAddr failed!"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/source/ipc/source_service_stub.h b/services/services/source/ipc/source_service_stub.h new file mode 100644 index 0000000000000000000000000000000000000000..607c89a995a0b9f16bd4affaf1775ef4f5ccd269 --- /dev/null +++ b/services/services/source/ipc/source_service_stub.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef SOURCE_SERVICE_STUB_H +#define SOURCE_SERVICE_STUB_H + +#include +#include "i_standard_source_service.h" +#include "source_server.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace Media { +class SourceServiceStub : public IRemoteStub, public NoCopyable { +public: + static sptr Create(); + virtual ~SourceServiceStub(); + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + using SourceStubFunc = int32_t(SourceServiceStub::*)(MessageParcel &data, MessageParcel &reply); + int32_t Init(const std::string &uri) override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + uint64_t GetSourceAddr() override; + int32_t DumpInfo(int32_t fd); + int32_t DestroyStub() override; +private: + SourceServiceStub(); + int32_t InitStub(); + int32_t Init(MessageParcel &data, MessageParcel &reply); + int32_t GetTrackCount(MessageParcel &data, MessageParcel &reply); + int32_t SetTrackFormat(MessageParcel &data, MessageParcel &reply); + int32_t GetTrackFormat(MessageParcel &data, MessageParcel &reply); + int32_t GetSourceFormat(MessageParcel &data, MessageParcel &reply); + int32_t GetSourceAddr(MessageParcel &data, MessageParcel &reply); + int32_t DestroyStub(MessageParcel &data, MessageParcel &reply); + std::mutex mutex_; + std::shared_ptr sourceServer_ = nullptr; + std::map sourceFuncs_; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCE_SERVICE_STUB_H \ No newline at end of file diff --git a/services/services/source/server/source_server.cpp b/services/services/source/server/source_server.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2253d7ea82888ecd319c3232a2099ec8b66e7d73 --- /dev/null +++ b/services/services/source/server/source_server.cpp @@ -0,0 +1,198 @@ +/* + * 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 "source_server.h" +#include +#include +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "avcodec_dump_utils.h" +#include "avcodec_dfx.h" +#include "ipc_skeleton.h" +#include "avcodec_common.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SourceServer"}; + constexpr uint32_t DUMP_INPUT_URL_INDEX = 0x01010000; + constexpr uint32_t DUMP_SOURCE_INFO_INDEX = 0x01020000; + constexpr uint32_t DUMP_TRACK_INFO_INDEX = 0x01030000; + constexpr uint32_t DUMP_OFFSET_8 = 8; + + const std::vector> SOURCE_DUMP_TABLE = { + { OHOS::Media::AVSourceFormat::SOURCE_TITLE, "Title" }, + { OHOS::Media::AVSourceFormat::SOURCE_ARTIST, "Artist" }, + { OHOS::Media::AVSourceFormat::SOURCE_ALBUM, "Album" }, + { OHOS::Media::AVSourceFormat::SOURCE_ALBUM_ARTIST, "Album_Artist" }, + { OHOS::Media::AVSourceFormat::SOURCE_DATE, "Date" }, + { OHOS::Media::AVSourceFormat::SOURCE_COMMENT, "Comment" }, + { OHOS::Media::AVSourceFormat::SOURCE_GENRE, "Genre" }, + { OHOS::Media::AVSourceFormat::SOURCE_COPYRIGHT, "Copyright" }, + { OHOS::Media::AVSourceFormat::SOURCE_LANGUAGE, "Language" }, + { OHOS::Media::AVSourceFormat::SOURCE_DESCRIPTION, "Description" }, + { OHOS::Media::AVSourceFormat::SOURCE_LYRICS, "Lyrics" }, + { OHOS::Media::AVSourceFormat::SOURCE_DURATION, "Duration" }, + { OHOS::Media::AVSourceFormat::SOURCE_TYPE, "Type" }, + }; + + const std::vector> AUDIO_TRACK_DUMP_TABLE = { + { OHOS::Media::AVSourceTrackFormat::TRACK_SAMPLE_COUNT, "Sample_Count" }, + { OHOS::Media::AVSourceTrackFormat::TRACK_DURATION, "Duration" }, + { OHOS::Media::AVSourceTrackFormat::TRACK_BITRATE, "Bit_Rate" }, + }; + + const std::vector> VIDEO_TRACK_DUMP_TABLE = { + { OHOS::Media::AVSourceTrackFormat::TRACK_SAMPLE_COUNT, "Sample_Count" }, + { OHOS::Media::AVSourceTrackFormat::TRACK_DURATION, "Duration" }, + { OHOS::Media::AVSourceTrackFormat::TRACK_BITRATE, "Bit_Rate" }, + { OHOS::Media::AVSourceTrackFormat::VIDEO_TRACK_ROTATION, "Rotation" }, + { OHOS::Media::AVSourceTrackFormat::VIDEO_TRACK_WIDTH, "Width" }, + { OHOS::Media::AVSourceTrackFormat::VIDEO_TRACK_HEIGHT, "Height" }, + { OHOS::Media::AVSourceTrackFormat::VIDEO_PIXEL_FORMAT, "Pixle_Format" }, + { OHOS::Media::AVSourceTrackFormat::VIDEO_BIT_STREAM_FORMAT, "Bit_Stream_Format" }, + }; +} + +namespace OHOS { +namespace Media { +std::shared_ptr SourceServer::Create() +{ + std::shared_ptr server = std::make_shared(); + CHECK_AND_RETURN_RET_LOG(server != nullptr, nullptr, "Source Service does not exist"); + return server; +} + +SourceServer::SourceServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this)); + appUid_ = IPCSkeleton::GetCallingUid(); + appPid_ = IPCSkeleton::GetCallingPid(); +} + +SourceServer::~SourceServer() +{ + AVCODEC_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this)); + sourceEngine_ = nullptr; +} + +int32_t SourceServer::Init(const std::string &uri) +{ + sourceEngine_ = ISourceEngineFactory::CreateSourceEngine(appUid_, appPid_, uri); + uri_ = uri; + return AVCS_ERR_OK; +} + +int32_t SourceServer::GetTrackCount(uint32_t &trackCount) +{ + CHECK_AND_RETURN_RET_LOG(sourceEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = sourceEngine_->GetTrackCount(trackCount); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t SourceServer::SetTrackFormat(const Format &format, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(sourceEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = sourceEngine_->SetTrackFormat(format, trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t SourceServer::GetTrackFormat(Format &format, uint32_t trackIndex) +{ + CHECK_AND_RETURN_RET_LOG(sourceEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = sourceEngine_->GetTrackFormat(format, trackIndex); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t SourceServer::GetSourceFormat(Format &format) +{ + CHECK_AND_RETURN_RET_LOG(sourceEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = sourceEngine_->GetSourceFormat(format); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +uint64_t SourceServer::GetSourceAddr() +{ + CHECK_AND_RETURN_RET_LOG(sourceEngine_ != nullptr, AVCS_ERR_INVALID_OPERATION, "Demuxer engine does not exist"); + int32_t ret = sourceEngine_->GetSourceAddr(); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, ret, "Failed to call SetRotation"); + return AVCS_ERR_OK; +} + +int32_t SourceServer::DumpInfo(int32_t fd) +{ + CHECK_AND_RETURN_RET_LOG(fd != -1, AVCS_ERR_INVALID_VAL, "Attempt to write to a invalid fd: %{public}d", fd); + std::string dumpInfo; + GetDumpInfo(dumpInfo); + + write(fd, dumpInfo.c_str(), dumpInfo.size()); + return AVCS_ERR_OK; +} + +int32_t SourceServer::GetDumpInfo(std::string &dumpInfo) +{ + Format sourceFormat, trackFormat; + uint32_t trackCount = 0; + int32_t ret = this->GetTrackCount(trackCount); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + AVCS_ERR_INVALID_OPERATION, "Get track count failed!"); + ret = GetSourceFormat(sourceFormat); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + AVCS_ERR_INVALID_OPERATION, "Get track format failed!"); + AVCodecDumpControler dumpControler; + + dumpControler.AddInfo(DUMP_INPUT_URL_INDEX, "Input_Url", uri_); + + int32_t sourceDumpIndex = 1; + dumpControler.AddInfo(DUMP_SOURCE_INFO_INDEX, "Source_Info"); + for (auto iter : SOURCE_DUMP_TABLE) { + dumpControler.AddInfoFromFormat( + DUMP_SOURCE_INFO_INDEX + (sourceDumpIndex << DUMP_OFFSET_8), + sourceFormat, iter.first, iter.second); + sourceDumpIndex++; + } + + dumpControler.AddInfo(DUMP_TRACK_INFO_INDEX, "Track_Info"); + for (int32_t idx = 0; idx < trackCount; idx++) { + ret = GetTrackFormat(trackFormat, idx); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + AVCS_ERR_INVALID_OPERATION, "Get track format failed!"); + + int32_t trackDumpIndex = 1; + int32_t trackListIndex = (idx + 1) << DUMP_OFFSET_8; + std::string trackType; + trackFormat.GetStringValue("track/type", trackType); + std::string indexString = + std::string("Index ") + std::to_string(idx) + std::string(" _ ") + trackType; + dumpControler.AddInfo(DUMP_TRACK_INFO_INDEX + trackListIndex, indexString); + auto &dumpTable = + trackType == "audio" ? AUDIO_TRACK_DUMP_TABLE : VIDEO_TRACK_DUMP_TABLE; + for (auto iter : dumpTable) { + dumpControler.AddInfoFromFormat( + DUMP_TRACK_INFO_INDEX + trackListIndex + trackDumpIndex, + trackFormat, iter.first, iter.second); + trackDumpIndex++; + } + } + + ret = dumpControler.GetDumpString(dumpInfo); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, + AVCS_ERR_INVALID_OPERATION, "Get dump string failed!"); + return AVCS_ERR_OK; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/services/source/server/source_server.h b/services/services/source/server/source_server.h new file mode 100644 index 0000000000000000000000000000000000000000..aab510e0a12a35bd7105f78e97de1a766014c3ea --- /dev/null +++ b/services/services/source/server/source_server.h @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#ifndef SOURCE_SERVER_H +#define SOURCE_SERVER_H + +#include "i_source_service.h" +#include "nocopyable.h" +#include "i_source_engine.h" + +namespace OHOS { +namespace Media { +class SourceServer : public std::enable_shared_from_this, public ISourceService, public NoCopyable { +public: + static std::shared_ptr Create(); + SourceServer(); + ~SourceServer(); + + int32_t Init(const std::string &uri) override; + int32_t GetTrackCount(uint32_t &trackCount) override; + int32_t SetTrackFormat(const Format &format, uint32_t trackIndex) override; + int32_t GetTrackFormat(Format &format, uint32_t trackIndex) override; + int32_t GetSourceFormat(Format &format) override; + uint64_t GetSourceAddr() override; + int32_t DumpInfo(int32_t fd); + +private: + int32_t GetDumpInfo(std::string &dumpInfo); + std::shared_ptr sourceEngine_ = nullptr; + std::string uri_; + int32_t appUid_ = 0; + int32_t appPid_ = 0; +}; +} // namespace Media +} // namespace OHOS +#endif // SOURCE_SERVER_H \ No newline at end of file diff --git a/services/utils/BUILD.gn b/services/utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b462aa072bb559a89104be5258536a22f354acd9 --- /dev/null +++ b/services/utils/BUILD.gn @@ -0,0 +1,97 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_static_library("av_codec_format") { + sources = [ "format.cpp" ] + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/dfx/include", + "//commonlibrary/c_utils/base/include", + ] + + defines = [] + defines += av_codec_defines + deps = [ "$av_codec_root_dir/services/utils:av_codec_service_utils" ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} + +ohos_shared_library("av_codec_service_utils") { + install_enable = true + + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/dfx/include", + + # "//commonlibrary/c_utils/base/include", + ] + + sources = [ + "avsharedmemorybase.cpp", + "task_thread.cpp", + ] + + 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", + "-Wfloat-equal", + "-Wdate-time", + "-Werror", + "-Wextra", + "-Wimplicit-fallthrough", + "-Wsign-compare", + "-Wunused-parameter", + ] + + external_deps = [ + "c_utils:utils", + "hisysevent_native:libhisysevent", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + "init:libbegetutil", + ] + + subsystem_name = "multimedia" + part_name = "av_codec" +} diff --git a/services/utils/avsharedmemorybase.cpp b/services/utils/avsharedmemorybase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d22e9c252ce952b9929e7a0f4129a4d87d0ea29b --- /dev/null +++ b/services/utils/avsharedmemorybase.cpp @@ -0,0 +1,202 @@ +/* + * 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 "avsharedmemorybase.h" +#include +#include +#include "ashmem.h" +#include "avcodec_errors.h" +#include "avcodec_log.h" +#include "scope_guard.h" +#include "securec.h" + +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVSharedMemoryBase"}; +} + +namespace OHOS { +namespace Media { +struct AVSharedMemoryBaseImpl : public AVSharedMemoryBase { +public: + AVSharedMemoryBaseImpl(int32_t fd, int32_t size, uint32_t flags, const std::string &name) + : AVSharedMemoryBase(fd, size, flags, name) {} +}; + +std::shared_ptr AVSharedMemoryBase::CreateFromLocal( + int32_t size, uint32_t flags, const std::string &name) +{ + std::shared_ptr memory = std::make_shared(size, flags, name); + int32_t ret = memory->Init(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Create avsharedmemory failed, ret = %{public}d", ret); + return nullptr; + } + + return memory; +} + +std::shared_ptr AVSharedMemoryBase::CreateFromRemote( + int32_t fd, int32_t size, uint32_t flags, const std::string &name) +{ + std::shared_ptr memory = std::make_shared(fd, size, flags, name); + int32_t ret = memory->Init(); + if (ret != AVCS_ERR_OK) { + AVCODEC_LOGE("Create avsharedmemory failed, ret = %{public}d", ret); + return nullptr; + } + + return memory; +} + +AVSharedMemoryBase::AVSharedMemoryBase(int32_t size, uint32_t flags, const std::string &name) + : base_(nullptr), capacity_(size), flags_(flags), name_(name), fd_(-1), size_(0) +{ + AVCODEC_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s", + FAKE_POINTER(this), name_.c_str()); +} + +AVSharedMemoryBase::AVSharedMemoryBase(int32_t fd, int32_t size, uint32_t flags, const std::string &name) + : base_(nullptr), capacity_(size), flags_(flags), name_(name), fd_(dup(fd)), size_(0) +{ + AVCODEC_LOGD("enter ctor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s", + FAKE_POINTER(this), name_.c_str()); +} + +AVSharedMemoryBase::~AVSharedMemoryBase() +{ + AVCODEC_LOGD("enter dtor, instance: 0x%{public}06" PRIXPTR ", name = %{public}s", + FAKE_POINTER(this), name_.c_str()); + Close(); +} + +int32_t AVSharedMemoryBase::Init() +{ + ON_SCOPE_EXIT(0) { + AVCODEC_LOGE("create avsharedmemory failed, name = %{public}s, size = %{public}d, " + "flags = 0x%{public}x, fd = %{public}d", name_.c_str(), capacity_, flags_, fd_); + Close(); + }; + + CHECK_AND_RETURN_RET_LOG(capacity_ > 0, AVCS_ERR_INVALID_VAL, "size is invalid, size = %{public}d", capacity_); + + bool isRemote = false; + if (fd_ > 0) { + int size = AshmemGetSize(fd_); + CHECK_AND_RETURN_RET_LOG(size == capacity_, AVCS_ERR_INVALID_VAL, + "size not equal capacity_, size = %{public}d, capacity_ = %{public}d", size, capacity_); + isRemote = true; + } else { + fd_ = AshmemCreate(name_.c_str(), static_cast(capacity_)); + CHECK_AND_RETURN_RET_LOG(fd_ > 0, AVCS_ERR_INVALID_VAL, "fd is invalid, fd = %{public}d", fd_); + } + + int32_t ret = MapMemory(isRemote); + CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_INVALID_VAL, "MapMemory failed, ret = %{plublic}d", ret); + + CANCEL_SCOPE_EXIT_GUARD(0); + return AVCS_ERR_OK; +} + +int32_t AVSharedMemoryBase::MapMemory(bool isRemote) +{ + unsigned int prot = PROT_READ | PROT_WRITE; + if (isRemote && (flags_ & FLAGS_READ_ONLY)) { + prot &= ~PROT_WRITE; + } + + int result = AshmemSetProt(fd_, static_cast(prot)); + CHECK_AND_RETURN_RET_LOG(result >= 0, AVCS_ERR_INVALID_OPERATION, + "AshmemSetProt failed, result = %{public}d", result); + + void *addr = ::mmap(nullptr, static_cast(capacity_), static_cast(prot), MAP_SHARED, fd_, 0); + CHECK_AND_RETURN_RET_LOG(addr != MAP_FAILED, AVCS_ERR_INVALID_OPERATION, "mmap failed, please check params"); + + base_ = reinterpret_cast(addr); + return AVCS_ERR_OK; +} + +void AVSharedMemoryBase::Close() noexcept +{ + if (base_ != nullptr) { + (void)::munmap(base_, static_cast(capacity_)); + base_ = nullptr; + capacity_ = 0; + flags_ = 0; + size_ = 0; + } + + if (fd_ > 0) { + (void)::close(fd_); + fd_ = -1; + } +} + +int32_t AVSharedMemoryBase::Write(const uint8_t *in, int32_t writeSize, int32_t position) +{ + CHECK_AND_RETURN_RET_LOG(in != nullptr, 0, "Input buffer is nullptr"); + CHECK_AND_RETURN_RET_LOG(writeSize > 0, 0, "Input writeSize:%{public}d is invalid", writeSize); + int32_t start = 0; + if (position == INVALID_POSITION) { + start = size_; + } else { + start = std::min(position, capacity_); + } + int32_t unusedSize = capacity_ - start; + int32_t length = std::min(writeSize, unusedSize); + AVCODEC_LOGD("write data,length:%{public}d, start:%{public}d, name:%{public}s", length, start, name_.c_str()); + CHECK_AND_RETURN_RET_LOG((length + start) <= capacity_, 0, "Write out of bounds, length:%{public}d, " + "start:%{public}d, capacity_:%{public}d", length, start, capacity_); + uint8_t *dstPtr = base_ + start; + CHECK_AND_RETURN_RET_LOG(dstPtr != nullptr, 0, "Inner dstPtr is nullptr"); + + auto error = memcpy_s(dstPtr, length, in, length); + CHECK_AND_RETURN_RET_LOG(error == EOK, 0, "Inner memcpy_s failed,name:%{public}s, %{public}s", + name_.c_str(), strerror(error)); + size_ = start + length; + return length; +} + +int32_t AVSharedMemoryBase::Read(uint8_t *out, int32_t readSize, int32_t position) +{ + CHECK_AND_RETURN_RET_LOG(out != nullptr, 0, "Input buffer is nullptr"); + CHECK_AND_RETURN_RET_LOG(readSize > 0, 0, "Input readSize:%{public}d is invalid", readSize); + int32_t start = 0; + int32_t maxLength = size_; + if (position != INVALID_POSITION) { + start = std::min(position, size_); + maxLength = size_ - start; + } + int32_t length = std::min(readSize, maxLength); + CHECK_AND_RETURN_RET_LOG((length + start) <= capacity_, 0, "Read out of bounds, length:%{public}d, " + "start:%{public}d, capacity_:%{public}d", length, start, capacity_); + uint8_t *srcPtr = base_ + start; + CHECK_AND_RETURN_RET_LOG(srcPtr != nullptr, 0, "Inner srcPtr is nullptr"); + auto error = memcpy_s(out, length, srcPtr, length); + CHECK_AND_RETURN_RET_LOG(error == EOK, 0, "Inner memcpy_s failed,name:%{public}s, %{public}s", + name_.c_str(), strerror(error)); + return length; +} + +void AVSharedMemoryBase::ClearUsedSize() +{ + size_ = 0; +} + +int32_t AVSharedMemoryBase::GetUsedSize() const +{ + return size_; +} +} // namespace Media +} // namespace OHOS diff --git a/services/utils/format.cpp b/services/utils/format.cpp new file mode 100644 index 0000000000000000000000000000000000000000..317384b3ccf2b9948554bd05598d4c73c1fe92ae --- /dev/null +++ b/services/utils/format.cpp @@ -0,0 +1,326 @@ +/* + * 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 "format.h" +#include "securec.h" +#include "avcodec_log.h" +#include "avcodec_errors.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "Format"}; +} + +namespace OHOS { +namespace Media { +void CopyFormatDataMap(const Format::FormatDataMap &from, Format::FormatDataMap &to) +{ + for (auto it = to.begin(); it != to.end(); ++it) { + if (it->second.type == FORMAT_TYPE_ADDR && it->second.addr != nullptr) { + free(it->second.addr); + it->second.addr = nullptr; + } + } + + to = from; + + for (auto it = to.begin(); it != to.end();) { + if (it->second.type != FORMAT_TYPE_ADDR || it->second.addr == nullptr) { + ++it; + continue; + } + + it->second.addr = reinterpret_cast(malloc(it->second.size)); + if (it->second.addr == nullptr) { + AVCODEC_LOGE("malloc addr failed. Key: %{public}s", it->first.c_str()); + it = to.erase(it); + continue; + } + + errno_t err = memcpy_s(reinterpret_cast(it->second.addr), + it->second.size, reinterpret_cast(from.at(it->first).addr), it->second.size); + if (err != EOK) { + AVCODEC_LOGE("memcpy addr failed. Key: %{public}s", it->first.c_str()); + free(it->second.addr); + it->second.addr = nullptr; + it = to.erase(it); + continue; + } + ++it; + } +} + +Format::~Format() +{ + for (auto it = formatMap_.begin(); it != formatMap_.end(); ++it) { + if (it->second.type == FORMAT_TYPE_ADDR && it->second.addr != nullptr) { + free(it->second.addr); + it->second.addr = nullptr; + } + } +} + +Format::Format(const Format &rhs) +{ + if (&rhs == this) { + return; + } + + CopyFormatDataMap(rhs.formatMap_, formatMap_); +} + +Format::Format(Format &&rhs) noexcept +{ + std::swap(formatMap_, rhs.formatMap_); +} + +Format &Format::operator=(const Format &rhs) +{ + if (&rhs == this) { + return *this; + } + + CopyFormatDataMap(rhs.formatMap_, this->formatMap_); + return *this; +} + +Format &Format::operator=(Format &&rhs) noexcept +{ + if (&rhs == this) { + return *this; + } + + std::swap(this->formatMap_, rhs.formatMap_); + return *this; +} + +bool Format::PutIntValue(const std::string_view &key, int32_t value) +{ + FormatData data; + data.type = FORMAT_TYPE_INT32; + data.val.int32Val = value; + RemoveKey(key); + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::PutLongValue(const std::string_view &key, int64_t value) +{ + FormatData data; + data.type = FORMAT_TYPE_INT64; + data.val.int64Val = value; + RemoveKey(key); + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::PutFloatValue(const std::string_view &key, float value) +{ + FormatData data; + data.type = FORMAT_TYPE_FLOAT; + data.val.floatVal = value; + RemoveKey(key); + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::PutDoubleValue(const std::string_view &key, double value) +{ + FormatData data; + data.type = FORMAT_TYPE_DOUBLE; + data.val.doubleVal = value; + RemoveKey(key); + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::PutStringValue(const std::string_view &key, const std::string_view &value) +{ + FormatData data; + data.type = FORMAT_TYPE_STRING; + data.stringVal = value; + RemoveKey(key); + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::GetStringValue(const std::string_view &key, std::string &value) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_STRING) { + AVCODEC_LOGE("Format::GetFormat failed. Key: %{public}s", key.data()); + return false; + } + value = iter->second.stringVal; + return true; +} + +bool Format::GetIntValue(const std::string_view &key, int32_t &value) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_INT32) { + AVCODEC_LOGE("Format::GetFormat failed. Key: %{public}s", key.data()); + return false; + } + value = iter->second.val.int32Val; + return true; +} + +bool Format::GetLongValue(const std::string_view &key, int64_t &value) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_INT64) { + AVCODEC_LOGE("Format::GetFormat failed. Key: %{public}s", key.data()); + return false; + } + value = iter->second.val.int64Val; + return true; +} + +bool Format::GetFloatValue(const std::string_view &key, float &value) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_FLOAT) { + AVCODEC_LOGE("Format::GetFormat failed. Key: %{public}s", key.data()); + return false; + } + value = iter->second.val.floatVal; + return true; +} + +bool Format::GetDoubleValue(const std::string_view &key, double &value) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_DOUBLE) { + AVCODEC_LOGE("Format::GetFormat failed. Key: %{public}s", key.data()); + return false; + } + value = iter->second.val.doubleVal; + return true; +} + +bool Format::PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) +{ + if (addr == nullptr) { + AVCODEC_LOGE("put buffer error, addr is nullptr"); + return false; + } + + constexpr size_t sizeMax = 1 * 1024 * 1024; + if (size > sizeMax) { + AVCODEC_LOGE("PutBuffer input size failed. Key: %{public}s", key.data()); + return false; + } + + FormatData data; + data.type = FORMAT_TYPE_ADDR; + data.addr = reinterpret_cast(malloc(size)); + if (data.addr == nullptr) { + AVCODEC_LOGE("malloc addr failed. Key: %{public}s", key.data()); + return false; + } + + errno_t err = memcpy_s(reinterpret_cast(data.addr), size, reinterpret_cast(addr), size); + if (err != EOK) { + AVCODEC_LOGE("PutBuffer memcpy addr failed. Key: %{public}s", key.data()); + free(data.addr); + return false; + } + + RemoveKey(key); + + data.size = size; + auto ret = formatMap_.insert(std::make_pair(key, data)); + return ret.second; +} + +bool Format::GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end() || iter->second.type != FORMAT_TYPE_ADDR) { + AVCODEC_LOGE("Format::GetBuffer failed. Key: %{public}s", key.data()); + return false; + } + *addr = iter->second.addr; + size = iter->second.size; + return true; +} + +bool Format::ContainKey(const std::string_view &key) const +{ + auto iter = formatMap_.find(key); + if (iter != formatMap_.end()) { + return true; + } + + return false; +} + +FormatDataType Format::GetValueType(const std::string_view &key) const +{ + auto iter = formatMap_.find(key); + if (iter == formatMap_.end()) { + return FORMAT_TYPE_NONE; + } + + return iter->second.type; +} + +void Format::RemoveKey(const std::string_view &key) +{ + auto iter = formatMap_.find(key); + if (iter != formatMap_.end()) { + if (iter->second.type == FORMAT_TYPE_ADDR && iter->second.addr != nullptr) { + free(iter->second.addr); + iter->second.addr = nullptr; + } + formatMap_.erase(iter); + } +} + +const Format::FormatDataMap &Format::GetFormatMap() const +{ + return formatMap_; +} + +std::string Format::Stringify() const +{ + std::string outString; + for (auto iter = formatMap_.begin(); iter != formatMap_.end(); iter++) { + switch (GetValueType(iter->first)) { + case FORMAT_TYPE_INT32: + outString += iter->first + " = " + std::to_string(iter->second.val.int32Val) + " | "; + break; + case FORMAT_TYPE_INT64: + outString += iter->first + " = " + std::to_string(iter->second.val.int64Val) + " | "; + break; + case FORMAT_TYPE_FLOAT: + outString += iter->first + " = " + std::to_string(iter->second.val.floatVal) + " | "; + break; + case FORMAT_TYPE_DOUBLE: + outString += iter->first + " = " + std::to_string(iter->second.val.doubleVal) + " | "; + break; + case FORMAT_TYPE_STRING: + outString += iter->first + " = " + iter->second.stringVal + " | "; + break; + case FORMAT_TYPE_ADDR: + break; + default: + AVCODEC_LOGE("Format::Stringify failed. Key: %{public}s", iter->first.c_str()); + } + } + return outString; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/services/utils/include/avsharedmemorybase.h b/services/utils/include/avsharedmemorybase.h new file mode 100644 index 0000000000000000000000000000000000000000..59b82b82d82dae3f6fd68a9764cd8a29e32cc3ce --- /dev/null +++ b/services/utils/include/avsharedmemorybase.h @@ -0,0 +1,137 @@ +/* + * 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 AVSHAREDMEMORYBASE_H +#define AVSHAREDMEMORYBASE_H + +#include +#include "nocopyable.h" +#include "avsharedmemory.h" + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) AVSharedMemoryBase + : public AVSharedMemory, public NoCopyable { +public: + /** + * @brief Construct a new AVSharedMemoryBase object. This function should only be used in the + * local process. + * + * @param size the memory's size, bytes. + * @param flags the memory's accessible flags, refer to {@AVSharedMemory::Flags}. + * @param name the debug string + */ + static std::shared_ptr CreateFromLocal( + int32_t size, uint32_t flags, const std::string &name); + + /** + * @brief Construct a new AVSharedMemoryBase object. This function should only be used in the + * remote process. + * + * @param fd the memory's fd + * @param size the memory's size, bytes. + * @param flags the memory's accessible flags, refer to {@AVSharedMemory::Flags}. + * @param name the debug string + */ + static std::shared_ptr CreateFromRemote( + int32_t fd, int32_t size, uint32_t flags, const std::string &name); + + ~AVSharedMemoryBase(); + + /** + * @brief Construct a new AVSharedMemoryBase object. This function should only be used in the + * local process. + * + * @param size the memory's size, bytes. + * @param flags the memory's accessible flags, refer to {@AVSharedMemory::Flags}. + * @param name the debug string + */ + AVSharedMemoryBase(int32_t size, uint32_t flags, const std::string &name); + + /** + * @brief Intialize the memory. Call this interface firstly before the other interface. + * @return AVCS_ERR_OK if success, otherwise the errcode. + */ + int32_t Init(); + + /** + * @brief Get the memory's fd, which only valid when the underlying memory + * chunk is allocated through the ashmem. + * @return the memory's fd if the memory is allocated through the ashmem, otherwise -1. + */ + int32_t GetFd() const + { + return fd_; + } + + std::string GetName() const + { + return name_; + } + + int32_t Write(const uint8_t *in, int32_t writeSize, int32_t position = INVALID_POSITION); + + int32_t Read(uint8_t *out, int32_t readSize, int32_t position = INVALID_POSITION); + + int32_t GetUsedSize() const; + + void ClearUsedSize(); + + /** + * @brief Get the memory's virtual address + * @return the memory's virtual address if the memory is valid, otherwise nullptr. + */ + virtual uint8_t *GetBase() const override + { + return base_; + } + + /** + * @brief Get the memory's size + * @return the memory's size if the memory is valid, otherwise -1. + */ + virtual int32_t GetSize() const override + { + return (base_ != nullptr) ? capacity_ : -1; + } + + /** + * @brief Get the memory's flags set by the creator, refer to {@Flags} + * @return the memory's flags if the memory is valid, otherwise 0. + */ + virtual uint32_t GetFlags() const final + { + return (base_ != nullptr) ? flags_ : 0; + } + +protected: + AVSharedMemoryBase(int32_t fd, int32_t size, uint32_t flags, const std::string &name); + +private: + int32_t MapMemory(bool isRemote); + void Close() noexcept; + + uint8_t *base_; + int32_t capacity_; + uint32_t flags_; + std::string name_; + int32_t fd_; + int32_t size_; + static constexpr int32_t INVALID_POSITION = -1; +}; +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/utils/include/block_queue.h b/services/utils/include/block_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..11f60377de826213171b51840e8a94422c1ba745 --- /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}zu.", + 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/services/utils/include/scope_guard.h b/services/utils/include/scope_guard.h new file mode 100644 index 0000000000000000000000000000000000000000..f75c5082aab27e1c8524a1668237f5b42a7fd9e0 --- /dev/null +++ b/services/utils/include/scope_guard.h @@ -0,0 +1,63 @@ +/* + * 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 SCOPE_GUARD_H +#define SCOPE_GUARD_H + +#include + +namespace OHOS { +/* + * The RAII feature is used to implement scope exit protection so that resources + * can be released and the closure action can be performed in a unified manner when + * the scope exits. + */ +namespace Detail { +template +class ScopeGuard { +public: + explicit ScopeGuard(ExitAction &&action) : action_(action), enable_(true) {} + ~ScopeGuard() + { + if (enable_) { + action_(); + } + } + + void Disable() + { + enable_ = false; + } + +private: + ExitAction action_; + bool enable_; +}; + +struct ScopeExitGuardHelper {}; +template +static inline ScopeGuard operator+(ScopeExitGuardHelper, ExitAction &&action) +{ + return ScopeGuard(std::forward(action)); +} +} + +#define ON_SCOPE_EXIT(id) \ + auto onScopeExitGuard##id = Detail::ScopeExitGuardHelper{} + [ & ] + +#define CANCEL_SCOPE_EXIT_GUARD(id) \ + onScopeExitGuard##id.Disable() +} +#endif diff --git a/services/utils/include/task_thread.h b/services/utils/include/task_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..6a5842df55d92d15ea01951f6c5d72ee2aa9d7a9 --- /dev/null +++ b/services/utils/include/task_thread.h @@ -0,0 +1,70 @@ +/* + * 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 AV_CODEC_TASK_THREAD_H +#define AV_CODEC_TASK_THREAD_H + +#include +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace Media { +class __attribute__((visibility("default"))) TaskThread { +public: + explicit TaskThread(std::string_view name); + + TaskThread(std::string_view name, std::function handler); + + ~TaskThread(); + + void Start(); + + void Stop(); + + void StopAsync(); + + void Pause(); + + void PauseAsync(); + + void RegisterHandler(std::function handler); + +private: + void doTask(); + void Run(); + +private: + enum class RunningState { + STARTED, + PAUSING, + PAUSED, + STOPPING, + STOPPED, + }; + const std::string_view name_; + std::atomic runningState_; + std::unique_ptr loop_; + std::function handler_ = [this] { doTask(); }; + std::mutex stateMutex_; + std::condition_variable syncCond_; +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/utils/include/utils.h b/services/utils/include/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..b3445ca026b07630bd8571469a33c7a01ce3556e --- /dev/null +++ b/services/utils/include/utils.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 UTILS_H +#define UTILS_H + +#include + +namespace OHOS { +namespace Media { +inline void SleepFor(unsigned ms) +{ + constexpr int factor = 1000; + usleep(ms * factor); +} + +template +using MakeUnsigned = typename std::make_unsigned::type; + +template +constexpr T AlignUp(T num, U alignment) +{ + return (alignment > 0) ? (static_cast((num + static_cast>(alignment) - 1)) & + static_cast((~(static_cast>(alignment) - 1)))) + : num; +} + +template +inline std::shared_ptr ReinterpretPointerCast(const std::shared_ptr& ptr) noexcept +{ + return std::shared_ptr(ptr, reinterpret_cast(ptr.get())); +} +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/utils/task_thread.cpp b/services/utils/task_thread.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c250458770c615651cd02d9611aaa57b664a2d7 --- /dev/null +++ b/services/utils/task_thread.cpp @@ -0,0 +1,157 @@ +/* + * 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 "task_thread.h" +#include "avcodec_log.h" + +namespace { +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AvCodec-TaskThread"}; +} +namespace OHOS { +namespace Media { +TaskThread::TaskThread(std::string_view name) : name_(name), runningState_(RunningState::STOPPED), loop_(nullptr) +{ + AVCODEC_LOGD("task %{public}s ctor called", name_.data()); +} + +TaskThread::TaskThread(std::string_view name, std::function handler) : TaskThread(name) +{ + handler_ = std::move(handler); + loop_ = std::make_unique(&TaskThread::Run, this); +} + +TaskThread::~TaskThread() +{ + AVCODEC_LOGD("task %{public}s dtor called", name_.data()); + runningState_ = RunningState::STOPPED; + syncCond_.notify_all(); + + if (loop_) { + if (loop_->joinable()) { + loop_->join(); + } + loop_ = nullptr; + } +} + +void TaskThread::Start() +{ + std::unique_lock lock(stateMutex_); + runningState_ = RunningState::STARTED; + + if (!loop_) { // thread not exist + loop_ = std::make_unique(&TaskThread::Run, this); + } + syncCond_.notify_all(); + AVCODEC_LOGD("task %{public}s start called", name_.data()); +} + +void TaskThread::Stop() +{ + AVCODEC_LOGW("task %{public}s stop entered, current state: %{public}d", name_.data(), runningState_.load()); + std::unique_lock lock(stateMutex_); + if (runningState_.load() != RunningState::STOPPED) { + runningState_ = RunningState::STOPPING; + syncCond_.notify_all(); + syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; }); + if (loop_) { + if (loop_->joinable()) { + loop_->join(); + } + loop_ = nullptr; + } + } + AVCODEC_LOGW("task %{public}s stop exited", name_.data()); +} + +void TaskThread::StopAsync() +{ + AVCODEC_LOGD("task %{public}s StopAsync called", name_.data()); + std::unique_lock lock(stateMutex_); + if (runningState_.load() != RunningState::STOPPED) { + runningState_ = RunningState::STOPPING; + } +} + +void TaskThread::Pause() +{ + AVCODEC_LOGD("task %{public}s Pause called", name_.data()); + std::unique_lock lock(stateMutex_); + switch (runningState_.load()) { + case RunningState::STARTED: { + runningState_ = RunningState::PAUSING; + syncCond_.wait(lock, [this] { + return runningState_.load() == RunningState::PAUSED || runningState_.load() == RunningState::STOPPED; + }); + break; + } + case RunningState::STOPPING: { + syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::STOPPED; }); + break; + } + case RunningState::PAUSING: { + syncCond_.wait(lock, [this] { return runningState_.load() == RunningState::PAUSED; }); + break; + } + default: + break; + } + AVCODEC_LOGD("task %{public}s Pause done.", name_.data()); +} + +void TaskThread::PauseAsync() +{ + AVCODEC_LOGD("task %{public}s PauseAsync called", name_.data()); + std::unique_lock lock(stateMutex_); + if (runningState_.load() == RunningState::STARTED) { + runningState_ = RunningState::PAUSING; + } +} + +void TaskThread::RegisterHandler(std::function handler) +{ + AVCODEC_LOGI("task %{public}s RegisterHandler called", name_.data()); + handler_ = std::move(handler); +} + +void TaskThread::doTask() +{ + AVCODEC_LOGD("task %{public}s not override DoTask...", name_.data()); +} + +void TaskThread::Run() +{ + for (;;) { + AVCODEC_LOGD("task %{public}s is running on state : %{public}d", name_.data(), runningState_.load()); + if (runningState_.load() == RunningState::STARTED) { + handler_(); + } + std::unique_lock lock(stateMutex_); + if (runningState_.load() == RunningState::PAUSING || runningState_.load() == RunningState::PAUSED) { + runningState_ = RunningState::PAUSED; + syncCond_.notify_all(); + constexpr int timeoutMs = 500; + syncCond_.wait_for(lock, std::chrono::milliseconds(timeoutMs), + [this] { return runningState_.load() != RunningState::PAUSED; }); + } + if (runningState_.load() == RunningState::STOPPING || runningState_.load() == RunningState::STOPPED) { + runningState_ = RunningState::STOPPED; + syncCond_.notify_all(); + break; + } + } +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/BUILD.gn b/test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..c051f268772b6d7536c8603fcb05f00e5980ff49 --- /dev/null +++ b/test/BUILD.gn @@ -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. + +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 = [] + if (multimedia_av_codec_support_test) { + deps += [ + "unittest:av_audio_unit_test", + "unittest:av_video_unit_test", + "unittest/avcodec_test:acodec_capi_unit_test", + "unittest/avcodec_test:vcodec_capi_unit_test", + "unittest/avmuxer_test:avmuxer_capi_unit_test", + "unittest/avmuxer_test:avmuxer_inner_unit_test", + "unittest/codeclist_test:codeclist_capi_unit_test", + "unittest/codeclist_test:codeclist_inner_unit_test", + "unittest/format_test:avformat_capi_unit_test", + "unittest/format_test:avformat_inner_unit_test", + ] + } +} diff --git a/test/nativedemo/BUILD.gn b/test/nativedemo/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..ae3de42badd304f6845a6cda7165d03790e7bd8f --- /dev/null +++ b/test/nativedemo/BUILD.gn @@ -0,0 +1,99 @@ +# 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/ohos.gni") +import("//foundation/multimedia/av_codec/config.gni") + +ohos_executable("av_codec_demo") { + include_dirs = [ + "$av_codec_root_dir/frameworks/native/capi/common", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/dfx/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/engine/codec/include/video", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/plugin/core", + "$av_codec_root_dir/services/engine/plugin/interface", + "$av_codec_root_dir/services/engine/source/hst_releated", + "$av_codec_root_dir/services/services/factory", + "$av_codec_root_dir/services/utils/include", + "./audio_demo", + "./avmuxer", + "./codeclist_demo", + "./include", + "//third_party/ffmpeg", + + ] + + cflags = [ + "-Wall", + "-fno-rtti", + "-fno-exceptions", + "-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", + "-Wno-deprecated-declarations", + ] + + cflags_cc = cflags + cflags_cc += [ "-std=c++17" ] + + sources = [ + "./audio_demo/avcodec_audio_decoder_demo.cpp", + "./audio_demo/avcodec_audio_encoder_demo.cpp", + "./audio_demo/avcodec_audio_decoder_inner_demo.cpp", + "./audio_demo/avcodec_audio_encoder_inner_demo.cpp", + "./av_codec_demo.cpp", + "./avmuxer/avmuxer_demo.cpp", + "./avmuxer/avmuxer_demo_base.cpp", + "./avmuxer/avmuxer_demo_common.c", + "./avmuxer/avmuxer_engine_demo.cpp", + "./avmuxer/avmuxer_ffmpeg_demo.cpp", + "./avmuxer/avmuxer_demo_runner.cpp", + "./avmuxer/native_avmuxer_demo.c", + "./codeclist_demo/codeclist_demo.cpp", + ] + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:capi_packages", + "$av_codec_root_dir/interfaces/kits/c:native_av_codec_avmuxer", + "$av_codec_root_dir/services/services:av_codec_service", + "$av_codec_root_dir/services/utils:av_codec_format", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/ffmpeg:libohosffmpeg", + ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + ] + install_enable = false + + part_name = "av_codec" + subsystem_name = "multimedia" +} diff --git a/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6aab55f714a0c4c58e1efc725e6870b1ba7f9bc2 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.cpp @@ -0,0 +1,308 @@ +/* + * 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 "avcodec_audio_decoder_demo.h" +#include +#include +#include "avcodec_audio_codec_key.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "demo_log.h" +#include "media_description.h" +#include "native_avcodec_base.h" +#include "native_avformat.h" +#include "securec.h" + +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::AudioDemo; +using namespace std; +namespace { +constexpr uint32_t CHANNEL_COUNT = 2; +constexpr uint32_t SAMPLE_RATE = 44100; +constexpr uint32_t BITS_RATE = 169000; +constexpr uint32_t BITS_PER_CODED_RATE = 4; +constexpr uint32_t FRAME_DURATION_US = 33000; +constexpr string_view inputFilePath = "/data/test441_2_noid3.mp3"; +constexpr string_view outputFilePath = "/data/audioOut.pcm"; +} // namespace + +static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)codec; + (void)errorCode; + (void)userData; + cout << "Error received, errorCode:" << errorCode << endl; +} + +static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)codec; + (void)format; + (void)userData; + cout << "OnOutputFormatChanged received" << endl; +} + +static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)codec; + ADecSignal *signal_ = static_cast(userData); + cout << "OnInputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(index); + signal_->inBufferQueue_.push(data); + signal_->inCond_.notify_all(); +} + +static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData) +{ + (void)codec; + ADecSignal *signal_ = static_cast(userData); + cout << "OnOutputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(index); + signal_->outBufferQueue_.push(data); + if (attr) { + cout << "OnOutputBufferAvailable received, index:" << index << ", attr->size:" << attr->size << endl; + signal_->attrQueue_.push(*attr); + } else { + cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl; + } + signal_->outCond_.notify_all(); +} + +void ADecDemo::RunCase() +{ + DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail"); + + OH_AVFormat *format = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY.data(), BITS_PER_CODED_RATE); + OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE); + DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail"); + + DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail"); + + while (isRunning_.load()) { + sleep(1); // sleep 1s + } + + DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail"); + std::cout << "end stop!\n"; + DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail"); +} + +ADecDemo::ADecDemo() +{ + int32_t ret = 0; + ret = avformat_open_input(&fmpt_ctx, inputFilePath.data(), NULL, NULL); + if (ret < 0) { + std::cout << "open file failed" << ret << "\n"; + exit(1); + } + if (avformat_find_stream_info(fmpt_ctx, NULL) < 0) { + std::cout << "get file stream failed" + << "\n"; + exit(1); + } + frame = av_frame_alloc(); + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; +} + +ADecDemo::~ADecDemo() +{ + if (signal_) { + delete signal_; + signal_ = nullptr; + } +} + +int32_t ADecDemo::CreateDec() +{ + audioDec_ = OH_AudioDecoder_CreateByName((AVCodecAudioCodecKey::AUDIO_DECODER_MP3_NAME_KEY).data()); + DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail"); + + signal_ = new ADecSignal(); + DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; + int32_t ret = OH_AudioDecoder_SetCallback(audioDec_, cb_, signal_); + DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail"); + + return AVCS_ERR_OK; +} + +int32_t ADecDemo::Configure(OH_AVFormat *format) +{ + return OH_AudioDecoder_Configure(audioDec_, format); +} + +int32_t ADecDemo::Start() +{ + isRunning_.store(true); + + inputLoop_ = make_unique(&ADecDemo::InputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + outputLoop_ = make_unique(&ADecDemo::OutputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + return OH_AudioDecoder_Start(audioDec_); +} + +int32_t ADecDemo::Stop() +{ + isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.notify_all(); + lock.unlock(); + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.notify_all(); + lock.unlock(); + outputLoop_->join(); + } + std::cout << "start stop!\n"; + return OH_AudioDecoder_Stop(audioDec_); +} + +int32_t ADecDemo::Flush() +{ + return OH_AudioDecoder_Flush(audioDec_); +} + +int32_t ADecDemo::Reset() +{ + return OH_AudioDecoder_Reset(audioDec_); +} + +int32_t ADecDemo::Release() +{ + return OH_AudioDecoder_Destroy(audioDec_); +} + +void ADecDemo::InputFunc() +{ + while (true) { + if (!isRunning_.load()) { + break; + } + + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); }); + + if (!isRunning_.load()) { + break; + } + + uint32_t index = signal_->inQueue_.front(); + auto buffer = signal_->inBufferQueue_.front(); + int32_t ret = av_read_frame(fmpt_ctx, &pkt); + if (ret < 0) { + OH_AVCodecBufferAttr info; + info.size = 0; + info.offset = 0; + info.pts = 0; + info.flags = AVCODEC_BUFFER_FLAGS_EOS; + av_packet_unref(&pkt); + OH_AudioDecoder_PushInputData(audioDec_, index, info); + signal_->inBufferQueue_.pop(); + signal_->inQueue_.pop(); + std::cout << "end buffer\n"; + break; + } + std::cout << "start read frame: size:" << pkt.size << ",pts:" << pkt.pts << "\n"; + DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail"); + OH_AVCodecBufferAttr info; + info.size = pkt.size; + info.offset = 0; + info.pts = pkt.pts; + memcpy_s(OH_AVMemory_GetAddr(buffer), pkt.size, pkt.data, pkt.size); + + ret = AVCS_ERR_OK; + if (isFirstFrame_) { + info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + ret = OH_AudioDecoder_PushInputData(audioDec_, index, info); + isFirstFrame_ = false; + } else { + info.flags = AVCODEC_BUFFER_FLAGS_NONE; + ret = OH_AudioDecoder_PushInputData(audioDec_, index, info); + } + + timeStamp_ += FRAME_DURATION_US; + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); + + frameCount_++; + + if (ret != AVCS_ERR_OK) { + cout << "Fatal error, exit" << endl; + break; + } + } +} + +void ADecDemo::OutputFunc() +{ + std::ofstream pcmFile; + pcmFile.open(outputFilePath.data(), std::ios::out | std::ios::binary); + if (!pcmFile.is_open()) { + std::cout << "open " << outputFilePath << " failed!" << std::endl; + } + + while (true) { + if (!isRunning_.load()) { + cout << "stop, exit" << endl; + break; + } + + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); }); + + if (!isRunning_.load()) { + cout << "wait to stop, exit" << endl; + break; + } + + uint32_t index = signal_->outQueue_.front(); + OH_AVCodecBufferAttr attr = signal_->attrQueue_.front(); + OH_AVMemory *data = signal_->outBufferQueue_.front(); + if (data != nullptr) { + cout << "OutputFunc write file,buffer index" << index << ", data size = :" << attr.size << endl; + pcmFile.write(reinterpret_cast(OH_AVMemory_GetAddr(data)), attr.size); + } + + if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) { + cout << "decode eos" << endl; + isRunning_.store(false); + } + signal_->outBufferQueue_.pop(); + signal_->attrQueue_.pop(); + signal_->outQueue_.pop(); + if (OH_AudioDecoder_FreeOutputData(audioDec_, index) != AV_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + break; + } + } + pcmFile.close(); +} \ No newline at end of file diff --git a/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.h b/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..443a17c3ba9f17da2708bc1989e0ea682132690a --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_decoder_demo.h @@ -0,0 +1,88 @@ +/* + * 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 AVCODEC_AUDIO_DECODER_DEMO_H +#define AVCODEC_AUDIO_DECODER_DEMO_H + +#include +#include +#include +#include +#include + +#include "native_avcodec_audiodecoder.h" +#include "nocopyable.h" + +#ifdef __cplusplus +extern "C" { +#endif +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +#ifdef __cplusplus +} +#endif + +namespace OHOS { +namespace Media { +namespace AudioDemo { +class ADecSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; + std::queue attrQueue_; +}; + +class ADecDemo : public NoCopyable { +public: + ADecDemo(); + virtual ~ADecDemo(); + void RunCase(); + +private: + int32_t CreateDec(); + int32_t Configure(OH_AVFormat *format); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + void InputFunc(); + void OutputFunc(); + + std::atomic isRunning_ = false; + std::unique_ptr testFile_; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + OH_AVCodec *audioDec_; + ADecSignal *signal_; + struct OH_AVCodecAsyncCallback cb_; + bool isFirstFrame_ = true; + int64_t timeStamp_ = 0; + uint32_t frameCount_ = 0; + + AVFormatContext *fmpt_ctx; + AVFrame *frame; + AVPacket pkt; +}; +} // namespace AudioDemo +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_DEMO_H diff --git a/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5245d17e998ce91328307404f755f991dd341545 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.cpp @@ -0,0 +1,288 @@ +/* + * 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 "avcodec_errors.h" +#include "avcodec_common.h" +#include "demo_log.h" +#include "media_description.h" +#include "securec.h" +#include "avcodec_audio_decoder_inner_demo.h" + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +#include "libavutil/imgutils.h" +#include "libavutil/samplefmt.h" +#include "libavutil/timestamp.h" +} + +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::InnerAudioDemo; +using namespace std; +namespace { +constexpr uint32_t CHANNEL_COUNT = 2; +constexpr uint32_t SAMPLE_RATE = 44100; +constexpr uint32_t BITS_RATE = 169000; // for mp3 +constexpr uint32_t BITS_PER_CODED_RATE = 4; +constexpr string_view inputFilePath = "/data/audioIn.mp3"; +constexpr string_view outputFilePath = "/data/audioOut.pcm"; +} // namespace + +void ADecInnerDemo::RunCase() +{ + DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail"); + + Format format; + format.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, CHANNEL_COUNT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, SAMPLE_RATE); + format.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, BITS_RATE); + format.PutIntValue("bits_per_coded_sample", BITS_PER_CODED_RATE); + DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail"); + + DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail"); + while (isRunning_.load()) { + sleep(1); // start run 1s + } + DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail"); + DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail"); +} + +int32_t ADecInnerDemo::CreateDec() +{ + audioDec_ = AudioDecoderFactory::CreateByName("OH.Media.Codec.MP3.FFMPEGMp3"); + DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail"); + + signal_ = make_shared(); + + cb_ = make_unique(signal_); + DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + DEMO_CHECK_AND_RETURN_RET_LOG(audioDec_->SetCallback(cb_) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Fatal: SetCallback fail"); + + return AVCS_ERR_OK; +} + +int32_t ADecInnerDemo::Configure(const Format &format) +{ + return audioDec_->Configure(format); +} + +int32_t ADecInnerDemo::Start() +{ + isRunning_.store(true); + + inputLoop_ = make_unique(&ADecInnerDemo::InputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + outputLoop_ = make_unique(&ADecInnerDemo::OutputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + return audioDec_->Start(); +} + +int32_t ADecInnerDemo::Stop() +{ + isRunning_.store(false); + + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(0); + signal_->inCond_.notify_all(); + lock.unlock(); + inputLoop_->join(); + inputLoop_.reset(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(0); + signal_->outCond_.notify_all(); + lock.unlock(); + outputLoop_->join(); + outputLoop_.reset(); + } + + return audioDec_->Stop(); +} + +int32_t ADecInnerDemo::Flush() +{ + return audioDec_->Flush(); +} + +int32_t ADecInnerDemo::Reset() +{ + return audioDec_->Reset(); +} + +int32_t ADecInnerDemo::Release() +{ + return audioDec_->Release(); +} + +void ADecInnerDemo::HandleInputEOS(const uint32_t &index) +{ + AVCodecBufferInfo attr; + AVCodecBufferFlag flag; + attr.presentationTimeUs = 0; + attr.size = 0; + attr.offset = 0; + flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS; + (void)audioDec_->QueueInputBuffer(index, attr, flag); + signal_->inQueue_.pop(); + std::cout << "end buffer\n"; +} + +int32_t ADecInnerDemo::HandleNormalInput(const uint32_t &index, const int64_t &pts, const size_t &size) +{ + AVCodecBufferInfo attr; + AVCodecBufferFlag flag; + attr.presentationTimeUs = pts; + attr.size = size; + attr.offset = 0; + flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + frameCount_++; + auto result = audioDec_->QueueInputBuffer(index, attr, flag); + signal_->inQueue_.pop(); + return result; +} + +void ADecInnerDemo::InputFunc() +{ + AVFormatContext *fmpt_ctx; + AVPacket pkt; + if (avformat_open_input(&fmpt_ctx, inputFilePath.data(), NULL, NULL) < 0) { + std::cout << "open file failed\n"; + return; + } + if (avformat_find_stream_info(fmpt_ctx, NULL) < 0) { + std::cout << "get file stream failed\n"; + return; + } + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + while (true) { + if (!isRunning_.load()) { + break; + } + std::unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->inQueue_.front(); + std::shared_ptr buffer = audioDec_->GetInputBuffer(index); + if (buffer == nullptr) { + isRunning_.store(false); + std::cout << "buffer is null:" << index << "\n"; + break; + } + int ret = av_read_frame(fmpt_ctx, &pkt); + if (ret < 0) { + HandleInputEOS(index); + av_packet_unref(&pkt); + break; + } + if (memcpy_s(buffer->GetBase(), buffer->GetSize(), pkt.data, pkt.size) != EOK) { + cout << "Fatal: memcpy fail" << endl; + break; + } + auto result = HandleNormalInput(index, pkt.pts, pkt.size); + av_packet_unref(&pkt); + if (result != AVCS_ERR_OK) { + std::cout << "QueueInputBuffer error:\n"; + isRunning_ = false; + break; + } + } +} + +void ADecInnerDemo::OutputFunc() +{ + std::ofstream outputFile(outputFilePath.data(), std::ios::binary); + while (true) { + if (!isRunning_.load()) { + break; + } + + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; }); + + if (!isRunning_.load()) { + break; + } + + uint32_t index = signal_->outQueue_.front(); + auto buffer = audioDec_->GetOutputBuffer(index); + if (buffer == nullptr) { + cout << "get output buffer failed" << endl; + isRunning_.store(false); + break; + } + auto attr = signal_->infoQueue_.front(); + auto flag = signal_->flagQueue_.front(); + if (flag == AVCODEC_BUFFER_FLAG_EOS) { + cout << "decode eos" << endl; + isRunning_.store(false); + } + outputFile.write((char *)buffer->GetBase(), attr.size); + if (audioDec_->ReleaseOutputBuffer(index) != AVCS_ERR_OK) { + cout << "Fatal: ReleaseOutputBuffer fail" << endl; + break; + } + + signal_->outQueue_.pop(); + signal_->infoQueue_.pop(); + signal_->flagQueue_.pop(); + } +} + +ADecDemoCallback::ADecDemoCallback(shared_ptr signal) : signal_(signal) {} + +void ADecDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl; +} + +void ADecDemoCallback::OnOutputFormatChanged(const Format &format) +{ + (void)format; + cout << "OnOutputFormatChanged received" << endl; +} + +void ADecDemoCallback::OnInputBufferAvailable(uint32_t index) +{ + cout << "OnInputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(index); + signal_->inCond_.notify_all(); +} + +void ADecDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + (void)info; + (void)flag; + cout << "OnOutputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(index); + signal_->infoQueue_.push(info); + signal_->flagQueue_.push(flag); + signal_->outCond_.notify_all(); +} \ No newline at end of file diff --git a/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.h b/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..ef5f8bdddab102a464aca5f7770a0b6a8a333348 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_decoder_inner_demo.h @@ -0,0 +1,88 @@ +/* + * 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 AVCODEC_AUDIO_DECODER_INNER_DEMO_H +#define AVCODEC_AUDIO_DECODER_INNER_DEMO_H + +#include +#include +#include +#include +#include +#include "avcodec_common.h" +#include "avcodec_audio_decoder.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +namespace InnerAudioDemo { +class ADecSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue infoQueue_; + std::queue flagQueue_; +}; + +class ADecDemoCallback : public AVCodecCallback, public NoCopyable { +public: + explicit ADecDemoCallback(std::shared_ptr signal); + virtual ~ADecDemoCallback() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr signal_; +}; + +class ADecInnerDemo : public NoCopyable { +public: + ADecInnerDemo() = default; + virtual ~ADecInnerDemo() = default; + void RunCase(); + +private: + int32_t CreateDec(); + int32_t Configure(const Format &format); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + void InputFunc(); + void OutputFunc(); + void HandleInputEOS(const uint32_t &index); + int32_t HandleNormalInput(const uint32_t &index, const int64_t &pts, const size_t &size); + + std::atomic isRunning_ = false; + std::unique_ptr testFile_; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + std::shared_ptr audioDec_; + std::shared_ptr signal_; + std::shared_ptr cb_; + uint32_t frameCount_ = 0; +}; +} // namespace InnerAudioDemo +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_INNER_DEMO_H diff --git a/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a929a2da2e646e1d42d429c4d2eb819b487147e --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.cpp @@ -0,0 +1,315 @@ +/* + * 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 "securec.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "media_description.h" +#include "native_avformat.h" +#include "demo_log.h" +#include "native_avcodec_base.h" +#include "avcodec_audio_codec_key.h" +#include "avcodec_audio_encoder_demo.h" + +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::AudioDemo; +using namespace std; +namespace { +constexpr uint32_t CHANNEL_COUNT = 2; +constexpr uint32_t SAMPLE_RATE = 44100; +constexpr uint32_t BITS_RATE = 169000; +constexpr uint32_t BITS_PER_CODED_RATE = 16; +constexpr uint32_t FRAME_DURATION_US = 33000; +constexpr uint32_t CHANNEL_LAYOUT = 3; +constexpr int32_t SAMPLE_FORMAT = 1; + +constexpr string_view inputFilePath = "/data/encoderTest.pcm"; +constexpr string_view outputFilePath = "/data/encoderTest.flac"; +} // namespace + +static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)codec; + (void)errorCode; + (void)userData; + cout << "Error received, errorCode:" << errorCode << endl; +} + +static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)codec; + (void)format; + (void)userData; + cout << "OnOutputFormatChanged received" << endl; +} + +static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)codec; + AEncSignal *signal_ = static_cast(userData); + cout << "OnInputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(index); + signal_->inBufferQueue_.push(data); + signal_->inCond_.notify_all(); +} + +static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData) +{ + (void)codec; + AEncSignal *signal_ = static_cast(userData); + cout << "OnOutputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(index); + signal_->outBufferQueue_.push(data); + if (attr) { + cout << "OnOutputBufferAvailable received, index:" << index << ", attr->size:" << attr->size + << ", attr->flags:" << attr->flags << endl; + signal_->attrQueue_.push(*attr); + } else { + cout << "OnOutputBufferAvailable error, attr is nullptr!" << endl; + } + signal_->outCond_.notify_all(); +} + +void AEncDemo::RunCase() +{ + std::cout << "RunCase enter" << std::endl; + DEMO_CHECK_AND_RETURN_LOG(CreateEnc() == AVCS_ERR_OK, "Fatal: CreateEnc fail"); + + OH_AVFormat *format = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT.data(), CHANNEL_COUNT); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_RATE.data(), SAMPLE_RATE); + OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_BITRATE.data(), BITS_RATE); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY.data(), BITS_PER_CODED_RATE); + OH_AVFormat_SetIntValue(format, MediaDescriptionKey::MD_KEY_SAMPLE_FORMAT.data(), SAMPLE_FORMAT); + OH_AVFormat_SetLongValue(format, MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT.data(), CHANNEL_LAYOUT); + + DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail"); + + DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail"); + + while (isRunning_.load()) { + sleep(1); + } + + DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail"); + DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail"); +} + +AEncDemo::AEncDemo() +{ + frameCount_ = 0; + isRunning_ = false; + inputFile_ = std::make_unique(inputFilePath, std::ios::binary); +} + +AEncDemo::~AEncDemo() +{ + OH_AudioEncoder_Destroy(audioEnc_); + if (signal_) { + delete signal_; + signal_ = nullptr; + } +} + +int32_t AEncDemo::CreateEnc() +{ + audioEnc_ = OH_AudioEncoder_CreateByName((AVCodecAudioCodecKey::AUDIO_DECODER_FLAC_NAME_KEY).data()); + DEMO_CHECK_AND_RETURN_RET_LOG(audioEnc_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail"); + + signal_ = new AEncSignal(); + DEMO_CHECK_AND_RETURN_RET_LOG(signal_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; + int32_t ret = OH_AudioEncoder_SetCallback(audioEnc_, cb_, signal_); + DEMO_CHECK_AND_RETURN_RET_LOG(ret == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, "Fatal: SetCallback fail"); + + return AVCS_ERR_OK; +} + +int32_t AEncDemo::Configure(OH_AVFormat *format) +{ + return OH_AudioEncoder_Configure(audioEnc_, format); +} + +int32_t AEncDemo::Start() +{ + isRunning_.store(true); + + inputLoop_ = make_unique(&AEncDemo::InputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + outputLoop_ = make_unique(&AEncDemo::OutputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + return OH_AudioEncoder_Start(audioEnc_); +} + +int32_t AEncDemo::Stop() +{ + isRunning_.store(false); + + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.notify_all(); + lock.unlock(); + inputLoop_->join(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.notify_all(); + lock.unlock(); + outputLoop_->join(); + } + + return OH_AudioEncoder_Stop(audioEnc_); +} + +int32_t AEncDemo::Flush() +{ + return OH_AudioEncoder_Flush(audioEnc_); +} + +int32_t AEncDemo::Reset() +{ + return OH_AudioEncoder_Reset(audioEnc_); +} + +int32_t AEncDemo::Release() +{ + return OH_AudioEncoder_Destroy(audioEnc_); +} + +void AEncDemo::HandleEOS(const uint32_t &index) +{ + OH_AVCodecBufferAttr info; + info.size = 0; + info.offset = 0; + info.pts = 0; + info.flags = AVCODEC_BUFFER_FLAGS_EOS; + OH_AudioEncoder_PushInputData(audioEnc_, index, info); + std::cout << "end buffer\n"; + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); +} + +void AEncDemo::InputFunc() +{ + DEMO_CHECK_AND_RETURN_LOG(inputFile_ != nullptr && inputFile_->is_open(), "Fatal: open file fail"); + inputFile_->seekg(0, ios::end); + int32_t fsize = inputFile_->tellg(); + inputFile_->seekg(0, ios::beg); + while (true) { + if (!isRunning_.load()) { + break; + } + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return (signal_->inQueue_.size() > 0 || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->inQueue_.front(); + auto buffer = signal_->inBufferQueue_.front(); + DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail"); + + uint32_t bufferSize = fsize > OH_AVMemory_GetSize(buffer) ? OH_AVMemory_GetSize(buffer) : fsize; + if (fsize > 0 || !inputFile_->eof()) { + (void)inputFile_->read((char *)OH_AVMemory_GetAddr(buffer), bufferSize); + fsize = fsize - bufferSize; + std::cout << "fsize " << fsize << std::endl; + } else { + HandleEOS(index); + break; + } + DEMO_CHECK_AND_BREAK_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail"); + OH_AVCodecBufferAttr info; + info.size = bufferSize; + info.offset = 0; + + int32_t ret = AVCS_ERR_OK; + if (isFirstFrame_) { + info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info); + isFirstFrame_ = false; + } else { + info.flags = AVCODEC_BUFFER_FLAGS_NONE; + ret = OH_AudioEncoder_PushInputData(audioEnc_, index, info); + } + timeStamp_ += FRAME_DURATION_US; + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); + frameCount_++; + if (ret != AVCS_ERR_OK) { + cout << "Fatal error, exit" << endl; + break; + } + } + inputFile_->close(); +} + +void AEncDemo::OutputFunc() +{ + std::ofstream outputFile; + outputFile.open(outputFilePath.data(), std::ios::out | std::ios::binary); + if (!outputFile.is_open()) { + std::cout << "open " << outputFilePath << " failed!" << std::endl; + } + + while (true) { + if (!isRunning_.load()) { + cout << "stop, exit" << endl; + break; + } + + unique_lock lock(signal_->outMutex_); + cout << "lock, before" << endl; + signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); }); + cout << "lock, after" << endl; + + if (!isRunning_.load()) { + cout << "wait to stop, exit" << endl; + break; + } + + uint32_t index = signal_->outQueue_.front(); + + OH_AVCodecBufferAttr attr = signal_->attrQueue_.front(); + OH_AVMemory *data = signal_->outBufferQueue_.front(); + if (data != nullptr) { + cout << "OutputFunc write file,buffer index" << index << ", data size = :" << attr.size << endl; + outputFile.write(reinterpret_cast(OH_AVMemory_GetAddr(data)), attr.size); + } + cout << "attr.flags: " << attr.flags << endl; + if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS || attr.size == 0) { + cout << "encode eos" << endl; + isRunning_.store(false); + } + + signal_->outBufferQueue_.pop(); + signal_->attrQueue_.pop(); + signal_->outQueue_.pop(); + if (OH_AudioEncoder_FreeOutputData(audioEnc_, index) != AV_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + break; + } + } + outputFile.close(); +} diff --git a/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.h b/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..1eda004bc10bb7b8dc1c79ee328670c41a69eac7 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_encoder_demo.h @@ -0,0 +1,76 @@ +/* + * 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 AVCODEC_AUDIO_ENCODER_DEMO_H +#define AVCODEC_AUDIO_ENCODER_DEMO_H + +#include +#include +#include +#include +#include +#include +#include "nocopyable.h" +#include "native_avcodec_audioencoder.h" + +namespace OHOS { +namespace Media { +namespace AudioDemo { +class AEncSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; + std::queue attrQueue_; +}; + +class AEncDemo : public NoCopyable { +public: + AEncDemo(); + virtual ~AEncDemo(); + void RunCase(); + +private: + int32_t CreateEnc(); + int32_t Configure(OH_AVFormat *format); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + void InputFunc(); + void OutputFunc(); + void HandleEOS(const uint32_t &index); + + std::atomic isRunning_; + std::unique_ptr inputFile_; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + OH_AVCodec *audioEnc_; + AEncSignal *signal_; + struct OH_AVCodecAsyncCallback cb_; + bool isFirstFrame_ = true; + int64_t timeStamp_ = 0; + uint32_t frameCount_ = 0; +}; +} // namespace AudioDemo +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_DEMO_H diff --git a/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.cpp b/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a68d19a5e89ab4652675f6e50665522b8a87176 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.cpp @@ -0,0 +1,255 @@ +/* + * 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 "avcodec_audio_codec_key.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "demo_log.h" +#include "media_description.h" +#include "securec.h" +#include "avcodec_audio_encoder_inner_demo.h" + +extern "C" { +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" +#include "libavutil/imgutils.h" +#include "libavutil/samplefmt.h" +#include "libavutil/timestamp.h" +} + +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::InnerAudioDemo; +using namespace std; +namespace { +constexpr uint32_t CHANNEL_COUNT = 2; +constexpr uint32_t SAMPLE_RATE = 44100; +constexpr uint32_t BITS_RATE = 112000; // for aac encoding +constexpr uint32_t BITS_PER_CODED_RATE = 4; +constexpr uint32_t DEFAULT_SAMPLE_FORMATE_VALE = 8; +constexpr uint32_t DEFAULT_CHANNEL_LAYOUT_COUNT = 3; +constexpr uint32_t DEFAULT_SLEEP_TIME = 30; +} // namespace + +void AEnInnerDemo::RunCase() +{ + DEMO_CHECK_AND_RETURN_LOG(CreateDec() == AVCS_ERR_OK, "Fatal: CreateDec fail"); + + Format format; + format.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, CHANNEL_COUNT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, SAMPLE_RATE); + format.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, BITS_RATE); + format.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, BITS_PER_CODED_RATE); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_FORMAT, DEFAULT_SAMPLE_FORMATE_VALE); + format.PutLongValue(MediaDescriptionKey::MD_KEY_CHANNEL_LAYOUT, DEFAULT_CHANNEL_LAYOUT_COUNT); + DEMO_CHECK_AND_RETURN_LOG(Configure(format) == AVCS_ERR_OK, "Fatal: Configure fail"); + + DEMO_CHECK_AND_RETURN_LOG(Start() == AVCS_ERR_OK, "Fatal: Start fail"); + sleep(DEFAULT_SLEEP_TIME); + DEMO_CHECK_AND_RETURN_LOG(Stop() == AVCS_ERR_OK, "Fatal: Stop fail"); + DEMO_CHECK_AND_RETURN_LOG(Release() == AVCS_ERR_OK, "Fatal: Release fail"); +} + +int32_t AEnInnerDemo::CreateDec() +{ + audioEn_ = AudioEncoderFactory::CreateByName((AVCodecAudioCodecKey::AUDIO_ENCODER_AAC_NAME_KEY).data()); + DEMO_CHECK_AND_RETURN_RET_LOG(audioEn_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: CreateByName fail"); + + signal_ = make_shared(); + + cb_ = make_unique(signal_); + DEMO_CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + DEMO_CHECK_AND_RETURN_RET_LOG(audioEn_->SetCallback(cb_) == AVCS_ERR_OK, AVCS_ERR_UNKNOWN, + "Fatal: SetCallback fail"); + + return AVCS_ERR_OK; +} + +int32_t AEnInnerDemo::Configure(const Format &format) +{ + return audioEn_->Configure(format); +} + +int32_t AEnInnerDemo::Start() +{ + isRunning_.store(true); + + inputLoop_ = make_unique(&AEnInnerDemo::InputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + outputLoop_ = make_unique(&AEnInnerDemo::OutputFunc, this); + DEMO_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + + return audioEn_->Start(); +} + +int32_t AEnInnerDemo::Stop() +{ + isRunning_.store(false); + + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(0); + signal_->inCond_.notify_all(); + lock.unlock(); + inputLoop_->join(); + inputLoop_.reset(); + } + + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(0); + signal_->outCond_.notify_all(); + lock.unlock(); + outputLoop_->join(); + outputLoop_.reset(); + } + + return audioEn_->Stop(); +} + +int32_t AEnInnerDemo::Flush() +{ + return audioEn_->Flush(); +} + +int32_t AEnInnerDemo::Reset() +{ + return audioEn_->Reset(); +} + +int32_t AEnInnerDemo::Release() +{ + return audioEn_->Release(); +} + +void AEnInnerDemo::InputFunc() +{ + const char *filePath = "/data/media/test_fltp.pcm"; + int frameBytes = 2 * 1024 * 4; + std::ifstream inputFile(filePath, std::ios::binary); + if (!inputFile.is_open()) { + std::cout << "open file " << filePath << " failed" << std::endl; + return; + } + + while (true) { + if (!isRunning_.load()) { + break; + } + std::unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return signal_->inQueue_.size() > 0; }); + if (!isRunning_.load()) { + break; + } + + uint32_t index = signal_->inQueue_.front(); + std::shared_ptr buffer = audioEn_->GetInputBuffer(index); + if (buffer == nullptr) { + isRunning_.store(false); + std::cout << "buffer is null:" << index << "\n"; + break; + } + inputFile.read((char *)buffer->GetBase(), frameBytes); + int readBytes = inputFile.gcount(); + AVCodecBufferInfo attr; + AVCodecBufferFlag flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE; + if (inputFile.eof() || readBytes == 0) { + flag = AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS; + (void)audioEn_->QueueInputBuffer(index, attr, flag); + signal_->inQueue_.pop(); + std::cout << "end buffer\n"; + continue; + } + auto result = audioEn_->QueueInputBuffer(index, attr, flag); + signal_->inQueue_.pop(); + if (result != AVCS_ERR_OK) { + std::cout << "QueueInputBuffer error:\n"; + isRunning_ = false; + break; + } + } +} + +void AEnInnerDemo::OutputFunc() +{ + std::ofstream outputFile("/data/media/encode.aac", std::ios::binary); + while (true) { + if (!isRunning_.load()) { + break; + } + + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return signal_->outQueue_.size() > 0; }); + + if (!isRunning_.load()) { + break; + } + + uint32_t index = signal_->outQueue_.front(); + auto buffer = audioEn_->GetOutputBuffer(index); + if (buffer == nullptr) { + cout << "get output buffer failed" << endl; + isRunning_.store(false); + break; + } + auto attr = signal_->sizeQueue_.front(); + outputFile.write((char *)buffer->GetBase(), attr.size); + cout << "output write size = " << attr.size << endl; + if (audioEn_->ReleaseOutputBuffer(index) != AVCS_ERR_OK) { + cout << "Fatal: ReleaseOutputBuffer fail" << endl; + break; + } + + signal_->outQueue_.pop(); + signal_->sizeQueue_.pop(); + } +} + +AEnDemoCallback::AEnDemoCallback(shared_ptr signal) : signal_(signal) {} + +void AEnDemoCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + cout << "Error received, errorType:" << errorType << " errorCode:" << errorCode << endl; +} + +void AEnDemoCallback::OnOutputFormatChanged(const Format &format) +{ + (void)format; + cout << "OnOutputFormatChanged received" << endl; +} + +void AEnDemoCallback::OnInputBufferAvailable(uint32_t index) +{ + cout << "OnInputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->inMutex_); + signal_->inQueue_.push(index); + signal_->inCond_.notify_all(); +} + +void AEnDemoCallback::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + (void)info; + (void)flag; + cout << "OnOutputBufferAvailable received, index:" << index << endl; + unique_lock lock(signal_->outMutex_); + signal_->outQueue_.push(index); + signal_->sizeQueue_.push(info); + cout << "**********out info size = " << info.size << endl; + signal_->outCond_.notify_all(); +} \ No newline at end of file diff --git a/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.h b/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..89a10ecfcf8aa7d5f13185cceda1a4c2ea23b870 --- /dev/null +++ b/test/nativedemo/audio_demo/avcodec_audio_encoder_inner_demo.h @@ -0,0 +1,84 @@ +/* + * 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 AVCODEC_AUDIO_ENCODER_INNER_DEMO_H +#define AVCODEC_AUDIO_ENCODER_INNER_DEMO_H + +#include +#include +#include +#include +#include +#include "avcodec_common.h" +#include "avcodec_audio_encoder.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +namespace InnerAudioDemo { +class AEnSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue sizeQueue_; +}; + +class AEnDemoCallback : public AVCodecCallback, public NoCopyable { +public: + explicit AEnDemoCallback(std::shared_ptr signal); + virtual ~AEnDemoCallback() = default; + + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr signal_; +}; + +class AEnInnerDemo : public NoCopyable { +public: + AEnInnerDemo() = default; + virtual ~AEnInnerDemo() = default; + void RunCase(); + +private: + int32_t CreateDec(); + int32_t Configure(const Format &format); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + void InputFunc(); + void OutputFunc(); + + std::atomic isRunning_ = false; + std::unique_ptr testFile_; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + std::shared_ptr audioEn_; + std::shared_ptr signal_; + std::shared_ptr cb_; +}; +} // namespace InnerAudioDemo +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_AUDIO_DECODER_INNER_DEMO_H diff --git a/test/nativedemo/av_codec_demo.cpp b/test/nativedemo/av_codec_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da0e05be8cb7afa73c37a000fd442b90881abdb0 --- /dev/null +++ b/test/nativedemo/av_codec_demo.cpp @@ -0,0 +1,130 @@ +/* + * 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 "avmuxer_demo_runner.h" +#include "avcodec_audio_decoder_inner_demo.h" +#include "avcodec_audio_encoder_inner_demo.h" +#include "avcodec_audio_decoder_demo.h" +#include "avcodec_audio_encoder_demo.h" +#include "codeclist_demo.h" + +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::AudioDemo; +using namespace OHOS::Media::InnerAudioDemo; +using namespace std; + +static int RunAudioDecoder() +{ + auto audioEnc = std::make_unique(); + if (audioEnc == nullptr) { + cout << "audio decoder is null" << endl; + return 0; + } + audioEnc->RunCase(); + cout << "demo audio decoder end" << endl; + return 0; +} + +static int RunAudioEncoder() +{ + auto audioEnc = std::make_unique(); + if (audioEnc == nullptr) { + cout << "audio encoder is null" << endl; + return 0; + } + audioEnc->RunCase(); + cout << "demo audio encoder end" << endl; + return 0; +} + +static int RunAudioInnerDecoder() +{ + auto audioEnc = std::make_unique(); + if (audioEnc == nullptr) { + cout << "audio decoder is null" << endl; + return 0; + } + audioEnc->RunCase(); + cout << "demo audio decoder end" << endl; + return 0; +} + +static int RunAudioInnerEncoder() +{ + auto audioEnc = std::make_unique(); + if (audioEnc == nullptr) { + cout << "audio encoder is null" << endl; + return 0; + } + audioEnc->RunCase(); + cout << "demo audio encoder end" << endl; + return 0; +} + + +static int RunCodecList() +{ + auto codecList = std::make_unique(); + if (codecList == nullptr) { + cout << "codec list is null" << endl; + return 0; + } + codecList->RunCase(); + cout << "codec list end" << endl; + return 0; +} + +static void OptionPrint() +{ + cout << "Please select a demo scenario number(default Audio Decoder): " << endl; + cout << "0:Audio Decoder" << endl; + cout << "1:Audio Encoder" << endl; + cout << "2:Audio Inner Decoder" << endl; + cout << "3:Audio Inner Encoder" << endl; + cout << "4:muxer demo" << endl; + cout << "6:codeclist" << endl; +} + +int main(int argc, char *argv[]) +{ + constexpr int minRequiredArgCount = 2; + string path; + if (argc >= minRequiredArgCount && argv[1] != nullptr) { + path = argv[1]; + } + OptionPrint(); + string mode; + (void)getline(cin, mode); + if (mode == "" || mode == "0") { + (void)RunAudioDecoder(); + } else if (mode == "1") { + (void)RunAudioEncoder(); + } else if (mode == "2") { + (void)RunAudioInnerDecoder(); + } else if (mode == "3") { + (void)RunAudioInnerEncoder(); + } else if (mode == "4") { + (void)AvmuxerDemoCase(); + } else if (mode == "6") { + (void)RunCodecList(); + } else { + cout << "no that selection" << endl; + } + return 0; +} diff --git a/test/nativedemo/avmuxer/avmuxer_demo.cpp b/test/nativedemo/avmuxer/avmuxer_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27741d8856c923a2d43f550cc328bcc799610882 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo.cpp @@ -0,0 +1,116 @@ +/* + * 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 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(latitude, longitude) != 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; + + 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 0000000000000000000000000000000000000000..81d4d56406417c2e4c461884ec09d75428fd1240 --- /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 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 0000000000000000000000000000000000000000..25988feea30902ef8ffddb85366ab97bdab13288 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_base.cpp @@ -0,0 +1,527 @@ +/* + * 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 int MODE_ZERO = 0; + constexpr int MODE_ONE = 1; + constexpr int MODE_TWO = 2; + constexpr int MODE_THREE = 3; + constexpr int CONFIG_BUFFER_SZIE = 100; +} + +namespace OHOS { +namespace Media { +const AudioTrackParam *AVMuxerDemoBase::audioParams_ = nullptr; +const VideoTrackParam *AVMuxerDemoBase::videoParams_ = nullptr; +const VideoTrackParam *AVMuxerDemoBase::coverParams_ = nullptr; +std::string AVMuxerDemoBase::videoType_ = std::string(""); +std::string AVMuxerDemoBase::audioType_ = std::string(""); +std::string AVMuxerDemoBase::coverType_ = std::string(""); +std::string AVMuxerDemoBase::format_ = std::string(""); +OutputFormat AVMuxerDemoBase::outputFormat_ = OUTPUT_FORMAT_DEFAULT; +bool AVMuxerDemoBase::hasSetMode_ = false; + +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; +} + +void AVMuxerDemoBase::SelectFormatMode() +{ + int num; + std::cout<<"\nplease select muxer type: 0.mp4 1.m4a"<>num; + switch (num) { + case MODE_ZERO: + format_ = "mp4"; + outputFormat_ = OUTPUT_FORMAT_MPEG_4; + break; + case MODE_ONE: + format_ = "m4a"; + outputFormat_ = OUTPUT_FORMAT_M4A; + break; + default: + format_ = "mp4"; + outputFormat_ = OUTPUT_FORMAT_MPEG_4; + break; + } +} + +void AVMuxerDemoBase::SelectAudioVideoMode() +{ + int num; + std::cout<<"\nplease select audio file: 0.noAudio 1.aac 2.mpeg"<>num; + switch (num) { + case MODE_ZERO: + audioType_ = "noAudio"; + audioParams_ = nullptr; + break; + case MODE_ONE: + audioType_ = "aac"; + audioParams_ = &g_audioAacPar; + break; + case MODE_TWO: + audioType_ = "mpeg"; + audioParams_ = &g_audioMpegPar; + break; + default: + videoType_ = "noAudio"; + audioParams_ = nullptr; + std::cout<<"do not support audio type index: "<>num; + switch (num) { + case MODE_ZERO: + videoType_ = "noVideo"; + videoParams_ = nullptr; + break; + case MODE_ONE: + videoType_ = "h264"; + videoParams_ = &g_videoH264Par; + break; + case MODE_TWO: + 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 MODE_ZERO: + coverType_ = "noCover"; + coverParams_ = nullptr; + break; + case MODE_ONE: + coverType_ = "jpg"; + coverParams_ = &g_jpegCoverPar; + break; + case MODE_TWO: + coverType_ = "png"; + coverParams_ = &g_pngCoverPar; + break; + case MODE_THREE: + 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, unsigned char *&buffer, + uint32_t &curSize, TrackSampleInfo &info) +{ + uint32_t dataSize = 0; + uint32_t flags = 0; + 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()) { + return -1; + } + info.flags = 0; + if (flags != 0) { + info.flags |= AVCODEC_BUFFER_FLAG_SYNC_FRAME; + } + + curFile->read((char *)&dataSize, sizeof(dataSize)); + if (curFile->eof()) { + return -1; + } + + if (buffer != nullptr && dataSize > curSize) { + delete [] buffer; + buffer = nullptr; + curSize = 0; + } + if (buffer == nullptr) { + buffer = new unsigned char[dataSize]; + curSize = dataSize; + } + + curFile->read((char *)buffer, dataSize); + if (curFile->eof()) { + return -1; + } + info.size = dataSize; + return 0; +} + +void AVMuxerDemoBase::WriteAvTrackSample() +{ + if (audioFile_ == nullptr || videoFile_ == nullptr) { + return; + } + TrackSampleInfo info {0, 0, 0, 0}; + std::shared_ptr 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 (ReadSampleDataInfo(curFile, avMuxerDemoBuffer, avMuxerDemoBufferSize, info) != 0) { + break; + } + + 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() +{ + if (coverParams_ == nullptr) { + return; + } + 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[CONFIG_BUFFER_SZIE] {0}; + videoFile_->read((char*)&extSize, sizeof(extSize)); + if (extSize > 0 && extSize < CONFIG_BUFFER_SZIE) { + 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[CONFIG_BUFFER_SZIE] {0}; + audioFile_->read((char*)&extSize, sizeof(extSize)); + if (extSize > 0 && extSize < CONFIG_BUFFER_SZIE) { + 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 0000000000000000000000000000000000000000..f02907511841cb355c861cd5af28a15dea35f340 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_base.h @@ -0,0 +1,76 @@ +/* + * 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(const VideoTrackParam *param); + int AddAudioTrack(const AudioTrackParam *param); + int AddCoverTrack(const VideoTrackParam *param); + void WriteTrackSample(); + void WriteAvTrackSample(); + void WriteSingleTrackSample(uint32_t trackId, std::shared_ptr file); + void WriteCoverSample(); + void SelectFormatMode(); + void SelectAudioVideoMode(); + void SelectCoverMode(); + int SelectMode(); + int SelectModeAndOpenFile(); + int ReadSampleDataInfo(std::shared_ptr &curFile, unsigned char *&buffer, + uint32_t &curSize, TrackSampleInfo &info); + void Reset(); + static void MulThdWriteTrackSample(AVMuxerDemoBase *muxerBase, uint32_t trackId, + std::shared_ptr file); + + const static AudioTrackParam *audioParams_; + const static VideoTrackParam *videoParams_; + const static VideoTrackParam *coverParams_; + static std::string videoType_; + static std::string audioType_; + static std::string coverType_; + static std::string format_; + static OutputFormat outputFormat_; + static bool hasSetMode_; + + 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}; + int32_t outFd_ {-1}; + uint64_t audioPts_ {0}; + uint64_t videoPts_ {0}; +}; +} // 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 0000000000000000000000000000000000000000..3675753054f2b56ecd0af1ec9a5ce563da413efa --- /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" + +const struct AudioTrackParam g_audioMpegPar = { + .fileName = "mpeg_44100_2.bin", + .mimeType = "audio/mpeg", + .sampleRate = 44100, + .channels = 2, +}; + +const struct AudioTrackParam g_audioAacPar = { + .fileName = "aac_44100_2.bin", + .mimeType = "audio/mp4a-latm", + .sampleRate = 44100, + .channels = 2, +}; + +const struct VideoTrackParam g_videoH264Par = { + .fileName = "h264_640_360.bin", + .mimeType = "video/avc", + .width = 640, + .height = 360, +}; + +const struct VideoTrackParam g_videoMpeg4Par = { + .fileName = "mpeg4_720_480.bin", + .mimeType = "video/mp4v-es", + .width = 720, + .height = 480, +}; + +const struct VideoTrackParam g_jpegCoverPar = { + .fileName = "greatwall.jpg", + .mimeType = "image/jpeg", + .width = 352, + .height = 288, +}; + +const struct VideoTrackParam g_pngCoverPar = { + .fileName = "greatwall.png", + .mimeType = "image/png", + .width = 352, + .height = 288, +}; + +const 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"; \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_common.h b/test/nativedemo/avmuxer/avmuxer_demo_common.h new file mode 100644 index 0000000000000000000000000000000000000000..a068bf3c45ffc88c8887c737f46c95d5bfeda138 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_common.h @@ -0,0 +1,56 @@ +/* + * 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 +#ifdef __cplusplus +extern "C" { +#endif +// only for demo +struct AudioTrackParam { + const char *fileName; + const char *mimeType; + int sampleRate; + int channels; +}; + +struct VideoTrackParam { + const char *fileName; + const char *mimeType; + int width; + int height; +}; + +struct FdListStr { + int start[0]; + int outputFd; + int inAudioFd; + int inVideoFd; + int inCoverFd; +}; + +extern const struct AudioTrackParam g_audioMpegPar; +extern const struct AudioTrackParam g_audioAacPar; +extern const struct VideoTrackParam g_videoH264Par; +extern const struct VideoTrackParam g_videoMpeg4Par; +extern const struct VideoTrackParam g_jpegCoverPar; +extern const struct VideoTrackParam g_pngCoverPar; +extern const struct VideoTrackParam g_bmpCoverPar; +extern const char *RUN_NORMAL; +extern const char *RUN_MUL_THREAD; +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_runner.cpp b/test/nativedemo/avmuxer/avmuxer_demo_runner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cee694a5c81f249ae5fec2cc27c6864a83e46922 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_runner.cpp @@ -0,0 +1,149 @@ +/* + * 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_runner.h" +#include +#include +#include "avmuxer_demo.h" +#include "avmuxer_ffmpeg_demo.h" +#include "avmuxer_engine_demo.h" +#include "native_avmuxer_demo.h" + +using namespace std; +using namespace OHOS::Media; +using namespace OHOS::Media::Plugin; + +constexpr int RUN_TIME = 600; +constexpr int DEMO_THREAD_COUNT = 10; + +static int RunLoopNativeMuxer(string out) +{ + time_t startTime = 0; + time_t curTime = 0; + (void)time(&startTime); + (void)time(&curTime); + while (difftime(curTime, startTime) < RUN_TIME) { + RunNativeMuxer(out.c_str()); + (void)time(&curTime); + } + return 0; +} + +static int RunAVMuxer() +{ + auto avmuxer = std::make_unique(); + if (avmuxer == nullptr) { + cout << "avmuxer is null" << endl; + return 0; + } + avmuxer->RunCase(); + cout << "demo avmuxer end" << endl; + return 0; +} + +static int RunAVMuxerWithMultithread() +{ + auto avmuxer = std::make_unique(); + if (avmuxer == nullptr) { + cout << "avmuxer is null" << endl; + return 0; + } + avmuxer->RunMultiThreadCase(); + cout << "demo multi thread avmuxer end" << endl; + return 0; +} + +static int RunFfmpegMuxer() +{ + std::unique_ptr ffmpegMuxer = std::make_unique(); + if (ffmpegMuxer == nullptr) { + cout << "ffmpegMuxer is null" << endl; + return 0; + } + ffmpegMuxer->RunCase(); + cout << "demo ffmpegMuxer end" << endl; + return 0; +} + +static int RunEngineMuxer() +{ + std::unique_ptr muxer = std::make_unique(); + if (muxer == nullptr) { + cout << "AVMuxerEngineDemo is null" << endl; + return 0; + } + muxer->RunCase(); + cout << "demo engine demo end" << endl; + return 0; +} + + +static int RunLoopEngineMuxer() +{ + time_t startTime = 0; + time_t curTime = 0; + (void)time(&startTime); + (void)time(&curTime); + while (difftime(curTime, startTime) < RUN_TIME) { + RunEngineMuxer(); + (void)time(&curTime); + } + return 0; +} + +void AvmuxerDemoCase(void) +{ + cout << "Please select a muxer demo(default native muxer demo): " << endl; + cout << "0:native_muxer" << endl; + cout << "1:native_muxer loop" << endl; + cout << "2:native_muxer multithread" << endl; + cout << "3:inner_muxer" << endl; + cout << "4:inner_muxer with multithread write" << endl; + cout << "5:ffmpeg_muxer" << endl; + cout << "6:engine_muxer" << endl; + cout << "7:engine_muxer loop" << endl; + + string mode; + (void)getline(cin, mode); + + if (mode == "0" || mode == "") { + (void)NativeSelectMode(); + (void)RunNativeMuxer("native_mux"); + } else if (mode == "1") { + (void)NativeSelectMode(); + (void)RunLoopNativeMuxer("loop_native_mux"); + } else if (mode == "2") { + (void)NativeSelectMode(); + vector vecThread; + for (int i = 0; i < DEMO_THREAD_COUNT; ++i) { + string out = to_string(i + 1); + out += "_native_mux"; + vecThread.push_back(thread(RunLoopNativeMuxer, out)); + } + for (int i = 0; i < DEMO_THREAD_COUNT; ++i) { + vecThread[i].join(); + } + } else if (mode == "3") { + (void)RunAVMuxer(); + } else if (mode == "4") { + (void)RunAVMuxerWithMultithread(); + } else if (mode == "5") { + (void)RunFfmpegMuxer(); + } else if (mode == "6") { + (void)RunEngineMuxer(); + } else if (mode == "7") { + (void)RunLoopEngineMuxer(); + } +} \ No newline at end of file diff --git a/test/nativedemo/avmuxer/avmuxer_demo_runner.h b/test/nativedemo/avmuxer/avmuxer_demo_runner.h new file mode 100644 index 0000000000000000000000000000000000000000..3a40e02a624d47c5206e60d9f490d4795b98ea28 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_demo_runner.h @@ -0,0 +1,21 @@ +/* + * 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_RUNNER_H +#define AVMUXER_DEMO_RUNNER_H + +void AvmuxerDemoCase(void); + +#endif // AVMUXER_DEMO_RUNNER_H \ 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 0000000000000000000000000000000000000000..61c82292a570a24b95f5b7d206e68b111e1449e5 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_engine_demo.cpp @@ -0,0 +1,131 @@ +/* + * 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 { +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(latitude, longitude) != 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; + + 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 0000000000000000000000000000000000000000..fee3a96893767a7033bf2940f7e84ee19cdeb4df --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_engine_demo.h @@ -0,0 +1,37 @@ +/* + * 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 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 0000000000000000000000000000000000000000..b3569af498c2d51138328c43847cc6a3557f8ee6 --- /dev/null +++ b/test/nativedemo/avmuxer/avmuxer_ffmpeg_demo.cpp @@ -0,0 +1,155 @@ +/* + * 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 + +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(latitude, longitude); + ffmpegMuxer_->SetRotation(0); + + AddAudioTrack(audioParams_); + AddVideoTrack(videoParams_); + AddCoverTrack(coverParams_); + + ffmpegMuxer_->Start(); + WriteCoverSample(); + 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 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 0000000000000000000000000000000000000000..950766cb7f07d02d3538615a02460585e99ab04f --- /dev/null +++ b/test/nativedemo/avmuxer/native_avmuxer_demo.c @@ -0,0 +1,664 @@ +/* + * 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 "native_avmuxer_demo.h" +#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 +#define MODE_ZERO 0 +#define MODE_ONE 1 +#define MODE_TWO 2 +#define MODE_THREE 3 +#define TYPE_BUFFER_SIZE 20 +#define CONFIG_BUFFER_SIZE 100 + +typedef struct AudioTrackParam AudioTrackParam; +typedef struct VideoTrackParam VideoTrackParam; +typedef struct FdListStr FdListStr; + +struct WriteTrackSampleParam { + OH_AVMuxer *muxer; + int trackId; + int fd; +}; + +struct MuxerParam { + int outputFormat; + char outputFormatType[TYPE_BUFFER_SIZE]; + int runMode; + char runModeType[TYPE_BUFFER_SIZE]; + const AudioTrackParam *audioParams; + char audioType[TYPE_BUFFER_SIZE]; + const VideoTrackParam *videoParams; + char videoType[TYPE_BUFFER_SIZE]; + const VideoTrackParam *coverParams; + char coverType[TYPE_BUFFER_SIZE]; +}; + +static struct MuxerParam g_muxerParam = { + .outputFormat = AV_OUTPUT_FORMAT_DEFAULT, + .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[CONFIG_BUFFER_SIZE] = {0}; + read(fdInput, (void*)&extraSize, sizeof(extraSize)); + if (extraSize <= CONFIG_BUFFER_SIZE && 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[CONFIG_BUFFER_SIZE] = {0}; + read(fdInput, (void*)&extraSize, sizeof(extraSize)); + if (extraSize <= CONFIG_BUFFER_SIZE && 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; +} + +static int UpDateWriteBufferInfo(int fd, unsigned char **buffer, int *curSize, OH_AVCodecBufferAttr *info) +{ + if (fd < 0 || buffer == NULL || curSize == NULL || info == NULL) { + return -1; + } + + int ret; + int flags = 0; + int dataSize = 0; + + ret = read(fd, (void*)&flags, sizeof(flags)); + if (ret <= 0) { + return -1; + } + + info->flags = 0; + if (flags != 0) { + info->flags |= AVCODEC_BUFFER_FLAGS_SYNC_FRAME; + } + + ret = read(fd, (void*)&dataSize, sizeof(dataSize)); + if (ret <= 0 || dataSize < 0) { + return -1; + } + + if (*buffer != NULL && dataSize > *curSize) { + free(*buffer); + *curSize = 0; + *buffer = NULL; + } + if (*buffer == NULL) { + *buffer = malloc(dataSize); + *curSize = dataSize; + if (*buffer == NULL) { + printf("error malloc memory! %d\n", dataSize); + return -1; + } + } + + ret = read(fd, (void*)*buffer, dataSize); + if (ret <= 0) { + return -1; + } + info->size = dataSize; + return 0; +} + +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; + 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; + } + + if (UpDateWriteBufferInfo(fd, &avMuxerDemoBuffer, &avMuxerDemoBufferSize, &info) != 0) { + break; + } + + 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; +} + +static int UpdatePtsByFd(int curFd, FdListStr *fdStr, int64_t *audioPts, int64_t *videoPts) +{ + if (curFd < 0 || fdStr == NULL || audioPts == NULL || videoPts == NULL) { + return -1; + } + + int ret; + if (curFd == fdStr->inVideoFd) { + ret = read(fdStr->inVideoFd, (void*)videoPts, sizeof(*videoPts)); + if (ret <= 0) { + return -1; + } + } else { + ret = read(fdStr->inAudioFd, (void*)audioPts, sizeof(*audioPts)); + if (ret <= 0) { + return -1; + } + } + return 0; +} + +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 ret = 0; + int trackId = 0; + int curFd = 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; + } + + if (UpDateWriteBufferInfo(curFd, &avMuxerDemoBuffer, &avMuxerDemoBufferSize, &info) != 0) { + break; + } + + if (OH_AVMuxer_WriteSampleBuffer(muxer, trackId, avMuxerDemoBuffer, info) != AV_ERR_OK) { + printf("OH_AVMuxer_WriteSampleBuffer error!\n"); + break; + } + + if (UpdatePtsByFd(curFd, fdStr, &audioPts, &videoPts) != 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 + return defaultNum; + } + if (ungetc(num, stdin) == EOF) { + printf("GetInputNum ungetc failed!"); + } + if (scanf_s("%d", &num) <= 0) { + num = defaultNum; + } + if (fflush(stdin) != 0) { + printf("GetInputNum fflush failed!"); + } + return num; +} + + +void NativeSelectMuxerType(void) +{ + int num; + + printf("\nplese select muxer type : 0.mp4 1.m4a\n"); + num = GetInputNum(0); + switch (num) { + case MODE_ZERO: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4; + (void)snprintf_s(g_muxerParam.outputFormatType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "mp4"); + break; + case MODE_ONE: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_M4A; + (void)snprintf_s(g_muxerParam.outputFormatType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "m4a"); + break; + default: + g_muxerParam.outputFormat = AV_OUTPUT_FORMAT_MPEG_4; + (void)snprintf_s(g_muxerParam.outputFormatType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "mp4"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectRunMode(void) +{ + 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 MODE_ZERO: + g_muxerParam.runMode = NORMAL; + (void)snprintf_s(g_muxerParam.runModeType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", RUN_NORMAL); + break; + case MODE_ONE: + g_muxerParam.runMode = THREAD; + (void)snprintf_s(g_muxerParam.runModeType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", RUN_MUL_THREAD); + break; + default: + g_muxerParam.runMode = NORMAL; + (void)snprintf_s(g_muxerParam.runModeType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", RUN_NORMAL); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectAudio(void) +{ + int num; + + printf("\nplese select audio mode: 0.noAudio 1.aac 2.mpeg\n"); + num = GetInputNum(1); + switch (num) { + case MODE_ONE: + g_muxerParam.audioParams = &g_audioAacPar; + (void)snprintf_s(g_muxerParam.audioType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "aac"); + break; + case MODE_TWO: + g_muxerParam.audioParams = &g_audioMpegPar; + (void)snprintf_s(g_muxerParam.audioType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "mpeg"); + break; + default: + g_muxerParam.audioParams = NULL; + (void)snprintf_s(g_muxerParam.audioType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "noAudio"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectVideo(void) +{ + int num; + + printf("\nplese select video mode: 0.noVideo 1.h264 2.mpeg4\n"); + num = GetInputNum(1); + switch (num) { + case MODE_ONE: + g_muxerParam.videoParams = &g_videoH264Par; + (void)snprintf_s(g_muxerParam.videoType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "h264"); + break; + case MODE_TWO: + g_muxerParam.videoParams = &g_videoMpeg4Par; + (void)snprintf_s(g_muxerParam.videoType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "mpeg4"); + break; + default: + g_muxerParam.videoParams = NULL; + (void)snprintf_s(g_muxerParam.videoType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "noVideo"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectCover(void) +{ + int num; + + printf("\nplese select cover mode: 0.noCover 1.jpg 2.png 3.bmp\n"); + num = GetInputNum(1); + switch (num) { + case MODE_ONE: + g_muxerParam.coverParams = &g_jpegCoverPar; + (void)snprintf_s(g_muxerParam.coverType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "jpg"); + break; + case MODE_TWO: + g_muxerParam.coverParams = &g_pngCoverPar; + (void)snprintf_s(g_muxerParam.coverType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "png"); + break; + case MODE_THREE: + g_muxerParam.coverParams = &g_bmpCoverPar; + (void)snprintf_s(g_muxerParam.coverType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "bmp"); + break; + default: + g_muxerParam.coverParams = NULL; + (void)snprintf_s(g_muxerParam.coverType, TYPE_BUFFER_SIZE, TYPE_BUFFER_SIZE - 1, "%s", "noCover"); + break; + } + printf("select mode:%d\n", num); +} + +void NativeSelectMode(void) +{ + if (g_muxerParam.outputFormat != AV_OUTPUT_FORMAT_DEFAULT) { + 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, 0, 0) != 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[CONFIG_BUFFER_SIZE] = {0}; + int err = snprintf_s(outFileName, sizeof(outFileName), sizeof(outFileName) - 1, "%s_%s_%s_%s_%s.%s", + out, g_muxerParam.runModeType, g_muxerParam.audioType, g_muxerParam.videoType, + g_muxerParam.coverType, g_muxerParam.outputFormatType); + if (err <= 0) { + CloseAllFd(&fdStr); + return -1; + } + + 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/avmuxer/native_avmuxer_demo.h b/test/nativedemo/avmuxer/native_avmuxer_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..54be093586958f58068c1d150c9dc8386ebeac43 --- /dev/null +++ b/test/nativedemo/avmuxer/native_avmuxer_demo.h @@ -0,0 +1,28 @@ +/* + * 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 NATIVE_AVMUXER_DEMO_H +#define NATIVE_AVMUXER_DEMO_H +#ifdef __cplusplus +extern "C" { +#endif + +void NativeSelectMode(void); +int RunNativeMuxer(const char *out); + +#ifdef __cplusplus +} +#endif +#endif // NATIVE_AVMUXER_DEMO_H \ No newline at end of file diff --git a/test/nativedemo/codeclist_demo/codeclist_demo.cpp b/test/nativedemo/codeclist_demo/codeclist_demo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1403546044b66382898662b20a734cda40be7034 --- /dev/null +++ b/test/nativedemo/codeclist_demo/codeclist_demo.cpp @@ -0,0 +1,39 @@ +/* + * 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 "native_avmagic.h" +#include "codeclist_demo.h" + +namespace OHOS { +namespace Media { +void CodecListDemo::RunCase() +{ + std::cout << "===== ============== ======" << std::endl; + const char *mime = "video/mpeg2"; + OH_AVFormat *format = OH_AVFormat_Create(); + OH_AVFormat_SetStringValue(format, "codec_mime", mime); + const char *codecName = OH_AVCodec_FindDecoder(format); + std::cout << codecName << std::endl; + std::cout << "start getting caps" << std::endl; + OH_AVCapability *cap = OH_AVCodec_CreateCapability(codecName); + const char *mimetype = OH_AVCapability_GetMimeType(cap); + CapabilityData capsData = cap->capabilityData_; + std::cout << mimetype << std::endl; + std::cout << capsData.maxInstance << std::endl; + std::cout << "get caps successful" << std::endl; +} +} // namespace Media +} // namespace OHOS diff --git a/test/nativedemo/codeclist_demo/codeclist_demo.h b/test/nativedemo/codeclist_demo/codeclist_demo.h new file mode 100644 index 0000000000000000000000000000000000000000..086daa7002c1fc9c5104fc4a591a5cbae95604cc --- /dev/null +++ b/test/nativedemo/codeclist_demo/codeclist_demo.h @@ -0,0 +1,29 @@ +/* + * 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 CODECLIST_DEMO_H +#define CODECLIST_DEMO_H +#include "native_avcodec_list.h" + +namespace OHOS { +namespace Media { +class CodecListDemo { +public: + CodecListDemo() = default; + ~CodecListDemo() = default; + void RunCase(); +}; +} // namespace Media +} // namespace OHOS +#endif \ No newline at end of file diff --git a/test/nativedemo/include/demo_log.h b/test/nativedemo/include/demo_log.h new file mode 100644 index 0000000000000000000000000000000000000000..3b724ec2ec656801d76363998a67c796f2a13f8a --- /dev/null +++ b/test/nativedemo/include/demo_log.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 DEMO_LOG_H +#define DEMO_LOG_H + +#include + +namespace OHOS { +#define DEMO_CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) + +#define DEMO_CHECK_AND_RETURN_LOG(cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + return; \ + } \ + } while (0) + +#define DEMO_CHECK_AND_BREAK_LOG(cond, fmt, ...) \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + break; \ + } + +#define DEMO_CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + continue; \ + } +} +#endif // DEMO_LOG_H \ No newline at end of file diff --git a/test/nativedemo/resources/aac_44100_2.bin b/test/nativedemo/resources/aac_44100_2.bin new file mode 100644 index 0000000000000000000000000000000000000000..9b9c7474987f9774b486cde76f2be582dbed8927 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 0000000000000000000000000000000000000000..0bba921e52548b37e9e68d6db30aea7fd9498217 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 0000000000000000000000000000000000000000..f9da44b1e64049e29ca5bcfe6bff4fca6fcd4dac 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 0000000000000000000000000000000000000000..024c46a731c8e3243883d315bb8e7c2f78b1c330 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 0000000000000000000000000000000000000000..b7d2145726116ab7f3fbb75ec1c3ada26c08078a 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 0000000000000000000000000000000000000000..dc88eef4ec8a38da9007e297536c63992a83971c --- /dev/null +++ b/test/unittest/BUILD.gn @@ -0,0 +1,121 @@ +# 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 = "$av_codec_root_dir" +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_video_unit_test") { + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + "//third_party/ffmpeg", + "//commonlibrary/c_utils/base/include", + "//base/startup/init/interfaces/innerkits/include/syspara", + "//foundation/graphic/graphic_2d/interfaces/inner_api", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/codec/include/video", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/utils/include", + ] + + cflags = av_codec_unittest_cflags + + cflags_cc = cflags + + public_configs = [] + + if (multimedia_av_codec_support_test) { + sources = [ "./video_test/fcodec_unit_test.cpp" ] + } + + public_deps = [ "$av_codec_root_dir/services/engine/codec/video:av_codec_video_ffmpeg_codec" ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("av_audio_unit_test") { + module_out_path = module_output_path + include_dirs = av_codec_unittest_include_dirs + include_dirs += [ + "./", + "//third_party/ffmpeg", + "//commonlibrary/c_utils/base/include", + "//base/startup/init/interfaces/innerkits/include/syspara", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/services/engine/common/include", + "$av_codec_root_dir/services/engine/base/include", + "$av_codec_root_dir/services/utils/include", + "$av_codec_root_dir/services/engine/codec/include/audio", + "$av_codec_root_dir/services/engine/factory", + ] + + cflags = av_codec_unittest_cflags + + cflags_cc = cflags + + public_configs = [] + + if (multimedia_av_codec_support_test) { + sources = [ "./audio_test/audio_decoder_unit_test.cpp" ] + } + + deps = [ + "$av_codec_root_dir/interfaces/inner_api/native:av_codec_client", + "$av_codec_root_dir/interfaces/kits/c:capi_packages", + "$av_codec_root_dir/services/engine/codec/audio:av_codec_audio_ffmpeg_codec", + "$av_codec_root_dir/services/services:av_codec_service", + "$av_codec_root_dir/services/services:av_codec_service", + "$av_codec_root_dir/services/utils:av_codec_format", + ] + + external_deps = [ "graphic_standard:surface" ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} diff --git a/test/unittest/audio_test/audio_decoder_unit_test.cpp b/test/unittest/audio_test/audio_decoder_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7131c5e1eeff874e0e41c44e15902fdae1a52c5 --- /dev/null +++ b/test/unittest/audio_test/audio_decoder_unit_test.cpp @@ -0,0 +1,1048 @@ +/* + * 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 "native_avcodec_audiodecoder.h" +#include "audio_ffmpeg_adapter.h" +#include "format.h" +#include "avcodec_audio_codec_key.h" +#include "avcodec_common.h" +#include "avcodec_errors.h" +#include "media_description.h" + +using namespace std; +using namespace testing::ext; +using namespace OHOS::Media; + +namespace { +const string CODEC_MP3_NAME = std::string(AVCodecAudioCodecKey::AUDIO_DECODER_MP3_NAME_KEY); +const string CODEC_FLAC_NAME = std::string(AVCodecAudioCodecKey::AUDIO_DECODER_FLAC_NAME_KEY); +const string CODEC_AAC_NAME = std::string(AVCodecAudioCodecKey::AUDIO_DECODER_AAC_NAME_KEY); +constexpr uint32_t MAX_CHANNEL_COUNT = 2; +constexpr uint32_t INVALID_CHANNEL_COUNT = 3; +constexpr uint32_t DEFAULT_SAMPLE_RATE = 8000; +constexpr uint32_t INVALID_SAMPLE_RATE = 9999990; +constexpr uint32_t DEFAULT_BITRATE = 128000; +constexpr uint32_t DEFAULT_WIDTH = 0; +constexpr uint32_t DEFAULT_BITS_PER_CODED_RATE = 16; +constexpr uint32_t DEFAULT_AAC_TYPE = 1; +constexpr uint32_t DEFAULT_AAC_LATM_TYPE = 2; +} // namespace + +namespace OHOS { +namespace Media { +class ADecSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inIdxQueue_; + std::queue outIdxQueue_; + std::queue infoQueue_; + std::queue flagQueue_; +}; + +class BufferCallback : public AVCodecCallback { +public: + explicit BufferCallback(ADecSignal *userData) : userData_(userData) {} + virtual ~BufferCallback() = default; + ADecSignal *userData_; + virtual void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + virtual void OnOutputFormatChanged(const Format &format) override; + virtual void OnInputBufferAvailable(size_t index) override; + virtual void OnOutputBufferAvailable(size_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; +}; + +void BufferCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + cout << "Error errorCode=" << errorCode << endl; +} + +void BufferCallback::OnOutputFormatChanged(const Format &format) +{ + (void)format; + cout << "Format Changed" << endl; +} + +void BufferCallback::OnInputBufferAvailable(size_t index) +{ + unique_lock lock(userData_->inMutex_); + userData_->inIdxQueue_.push(index); + userData_->inCond_.notify_all(); +} + +void BufferCallback::OnOutputBufferAvailable(size_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + unique_lock lock(userData_->outMutex_); + userData_->outIdxQueue_.push(index); + userData_->infoQueue_.push(info); + userData_->flagQueue_.push(flag); + userData_->outCond_.notify_all(); + (void)flag; +} + +class AudioCodeDecoderUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + int32_t ProceMp3Func(); + int32_t ProceFlacFunc(); + int32_t ProceAacFunc(); + +protected: + int32_t index_; + int64_t timeStamp_ {0}; + + ADecSignal *signal_; + + FILE *inFile_ {nullptr}; + FILE *dumpFd_ {nullptr}; + std::string codecName_ {CODEC_MP3_NAME}; + + OHOS::Media::Format format_; + std::shared_ptr adec_ {nullptr}; +}; + +void AudioCodeDecoderUnitTest::SetUpTestCase(void) +{ + cout << "[SetUpTestCase]: " << endl; +} + +void AudioCodeDecoderUnitTest::TearDownTestCase(void) +{ + cout << "[TearDownTestCase]: " << endl; +} + +void AudioCodeDecoderUnitTest::SetUp(void) +{ + cout << "[SetUp]: SetUp!!!" << endl; + adec_ = std::make_shared(codecName_); + ASSERT_NE(nullptr, adec_); + + signal_ = new ADecSignal(); + ASSERT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->SetCallback( + std::shared_ptr(std::make_shared(signal_)))); +} + +void AudioCodeDecoderUnitTest::TearDown(void) +{ + adec_->Release(); + cout << "[TearDown]: over!!!" << endl; +} + +int32_t AudioCodeDecoderUnitTest::ProceMp3Func(void) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + + if (adec_->Configure(format_) != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } else if (adec_->Start() != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioCodeDecoderUnitTest::ProceFlacFunc(void) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + + if (adec_->Configure(format_) != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } else if (adec_->Start() != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +int32_t AudioCodeDecoderUnitTest::ProceAacFunc(void) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + + if (adec_->Configure(format_) != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } else if (adec_->Start() != AVCodecServiceErrCode::AVCS_ERR_OK) { + return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; + } + return AVCodecServiceErrCode::AVCS_ERR_OK; +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_01, TestSize.Level1) +{ + // lack of correct key + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_02, TestSize.Level1) +{ + // correct key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_03, TestSize.Level1) +{ + // correct key input with redundancy key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_04, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_05, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, INVALID_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, INVALID_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Configure_06, TestSize.Level1) +{ + // empty format input + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Start_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Start_02, TestSize.Level1) +{ + // correct flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Start_03, TestSize.Level1) +{ + // wrong flow 1 + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Start_04, TestSize.Level1) +{ + // wrong flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Pause_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Resume_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Resume()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Stop_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Stop_02, TestSize.Level1) +{ + // correct flow 2 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Flush_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Flush_02, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Reset_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Reset_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Reset_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Release_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Release_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_Release_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_NotifyEos_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->NotifyEos()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_SetParameter_01, TestSize.Level1) +{ + // 尚未实现 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE, adec_->SetParameter(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_GetOutputFormat_01, TestSize.Level1) +{ + // 尚未实现 + EXPECT_EQ(AVCS_ERR_OK, ProceMp3Func()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->GetOutputFormat(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_GetInputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + sleep(1); + std::shared_ptr buffer = nullptr; + index_ = -1; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = 1024; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = signal_->inIdxQueue_.front(); + buffer = adec_->GetInputBuffer(index_); + EXPECT_NE(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_QueueInputBuffer_01, TestSize.Level1) +{ + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceMp3Func()); + sleep(1); + // case0 传参异常 + index_ = -1; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + // case1 info未赋值 + index_ = 1024; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + + // case2 EOS帧数据 + index_ = 0; + info.presentationTimeUs = 0; + info.size = -1; + info.offset = 0; + flag = AVCODEC_BUFFER_FLAG_EOS; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->QueueInputBuffer(index_, info, flag)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_GetOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceMp3Func()); + std::shared_ptr buffer = nullptr; + + // case1 传参异常 + index_ = -1; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + index_ = 1024; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Mp3_ReleaseOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceMp3Func()); + + // case1 传参异常 + index_ = -1; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + index_ = 1024; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + // case2 传参正常 + index_ = 0; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_SetCodecName_01, TestSize.Level1) +{ + codecName_ = CODEC_FLAC_NAME; +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_01, TestSize.Level1) +{ + // lack of correct key + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_02, TestSize.Level1) +{ + // correct key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_03, TestSize.Level1) +{ + // correct key input with redundancy key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_04, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_05, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, INVALID_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, INVALID_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Configure_06, TestSize.Level1) +{ + // empty format input + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Start_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Start_02, TestSize.Level1) +{ + // correct flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Start_03, TestSize.Level1) +{ + // wrong flow 1 + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Start_04, TestSize.Level1) +{ + // wrong flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Pause_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Resume_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Resume()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Stop_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Stop_02, TestSize.Level1) +{ + // correct flow 2 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Flush_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Flush_02, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Reset_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Reset_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Reset_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Release_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Release_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_BITS_PER_CODED_SAMPLE_KEY, DEFAULT_BITS_PER_CODED_RATE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_Release_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_NotifyEos_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->NotifyEos()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_SetParameter_01, TestSize.Level1) +{ + // 尚未实现 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE, adec_->SetParameter(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_GetOutputFormat_01, TestSize.Level1) +{ + // 尚未实现 + EXPECT_EQ(AVCS_ERR_OK, ProceFlacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->GetOutputFormat(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_GetInputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + sleep(1); + std::shared_ptr buffer = nullptr; + index_ = -1; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = 1024; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = signal_->inIdxQueue_.front(); + buffer = adec_->GetInputBuffer(index_); + EXPECT_NE(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_QueueInputBuffer_01, TestSize.Level1) +{ + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceFlacFunc()); + sleep(1); + // case0 传参异常 + index_ = -1; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + // case1 info未赋值 + index_ = 1024; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + + // case2 EOS帧数据 + index_ = 0; + info.presentationTimeUs = 0; + info.size = -1; + info.offset = 0; + flag = AVCODEC_BUFFER_FLAG_EOS; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->QueueInputBuffer(index_, info, flag)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_GetOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFlacFunc()); + std::shared_ptr buffer = nullptr; + + // case1 传参异常 + index_ = -1; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + index_ = 1024; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Flac_ReleaseOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFlacFunc()); + + // case1 传参异常 + index_ = -1; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + index_ = 1024; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + // case2 传参正常 + index_ = 0; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_SetCodecName_02, TestSize.Level1) +{ + codecName_ = CODEC_AAC_NAME; +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_01, TestSize.Level1) +{ + // lack of correct key + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_CONFIGURE_MISMATCH_CHANNEL_COUNT, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_02, TestSize.Level1) +{ + // correct key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_03, TestSize.Level1) +{ + // correct key input with redundancy key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_04, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_05, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, INVALID_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, INVALID_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_06, TestSize.Level1) +{ + // correct key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_LATM_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_07, TestSize.Level1) +{ + // correct key input with redundancy key input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_LATM_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_08, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_LATM_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_09, TestSize.Level1) +{ + // correct key input with wrong value type input + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, INVALID_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, INVALID_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_LATM_TYPE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Configure_10, TestSize.Level1) +{ + // empty format input + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Start_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Start_02, TestSize.Level1) +{ + // correct flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Start_03, TestSize.Level1) +{ + // wrong flow 1 + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Start_04, TestSize.Level1) +{ + // wrong flow 2 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Start()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Pause_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Resume_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Pause()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Resume()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Stop_01, TestSize.Level1) +{ + // correct flow 1 + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Stop_02, TestSize.Level1) +{ + // correct flow 2 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Flush_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Flush_02, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Flush()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Reset_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Reset_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Reset_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Reset()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Release_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Release_02, TestSize.Level1) +{ + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Configure(format_)); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_Release_03, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Release()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_NotifyEos_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->Stop()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->NotifyEos()); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_SetParameter_01, TestSize.Level1) +{ + // 尚未实现 + format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, MAX_CHANNEL_COUNT); + format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, DEFAULT_SAMPLE_RATE); + format_.PutLongValue(MediaDescriptionKey::MD_KEY_BITRATE, DEFAULT_BITRATE); + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_INVALID_STATE, adec_->SetParameter(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_GetOutputFormat_01, TestSize.Level1) +{ + // 尚未实现 + EXPECT_EQ(AVCS_ERR_OK, ProceAacFunc()); + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->GetOutputFormat(format_)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_GetInputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + sleep(1); + std::shared_ptr buffer = nullptr; + index_ = -1; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = 1024; + buffer = adec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = signal_->inIdxQueue_.front(); + buffer = adec_->GetInputBuffer(index_); + EXPECT_NE(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_QueueInputBuffer_01, TestSize.Level1) +{ + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, ProceAacFunc()); + sleep(1); + // case0 传参异常 + index_ = -1; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + // case1 info未赋值 + index_ = 1024; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY, adec_->QueueInputBuffer(index_, info, flag)); + + // case2 EOS帧数据 + index_ = 0; + info.presentationTimeUs = 0; + info.size = -1; + info.offset = 0; + flag = AVCODEC_BUFFER_FLAG_EOS; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->QueueInputBuffer(index_, info, flag)); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_GetOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceAacFunc()); + std::shared_ptr buffer = nullptr; + + // case1 传参异常 + index_ = -1; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + index_ = 1024; + buffer = adec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); +} + +HWTEST_F(AudioCodeDecoderUnitTest, audioDecoder_Aac_ReleaseOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceAacFunc()); + + // case1 传参异常 + index_ = -1; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + index_ = 1024; + EXPECT_NE(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); + // case2 传参正常 + index_ = 0; + EXPECT_EQ(AVCodecServiceErrCode::AVCS_ERR_OK, adec_->ReleaseOutputBuffer(index_)); +} + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/BUILD.gn b/test/unittest/avcodec_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..5aebbf238463f0f050a521e6f61e4b1c3fc38479 --- /dev/null +++ b/test/unittest/avcodec_test/BUILD.gn @@ -0,0 +1,324 @@ +# 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. + +import("//build/test.gni") +import("//foundation/multimedia/av_codec/config.gni") + +MEDIA_ROOT_DIR = "//foundation/multimedia/av_codec/" +module_output_path = "av_codec/avcodec" + +avcodec_unittest_native_include_dirs = [ + "//graphic/graphic_2d/interfaces/innerkits/surface", + "//foundation//window/window_manager/interfaces/innerkits/wm", + "$MEDIA_ROOT_DIR/interfaces/inner_api/native", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/audiodecoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/audioencoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/avcodec_info/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/avcodec_list/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/avformat/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/avmemory/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/enum/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/surface/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/videodecoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/native/videoencoder/", + "$MEDIA_ROOT_DIR/test/unittest/common/include/", +] + +avcodec_unittest_capi_include_dirs = [ + "//graphic/graphic_2d/interfaces/kits/surface", + "//graphic/graphic_2d/interfaces/inner_api/surface", + "//foundation//window/window_manager/interfaces/innerkits/wm", + "$MEDIA_ROOT_DIR/interfaces/kits/c", + "$MEDIA_ROOT_DIR/interfaces/inner_api/native", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/audiodecoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/audioencoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/avformat/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/avmemory/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/surface/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/videodecoder/", + "$MEDIA_ROOT_DIR/test/unittest/avcodec_test/capi/videoencoder/", + "$MEDIA_ROOT_DIR/test/unittest/common/include/", + "../../../../../../commonlibrary/c_utils/base/include", + "../../../../../../foundation/multimedia/image_framework/interfaces/innerkits/include", +] + +avcodec_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("vcodec_native_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_native_include_dirs + include_dirs += [ + "./", + "./vcodec_test", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./native/avcodec_info/avcodec_info_native_mock.cpp", + "./native/avcodec_list/avcodec_list_native_mock.cpp", + "./native/avcodec_mock_factory.cpp", + "./native/avformat/avformat_native_mock.cpp", + "./native/avmemory/avmemory_native_mock.cpp", + "./native/enum/enum_native_mock.cpp", + "./native/surface/surface_native_mock.cpp", + "./native/videodecoder/videodec_native_mock.cpp", + "./native/videoencoder/videoenc_native_mock.cpp", + "./vcodec_test/vcodec_unit_test.cpp", + "./vcodec_test/vdec_mock.cpp", + "./vcodec_test/venc_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d:libsurface", + "//foundation/graphic/graphic_2d/frameworks/surface:surface", + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "//foundation/window/window_manager/wm:libwm", + ] + + resource_config_file = + "//foundation/multimedia/av_codec/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("acodec_native_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_native_include_dirs + include_dirs += [ + "./", + "./acodec_test", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./acodec_test/acodec_mock.cpp", + "./acodec_test/acodec_unit_test.cpp", + "./native/audiodecoder/audiodec_native_mock.cpp", + "./native/audioencoder/audioenc_native_mock.cpp", + "./native/avcodec_info/avcodec_info_native_mock.cpp", + "./native/avcodec_list/avcodec_list_native_mock.cpp", + "./native/avcodec_mock_factory.cpp", + "./native/avformat/avformat_native_mock.cpp", + "./native/avmemory/avmemory_native_mock.cpp", + "./native/enum/enum_native_mock.cpp", + "./native/surface/surface_native_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d:libsurface", + "//foundation/graphic/graphic_2d/frameworks/surface:surface", + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "//foundation/window/window_manager/wm:libwm", + ] + + resource_config_file = + "//foundation/multimedia/av_codec/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("avcodec_list_native_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_native_include_dirs + include_dirs += [ + "./", + "./avcodec_list_test", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./avcodec_list_test/avcodec_list_unit_test.cpp", + "./native/avcodec_info/avcodec_info_native_mock.cpp", + "./native/avcodec_list/avcodec_list_native_mock.cpp", + "./native/avcodec_mock_factory.cpp", + "./native/avformat/avformat_native_mock.cpp", + "./native/enum/enum_native_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + ] + + resource_config_file = + "//foundation/multimedia/av_codec/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("format_native_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_native_include_dirs + include_dirs += [ + "./", + "./format_test", + ] + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./format_test/format_unit_test.cpp", + "./native/avcodec_mock_factory.cpp", + "./native/avformat/avformat_native_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + ] + external_deps = [ "bounds_checking_function:libsec_shared" ] +} + +################################################################################################################## +ohos_unittest("vcodec_capi_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_capi_include_dirs + include_dirs += [ + "./", + "./vcodec_test", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + "//foundation/graphic/graphic_2d/interfaces/inner_api/common", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./capi/avcodec_mock_factory.cpp", + "./capi/avformat/avformat_capi_mock.cpp", + "./capi/avmemory/avmemory_capi_mock.cpp", + "./capi/surface/surface_capi_mock.cpp", + "./capi/videodecoder/videodec_capi_mock.cpp", + "./capi/videoencoder/videoenc_capi_mock.cpp", + "./vcodec_test/vcodec_unit_test.cpp", + "./vcodec_test/vdec_mock.cpp", + "./vcodec_test/venc_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d:libsurface", + "//foundation/graphic/graphic_2d/frameworks/surface:surface", + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_codec", + + # "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_codecbase", + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_core", + + # "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_venc", + "//foundation/window/window_manager/wm:libwm", + ] + + resource_config_file = + "//foundation/multimedia/av_codec/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("acodec_capi_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_capi_include_dirs + include_dirs += [ + "./", + "./acodec_test", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./acodec_test/acodec_mock.cpp", + "./acodec_test/acodec_unit_test.cpp", + "./capi/audiodecoder/audiodec_capi_mock.cpp", + "./capi/audioencoder/audioenc_capi_mock.cpp", + "./capi/avcodec_mock_factory.cpp", + "./capi/avformat/avformat_capi_mock.cpp", + "./capi/avmemory/avmemory_capi_mock.cpp", + ] + } + + deps = [ + "//foundation/graphic/graphic_2d/rosen/modules/render_service_client:librender_service_client", + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + + # "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_adec", + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_codec", + + # "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_codecbase", + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_core", + "//foundation/window/window_manager/wm:libwm", + ] + + resource_config_file = + "//foundation/multimedia/av_codec/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("format_capi_unit_test") { + module_out_path = module_output_path + include_dirs = avcodec_unittest_capi_include_dirs + include_dirs += [ + "./", + "./format_test", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./capi/avcodec_mock_factory.cpp", + "./capi/avformat/avformat_capi_mock.cpp", + "./format_test/format_unit_test.cpp", + ] + } + deps = [ + "//foundation/multimedia/av_codec/interfaces/inner_api/native:av_codec_client", + "//foundation/multimedia/av_codec/interfaces/kits/c:native_av_codec_core", + "//foundation/window/window_manager/wm:libwm", + ] + external_deps = [ + "bounds_checking_function:libsec_shared", + "graphic_standard:surface", + ] +} diff --git a/test/unittest/avcodec_test/acodec_test/acodec_mock.cpp b/test/unittest/avcodec_test/acodec_test/acodec_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7d349226078692a9566d5d93c6e5aca383242aa --- /dev/null +++ b/test/unittest/avcodec_test/acodec_test/acodec_mock.cpp @@ -0,0 +1,770 @@ +/* + * 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 "acodec_mock.h" +#include +#include "avcodec_common.h" +#include "avcodec_errors.h" + +using namespace std; +using namespace OHOS::Media::ACodecTestParam; + +namespace OHOS { +namespace Media { +ADecCallbackTest::ADecCallbackTest(std::shared_ptr signal) + : acodecSignal_(signal) +{ +} + +ADecCallbackTest::~ADecCallbackTest() +{ +} + +void ADecCallbackTest::OnError(int32_t errorCode) +{ + cout << "DEC Error errorCode = " << errorCode << endl; + if (acodecSignal_ == nullptr) { + return; + } + acodecSignal_->errorNum_ += 1; +} + +void ADecCallbackTest::OnStreamChanged(std::shared_ptr format) +{ + cout << "DEC Format Changed" << endl; +} + +void ADecCallbackTest::OnNeedInputData(uint32_t index, std::shared_ptr data) +{ + if (acodecSignal_ == nullptr) { + return; + } + unique_lock lock(acodecSignal_->inMutexDec_); + if (acodecSignal_->isFlushing_.load()) { + return; + } + acodecSignal_->inQueueDec_.push(index); + acodecSignal_->inBufferQueueDec_.push(data); + acodecSignal_->inCondDec_.notify_all(); +} + +void ADecCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) +{ + if (acodecSignal_ == nullptr) { + return; + } + unique_lock lock(acodecSignal_->inMutexEnc_); + if (acodecSignal_->isFlushing_.load()) { + cout << "DEC OutputAvailable: isFlushing_.load() is true, return" << endl; + return; + } + acodecSignal_->outQueueDec_.push(index); + acodecSignal_->sizeQueueDec_.push(attr.size); + acodecSignal_->flagQueueDec_.push(attr.flags); + acodecSignal_->outBufferQueueDec_.push(data); + acodecSignal_->inCondEnc_.notify_all(); +} + +AEncCallbackTest::AEncCallbackTest(std::shared_ptr signal) + : acodecSignal_(signal) +{ +} + +AEncCallbackTest::~AEncCallbackTest() +{ +} + +void AEncCallbackTest::OnError(int32_t errorCode) +{ + cout << "ENC Error errorCode=" << errorCode << endl; +} + +void AEncCallbackTest::OnStreamChanged(std::shared_ptr format) +{ + cout << "ENC Format Changed" << endl; +} + +void AEncCallbackTest::OnNeedInputData(uint32_t index, std::shared_ptr data) +{ + if (acodecSignal_ == nullptr) { + return; + } + unique_lock lock(acodecSignal_->inMutexEnc_); + if (acodecSignal_->isFlushing_.load()) { + return; + } + acodecSignal_->inQueueEnc_.push(index); + acodecSignal_->inBufferQueueEnc_.push(data); + acodecSignal_->inCondEnc_.notify_all(); +} + +void AEncCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) +{ + if (acodecSignal_ == nullptr) { + return; + } + unique_lock lock(acodecSignal_->outMutexEnc_); + if (acodecSignal_->isFlushing_.load()) { + return; + } + acodecSignal_->outQueueEnc_.push(index); + acodecSignal_->sizeQueueEnc_.push(attr.size); + acodecSignal_->flagQueueEnc_.push(attr.flags); + acodecSignal_->outBufferQueueEnc_.push(data); + acodecSignal_->outCondEnc_.notify_all(); +} + +void ACodecMock::clearIntQueue (std::queue& q) +{ + std::queue empty; + swap(empty, q); +} + +void ACodecMock::clearBufferQueue (std::queue>& q) +{ + std::queue> empty; + swap(empty, q); +} + +ACodecMock::ACodecMock(std::shared_ptr signal) + : acodecSignal_(signal) +{ +} + +ACodecMock::~ACodecMock() +{ +} + +bool ACodecMock::CreateAudioDecMockByMime(const std::string &mime) +{ + audioDec_ = AVCodecMockFactory::CreateAudioDecMockByMime(mime); + return audioDec_ != nullptr; +} + +bool ACodecMock::CreateAudioDecMockByName(const std::string &name) +{ + audioDec_ = AVCodecMockFactory::CreateAudioDecMockByName(name); + return audioDec_ != nullptr; +} + +int32_t ACodecMock::SetCallbackDec(std::shared_ptr cb) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->SetCallback(cb); +} + +int32_t ACodecMock::ConfigureDec(std::shared_ptr format) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->Configure(format); +} + +int32_t ACodecMock::PrepareDec() +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->Prepare(); +} + +int32_t ACodecMock::StartDec() +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + isDecRunning_.store(true); + + if (testFile_ == nullptr) { + testFile_ = std::make_unique(); + UNITTEST_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + testFile_->open("/data/test/media/AAC_48000_32_1.aac", std::ios::in | std::ios::binary); + } + if (inputLoopDec_ == nullptr) { + inputLoopDec_ = make_unique(&ACodecMock::InputFuncDec, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(inputLoopDec_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + } + return audioDec_->Start(); +} + +int32_t ACodecMock::StopDec() +{ + if (acodecSignal_ == nullptr || audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->inMutexDec_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioDec_->Stop(); + unique_lock lockIn(acodecSignal_->inMutexDec_); + clearIntQueue(acodecSignal_->inQueueDec_); + clearBufferQueue(acodecSignal_->inBufferQueueDec_); + acodecSignal_->inCondDec_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->outQueueDec_); + clearIntQueue(acodecSignal_->sizeQueueDec_); + clearIntQueue(acodecSignal_->flagQueueDec_); + clearBufferQueue(acodecSignal_->outBufferQueueDec_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::FlushDec() +{ + if (acodecSignal_ == nullptr || audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->inMutexDec_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioDec_->Flush(); + unique_lock lockIn(acodecSignal_->inMutexDec_); + clearIntQueue(acodecSignal_->inQueueDec_); + clearBufferQueue(acodecSignal_->inBufferQueueDec_); + acodecSignal_->inCondDec_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->outQueueDec_); + clearIntQueue(acodecSignal_->sizeQueueDec_); + clearIntQueue(acodecSignal_->flagQueueDec_); + clearBufferQueue(acodecSignal_->outBufferQueueDec_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::ResetDec() +{ + if (acodecSignal_ == nullptr || audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->inMutexDec_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioDec_->Reset(); + unique_lock lockIn(acodecSignal_->inMutexDec_); + clearIntQueue(acodecSignal_->inQueueDec_); + clearBufferQueue(acodecSignal_->inBufferQueueDec_); + acodecSignal_->inCondDec_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->outQueueDec_); + clearIntQueue(acodecSignal_->sizeQueueDec_); + clearIntQueue(acodecSignal_->flagQueueDec_); + clearBufferQueue(acodecSignal_->outBufferQueueDec_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::ReleaseDec() +{ + if (acodecSignal_ == nullptr || audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + isDecRunning_.store(false); + isEncRunning_.store(false); + if (inputLoopDec_ != nullptr && inputLoopDec_->joinable()) { + unique_lock lock(acodecSignal_->inMutexDec_); + acodecSignal_->inQueueDec_.push(10000); // push 10000 to stop queue + acodecSignal_->inCondDec_.notify_all(); + lock.unlock(); + inputLoopDec_->join(); + inputLoopDec_.reset(); + } + return audioDec_->Release(); +} + +std::shared_ptr ACodecMock::GetOutputMediaDescriptionDec() +{ + if (audioDec_ == nullptr) { + return nullptr; + } + return audioDec_->GetOutputMediaDescription(); +} + +int32_t ACodecMock::SetParameterDec(std::shared_ptr format) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->SetParameter(format); +} + +int32_t ACodecMock::PushInputDataDec(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->PushInputData(index, attr); +} + +int32_t ACodecMock::FreeOutputDataDec(uint32_t index) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioDec_->FreeOutputData(index); +} + +void ACodecMock::SetOutPath(const std::string &path) +{ + outPath_ = path; +} + +void ACodecMock::PopOutQueueDec() +{ + if (acodecSignal_ == nullptr) { + return; + } + acodecSignal_->outQueueDec_.pop(); + acodecSignal_->sizeQueueDec_.pop(); + acodecSignal_->flagQueueDec_.pop(); + acodecSignal_->outBufferQueueDec_.pop(); +} + +void ACodecMock::PopInQueueDec() +{ + if (acodecSignal_ == nullptr) { + return; + } + acodecSignal_->inQueueDec_.pop(); + acodecSignal_->inBufferQueueDec_.pop(); +} + +int32_t ACodecMock::PushInputDataDecInner(uint32_t index, uint32_t bufferSize) +{ + if (audioDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + struct AVCodecBufferAttrMock attr; + attr.offset = 0; + attr.flags = AVCODEC_BUFFER_FLAG_NONE; + if (decInCnt_ == ES_LENGTH) { + cout << "DEC input: set EOS" << endl; + attr.flags = AVCODEC_BUFFER_FLAG_EOS; + attr.pts = 0; + attr.size = 0; + attr.offset = 0; + isDecInputEOS_ = true; + } else { + attr.pts = timeStampDec_; + attr.size = bufferSize; + attr.offset = 0; + if (decInCnt_ == 0 && MIME_TYPE == "audio/vorbis") { + attr.flags = AVCODEC_BUFFER_FLAG_CODEC_DATA; + } else { + attr.flags = AVCODEC_BUFFER_FLAG_NONE; + } + } + return audioDec_->PushInputData(index, attr); +} + +void ACodecMock::InputFuncDec() +{ + if (acodecSignal_ == nullptr || audioDec_ == nullptr) { + return; + } + while (true) { + if (!isDecRunning_.load()) { + break; + } + + unique_lock lock(acodecSignal_->inMutexDec_); + acodecSignal_->inCondDec_.wait(lock, [this]() { return acodecSignal_->inQueueDec_.size() > 0; }); + + if (!isDecRunning_.load()) { + break; + } + + uint32_t index = acodecSignal_->inQueueDec_.front(); + std::shared_ptr buffer = acodecSignal_->inBufferQueueDec_.front(); + if (acodecSignal_->isFlushing_.load() || isDecInputEOS_ || buffer == nullptr) { + PopInQueueDec(); + continue; + } + UNITTEST_CHECK_AND_RETURN_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail"); + + uint32_t bufferSize = 0; // replace with the actual size + if (decInCnt_ < ES_LENGTH) { + bufferSize = ES[decInCnt_]; + char *fileBuffer = static_cast(malloc(sizeof(char) * bufferSize + 1)); + UNITTEST_CHECK_AND_RETURN_LOG(fileBuffer != nullptr, "Fatal: malloc fail"); + + (void)testFile_->read(fileBuffer, bufferSize); + if (testFile_->eof()) { + free(fileBuffer); + break; + } + if (memcpy_s(buffer->GetAddr(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) { + free(fileBuffer); + PopInQueueDec(); + break; + } + free(fileBuffer); + } + if (PushInputDataDecInner(index, bufferSize) != AVCS_ERR_OK) { + acodecSignal_->errorNum_ += 1; + } else { + decInCnt_ ++; + } + timeStampDec_ += SAMPLE_DURATION_US; + PopInQueueDec(); + } +} + +bool ACodecMock::CreateAudioEncMockByMime(const std::string &mime) +{ + audioEnc_ = AVCodecMockFactory::CreateAudioEncMockByMime(mime); + return audioEnc_ != nullptr; +} + +bool ACodecMock::CreateAudioEncMockByName(const std::string &name) +{ + audioEnc_ = AVCodecMockFactory::CreateAudioEncMockByName(name); + return audioEnc_ != nullptr; +} + +int32_t ACodecMock::SetCallbackEnc(std::shared_ptr cb) +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->SetCallback(cb); +} + +int32_t ACodecMock::ConfigureEnc(std::shared_ptr format) +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->Configure(format); +} + +int32_t ACodecMock::PrepareEnc() +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->Prepare(); +} + +int32_t ACodecMock::StartEnc() +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + + isEncRunning_.store(true); + if (inputLoopEnc_ == nullptr) { + inputLoopEnc_ = make_unique(&ACodecMock::InputFuncEnc, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(inputLoopEnc_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + } + + if (outputLoopEnc_ == nullptr) { + outputLoopEnc_ = make_unique(&ACodecMock::OutputFuncEnc, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(outputLoopEnc_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + } + return audioEnc_->Start(); +} + +int32_t ACodecMock::StopEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->outMutexEnc_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioEnc_->Stop(); + unique_lock lockIn(acodecSignal_->outMutexEnc_); + clearIntQueue(acodecSignal_->outQueueEnc_); + clearIntQueue(acodecSignal_->sizeQueueEnc_); + clearIntQueue(acodecSignal_->flagQueueEnc_); + clearBufferQueue(acodecSignal_->outBufferQueueEnc_); + acodecSignal_->outCondEnc_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->inQueueEnc_); + clearBufferQueue(acodecSignal_->inBufferQueueEnc_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::FlushEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->outMutexEnc_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioEnc_->Flush(); + unique_lock lockIn(acodecSignal_->outMutexEnc_); + clearIntQueue(acodecSignal_->outQueueEnc_); + clearIntQueue(acodecSignal_->sizeQueueEnc_); + clearIntQueue(acodecSignal_->flagQueueEnc_); + clearBufferQueue(acodecSignal_->outBufferQueueEnc_); + acodecSignal_->outCondEnc_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->inQueueEnc_); + clearBufferQueue(acodecSignal_->inBufferQueueEnc_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::ResetEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + unique_lock lock(acodecSignal_->outMutexEnc_); + unique_lock lock2(acodecSignal_->inMutexEnc_); + acodecSignal_->isFlushing_.store(true); + lock.unlock(); + lock2.unlock(); + int32_t ret = audioEnc_->Reset(); + unique_lock lockIn(acodecSignal_->outMutexEnc_); + clearIntQueue(acodecSignal_->outQueueEnc_); + clearIntQueue(acodecSignal_->sizeQueueEnc_); + clearIntQueue(acodecSignal_->flagQueueEnc_); + clearBufferQueue(acodecSignal_->outBufferQueueEnc_); + acodecSignal_->outCondEnc_.notify_all(); + unique_lock lockOut(acodecSignal_->inMutexEnc_); + clearIntQueue(acodecSignal_->inQueueEnc_); + clearBufferQueue(acodecSignal_->inBufferQueueEnc_); + acodecSignal_->inCondEnc_.notify_all(); + acodecSignal_->isFlushing_.store(false); + lockIn.unlock(); + lockOut.unlock(); + return ret; +} + +int32_t ACodecMock::ReleaseEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + isEncRunning_.store(false); + if (inputLoopEnc_ != nullptr && inputLoopEnc_->joinable()) { + unique_lock lock(acodecSignal_->inMutexEnc_); + acodecSignal_->outQueueDec_.push(10000); // push 10000 to stop queue + acodecSignal_->inQueueEnc_.push(10000); // push 10000 to stop queue + acodecSignal_->inCondEnc_.notify_all(); + lock.unlock(); + inputLoopEnc_->join(); + inputLoopEnc_.reset(); + } + if (outputLoopEnc_ != nullptr && outputLoopEnc_->joinable()) { + unique_lock lock(acodecSignal_->outMutexEnc_); + acodecSignal_->outQueueEnc_.push(10000); // push 10000 to stop queue + acodecSignal_->outCondEnc_.notify_all(); + lock.unlock(); + outputLoopEnc_->join(); + outputLoopEnc_.reset(); + } + return audioEnc_->Release(); +} + +std::shared_ptr ACodecMock::GetOutputMediaDescriptionEnc() +{ + if (audioEnc_ == nullptr) { + return nullptr; + } + return audioEnc_->GetOutputMediaDescription(); +} + +int32_t ACodecMock::SetParameterEnc(std::shared_ptr format) +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->SetParameter(format); +} + +int32_t ACodecMock::PushInputDataEnc(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->PushInputData(index, attr); +} + +int32_t ACodecMock::FreeOutputDataEnc(uint32_t index) +{ + if (audioEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return audioEnc_->FreeOutputData(index); +} + +void ACodecMock::PopInQueueEnc() +{ + if (acodecSignal_ == nullptr) { + return; + } + acodecSignal_->inQueueEnc_.pop(); + acodecSignal_->inBufferQueueEnc_.pop(); +} + +int32_t ACodecMock::PushInputDataEncInner() +{ + uint32_t indexEnc = acodecSignal_->inQueueEnc_.front(); + std::shared_ptr bufferEnc = acodecSignal_->inBufferQueueEnc_.front(); + UNITTEST_CHECK_AND_RETURN_RET_LOG(bufferEnc != nullptr, AVCS_ERR_INVALID_VAL, "Fatal: GetEncInputBuffer fail"); + + uint32_t indexDec = acodecSignal_->outQueueDec_.front(); + std::shared_ptr bufferDec = acodecSignal_->outBufferQueueDec_.front(); + uint32_t sizeDecOut = acodecSignal_->sizeQueueDec_.front(); + uint32_t flagDecOut = acodecSignal_->flagQueueDec_.front(); + struct AVCodecBufferAttrMock attr; + attr.offset = 0; + attr.size = sizeDecOut; + attr.pts = timeStampEnc_; + attr.flags = 0; + if (flagDecOut == 1) { + cout << "DEC output EOS " << endl; + isDecOutputEOS_ = true; + isEncInputEOS_ = true; + attr.flags = 1; + } else { + if (memcpy_s(bufferEnc->GetAddr(), bufferEnc->GetSize(), bufferDec->GetAddr(), sizeDecOut) != AVCS_ERR_OK) { + cout << "Fatal: memcpy fail" << endl; + acodecSignal_->errorNum_ += 1; + PopOutQueueDec(); + PopInQueueEnc(); + return AVCS_ERR_INVALID_VAL; + } + if (audioDec_->FreeOutputData(indexDec) != AVCS_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + acodecSignal_->errorNum_ += 1; + } else { + decOutCnt_ += 1; + } + } + + PopOutQueueDec(); + PopInQueueEnc(); + return audioEnc_->PushInputData(indexEnc, attr); +} + +void ACodecMock::InputFuncEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return; + } + while (true) { + if (!isEncRunning_.load()) { + break; + } + + unique_lock lock(acodecSignal_->inMutexEnc_); + acodecSignal_->inCondEnc_.wait(lock, [this]() { return acodecSignal_->inQueueEnc_.size() > 0; }); + acodecSignal_->inCondEnc_.wait(lock, [this]() { return acodecSignal_->outQueueDec_.size() > 0; }); + + if (!isEncRunning_.load()) { + break; + } + if (acodecSignal_->isFlushing_.load() || isDecOutputEOS_) { + PopOutQueueDec(); + PopInQueueEnc(); + continue; + } + if (PushInputDataEncInner() != AVCS_ERR_OK) { + cout << "Fatal: PushInputData fail, exit" << endl; + acodecSignal_->errorNum_ += 1; + break; + } + timeStampEnc_ += SAMPLE_DURATION_US; + } +} + +void ACodecMock::OutputFuncEnc() +{ + if (acodecSignal_ == nullptr || audioEnc_ == nullptr) { + return; + } + while (!isEncOutputEOS_) { + if (!isEncRunning_.load()) { + break; + } + + unique_lock lock(acodecSignal_->outMutexEnc_); + acodecSignal_->outCondEnc_.wait(lock, [this]() { return acodecSignal_->outQueueEnc_.size() > 0; }); + + if (!isEncRunning_.load()) { + break; + } + if (acodecSignal_->isFlushing_.load() || isEncOutputEOS_) { + acodecSignal_->outQueueEnc_.pop(); + acodecSignal_->sizeQueueEnc_.pop(); + acodecSignal_->flagQueueEnc_.pop(); + acodecSignal_->outBufferQueueEnc_.pop(); + continue; + } + uint32_t index = acodecSignal_->outQueueEnc_.front(); + auto buffer = acodecSignal_->outBufferQueueEnc_.front(); + uint32_t size = acodecSignal_->sizeQueueEnc_.front(); + uint32_t encOutflag = acodecSignal_->flagQueueEnc_.front(); + if (encOutflag == 1) { + cout << "ENC get output EOS" << endl; + isEncOutputEOS_ = true; + } else { + FILE *outFile; + const char *savepath = outPath_.c_str(); + outFile = fopen(savepath, "a"); + if (outFile == nullptr) { + cout << "dump data fail" << endl; + } else { + fwrite(buffer->GetAddr(), 1, size, outFile); + fclose(outFile); + } + if (audioEnc_->FreeOutputData(index) != AVCS_ERR_OK) { + cout << "Fatal: FreeOutputData fail" << endl; + acodecSignal_->errorNum_ += 1; + } + } + acodecSignal_->outQueueEnc_.pop(); + acodecSignal_->sizeQueueEnc_.pop(); + acodecSignal_->flagQueueEnc_.pop(); + acodecSignal_->outBufferQueueEnc_.pop(); + } +} +} +} + diff --git a/test/unittest/avcodec_test/acodec_test/acodec_mock.h b/test/unittest/avcodec_test/acodec_test/acodec_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..e233be6d33fbabe61278472f0cf746c5bde86a59 --- /dev/null +++ b/test/unittest/avcodec_test/acodec_test/acodec_mock.h @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#ifndef ACODEC_MOCK_H +#define ACODEC_MOCK_H + +#include +#include +#include +#include +#include +#include +#include +#include "avcodec_mock.h" +#include "securec.h" +#include "test_params_config.h" +#include "unittest_log.h" + +namespace OHOS { +namespace Media { +struct ACodecSignal { +public: + std::mutex inMutexDec_; + std::condition_variable inCondDec_; + std::queue inQueueDec_; + std::queue outQueueDec_; + std::queue sizeQueueDec_; + std::queue flagQueueDec_; + std::queue> inBufferQueueDec_; + std::queue> outBufferQueueDec_; + + std::mutex inMutexEnc_; + std::mutex outMutexEnc_; + std::condition_variable inCondEnc_; + std::condition_variable outCondEnc_; + std::queue inQueueEnc_; + std::queue outQueueEnc_; + std::queue sizeQueueEnc_; + std::queue flagQueueEnc_; + std::queue> inBufferQueueEnc_; + std::queue> outBufferQueueEnc_; + int32_t errorNum_ = 0; + std::atomic isFlushing_ = false; +}; + +class ADecCallbackTest : public AVCodecCallbackMock { +public: + explicit ADecCallbackTest(std::shared_ptr signal); + virtual ~ADecCallbackTest(); + void OnError(int32_t errorCode); + void OnStreamChanged(std::shared_ptr format); + void OnNeedInputData(uint32_t index, std::shared_ptr data); + void OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr); + +private: + std::shared_ptr acodecSignal_; +}; + +class AEncCallbackTest : public AVCodecCallbackMock { +public: + explicit AEncCallbackTest(std::shared_ptr signal); + virtual ~AEncCallbackTest(); + void OnError(int32_t errorCode); + void OnStreamChanged(std::shared_ptr format); + void OnNeedInputData(uint32_t index, std::shared_ptr data); + void OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr); + +private: + std::shared_ptr acodecSignal_; +}; + +class ACodecMock : public NoCopyable { +public: + explicit ACodecMock(std::shared_ptr signal); + ~ACodecMock(); + + bool CreateAudioDecMockByMime(const std::string &mime); + bool CreateAudioDecMockByName(const std::string &name); + int32_t SetCallbackDec(std::shared_ptr cb); + int32_t ConfigureDec(std::shared_ptr format); + int32_t PrepareDec(); + int32_t StartDec(); + int32_t StopDec(); + int32_t FlushDec(); + int32_t ResetDec(); + int32_t ReleaseDec(); + std::shared_ptr GetOutputMediaDescriptionDec(); + int32_t SetParameterDec(std::shared_ptr format); + int32_t PushInputDataDec(uint32_t index, AVCodecBufferAttrMock &attr); + int32_t FreeOutputDataDec(uint32_t index); + bool CreateAudioEncMockByMime(const std::string &mime); + bool CreateAudioEncMockByName(const std::string &name); + int32_t SetCallbackEnc(std::shared_ptr cb); + int32_t ConfigureEnc(std::shared_ptr format); + int32_t PrepareEnc(); + int32_t StartEnc(); + int32_t StopEnc(); + int32_t FlushEnc(); + int32_t ResetEnc(); + int32_t ReleaseEnc(); + int32_t PushInputDataEnc(uint32_t index, AVCodecBufferAttrMock &attr); + std::shared_ptr GetOutputMediaDescriptionEnc(); + int32_t SetParameterEnc(std::shared_ptr format); + int32_t FreeOutputDataEnc(uint32_t index); + void InputLoopFunc(); + void OutputLoopFunc(); + void SetOutPath(const std::string &path); + +private: + void clearIntQueue(std::queue &q); + void clearBufferQueue(std::queue> &q); + std::shared_ptr audioDec_; + std::shared_ptr acodecSignal_; + void InputFuncDec(); + void PopOutQueueDec(); + void PopInQueueDec(); + int32_t PushInputDataDecInner(uint32_t index, uint32_t bufferSize); + std::atomic isDecRunning_ = false; + std::unique_ptr testFile_; + std::unique_ptr inputLoopDec_; + std::unique_ptr outputLoopDec_; + int64_t timeStampDec_ = 0; + uint32_t decInCnt_ = 0; + uint32_t decOutCnt_ = 0; + + std::shared_ptr audioEnc_ = nullptr; + void InputFuncEnc(); + void OutputFuncEnc(); + int32_t PushInputDataEncInner(); + void PopInQueueEnc(); + std::atomic isEncRunning_ = false; + std::unique_ptr inputLoopEnc_; + std::unique_ptr outputLoopEnc_; + bool isDecInputEOS_ = false; + bool isEncInputEOS_ = false; + bool isDecOutputEOS_ = false; + bool isEncOutputEOS_ = false; + int64_t timeStampEnc_ = 0; + std::string outPath_ = "/data/test/media/out.es"; +}; +} // namespace Media +} // namespace OHOS +#endif // ACODEC_MOCK_H diff --git a/test/unittest/avcodec_test/acodec_test/acodec_unit_test.cpp b/test/unittest/avcodec_test/acodec_test/acodec_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1958c31740fe7477e994168af671093064a14988 --- /dev/null +++ b/test/unittest/avcodec_test/acodec_test/acodec_unit_test.cpp @@ -0,0 +1,311 @@ +/* + * 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 "acodec_unit_test.h" +#include "gtest/gtest.h" +#include "avcodec_errors.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::Media; +using namespace testing::ext; +using namespace OHOS::Media::ACodecTestParam; + +void ACodecUnitTest::SetUpTestCase(void) {} + +void ACodecUnitTest::TearDownTestCase(void) {} + +void ACodecUnitTest::SetUp(void) +{ + createCodecSuccess_ = false; + std::shared_ptr acodecSignal = std::make_shared(); + adecCallback_ = std::make_shared(acodecSignal); + ASSERT_NE(nullptr, adecCallback_); + + aencCallback_ = std::make_shared(acodecSignal); + ASSERT_NE(nullptr, aencCallback_); + + audioCodec_ = std::make_shared(acodecSignal); + ASSERT_NE(nullptr, audioCodec_); + + defaultFormat_ = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, defaultFormat_); + (void)defaultFormat_->PutIntValue("channel_count", MAX_CHANNEL); + (void)defaultFormat_->PutIntValue("sample_rate", DEFAULT_SAMPLERATE); + (void)defaultFormat_->PutLongValue("bitrate", DEFAULT_BITRATE); + (void)defaultFormat_->PutIntValue("aac_is_adts", 1); + + testInfo_ = ::testing::UnitTest::GetInstance()->current_test_info(); + string prefix = "/data/test/media/"; + string fileName = testInfo_->name(); + string suffix = ".es"; + audioCodec_->SetOutPath(prefix + fileName + suffix); +} + +bool ACodecUnitTest::CreateAudioCodecByMime(const std::string &decMime, const std::string &encMime) +{ + if (audioCodec_->CreateAudioDecMockByMime(decMime) == false || + audioCodec_->CreateAudioEncMockByMime(encMime) == false || + audioCodec_->SetCallbackDec(adecCallback_) != AVCS_ERR_OK || + audioCodec_->SetCallbackEnc(aencCallback_) != AVCS_ERR_OK) { + return false; + } + createCodecSuccess_ = true; + return true; +} + +bool ACodecUnitTest::CreateAudioCodecByName(const std::string &decName, const std::string &encName) +{ + if (audioCodec_->CreateAudioDecMockByName(decName) == false || + audioCodec_->CreateAudioEncMockByName(encName) == false || + audioCodec_->SetCallbackDec(adecCallback_) != AVCS_ERR_OK || + audioCodec_->SetCallbackEnc(aencCallback_) != AVCS_ERR_OK) { + return false; + } + createCodecSuccess_ = true; + return true; +} + +void ACodecUnitTest::TearDown(void) +{ + if (audioCodec_ != nullptr && createCodecSuccess_) { + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ReleaseDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ReleaseEnc()); + } + if (defaultFormat_ != nullptr) { + defaultFormat_->Destroy(); + } +} + +/** + * @tc.name: audio_codec_Configure_0100 + * @tc.desc: audio create + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_Configure_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); +} + +/** + * @tc.name: audio_codec_0100 + * @tc.desc: audio decodec aac->aac + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_TRUE(defaultFormat_->PutIntValue("profile", 0)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + system("hidumper -s 3002 -a codec"); + sleep(10); // start run 10s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopEnc()); +} + +/** + * @tc.name: audio_decodec_flush_0100 + * @tc.desc: audio decodec flush + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_decodec_flush_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(3); // start run 3s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->FlushDec()); + sleep(7); // start run 7s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopEnc()); +} + +/** + * @tc.name: audio_encodec_flush_0100 + * @tc.desc: audio encodec flush + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_encodec_flush_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(3); // start run 3s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->FlushEnc()); + sleep(7); // start run 7s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StopEnc()); +} + +/** + * @tc.name: audio_codec_reset_0100 + * @tc.desc: audio reset at end of stream + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_reset_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(10); // start run 10s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetEnc()); +} + +/** + * @tc.name: audio_codec_reset_0200 + * @tc.desc: audio reset at running state + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_reset_0200, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(2); // start run 2s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetEnc()); +} + +/** + * @tc.name: audio_codec_SetParameter_0100 + * @tc.desc: audio codec SetParameter + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_SetParameter_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(2); // start run 2s + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->SetParameterDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->SetParameterEnc(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetEnc()); +} + +/** + * @tc.name: audio_codec_GetOutputMediaDescription_0100 + * @tc.desc: audio codec GetOutputMediaDescription + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(ACodecUnitTest, audio_codec_GetOutputMediaDescription_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_aac", "avdec_aac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->StartEnc()); + sleep(2); // start run 2s + EXPECT_NE(nullptr, audioCodec_->GetOutputMediaDescriptionDec()); + EXPECT_NE(nullptr, audioCodec_->GetOutputMediaDescriptionEnc()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->ResetEnc()); +} + +/** + * @tc.name: audio_codec_format_vorbis_0100 + * @tc.desc: test audio codec format vorbis + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ACodecUnitTest, audio_codec_format_vorbis_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_vorbis", "avdec_vorbis")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); +} + +/** + * @tc.name: audio_codec_format_flac_0100 + * @tc.desc: test audio codec format flac + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ACodecUnitTest, audio_codec_format_flac_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_flac", "avdec_flac")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); +} + +/** + * @tc.name: audio_codec_format_mp3_0100 + * @tc.desc: test audio codec format flac + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ACodecUnitTest, audio_codec_format_mp3_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateAudioCodecByName("avdec_mp3", "avdec_mp3")); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureDec(defaultFormat_)); + ASSERT_EQ(AVCS_ERR_OK, audioCodec_->ConfigureEnc(defaultFormat_)); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareDec()); + EXPECT_EQ(AVCS_ERR_OK, audioCodec_->PrepareEnc()); +} + +/** + * @tc.name: audio_codec_format_none_0100 + * @tc.desc: test audio codec format none + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ACodecUnitTest, audio_codec_format_none_0100, TestSize.Level0) +{ + CreateAudioCodecByMime("", ""); + ASSERT_NE(AVCS_ERR_OK, audioCodec_->ReleaseDec()); + ASSERT_NE(AVCS_ERR_OK, audioCodec_->ReleaseEnc()); +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/acodec_test/acodec_unit_test.h b/test/unittest/avcodec_test/acodec_test/acodec_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..91db17df981dd5e5b67ee95236ff3d3ce6066730 --- /dev/null +++ b/test/unittest/avcodec_test/acodec_test/acodec_unit_test.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef ACODEC_UNIT_TEST_H +#define ACODEC_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "acodec_mock.h" +namespace OHOS { +namespace Media { +class ACodecUnitTest : 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); + bool CreateAudioCodecByMime(const std::string &decMime, const std::string &encMime); + bool CreateAudioCodecByName(const std::string &decName, const std::string &encName); + +protected: + std::shared_ptr audioCodec_ = nullptr; + std::shared_ptr adecCallback_ = nullptr; + std::shared_ptr aencCallback_ = nullptr; + const ::testing::TestInfo *testInfo_ = nullptr; + std::shared_ptr defaultFormat_ = nullptr; + bool createCodecSuccess_ = false; +}; +} // namespace Media +} // namespace OHOS +#endif // ACODEC_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.cpp b/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7e1ef97df25397773d3494c1ef7db9f67ea1a079 --- /dev/null +++ b/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.cpp @@ -0,0 +1,639 @@ +/* + * 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 "gtest/gtest.h" +#include "avcodec_errors.h" +#include "avcodec_list_unit_test.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::Media; +using namespace testing::ext; + +namespace OHOS { +namespace Media { +void AVCodecListUnitTest::SetUpTestCase(void) {} + +void AVCodecListUnitTest::TearDownTestCase(void) {} + +void AVCodecListUnitTest::SetUp(void) +{ + avCodecList_ = AVCodecMockFactory::CreateAVCodecList(); + ASSERT_NE(nullptr, avCodecList_); + enum_ = AVCodecMockFactory::CreateEnum(); + ASSERT_NE(nullptr, enum_); + codecMimeKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_CODEC_MIME); + bitrateKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_BITRATE); + widthKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_WIDTH); + heightKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_HEIGHT); + pixelFormatKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_PIXEL_FORMAT); + frameRateKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_FRAME_RATE); + channelCountKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_CHANNEL_COUNT); + sampleRateKey_ = enum_->GetMediaDescriptionKey(MediaDescriptionKeyMock::MOCK_MD_KEY_SAMPLE_RATE); +} + +void AVCodecListUnitTest::TearDown(void) +{ +} + +/** + * @tc.name: AVCdecList_FindVideoDecoder_0100 + * @tc.desc: AVCdecList FindVideoDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_FindVideoDecoder_0100, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + (void)format->PutStringValue(codecMimeKey_, enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_AVC)); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, DEFAULT_WIDTH); + (void)format->PutIntValue(heightKey_, DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormatKey_, enum_->GetVideoPixelFormat(VideoPixelFormatMock::MOCK_NV12)); + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = avCodecList_->FindVideoDecoder(format); + EXPECT_NE("", codecName); +} + +/** + * @tc.name: AVCdecList_FindVideoEncoder_0100 + * @tc.desc: AVCdecList FindVideoEncoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_FindVideoEncoder_0100, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_MPEG4)); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, DEFAULT_WIDTH); + (void)format->PutIntValue(heightKey_, DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormatKey_, enum_->GetVideoPixelFormat(VideoPixelFormatMock::MOCK_NV21)); + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = avCodecList_->FindVideoEncoder(format); + EXPECT_NE("", codecName); +} + +/** + * @tc.name: AVCdecList_FindAudioDecoder_0100 + * @tc.desc: AVCdecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_FindAudioDecoder_0100, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_MPEG)); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = avCodecList_->FindAudioDecoder(format); + EXPECT_EQ("avdec_mp3", codecName); +} + +/** + * @tc.name: AVCdecList_FindAudioEncoder_0100 + * @tc.desc: AVCdecList FindAudioEncoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_FindAudioEncoder_0100, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_AAC)); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = avCodecList_->FindAudioEncoder(format); + EXPECT_EQ("avenc_aac", codecName); +} + +void AVCodecListUnitTest::CheckVideoCapsArray(const std::vector> &videoCapsArray) const +{ + for (auto iter = videoCapsArray.begin(); iter != videoCapsArray.end(); iter++) { + std::shared_ptr pVideoCaps = *iter; + if (pVideoCaps == nullptr) { + cout << "pVideoCaps is nullptr" << endl; + break; + } + CheckVideoCaps(pVideoCaps); + } +} + +void AVCodecListUnitTest::CheckVideoCaps(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps; + videoCodecCaps = videoCaps->GetCodecInfo(); + std::string codecName = videoCodecCaps->GetName(); + cout << "codecName is : " << codecName << endl; + if (codecName.compare("avdec_h264") == 0) { + CheckAVDecH264(videoCaps); + } else if (codecName.compare("avdec_h263") == 0) { + CheckAVDecH263(videoCaps); + } else if (codecName.compare("avdec_mpeg2video") == 0) { + CheckAVDecMpeg2Video(videoCaps); + } else if (codecName.compare("avdec_mpeg4") == 0) { + CheckAVDecMpeg4(videoCaps); + } else if (codecName.compare("avenc_mpeg4") == 0) { + CheckAVEncMpeg4(videoCaps); + } +} + +void AVCodecListUnitTest::CheckAVDecH264(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps = videoCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_VIDEO_DECODER, videoCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_AVC), videoCodecCaps->GetMimeType()); + EXPECT_EQ(0, videoCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, videoCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, videoCodecCaps->IsVendor()); + EXPECT_EQ(1, videoCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_VIDEO_BITRATE, videoCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedWidthAlignment()); + EXPECT_EQ(MIN_WIDTH, videoCaps->GetSupportedWidth().minVal); + EXPECT_EQ(MAX_WIDTH, videoCaps->GetSupportedWidth().maxVal); + EXPECT_EQ(MIN_HEIGHT, videoCaps->GetSupportedHeight().minVal); + EXPECT_EQ(MAX_HEIGHT, videoCaps->GetSupportedHeight().maxVal); + EXPECT_EQ(1, videoCaps->GetSupportedFrameRate().minVal); + EXPECT_EQ(MAX_FRAME_RATE, videoCaps->GetSupportedFrameRate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(2, videoCaps->GetSupportedFormats().size()); // 2: supported formats count + EXPECT_EQ(3, videoCaps->GetSupportedProfiles().size()); // 3: supported profile count + EXPECT_EQ(0, videoCaps->GetSupportedBitrateMode().size()); + EXPECT_EQ(0, videoCaps->GetSupportedLevels().size()); + EXPECT_EQ(false, videoCaps->IsSupportDynamicIframe()); + EXPECT_EQ(true, videoCaps->IsSizeSupported(videoCaps->GetSupportedWidth().minVal, + videoCaps->GetSupportedHeight().maxVal)); +} + +void AVCodecListUnitTest::CheckAVDecH263(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps = videoCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_VIDEO_DECODER, videoCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_H263), videoCodecCaps->GetMimeType()); + EXPECT_EQ(0, videoCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, videoCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, videoCodecCaps->IsVendor()); + EXPECT_EQ(1, videoCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_VIDEO_BITRATE, videoCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedWidthAlignment()); + EXPECT_EQ(0, videoCaps->GetSupportedHeightAlignment()); + EXPECT_EQ(MIN_WIDTH, videoCaps->GetSupportedWidth().minVal); + EXPECT_EQ(MAX_WIDTH, videoCaps->GetSupportedWidth().maxVal); + EXPECT_EQ(MIN_HEIGHT, videoCaps->GetSupportedHeight().minVal); + EXPECT_EQ(MAX_HEIGHT, videoCaps->GetSupportedHeight().maxVal); + EXPECT_EQ(1, videoCaps->GetSupportedFrameRate().minVal); + EXPECT_EQ(MAX_FRAME_RATE, videoCaps->GetSupportedFrameRate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(2, videoCaps->GetSupportedFormats().size()); // 2: supported formats count + EXPECT_EQ(1, videoCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, videoCaps->GetSupportedBitrateMode().size()); + EXPECT_EQ(0, videoCaps->GetSupportedLevels().size()); + EXPECT_EQ(false, videoCaps->IsSupportDynamicIframe()); + EXPECT_EQ(false, videoCaps->IsSizeSupported(videoCaps->GetSupportedWidth().minVal - 1, + videoCaps->GetSupportedHeight().maxVal)); +} + +void AVCodecListUnitTest::CheckAVDecMpeg2Video(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps = videoCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_VIDEO_DECODER, videoCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_MPEG2), videoCodecCaps->GetMimeType()); + EXPECT_EQ(0, videoCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, videoCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, videoCodecCaps->IsVendor()); + EXPECT_EQ(1, videoCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_VIDEO_BITRATE, videoCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedWidthAlignment()); + EXPECT_EQ(0, videoCaps->GetSupportedHeightAlignment()); + EXPECT_EQ(MIN_WIDTH, videoCaps->GetSupportedWidth().minVal); + EXPECT_EQ(MAX_WIDTH, videoCaps->GetSupportedWidth().maxVal); + EXPECT_EQ(MIN_HEIGHT, videoCaps->GetSupportedHeight().minVal); + EXPECT_EQ(MAX_HEIGHT, videoCaps->GetSupportedHeight().maxVal); + EXPECT_EQ(1, videoCaps->GetSupportedFrameRate().minVal); + EXPECT_EQ(MAX_FRAME_RATE, videoCaps->GetSupportedFrameRate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(2, videoCaps->GetSupportedFormats().size()); // 2: supported formats count + EXPECT_EQ(2, videoCaps->GetSupportedProfiles().size()); // 2: supported profile count + EXPECT_EQ(0, videoCaps->GetSupportedBitrateMode().size()); + EXPECT_EQ(0, videoCaps->GetSupportedLevels().size()); + EXPECT_EQ(false, videoCaps->IsSupportDynamicIframe()); + EXPECT_EQ(0, videoCaps->IsSizeAndRateSupported(videoCaps->GetSupportedWidth().minVal, + videoCaps->GetSupportedHeight().maxVal, videoCaps->GetSupportedFrameRate().maxVal)); + EXPECT_EQ(false, videoCaps->IsSizeAndRateSupported(videoCaps->GetSupportedWidth().minVal-1, + videoCaps->GetSupportedHeight().maxVal + 1, videoCaps->GetSupportedFrameRate().maxVal)); +} + +void AVCodecListUnitTest::CheckAVDecMpeg4(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps = videoCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_VIDEO_DECODER, videoCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_MPEG4), videoCodecCaps->GetMimeType()); + EXPECT_EQ(0, videoCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, videoCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, videoCodecCaps->IsVendor()); + EXPECT_EQ(1, videoCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_VIDEO_BITRATE, videoCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedWidthAlignment()); + EXPECT_EQ(0, videoCaps->GetSupportedHeightAlignment()); + EXPECT_EQ(MIN_WIDTH, videoCaps->GetSupportedWidth().minVal); + EXPECT_EQ(MAX_WIDTH, videoCaps->GetSupportedWidth().maxVal); + EXPECT_EQ(MIN_HEIGHT, videoCaps->GetSupportedHeight().minVal); + EXPECT_EQ(MAX_HEIGHT, videoCaps->GetSupportedHeight().maxVal); + EXPECT_EQ(1, videoCaps->GetSupportedFrameRate().minVal); + EXPECT_EQ(MAX_FRAME_RATE, videoCaps->GetSupportedFrameRate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(2, videoCaps->GetSupportedFormats().size()); // 2: supported formats count + EXPECT_EQ(2, videoCaps->GetSupportedProfiles().size()); // 2: supported profile count + EXPECT_EQ(0, videoCaps->GetSupportedBitrateMode().size()); + EXPECT_EQ(0, videoCaps->GetSupportedLevels().size()); + EXPECT_EQ(false, videoCaps->IsSupportDynamicIframe()); + EXPECT_EQ(false, videoCaps->IsSizeAndRateSupported(videoCaps->GetSupportedWidth().minVal, + videoCaps->GetSupportedHeight().maxVal, videoCaps->GetSupportedFrameRate().maxVal + 1)); +} + +void AVCodecListUnitTest::CheckAVEncMpeg4(const std::shared_ptr &videoCaps) const +{ + std::shared_ptr videoCodecCaps = videoCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_VIDEO_ENCODER, videoCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::VIDEO_MPEG4), videoCodecCaps->GetMimeType()); + EXPECT_EQ(0, videoCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, videoCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, videoCodecCaps->IsVendor()); + EXPECT_EQ(1, videoCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_VIDEO_BITRATE, videoCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedWidthAlignment()); + EXPECT_EQ(0, videoCaps->GetSupportedHeightAlignment()); + EXPECT_EQ(MIN_WIDTH, videoCaps->GetSupportedWidth().minVal); + EXPECT_EQ(DEFAULT_WIDTH, videoCaps->GetSupportedWidth().maxVal); + EXPECT_EQ(MIN_HEIGHT, videoCaps->GetSupportedHeight().minVal); + EXPECT_EQ(DEFAULT_HEIGHT, videoCaps->GetSupportedHeight().maxVal); + EXPECT_EQ(1, videoCaps->GetSupportedFrameRate().minVal); + EXPECT_EQ(MAX_FRAME_RATE, videoCaps->GetSupportedFrameRate().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedEncodeQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedQuality().maxVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, videoCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(2, videoCaps->GetSupportedFormats().size()); // 2: supported formats count + EXPECT_EQ(2, videoCaps->GetSupportedProfiles().size()); // 2: supported profile count + EXPECT_EQ(2, videoCaps->GetSupportedBitrateMode().size()); // 2: supported bitretemode count + EXPECT_EQ(0, videoCaps->GetSupportedLevels().size()); + EXPECT_EQ(false, videoCaps->IsSupportDynamicIframe()); +} + +void AVCodecListUnitTest::CheckAudioCapsArray(const std::vector> &audioCapsArray) const +{ + for (auto iter = audioCapsArray.begin(); iter != audioCapsArray.end(); iter++) { + std::shared_ptr pAudioCaps = *iter; + if (pAudioCaps == nullptr) { + cout << "pAudioCaps is nullptr" << endl; + break; + } + CheckAudioCaps(pAudioCaps); + } +} + +void AVCodecListUnitTest::CheckAudioCaps(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps; + audioCodecCaps = audioCaps->GetCodecInfo(); + std::string codecName = audioCodecCaps->GetName(); + if (codecName.compare("avdec_mp3") == 0) { + CheckAVDecMP3(audioCaps); + } else if (codecName.compare("avdec_aac") == 0) { + CheckAVDecAAC(audioCaps); + } else if (codecName.compare("avdec_vorbis") == 0) { + CheckAVDecVorbis(audioCaps); + } else if (codecName.compare("avdec_flac") == 0) { + CheckAVDecFlac(audioCaps); + } else if (codecName.compare("avdec_opus") == 0) { + CheckAVDecOpus(audioCaps); + } else if (codecName.compare("avenc_aac") == 0) { + CheckAVEncAAC(audioCaps); + } else if (codecName.compare("avenc_opus") == 0) { + CheckAVEncOpus(audioCaps); + } +} + +void AVCodecListUnitTest::CheckAVDecMP3(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_DECODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_MPEG), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(12, audioCaps->GetSupportedSampleRates().size()); // 12: supported samplerate count + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVDecAAC(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_DECODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_AAC), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(12, audioCaps->GetSupportedSampleRates().size()); // 12: supported samplerate count + EXPECT_EQ(1, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVDecVorbis(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_DECODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_VORBIS), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT_VORBIS, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(14, audioCaps->GetSupportedSampleRates().size()); // 14: supported samplerate count + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVDecFlac(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_DECODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_FLAC), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(12, audioCaps->GetSupportedSampleRates().size()); // 12: supported samplerate count + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVDecOpus(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_DECODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_OPUS), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(1, audioCaps->GetSupportedSampleRates().size()); + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVEncAAC(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_ENCODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_AAC), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(8000, audioCaps->GetSupportedBitrate().minVal); // 8000: supported min bitrate + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(11, audioCaps->GetSupportedSampleRates().size()); // 11: supported samplerate count + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +void AVCodecListUnitTest::CheckAVEncOpus(const std::shared_ptr &audioCaps) const +{ + std::shared_ptr audioCodecCaps = audioCaps->GetCodecInfo(); + EXPECT_EQ(AVCODEC_TYPE_MOCK_AUDIO_ENCODER, audioCodecCaps->GetType()); + EXPECT_EQ(enum_->GetCodecMimeType(CodecMimeTypeMock::AUDIO_OPUS), audioCodecCaps->GetMimeType()); + EXPECT_EQ(0, audioCodecCaps->IsHardwareAccelerated()); + EXPECT_EQ(1, audioCodecCaps->IsSoftwareOnly()); + EXPECT_EQ(0, audioCodecCaps->IsVendor()); + EXPECT_EQ(1, audioCaps->GetSupportedBitrate().minVal); + EXPECT_EQ(MAX_AUDIO_BITRATE, audioCaps->GetSupportedBitrate().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedChannel().minVal); + EXPECT_EQ(MAX_CHANNEL_COUNT, audioCaps->GetSupportedChannel().maxVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().minVal); + EXPECT_EQ(0, audioCaps->GetSupportedComplexity().maxVal); + EXPECT_EQ(1, audioCaps->GetSupportedFormats().size()); + EXPECT_EQ(1, audioCaps->GetSupportedSampleRates().size()); + EXPECT_EQ(0, audioCaps->GetSupportedProfiles().size()); + EXPECT_EQ(0, audioCaps->GetSupportedLevels().size()); +} + +/** + * @tc.name: AVCdecList_GetVideoDecoderCaps_0100 + * @tc.desc: AVCdecList GetVideoDecoderCaps + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetVideoDecoderCaps_0100, TestSize.Level0) +{ + std::vector> videoDecoderArray; + videoDecoderArray = avCodecList_->GetVideoDecoderCaps(); + CheckVideoCapsArray(videoDecoderArray); +} + +/** + * @tc.name: AVCdecList_GetVideoEncoderCaps_0100 + * @tc.desc: AVCdecList GetVideoEncoderCaps + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetVideoEncoderCaps_0100, TestSize.Level0) +{ + std::vector> videoEncoderArray; + videoEncoderArray = avCodecList_->GetVideoEncoderCaps(); + CheckVideoCapsArray(videoEncoderArray); +} + +/** + * @tc.name: AVCdecList_GetAudioDecoderCaps_0100 + * @tc.desc: AVCdecList GetAudioDecoderCaps + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetAudioDecoderCaps_0100, TestSize.Level0) +{ + std::vector> audioDecoderArray; + audioDecoderArray = avCodecList_->GetAudioDecoderCaps(); + CheckAudioCapsArray(audioDecoderArray); +} + +/** + * @tc.name: AVCdecList_GetAudioEncoderCaps_0100 + * @tc.desc: AVCdecList GetAudioEncoderCaps + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetAudioEncoderCaps_0100, TestSize.Level0) +{ + std::vector> audioEncoderArray; + audioEncoderArray = avCodecList_->GetAudioEncoderCaps(); + CheckAudioCapsArray(audioEncoderArray); +} + +/** + * @tc.name: AVCdecList_GetSupportedFrameRatesFor_0100 + * @tc.desc: AVCdecList GetSupportedFrameRatesFor + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetSupportedFrameRatesFor_0100, TestSize.Level0) +{ + RangeMock ret; + std::vector> videoDecoderArray = avCodecList_->GetVideoDecoderCaps(); + for (auto iter = videoDecoderArray.begin(); iter != videoDecoderArray.end(); iter++) { + std::shared_ptr pVideoCaps = *iter; + ret = (*iter)->GetSupportedFrameRatesFor(DEFAULT_WIDTH, DEFAULT_HEIGHT); + EXPECT_GE(ret.minVal, 0); + EXPECT_LE(ret.maxVal, MAX_FRAME_RATE); + } + std::vector> videoEncoderArray = avCodecList_->GetVideoEncoderCaps(); + for (auto iter = videoEncoderArray.begin(); iter != videoEncoderArray.end(); iter++) { + ret = (*iter)->GetSupportedFrameRatesFor(DEFAULT_WIDTH, DEFAULT_HEIGHT); + EXPECT_GE(ret.minVal, 0); + EXPECT_LE(ret.maxVal, MAX_FRAME_RATE); + } +} + +/** + * @tc.name: AVCdecList_GetSupportedFrameRatesFor_0200 + * @tc.desc: AVCdecList GetSupportedFrameRatesFor not supported size + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetSupportedFrameRatesFor_0200, TestSize.Level0) +{ + RangeMock ret; + std::vector> videoDecoderArray = avCodecList_->GetVideoDecoderCaps(); + for (auto iter = videoDecoderArray.begin(); iter != videoDecoderArray.end(); iter++) { + std::shared_ptr pVideoCaps = *iter; + ret = (*iter)->GetSupportedFrameRatesFor(MAX_WIDTH + 1, MAX_HEIGHT + 1); + EXPECT_GE(ret.minVal, 0); + EXPECT_LE(ret.maxVal, MAX_FRAME_RATE); + } + std::vector> videoEncoderArray = avCodecList_->GetVideoEncoderCaps(); + for (auto iter = videoEncoderArray.begin(); iter != videoEncoderArray.end(); iter++) { + ret = (*iter)->GetSupportedFrameRatesFor(MIN_WIDTH - 1, MIN_HEIGHT - 1); + EXPECT_GE(ret.minVal, 0); + EXPECT_LE(ret.maxVal, MAX_FRAME_RATE); + } +} + +/** + * @tc.name: AVCdecList_GetPreferredFrameRate_0100 + * @tc.desc: AVCdecList GetPreferredFrameRate + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetPreferredFrameRate_0100, TestSize.Level0) +{ + RangeMock ret; + std::vector> videoEncoderArray = avCodecList_->GetVideoEncoderCaps(); + for (auto iter = videoEncoderArray.begin(); iter != videoEncoderArray.end(); iter++) { + ret = (*iter)->GetPreferredFrameRate(DEFAULT_WIDTH, DEFAULT_HEIGHT); + EXPECT_GE(ret.minVal, 0); + } + std::vector> videoDecoderArray = avCodecList_->GetVideoDecoderCaps(); + for (auto iter = videoDecoderArray.begin(); iter != videoDecoderArray.end(); iter++) { + ret = (*iter)->GetPreferredFrameRate(DEFAULT_WIDTH, DEFAULT_HEIGHT); + EXPECT_GE(ret.minVal, 0); + } +} + +/** + * @tc.name: AVCdecList_GetPreferredFrameRate_0200 + * @tc.desc: AVCdecList GetPreferredFrameRate for not supported size + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AVCodecListUnitTest, AVCdecList_GetPreferredFrameRate_0200, TestSize.Level0) +{ + RangeMock ret; + std::vector> videoEncoderArray = avCodecList_->GetVideoEncoderCaps(); + for (auto iter = videoEncoderArray.begin(); iter != videoEncoderArray.end(); iter++) { + ret = (*iter)->GetPreferredFrameRate(MAX_WIDTH + 1, MAX_HEIGHT + 1); + EXPECT_GE(ret.minVal, 0); + } + std::vector> videoDecoderArray = avCodecList_->GetVideoDecoderCaps(); + for (auto iter = videoDecoderArray.begin(); iter != videoDecoderArray.end(); iter++) { + ret = (*iter)->GetPreferredFrameRate(MIN_WIDTH - 1, MIN_HEIGHT - 1); + EXPECT_GE(ret.minVal, 0); + } +} +} // namespace Media +} // namespace OHOS diff --git a/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.h b/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..2ecb782a57c4d026e6a4dabe9936b81a80475164 --- /dev/null +++ b/test/unittest/avcodec_test/avcodec_list_test/avcodec_list_unit_test.h @@ -0,0 +1,72 @@ +/* + * 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. + */ +#ifndef AVCODEC_LIST_UNIT_TEST_H +#define AVCODEC_LIST_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "avcodec_mock.h" +#include "enum_mock.h" + +namespace OHOS { +namespace Media { +constexpr uint32_t DEFAULT_WIDTH = 1920; +constexpr uint32_t DEFAULT_HEIGHT = 1080; +constexpr uint32_t MIN_WIDTH = 2; +constexpr uint32_t MIN_HEIGHT = 2; +constexpr uint32_t MAX_WIDTH = 3840; +constexpr uint32_t MAX_HEIGHT = 2160; +constexpr uint32_t MAX_FRAME_RATE = 30; +constexpr uint32_t MAX_VIDEO_BITRATE = 3000000; +constexpr uint32_t MAX_AUDIO_BITRATE = 384000; +constexpr uint32_t DEFAULT_SAMPLE_RATE = 8000; +constexpr uint32_t MAX_CHANNEL_COUNT = 2; +constexpr uint32_t MAX_CHANNEL_COUNT_VORBIS = 7; +class AVCodecListUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(void); + void TearDown(void); +protected: + std::shared_ptr avCodecList_ = nullptr; + std::shared_ptr enum_ = nullptr; + void CheckAVDecH264(const std::shared_ptr &videoCaps) const; + void CheckAVDecH263(const std::shared_ptr &videoCaps) const; + void CheckAVDecMpeg2Video(const std::shared_ptr &videoCaps) const; + void CheckAVDecMpeg4(const std::shared_ptr &videoCaps) const; + void CheckAVEncMpeg4(const std::shared_ptr &videoCaps) const; + void CheckVideoCaps(const std::shared_ptr &videoCaps) const; + void CheckVideoCapsArray(const std::vector> &videoCapsArray) const; + void CheckAVDecMP3(const std::shared_ptr &audioCaps) const; + void CheckAVDecAAC(const std::shared_ptr &audioCaps) const; + void CheckAVDecVorbis(const std::shared_ptr &audioCaps) const; + void CheckAVDecFlac(const std::shared_ptr &audioCaps) const; + void CheckAVDecOpus(const std::shared_ptr &audioCaps) const; + void CheckAVEncAAC(const std::shared_ptr &audioCaps) const; + void CheckAVEncOpus(const std::shared_ptr &audioCaps) const; + void CheckAudioCaps(const std::shared_ptr &audioCaps) const; + void CheckAudioCapsArray(const std::vector> &audioCapsArray) const; + std::string codecMimeKey_; + std::string bitrateKey_; + std::string widthKey_; + std::string heightKey_; + std::string pixelFormatKey_; + std::string frameRateKey_; + std::string channelCountKey_; + std::string sampleRateKey_; +}; +} +} +#endif diff --git a/test/unittest/avcodec_test/avcodec_mock.h b/test/unittest/avcodec_test/avcodec_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..355f4b71dbe72fb0c1dd15a381e61ae5bfb0eac8 --- /dev/null +++ b/test/unittest/avcodec_test/avcodec_mock.h @@ -0,0 +1,242 @@ +/* + * 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. + */ + +#ifndef AVCODEC_MOCK_H +#define AVCODEC_MOCK_H + +#include +#include "enum_mock.h" +#include "nocopyable.h" + + +namespace OHOS { +namespace Media { +enum AVCodecTypeMock : int32_t { + AVCODEC_TYPE_MOCK_NONE = -1, + AVCODEC_TYPE_MOCK_VIDEO_ENCODER = 0, + AVCODEC_TYPE_MOCK_VIDEO_DECODER, + AVCODEC_TYPE_MOCK_AUDIO_ENCODER, + AVCODEC_TYPE_MOCK_AUDIO_DECODER, +}; + +struct RangeMock { + int32_t minVal = 0; + int32_t maxVal = 0; +}; + +class SurfaceMock : public NoCopyable { +public: + virtual ~SurfaceMock() = default; +}; + +class FormatMock : public NoCopyable { +public: + virtual ~FormatMock() = default; + virtual bool PutIntValue(const std::string_view &key, int32_t value) = 0; + virtual bool GetIntValue(const std::string_view &key, int32_t &value) = 0; + virtual bool PutLongValue(const std::string_view &key, int64_t value) = 0; + virtual bool GetLongValue(const std::string_view &key, int64_t &value) = 0; + virtual bool PutFloatValue(const std::string_view &key, float value) = 0; + virtual bool GetFloatValue(const std::string_view &key, float &value) = 0; + virtual bool PutDoubleValue(const std::string_view &key, double value) = 0; + virtual bool GetDoubleValue(const std::string_view &key, double &value) = 0; + virtual bool PutStringValue(const std::string_view &key, const std::string_view &value) = 0; + virtual bool GetStringValue(const std::string_view &key, std::string &value) = 0; + virtual bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) = 0; + virtual bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) = 0; + virtual const char *DumpInfo() = 0; + virtual void Destroy() = 0; +}; + +class AVMemoryMock : public NoCopyable { +public: + virtual ~AVMemoryMock() = default; + virtual uint8_t *GetAddr() const = 0; + virtual int32_t GetSize() const = 0; + virtual uint32_t GetFlags() const = 0; +}; + +class AVCodecInfoMock : public NoCopyable { +public: + virtual ~AVCodecInfoMock() = default; + virtual std::string GetName() const = 0; + virtual int32_t GetType() const = 0; + virtual std::string GetMimeType() const = 0; + virtual bool IsHardwareAccelerated() const = 0; + virtual bool IsSoftwareOnly() const = 0; + virtual bool IsVendor() const = 0; +}; + +class VideoCapsMock : public NoCopyable { +public: + virtual ~VideoCapsMock() = default; + virtual std::shared_ptr GetCodecInfo() const = 0; + virtual RangeMock GetSupportedBitrate() const = 0; + virtual std::vector GetSupportedFormats() const = 0; + virtual int32_t GetSupportedHeightAlignment() const = 0; + virtual int32_t GetSupportedWidthAlignment() const = 0; + virtual RangeMock GetSupportedWidth() const = 0; + virtual RangeMock GetSupportedHeight() const = 0; + virtual std::vector GetSupportedProfiles() const = 0; + virtual std::vector GetSupportedLevels() const = 0; + virtual RangeMock GetSupportedEncodeQuality() const = 0; + virtual bool IsSizeSupported(int32_t width, int32_t height) const = 0; + virtual RangeMock GetSupportedFrameRate() const = 0; + virtual RangeMock GetSupportedFrameRatesFor(int32_t width, int32_t height) const = 0; + virtual bool IsSizeAndRateSupported(int32_t width, int32_t height, double frameRate) const = 0; + virtual RangeMock GetPreferredFrameRate(int32_t width, int32_t height) const = 0; + virtual std::vector GetSupportedBitrateMode() const = 0; + virtual RangeMock GetSupportedQuality() const = 0; + virtual RangeMock GetSupportedComplexity() const = 0; + virtual bool IsSupportDynamicIframe() const = 0; +}; + +class AudioCapsMock : public NoCopyable { +public: + virtual ~AudioCapsMock() = default; + virtual std::shared_ptr GetCodecInfo() const = 0; + virtual RangeMock GetSupportedBitrate() const = 0; + virtual RangeMock GetSupportedChannel() const = 0; + virtual std::vector GetSupportedFormats() const = 0; + virtual std::vector GetSupportedSampleRates() const = 0; + virtual std::vector GetSupportedProfiles() const = 0; + virtual std::vector GetSupportedLevels() const = 0; + virtual RangeMock GetSupportedComplexity() const = 0; +}; + +class AVCodecListMock : public NoCopyable { +public: + virtual ~AVCodecListMock() = default; + virtual std::string FindVideoDecoder(std::shared_ptr format) const = 0; + virtual std::string FindVideoEncoder(std::shared_ptr format) const = 0; + virtual std::string FindAudioDecoder(std::shared_ptr format) const = 0; + virtual std::string FindAudioEncoder(std::shared_ptr format) const = 0; + virtual std::vector> GetVideoDecoderCaps() const = 0; + virtual std::vector> GetVideoEncoderCaps() const = 0; + virtual std::vector> GetAudioDecoderCaps() const = 0; + virtual std::vector> GetAudioEncoderCaps() const = 0; +}; + +struct AVCodecBufferAttrMock { + int64_t pts = 0; + int32_t size = 0; + int32_t offset = 0; + uint32_t flags = 0; +}; + +class AVCodecCallbackMock : public NoCopyable { +public: + virtual ~AVCodecCallbackMock() = default; + virtual void OnError(int32_t errorCode) = 0; + virtual void OnStreamChanged(std::shared_ptr format) = 0; + virtual void OnNeedInputData(uint32_t index, std::shared_ptr data) = 0; + virtual void OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) = 0; +}; + +class VideoDecMock : public NoCopyable { +public: + virtual ~VideoDecMock() = default; + virtual int32_t SetCallback(std::shared_ptr cb) = 0; + virtual int32_t SetOutputSurface(std::shared_ptr surface) = 0; + virtual int32_t Configure(std::shared_ptr format) = 0; + virtual int32_t Prepare() = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual std::shared_ptr GetOutputMediaDescription() = 0; + virtual int32_t SetParameter(std::shared_ptr format) = 0; + virtual int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) = 0; + virtual int32_t RenderOutputData(uint32_t index) = 0; + virtual int32_t FreeOutputData(uint32_t index) = 0; +}; + +class VideoEncMock : public NoCopyable { +public: + virtual ~VideoEncMock() = default; + virtual int32_t SetCallback(std::shared_ptr cb) = 0; + virtual std::shared_ptr GetInputSurface() = 0; + virtual int32_t Configure(std::shared_ptr format) = 0; + virtual int32_t Prepare() = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t NotifyEos() = 0; + virtual std::shared_ptr GetOutputMediaDescription() = 0; + virtual int32_t SetParameter(std::shared_ptr format) = 0; + virtual int32_t FreeOutputData(uint32_t index) = 0; +}; + +class AudioDecMock : public NoCopyable { +public: + virtual ~AudioDecMock() = default; + virtual int32_t SetCallback(std::shared_ptr cb) = 0; + virtual int32_t Configure(std::shared_ptr format) = 0; + virtual int32_t Prepare() = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) = 0; + virtual std::shared_ptr GetOutputMediaDescription() = 0; + virtual int32_t SetParameter(std::shared_ptr format) = 0; + virtual int32_t FreeOutputData(uint32_t index) = 0; +}; + +class AudioEncMock : public NoCopyable { +public: + virtual ~AudioEncMock() = default; + virtual int32_t SetCallback(std::shared_ptr cb) = 0; + virtual int32_t Configure(std::shared_ptr format) = 0; + virtual int32_t Prepare() = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Flush() = 0; + virtual int32_t Reset() = 0; + virtual int32_t Release() = 0; + virtual int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) = 0; + virtual std::shared_ptr GetOutputMediaDescription() = 0; + virtual int32_t SetParameter(std::shared_ptr format) = 0; + virtual int32_t FreeOutputData(uint32_t index) = 0; +}; + +class __attribute__((visibility("default"))) AVCodecMockFactory { +public: + static std::shared_ptr CreateVideoDecMockByMime(const std::string &mime); + static std::shared_ptr CreateVideoDecMockByName(const std::string &name); + static std::shared_ptr CreateVideoEncMockByMime(const std::string &mime); + static std::shared_ptr CreateVideoEncMockByName(const std::string &name); + static std::shared_ptr CreateAudioDecMockByMime(const std::string &mime); + static std::shared_ptr CreateAudioDecMockByName(const std::string &name); + static std::shared_ptr CreateAudioEncMockByMime(const std::string &mime); + static std::shared_ptr CreateAudioEncMockByName(const std::string &name); + static std::shared_ptr CreateFormat(); + static std::shared_ptr CreateSurface(); + static std::shared_ptr CreateAVCodecInfo(); + static std::shared_ptr CreateAVCodecList(); + static std::shared_ptr CreateVideoCaps(); + static std::shared_ptr CreateEnum(); + +private: + AVCodecMockFactory() = delete; + ~AVCodecMockFactory() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // AVCODEC_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.cpp b/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26ea21b8e7038e5b480e2be715d20bc2669e3702 --- /dev/null +++ b/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.cpp @@ -0,0 +1,208 @@ +/* + * 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 "audiodec_capi_mock.h" +#include "avformat_capi_mock.h" +#include "avmemory_capi_mock.h" +#include "native_avcodec_base.h" + +namespace OHOS { +namespace Media { +std::mutex AudioDecCapiMock::mutex_; +std::map> AudioDecCapiMock::mockCbMap_; + +void AudioDecCapiMock::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + mockCb->OnError(errorCode); + } +} + +void AudioDecCapiMock::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + auto formatMock = std::make_shared(format); + mockCb->OnStreamChanged(formatMock); + } +} + +void AudioDecCapiMock::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + std::shared_ptr memMock = std::make_shared(data); + mockCb->OnNeedInputData(index, memMock); + } +} + +void AudioDecCapiMock::OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, + OH_AVCodecBufferAttr *attr, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + std::shared_ptr memMock = std::make_shared(data); + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = attr->pts; + bufferInfo.size = attr->size; + bufferInfo.offset = attr->offset; + bufferInfo.flags = attr->flags; + mockCb->OnNewOutputData(index, memMock, bufferInfo); + } +} + +std::shared_ptr AudioDecCapiMock::GetCallback(OH_AVCodec *codec) +{ + std::lock_guard lock(mutex_); + if (mockCbMap_.find(codec) != mockCbMap_.end()) { + return mockCbMap_.at(codec); + } + return nullptr; +} + +void AudioDecCapiMock::SetCallback(OH_AVCodec *codec, std::shared_ptr cb) +{ + std::lock_guard lock(mutex_); + mockCbMap_[codec] = cb; +} + +void AudioDecCapiMock::DelCallback(OH_AVCodec *codec) +{ + auto it = mockCbMap_.find(codec); + if (it != mockCbMap_.end()) { + mockCbMap_.erase(it); + } +} + +int32_t AudioDecCapiMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr && codec_ != nullptr) { + SetCallback(codec_, cb); + struct OH_AVCodecAsyncCallback callback; + callback.onError = AudioDecCapiMock::OnError; + callback.onStreamChanged = AudioDecCapiMock::OnStreamChanged; + callback.onNeedInputData = AudioDecCapiMock::OnNeedInputData; + callback.onNeedOutputData = AudioDecCapiMock::OnNewOutputData; + return OH_AudioDecoder_SetCallback(codec_, callback, NULL); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Configure(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + OH_AVFormat *avFormat = formatMock->GetFormat(); + if (avFormat != nullptr) { + return OH_AudioDecoder_Configure(codec_, avFormat); + } + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Prepare() +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_Prepare(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Start() +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_Start(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Stop() +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_Stop(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Flush() +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_Flush(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Reset() +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_Reset(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::Release() +{ + if (codec_ != nullptr) { + DelCallback(codec_); + return OH_AudioDecoder_Destroy(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +std::shared_ptr AudioDecCapiMock::GetOutputMediaDescription() +{ + if (codec_ != nullptr) { + OH_AVFormat *format = OH_AudioDecoder_GetOutputDescription(codec_); + return std::make_shared(format); + } + return nullptr; +} + +int32_t AudioDecCapiMock::SetParameter(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return OH_AudioDecoder_SetParameter(codec_, formatMock->GetFormat()); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (codec_ != nullptr) { + OH_AVCodecBufferAttr info; + info.pts = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + info.flags = attr.flags; + return OH_AudioDecoder_PushInputData(codec_, index, info); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioDecCapiMock::FreeOutputData(uint32_t index) +{ + if (codec_ != nullptr) { + return OH_AudioDecoder_FreeOutputData(codec_, index); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} +} +} diff --git a/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.h b/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..d16936c50146e2a3e2dab71c15d0b9b38eef8ca8 --- /dev/null +++ b/test/unittest/avcodec_test/capi/audiodecoder/audiodec_capi_mock.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef AUDIO_DEC_CAPI_MOCK_H +#define AUDIO_DEC_CAPI_MOCK_H + +#include +#include +#include "avcodec_mock.h" +#include "native_avcodec_audiodecoder.h" + +namespace OHOS { +namespace Media { +class AudioDecCapiMock : public AudioDecMock { +public: + explicit AudioDecCapiMock(OH_AVCodec *codec) : codec_(codec) {} + ~AudioDecCapiMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData); + static void OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, + OH_AVCodecBufferAttr *attr, void *userData); + static void SetCallback(OH_AVCodec *codec, std::shared_ptr cb); + static void DelCallback(OH_AVCodec *codec); + static std::shared_ptr GetCallback(OH_AVCodec *codec); + + static std::mutex mutex_; + static std::map> mockCbMap_; + OH_AVCodec *codec_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AUDIO_DEC_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.cpp b/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..17dc28a40611c04dda8930b64ed3bad3e79df5d1 --- /dev/null +++ b/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.cpp @@ -0,0 +1,208 @@ +/* + * 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 "audioenc_capi_mock.h" +#include "avformat_capi_mock.h" +#include "avmemory_capi_mock.h" +#include "native_avcodec_base.h" + +namespace OHOS { +namespace Media { +std::mutex AudioEncCapiMock::mutex_; +std::map> AudioEncCapiMock::mockCbMap_; + +void AudioEncCapiMock::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + mockCb->OnError(errorCode); + } +} + +void AudioEncCapiMock::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + auto formatMock = std::make_shared(format); + mockCb->OnStreamChanged(formatMock); + } +} + +void AudioEncCapiMock::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + std::shared_ptr memMock = std::make_shared(data); + mockCb->OnNeedInputData(index, memMock); + } +} + +void AudioEncCapiMock::OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, + OH_AVCodecBufferAttr *attr, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + std::shared_ptr memMock = std::make_shared(data); + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = attr->pts; + bufferInfo.size = attr->size; + bufferInfo.offset = attr->offset; + bufferInfo.flags = attr->flags; + mockCb->OnNewOutputData(index, memMock, bufferInfo); + } +} + +std::shared_ptr AudioEncCapiMock::GetCallback(OH_AVCodec *codec) +{ + std::lock_guard lock(mutex_); + if (mockCbMap_.find(codec) != mockCbMap_.end()) { + return mockCbMap_.at(codec); + } + return nullptr; +} + +void AudioEncCapiMock::SetCallback(OH_AVCodec *codec, std::shared_ptr cb) +{ + std::lock_guard lock(mutex_); + mockCbMap_[codec] = cb; +} + +void AudioEncCapiMock::DelCallback(OH_AVCodec *codec) +{ + auto it = mockCbMap_.find(codec); + if (it != mockCbMap_.end()) { + mockCbMap_.erase(it); + } +} + +int32_t AudioEncCapiMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr && codec_ != nullptr) { + SetCallback(codec_, cb); + struct OH_AVCodecAsyncCallback callback; + callback.onError = AudioEncCapiMock::OnError; + callback.onStreamChanged = AudioEncCapiMock::OnStreamChanged; + callback.onNeedInputData = AudioEncCapiMock::OnNeedInputData; + callback.onNeedOutputData = AudioEncCapiMock::OnNewOutputData; + return OH_AudioEncoder_SetCallback(codec_, callback, NULL); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Configure(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + OH_AVFormat *avFormat = formatMock->GetFormat(); + if (avFormat != nullptr) { + return OH_AudioEncoder_Configure(codec_, avFormat); + } + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Prepare() +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_Prepare(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Start() +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_Start(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Stop() +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_Stop(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Flush() +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_Flush(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Reset() +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_Reset(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::Release() +{ + if (codec_ != nullptr) { + DelCallback(codec_); + return OH_AudioEncoder_Destroy(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +std::shared_ptr AudioEncCapiMock::GetOutputMediaDescription() +{ + if (codec_ != nullptr) { + OH_AVFormat *format = OH_AudioEncoder_GetOutputDescription(codec_); + return std::make_shared(format); + } + return nullptr; +} + +int32_t AudioEncCapiMock::SetParameter(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return OH_AudioEncoder_SetParameter(codec_, formatMock->GetFormat()); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (codec_ != nullptr) { + OH_AVCodecBufferAttr info; + info.pts = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + info.flags = attr.flags; + return OH_AudioEncoder_PushInputData(codec_, index, info); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t AudioEncCapiMock::FreeOutputData(uint32_t index) +{ + if (codec_ != nullptr) { + return OH_AudioEncoder_FreeOutputData(codec_, index); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} +} +} diff --git a/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.h b/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..3c6ddef27786440ae3bcbdeb7f70072f2318b4ff --- /dev/null +++ b/test/unittest/avcodec_test/capi/audioencoder/audioenc_capi_mock.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef AUDIO_ENC_CAPI_MOCK_H +#define AUDIO_ENC_CAPI_MOCK_H + +#include +#include +#include "avcodec_mock.h" +#include "avcodec_common.h" +#include "native_avcodec_audioencoder.h" + +namespace OHOS { +namespace Media { +class AudioEncCapiMock : public AudioEncMock { +public: + explicit AudioEncCapiMock(OH_AVCodec *codec) : codec_(codec) {} + ~AudioEncCapiMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData); + static void OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, + OH_AVCodecBufferAttr *attr, void *userData); + void SetCallback(OH_AVCodec *codec, std::shared_ptr cb); + static void DelCallback(OH_AVCodec *codec); + static std::shared_ptr GetCallback(OH_AVCodec *codec); + + static std::mutex mutex_; + static std::map> mockCbMap_; + OH_AVCodec *codec_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AUDIO_ENC_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/avcodec_mock_factory.cpp b/test/unittest/avcodec_test/capi/avcodec_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ba9c6cff2477598186da1230352badb5da34ef2 --- /dev/null +++ b/test/unittest/avcodec_test/capi/avcodec_mock_factory.cpp @@ -0,0 +1,109 @@ +/* + * 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 "avcodec_mock.h" +#include "avformat_capi_mock.h" +#include "avmemory_capi_mock.h" +#include "surface_capi_mock.h" +#include "audiodec_capi_mock.h" +#include "audioenc_capi_mock.h" +#include "videodec_capi_mock.h" +#include "videoenc_capi_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr AVCodecMockFactory::CreateVideoDecMockByMime(const std::string &mime) +{ + OH_AVCodec *videoDec = OH_VideoDecoder_CreateByMime(mime.c_str()); + if (videoDec != nullptr) { + return std::make_shared(videoDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoDecMockByName(const std::string &name) +{ + OH_AVCodec *videoDec = OH_VideoDecoder_CreateByName(name.c_str()); + if (videoDec != nullptr) { + return std::make_shared(videoDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoEncMockByMime(const std::string &mime) +{ + OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByMime(mime.c_str()); + if (videoEnc != nullptr) { + return std::make_shared(videoEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoEncMockByName(const std::string &name) +{ + OH_AVCodec *videoEnc = OH_VideoEncoder_CreateByName(name.c_str()); + if (videoEnc != nullptr) { + return std::make_shared(videoEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioDecMockByMime(const std::string &mime) +{ + OH_AVCodec *audioDec = OH_AudioDecoder_CreateByMime(mime.c_str()); + if (audioDec != nullptr) { + return std::make_shared(audioDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioDecMockByName(const std::string &name) +{ + OH_AVCodec *audioDec = OH_AudioDecoder_CreateByName(name.c_str()); + if (audioDec != nullptr) { + return std::make_shared(audioDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioEncMockByMime(const std::string &mime) +{ + OH_AVCodec *audioEnc = OH_AudioEncoder_CreateByMime(mime.c_str()); + if (audioEnc != nullptr) { + return std::make_shared(audioEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioEncMockByName(const std::string &name) +{ + OH_AVCodec *audioEnc = OH_AudioEncoder_CreateByName(name.c_str()); + if (audioEnc != nullptr) { + return std::make_shared(audioEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateFormat() +{ + return std::make_shared(); +} + +std::shared_ptr AVCodecMockFactory::CreateSurface() +{ + return std::make_shared(); +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.cpp b/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f225cc2808141e4e5c115a71dd7256922fbb9658 --- /dev/null +++ b/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.cpp @@ -0,0 +1,154 @@ +/* + * 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 "avformat_capi_mock.h" + +namespace OHOS { +namespace Media { +AVFormatCapiMock::AVFormatCapiMock() +{ + format_ = OH_AVFormat_Create(); +} + +AVFormatCapiMock::~AVFormatCapiMock() +{ +} + +bool AVFormatCapiMock::PutIntValue(const std::string_view &key, int32_t value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetIntValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetIntValue(const std::string_view &key, int32_t &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetIntValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutStringValue(const std::string_view &key, const std::string_view &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetStringValue(format_, std::string(key).c_str(), std::string(value).c_str()); + } + return false; +} + +bool AVFormatCapiMock::GetStringValue(const std::string_view &key, std::string &value) +{ + if (format_ != nullptr) { + const char *out = nullptr; + if (OH_AVFormat_GetStringValue(format_, std::string(key).c_str(), &out)) { + value = out; + return true; + } + } + return false; +} + +void AVFormatCapiMock::Destroy() +{ + if (format_ != nullptr) { + OH_AVFormat_Destroy(format_); + } +} + +OH_AVFormat *AVFormatCapiMock::GetFormat() +{ + return format_; +} + +bool AVFormatCapiMock::AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from) +{ + return OH_AVFormat_Copy(to, from); +} + +bool AVFormatCapiMock::PutLongValue(const std::string_view &key, int64_t value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetLongValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetLongValue(const std::string_view &key, int64_t &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetLongValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutFloatValue(const std::string_view &key, float value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetFloatValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetFloatValue(const std::string_view &key, float &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetFloatValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutDoubleValue(const std::string_view &key, double value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetDoubleValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetDoubleValue(const std::string_view &key, double &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetDoubleValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetBuffer(format_, std::string(key).c_str(), addr, &size); + } + return false; +} + +bool AVFormatCapiMock::PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetBuffer(format_, std::string(key).c_str(), addr, size); + } + return false; +} + +const char *AVFormatCapiMock::DumpInfo() +{ + if (format_ != nullptr) { + return OH_AVFormat_DumpInfo(format_); + } + return nullptr; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.h b/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..9bceb3a250d0e64816d6d868af8026ee2576d170 --- /dev/null +++ b/test/unittest/avcodec_test/capi/avformat/avformat_capi_mock.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef AVFORMAT_CAPI_MOCK_H +#define AVFORMAT_CAPI_MOCK_H + +#include "avcodec_mock.h" +#include "native_avformat.h" + +namespace OHOS { +namespace Media { +class AVFormatCapiMock : public FormatMock { +public: + explicit AVFormatCapiMock(OH_AVFormat *format) : format_(format) {} + AVFormatCapiMock(); + ~AVFormatCapiMock(); + bool PutIntValue(const std::string_view &key, int32_t value) override; + bool GetIntValue(const std::string_view &key, int32_t &value) override; + bool PutStringValue(const std::string_view &key, const std::string_view &value) override; + bool GetStringValue(const std::string_view &key, std::string &value) override; + void Destroy() override; + bool PutLongValue(const std::string_view &key, int64_t value) override; + bool GetLongValue(const std::string_view &key, int64_t &value) override; + bool PutFloatValue(const std::string_view &key, float value) override; + bool GetFloatValue(const std::string_view &key, float &value) override; + bool PutDoubleValue(const std::string_view &key, double value) override; + bool GetDoubleValue(const std::string_view &key, double &value) override; + bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) override; + bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) override; + const char *DumpInfo() override; + bool AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from); + OH_AVFormat *GetFormat(); + +private: + OH_AVFormat *format_; +}; +} // Media +} // OHOS +#endif // AVFORMAT_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.cpp b/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9cef40ab3a8127c44da2f3af315eac5db745c58e --- /dev/null +++ b/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.cpp @@ -0,0 +1,41 @@ +/* + * 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 "avmemory_capi_mock.h" + +namespace OHOS { +namespace Media { +uint8_t *AVMemoryCapiMock::GetAddr() const +{ + if (memory_ != nullptr) { + return OH_AVMemory_GetAddr(memory_); + } + return nullptr; +} + +int32_t AVMemoryCapiMock::GetSize() const +{ + if (memory_ != nullptr) { + return OH_AVMemory_GetSize(memory_); + } + return -1; +} + +uint32_t AVMemoryCapiMock::GetFlags() const +{ + return 0; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.h b/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..db9a282762f37bcc760fb680136aab7ba316e28d --- /dev/null +++ b/test/unittest/avcodec_test/capi/avmemory/avmemory_capi_mock.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef AVMEMORY_CAPI_MOCK_H +#define AVMEMORY_CAPI_MOCK_H + +#include "avcodec_mock.h" +#include "native_avmemory.h" + +namespace OHOS { +namespace Media { +class AVMemoryCapiMock : public AVMemoryMock { +public: + explicit AVMemoryCapiMock(OH_AVMemory *mem) : memory_(mem) {} + uint8_t *GetAddr() const override; + int32_t GetSize() const override; + uint32_t GetFlags() const override; + +private: + OH_AVMemory *memory_ = nullptr; +}; +} // Media +} // OHOS +#endif // AVMEMORY_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/surface/surface_capi_mock.cpp b/test/unittest/avcodec_test/capi/surface/surface_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86de5971cbd342e7d9a19f6b2da562d052302ad7 --- /dev/null +++ b/test/unittest/avcodec_test/capi/surface/surface_capi_mock.cpp @@ -0,0 +1,25 @@ +/* + * 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 "surface_capi_mock.h" + +namespace OHOS { +namespace Media { +OHNativeWindow *SurfaceCapiMock::GetSurface() +{ + return nativeWindow_; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/surface/surface_capi_mock.h b/test/unittest/avcodec_test/capi/surface/surface_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..d1d54ff6a5d0ce32b574d163d21f28903f575b0b --- /dev/null +++ b/test/unittest/avcodec_test/capi/surface/surface_capi_mock.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef SURFACE_CAPI_MOCK_H +#define SURFACE_CAPI_MOCK_H + +#include "avcodec_mock.h" +#include "native_avcodec_base.h" +#include "window.h" + + +namespace OHOS { +namespace Media { +class SurfaceCapiMock : public SurfaceMock { +public: + explicit SurfaceCapiMock(OHNativeWindow *nativeWindow) : nativeWindow_(nativeWindow) {} + SurfaceCapiMock() = default; + ~SurfaceCapiMock() = default; + OHNativeWindow *GetSurface(); + +private: + OHNativeWindow *nativeWindow_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // SURFACE_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.cpp b/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d34a1f7c8107103201ce52f3ac6e0ba5be23e76 --- /dev/null +++ b/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.cpp @@ -0,0 +1,233 @@ +/* + * 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 "videodec_capi_mock.h" +#include +#include "avcodec_video_decoder.h" +#include "avformat_capi_mock.h" +#include "avmemory_capi_mock.h" +#include "native_avcodec_base.h" +#include "surface_capi_mock.h" +#include "window.h" + +using namespace std; + +namespace OHOS { +namespace Media { +std::mutex VideoDecCapiMock::mutex_; +std::map> VideoDecCapiMock::mockCbMap_; +void VideoDecCapiMock::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + mockCb->OnError(errorCode); + } +} + +void VideoDecCapiMock::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + auto formatMock = std::make_shared(format); + mockCb->OnStreamChanged(formatMock); + } +} + +void VideoDecCapiMock::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + std::shared_ptr memMock = std::make_shared(data); + mockCb->OnNeedInputData(index, memMock); + } +} + +void VideoDecCapiMock::OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData) +{ + (void)data; + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = attr->pts; + bufferInfo.size = attr->size; + bufferInfo.offset = attr->offset; + bufferInfo.flags = attr->flags; + mockCb->OnNewOutputData(index, nullptr, bufferInfo); + } +} + +std::shared_ptr VideoDecCapiMock::GetCallback(OH_AVCodec *codec) +{ + std::lock_guard lock(mutex_); + if (mockCbMap_.find(codec) != mockCbMap_.end()) { + return mockCbMap_.at(codec); + } + return nullptr; +} + +void VideoDecCapiMock::SetCallback(OH_AVCodec *codec, std::shared_ptr cb) +{ + std::lock_guard lock(mutex_); + mockCbMap_[codec] = cb; +} + +void VideoDecCapiMock::DelCallback(OH_AVCodec *codec) +{ + auto it = mockCbMap_.find(codec); + if (it != mockCbMap_.end()) { + mockCbMap_.erase(it); + } +} + +int32_t VideoDecCapiMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr && codec_ != nullptr) { + SetCallback(codec_, cb); + struct OH_AVCodecAsyncCallback callback; + callback.onError = VideoDecCapiMock::OnError; + callback.onStreamChanged = VideoDecCapiMock::OnStreamChanged; + callback.onNeedInputData = VideoDecCapiMock::OnNeedInputData; + callback.onNeedOutputData = VideoDecCapiMock::OnNewOutputData; + return OH_VideoDecoder_SetCallback(codec_, callback, NULL); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::SetOutputSurface(std::shared_ptr surface) +{ + if (codec_ != nullptr && surface != nullptr) { + auto surfaceMock = std::static_pointer_cast(surface); + OHNativeWindow *nativeWindow = surfaceMock->GetSurface(); + if (nativeWindow != nullptr) { + return OH_VideoDecoder_SetSurface(codec_, nativeWindow); + } + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Configure(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + OH_AVFormat *avFormat = formatMock->GetFormat(); + if (avFormat != nullptr) { + return OH_VideoDecoder_Configure(codec_, avFormat); + } + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Prepare() +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_Prepare(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Start() +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_Start(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Stop() +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_Stop(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Flush() +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_Flush(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Reset() +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_Reset(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::Release() +{ + if (codec_ != nullptr) { + DelCallback(codec_); + return OH_VideoDecoder_Destroy(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +std::shared_ptr VideoDecCapiMock::GetOutputMediaDescription() +{ + if (codec_ != nullptr) { + OH_AVFormat *format = OH_VideoDecoder_GetOutputDescription(codec_); + return std::make_shared(format); + } + return nullptr; +} + +int32_t VideoDecCapiMock::SetParameter(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return OH_VideoDecoder_SetParameter(codec_, formatMock->GetFormat()); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (codec_ != nullptr) { + OH_AVCodecBufferAttr info; + info.pts = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + info.flags = attr.flags; + return OH_VideoDecoder_PushInputData(codec_, index, info); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::RenderOutputData(uint32_t index) +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_RenderOutputData(codec_, index); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoDecCapiMock::FreeOutputData(uint32_t index) +{ + if (codec_ != nullptr) { + return OH_VideoDecoder_FreeOutputData(codec_, index); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.h b/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..a666de7edf6e6cfdca834aa381d5f90dd1023daf --- /dev/null +++ b/test/unittest/avcodec_test/capi/videodecoder/videodec_capi_mock.h @@ -0,0 +1,63 @@ + +/* + * 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. + */ + +#ifndef VIDEODEC_CAPI_MOCK_H +#define VIDEODEC_CAPI_MOCK_H + +#include +#include +#include "avcodec_mock.h" +#include "native_avcodec_videodecoder.h" + + +namespace OHOS { +namespace Media { +class VideoDecCapiMock : public VideoDecMock { +public: + explicit VideoDecCapiMock(OH_AVCodec *codec) : codec_(codec) {} + ~VideoDecCapiMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t SetOutputSurface(std::shared_ptr surface) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + int32_t RenderOutputData(uint32_t index) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData); + static void OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData); + static void SetCallback(OH_AVCodec *codec, std::shared_ptr cb); + static void DelCallback(OH_AVCodec *codec); + static std::shared_ptr GetCallback(OH_AVCodec *codec); + + static std::mutex mutex_; + static std::map> mockCbMap_; + OH_AVCodec *codec_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // VIDEODEC_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.cpp b/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bec4faf87fc690faba39b661248ded2b60463f20 --- /dev/null +++ b/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.cpp @@ -0,0 +1,222 @@ +/* + * 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 "videoenc_capi_mock.h" +#include +#include "avcodec_errors.h" +#include "avcodec_video_encoder.h" +#include "avformat_capi_mock.h" +#include "avmemory_capi_mock.h" +#include "native_avcodec_base.h" +#include "surface_capi_mock.h" +#include "window.h" + +using namespace std; + +namespace OHOS { +namespace Media { +std::mutex VideoEncCapiMock::mutex_; +std::map> VideoEncCapiMock::mockCbMap_; +void VideoEncCapiMock::OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + mockCb->OnError(errorCode); + } +} + +void VideoEncCapiMock::OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + auto formatMock = std::make_shared(format); + mockCb->OnStreamChanged(formatMock); + } +} + +void VideoEncCapiMock::OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData) +{ + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + mockCb->OnNeedInputData(index, nullptr); + } +} + +void VideoEncCapiMock::OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData) +{ + (void)data; + (void)userData; + std::shared_ptr mockCb = GetCallback(codec); + if (mockCb != nullptr) { + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = attr->pts; + bufferInfo.size = attr->size; + bufferInfo.offset = attr->offset; + bufferInfo.flags = attr->flags; + std::shared_ptr memMock = std::make_shared(data); + mockCb->OnNewOutputData(index, memMock, bufferInfo); + } +} + +std::shared_ptr VideoEncCapiMock::GetCallback(OH_AVCodec *codec) +{ + std::lock_guard lock(mutex_); + if (mockCbMap_.find(codec) != mockCbMap_.end()) { + return mockCbMap_.at(codec); + } + return nullptr; +} + +void VideoEncCapiMock::SetCallback(OH_AVCodec *codec, std::shared_ptr cb) +{ + std::lock_guard lock(mutex_); + mockCbMap_[codec] = cb; +} + +void VideoEncCapiMock::DelCallback(OH_AVCodec *codec) +{ + auto it = mockCbMap_.find(codec); + if (it != mockCbMap_.end()) { + mockCbMap_.erase(it); + } +} + +int32_t VideoEncCapiMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr && codec_ != nullptr) { + SetCallback(codec_, cb); + struct OH_AVCodecAsyncCallback callback; + callback.onError = VideoEncCapiMock::OnError; + callback.onStreamChanged = VideoEncCapiMock::OnStreamChanged; + callback.onNeedInputData = VideoEncCapiMock::OnNeedInputData; + callback.onNeedOutputData = VideoEncCapiMock::OnNewOutputData; + return OH_VideoEncoder_SetCallback(codec_, callback, NULL); + } + return AV_ERR_OPERATE_NOT_PERMIT; +}; + +std::shared_ptr VideoEncCapiMock::GetInputSurface() +{ + if (codec_ != nullptr) { + OHNativeWindow *window; + (void)OH_VideoEncoder_GetSurface(codec_, &window); + if (window != nullptr) { + return std::make_shared(window); + } + } + return nullptr; +} + +int32_t VideoEncCapiMock::Configure(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + OH_AVFormat *avFormat = formatMock->GetFormat(); + if (avFormat != nullptr) { + return OH_VideoEncoder_Configure(codec_, avFormat); + } else { + cout << "VideoEncCapiMock::Configure: avFormat is null" << endl; + } + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Prepare() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Prepare(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Start() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Start(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Stop() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Stop(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Flush() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Flush(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Reset() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Reset(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::Release() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_Destroy(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::NotifyEos() +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_NotifyEndOfStream(codec_); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +std::shared_ptr VideoEncCapiMock::GetOutputMediaDescription() +{ + if (codec_ != nullptr) { + OH_AVFormat *format = OH_VideoEncoder_GetOutputDescription(codec_); + return std::make_shared(format); + } + return nullptr; +} + +int32_t VideoEncCapiMock::SetParameter(std::shared_ptr format) +{ + if (codec_ != nullptr && format != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return OH_VideoEncoder_SetParameter(codec_, formatMock->GetFormat()); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} + +int32_t VideoEncCapiMock::FreeOutputData(uint32_t index) +{ + if (codec_ != nullptr) { + return OH_VideoEncoder_FreeOutputData(codec_, index); + } + return AV_ERR_OPERATE_NOT_PERMIT; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.h b/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..146e1776fae2c74b6be0daadef0792d7ade66fc4 --- /dev/null +++ b/test/unittest/avcodec_test/capi/videoencoder/videoenc_capi_mock.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef VIDEOENC_CAPI_MOCK_H +#define VIDEOENC_CAPI_MOCK_H + +#include +#include +#include "avcodec_mock.h" +#include "native_avcodec_videoencoder.h" + +namespace OHOS { +namespace Media { +class VideoEncCapiMock : public VideoEncMock { +public: + explicit VideoEncCapiMock(OH_AVCodec *codec) : codec_(codec) {} + int32_t SetCallback(std::shared_ptr cb) override; + std::shared_ptr GetInputSurface() override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData); + static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData); + static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData); + static void OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, OH_AVCodecBufferAttr *attr, + void *userData); + static void SetCallback(OH_AVCodec *codec, std::shared_ptr cb); + static void DelCallback(OH_AVCodec *codec); + static std::shared_ptr GetCallback(OH_AVCodec *codec); + + static std::mutex mutex_; + static std::map> mockCbMap_; + OH_AVCodec *codec_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // VIDEOENC_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/enum_mock.h b/test/unittest/avcodec_test/enum_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..99a44e4305589068e35d289a46dcbfd6bf6516ec --- /dev/null +++ b/test/unittest/avcodec_test/enum_mock.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +#ifndef ENUM_MOCK_H +#define ENUM_MOCK_H + +#include +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +enum MediaDescriptionKeyMock : int32_t { + MOCK_MD_KEY_TRACK_INDEX = 0, + MOCK_MD_KEY_TRACK_TYPE, + MOCK_MD_KEY_CODEC_MIME, + MOCK_MD_KEY_DURATION, + MOCK_MD_KEY_BITRATE, + MOCK_MD_KEY_WIDTH, + MOCK_MD_KEY_HEIGHT, + MOCK_MD_KEY_PIXEL_FORMAT, + MOCK_MD_KEY_FRAME_RATE, + MOCK_MD_KEY_CHANNEL_COUNT, + MOCK_MD_KEY_SAMPLE_RATE, +}; + +enum VideoPixelFormatMock : int32_t { + MOCK_YUVI420 = 1, + MOCK_NV12, + MOCK_NV21, + MOCK_SURFACE_FORMAT, + MOCK_RGBA, +}; + +enum CodecMimeTypeMock : int32_t { + VIDEO_H263 = 0, + VIDEO_AVC, + VIDEO_MPEG2, + VIDEO_HEVC, + VIDEO_MPEG4, + VIDEO_VP8, + VIDEO_VP9, + AUDIO_AMR_NB, + AUDIO_AMR_WB, + AUDIO_MPEG, + AUDIO_AAC, + AUDIO_VORBIS, + AUDIO_OPUS, + AUDIO_FLAC, + AUDIO_RAW, +}; + +class EnumMock : public NoCopyable { +public: + virtual ~EnumMock() = default; + virtual std::string GetMediaDescriptionKey(const MediaDescriptionKeyMock &key) const = 0; + virtual int32_t GetVideoPixelFormat(const VideoPixelFormatMock &key) const = 0; + virtual std::string GetCodecMimeType(const CodecMimeTypeMock &key) const = 0; +}; +} // Media +} // OHOS +#endif // ENUM_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/format_test/format_unit_test.cpp b/test/unittest/avcodec_test/format_test/format_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5850f3e644fda48e8fae3bbf91bf26975e56337 --- /dev/null +++ b/test/unittest/avcodec_test/format_test/format_unit_test.cpp @@ -0,0 +1,130 @@ +/* + * 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 "format_unit_test.h" +#include +#include "gtest/gtest.h" +#include "avcodec_errors.h" +#include "securec.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::Media; +using namespace testing::ext; +using namespace OHOS::Media::FormatTestParam; + +void AVFormatUnitTest::SetUpTestCase(void) {} + +void AVFormatUnitTest::TearDownTestCase(void) {} + +void AVFormatUnitTest::SetUp(void) +{ + format_ = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format_); +} + +void AVFormatUnitTest::TearDown(void) +{ + if (format_ != nullptr) { + format_->Destroy(); + } +} + +/** + * @tc.name: format_value_0100 + * @tc.desc: format set and get value + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(AVFormatUnitTest, 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_->PutIntValue(intKey, intValue)); + ASSERT_TRUE(format_->GetIntValue(intKey, getIntValue)); + ASSERT_TRUE(intValue == getIntValue); + + ASSERT_TRUE(format_->PutLongValue(longKey, longValue)); + ASSERT_TRUE(format_->GetLongValue(longKey, getLongValue)); + ASSERT_TRUE(longValue == getLongValue); + + ASSERT_TRUE(format_->PutFloatValue(floatKey, floatValue)); + ASSERT_TRUE(format_->GetFloatValue(floatKey, getFloatValue)); + ASSERT_TRUE(fabs(floatValue - getFloatValue) < EPSINON_FLOAT); + + ASSERT_TRUE(format_->PutDoubleValue(doubleKey, doubleValue)); + ASSERT_TRUE(format_->GetDoubleValue(doubleKey, getDoubleValue)); + ASSERT_TRUE(fabs(doubleValue - getDoubleValue) < EPSINON_DOUBLE); + + 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(AVFormatUnitTest, format_buffer_0100, TestSize.Level0) +{ + constexpr int32_t num = 10; + const std::string_view key = "BufferKey"; + size_t size = num * sizeof(uint8_t); + uint8_t *buffer = reinterpret_cast(malloc(size)); + (void)memset_s(buffer, size, 1, size); + + 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 < num; i++) { + ASSERT_TRUE(buffer[i] == getBuffer[i]); + } + free(buffer); +} + +/** + * @tc.name: format_dump_info_0100 + * @tc.desc: format dump info + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(AVFormatUnitTest, format_dump_info_0100, TestSize.Level0) +{ + ASSERT_TRUE(format_->PutIntValue("width", 1)); + ASSERT_TRUE(format_->PutIntValue("height", 1)); + ASSERT_TRUE(format_->PutStringValue("codec_mime", "video/avc")); + const char *info = format_->DumpInfo(); + ASSERT_TRUE(info != nullptr); + std::cout << info << std::endl; +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/format_test/format_unit_test.h b/test/unittest/avcodec_test/format_test/format_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..614f7fd95de802c4551ffc600d0c96b48704d6a0 --- /dev/null +++ b/test/unittest/avcodec_test/format_test/format_unit_test.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef FORMAT_UNIT_TEST_H +#define FORMAT_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "avcodec_mock.h" +#include "test_params_config.h" + +namespace OHOS { +namespace Media { +class AVFormatUnitTest : 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: + std::shared_ptr format_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // FORMAT_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.cpp b/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6f55887e59da4a6a9aed9c2e5900ad139d33b0b --- /dev/null +++ b/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.cpp @@ -0,0 +1,182 @@ +/* + * 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 "audiodec_native_mock.h" +#include "avformat_native_mock.h" +#include "avmemory_native_mock.h" +#include "avcodec_errors.h" + +namespace OHOS { +namespace Media { +AudioDecCallbackMock::AudioDecCallbackMock(std::shared_ptr cb, + std::weak_ptr ad) + : mockCb_(cb), audioDec_(ad) +{ +} + +void AudioDecCallbackMock::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + if (mockCb_ != nullptr) { + mockCb_->OnError(errorCode); + } +} + +void AudioDecCallbackMock::OnOutputFormatChanged(const Format &format) +{ + if (mockCb_ != nullptr) { + auto formatMock = std::make_shared(format); + mockCb_->OnStreamChanged(formatMock); + } +} + +void AudioDecCallbackMock::OnInputBufferAvailable(uint32_t index) +{ + auto audioDec = audioDec_.lock(); + if (mockCb_ != nullptr && audioDec != nullptr) { + std::shared_ptr mem = audioDec->GetInputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + mockCb_->OnNeedInputData(index, memMock); + } + } +} + +void AudioDecCallbackMock::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + auto audioDec = audioDec_.lock(); + if (mockCb_ != nullptr && audioDec != nullptr) { + std::shared_ptr mem = audioDec->GetOutputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = info.presentationTimeUs; + bufferInfo.size = info.size; + bufferInfo.offset = info.offset; + bufferInfo.flags = flag; + return mockCb_->OnNewOutputData(index, memMock, bufferInfo); + } + } +} + +int32_t AudioDecNativeMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr) { + auto callback = std::make_shared(cb, audioDec_); + if (audioDec_ != nullptr && callback != nullptr) { + return audioDec_->SetCallback(callback); + } + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Configure(std::shared_ptr format) +{ + if (audioDec_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return audioDec_->Configure(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Prepare() +{ + if (audioDec_ != nullptr) { + return audioDec_->Prepare(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Start() +{ + if (audioDec_ != nullptr) { + return audioDec_->Start(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Stop() +{ + if (audioDec_ != nullptr) { + return audioDec_->Stop(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Flush() +{ + if (audioDec_ != nullptr) { + return audioDec_->Flush(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Reset() +{ + if (audioDec_ != nullptr) { + return audioDec_->Reset(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::Release() +{ + if (audioDec_ != nullptr) { + return audioDec_->Release(); + } + return MSERR_INVALID_OPERATION; +} + +std::shared_ptr AudioDecNativeMock::GetOutputMediaDescription() +{ + if (audioDec_ != nullptr) { + Format format; + (void)audioDec_->GetOutputFormat(format); + return std::make_shared(format); + } + return nullptr; +} + +int32_t AudioDecNativeMock::SetParameter(std::shared_ptr format) +{ + if (audioDec_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return audioDec_->SetParameter(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (audioDec_ != nullptr) { + AVCodecBufferInfo info; + info.presentationTimeUs = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + AVCodecBufferFlag flags = static_cast(attr.flags); + return audioDec_->QueueInputBuffer(index, info, flags); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioDecNativeMock::FreeOutputData(uint32_t index) +{ + if (audioDec_ != nullptr) { + return audioDec_->ReleaseOutputBuffer(index); + } + return MSERR_INVALID_OPERATION; +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.h b/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..7127415803a3226b8f78713593e950063942b64f --- /dev/null +++ b/test/unittest/avcodec_test/native/audiodecoder/audiodec_native_mock.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#ifndef AUDIO_DEC_NATIVE_MOCK_H +#define AUDIO_DEC_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_common.h" +#include "avcodec_audio_decoder.h" + +namespace OHOS { +namespace Media { +class AudioDecNativeMock : public AudioDecMock { +public: + explicit AudioDecNativeMock(std::shared_ptr audioDec) : audioDec_(audioDec) {} + ~AudioDecNativeMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + std::shared_ptr audioDec_ = nullptr; +}; + +class AudioDecCallbackMock : public AVCodecCallback { +public: + AudioDecCallbackMock(std::shared_ptr cb, std::weak_ptr ad); + ~AudioDecCallbackMock() = default; + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr mockCb_ = nullptr; + std::weak_ptr audioDec_; +}; +} // namespace Media +} // namespace OHOS +#endif // AUDIO_DEC_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.cpp b/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba2b09401eeb2de82f5734393f69eba99cd8617e --- /dev/null +++ b/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.cpp @@ -0,0 +1,182 @@ +/* + * 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 "audioenc_native_mock.h" +#include "avformat_native_mock.h" +#include "avmemory_native_mock.h" +#include "avcodec_errors.h" + +namespace OHOS { +namespace Media { +AudioEncCallbackMock::AudioEncCallbackMock(std::shared_ptr cb, + std::weak_ptr ad) + : mockCb_(cb), audioEnc_(ad) +{ +} + +void AudioEncCallbackMock::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + if (mockCb_ != nullptr) { + mockCb_->OnError(errorCode); + } +} + +void AudioEncCallbackMock::OnOutputFormatChanged(const Format &format) +{ + if (mockCb_ != nullptr) { + auto formatMock = std::make_shared(format); + mockCb_->OnStreamChanged(formatMock); + } +} + +void AudioEncCallbackMock::OnInputBufferAvailable(uint32_t index) +{ + auto audioEnc = audioEnc_.lock(); + if (mockCb_ != nullptr && audioEnc != nullptr) { + std::shared_ptr mem = audioEnc->GetInputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + mockCb_->OnNeedInputData(index, memMock); + } + } +} + +void AudioEncCallbackMock::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + auto audioEnc = audioEnc_.lock(); + if (mockCb_ != nullptr && audioEnc != nullptr) { + std::shared_ptr mem = audioEnc->GetOutputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = info.presentationTimeUs; + bufferInfo.size = info.size; + bufferInfo.offset = info.offset; + bufferInfo.flags = flag; + return mockCb_->OnNewOutputData(index, memMock, bufferInfo); + } + } +} + +int32_t AudioEncNativeMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr) { + auto callback = std::make_shared(cb, audioEnc_); + if (audioEnc_ != nullptr && callback != nullptr) { + return audioEnc_->SetCallback(callback); + } + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Configure(std::shared_ptr format) +{ + if (audioEnc_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return audioEnc_->Configure(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Prepare() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Prepare(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Start() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Start(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Stop() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Stop(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Flush() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Flush(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Reset() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Reset(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::Release() +{ + if (audioEnc_ != nullptr) { + return audioEnc_->Release(); + } + return MSERR_INVALID_OPERATION; +} + +std::shared_ptr AudioEncNativeMock::GetOutputMediaDescription() +{ + if (audioEnc_ != nullptr) { + Format format; + (void)audioEnc_->GetOutputFormat(format); + return std::make_shared(format); + } + return nullptr; +} + +int32_t AudioEncNativeMock::SetParameter(std::shared_ptr format) +{ + if (audioEnc_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return audioEnc_->SetParameter(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (audioEnc_ != nullptr) { + AVCodecBufferInfo info; + info.presentationTimeUs = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + AVCodecBufferFlag flags = static_cast(attr.flags); + return audioEnc_->QueueInputBuffer(index, info, flags); + } + return MSERR_INVALID_OPERATION; +} + +int32_t AudioEncNativeMock::FreeOutputData(uint32_t index) +{ + if (audioEnc_ != nullptr) { + return audioEnc_->ReleaseOutputBuffer(index); + } + return MSERR_INVALID_OPERATION; +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.h b/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..f8d8a4b55425a97ef8d05453fdae00bcf8b381f6 --- /dev/null +++ b/test/unittest/avcodec_test/native/audioencoder/audioenc_native_mock.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#ifndef AUDIO_ENC_NATIVE_MOCK_H +#define AUDIO_ENC_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_common.h" +#include "avcodec_audio_encoder.h" + +namespace OHOS { +namespace Media { +class AudioEncNativeMock : public AudioEncMock { +public: + explicit AudioEncNativeMock(std::shared_ptr audioEnc) : audioEnc_(audioEnc) {} + ~AudioEncNativeMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + std::shared_ptr audioEnc_ = nullptr; +}; + +class AudioEncCallbackMock : public AVCodecCallback { +public: + AudioEncCallbackMock(std::shared_ptr cb, std::weak_ptr ae); + ~AudioEncCallbackMock() = default; + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr mockCb_ = nullptr; + std::weak_ptr audioEnc_; +}; +} // namespace Media +} // namespace OHOS +#endif // AUDIO_ENC_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.cpp b/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98c76a821e52e95c18052189096c37b70da826d2 --- /dev/null +++ b/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.cpp @@ -0,0 +1,316 @@ +/* + * 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 "avcodec_info_native_mock.h" + +namespace OHOS { +namespace Media { +std::string AVCodecInfoNativeMock::GetName() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->GetName(); + } + return nullptr; +} + +int32_t AVCodecInfoNativeMock::GetType() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->GetType(); + } + return -1; +} + +std::string AVCodecInfoNativeMock::GetMimeType() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->GetMimeType(); + } + return ""; +} + +bool AVCodecInfoNativeMock::IsHardwareAccelerated() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->IsHardwareAccelerated(); + } + return false; +} + +bool AVCodecInfoNativeMock::IsSoftwareOnly() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->IsSoftwareOnly(); + } + return false; +} + +bool AVCodecInfoNativeMock::IsVendor() const +{ + if (codecInfo_ != nullptr) { + return codecInfo_->IsVendor(); + } + return false; +} + +std::shared_ptr VideoCapsNativeMock::GetCodecInfo() const +{ + if (videoCaps_ != nullptr) { + return std::make_shared(videoCaps_->GetCodecInfo()); + } + return nullptr; +} + +RangeMock VideoCapsNativeMock::GetSupportedBitrate() const +{ + RangeMock bitrate; + if (videoCaps_ != nullptr) { + bitrate.minVal = videoCaps_->GetSupportedBitrate().minVal; + bitrate.maxVal = videoCaps_->GetSupportedBitrate().maxVal; + } + return bitrate; +} + +std::vector VideoCapsNativeMock::GetSupportedFormats() const +{ + std::vector formats; + if (videoCaps_ != nullptr) { + formats = videoCaps_->GetSupportedFormats(); + } + return formats; +} + +int32_t VideoCapsNativeMock::GetSupportedHeightAlignment() const +{ + if (videoCaps_ != nullptr) { + return videoCaps_->GetSupportedHeightAlignment(); + } + return -1; +} + +int32_t VideoCapsNativeMock::GetSupportedWidthAlignment() const +{ + if (videoCaps_ != nullptr) { + return videoCaps_->GetSupportedWidthAlignment(); + } + return -1; +} + +RangeMock VideoCapsNativeMock::GetSupportedWidth() const +{ + RangeMock width; + if (videoCaps_ != nullptr) { + width.minVal = videoCaps_->GetSupportedWidth().minVal; + width.maxVal = videoCaps_->GetSupportedWidth().maxVal; + } + return width; +} + +RangeMock VideoCapsNativeMock::GetSupportedHeight() const +{ + RangeMock height; + if (videoCaps_ != nullptr) { + height.minVal = videoCaps_->GetSupportedHeight().minVal; + height.maxVal = videoCaps_->GetSupportedHeight().maxVal; + } + return height; +} + +std::vector VideoCapsNativeMock::GetSupportedProfiles() const +{ + std::vector profiles; + if (videoCaps_ != nullptr) { + profiles = videoCaps_->GetSupportedProfiles(); + } + return profiles; +} + +std::vector VideoCapsNativeMock::GetSupportedLevels() const +{ + std::vector levels; + if (videoCaps_ != nullptr) { + levels = videoCaps_->GetSupportedLevels(); + } + return levels; +} + +RangeMock VideoCapsNativeMock::GetSupportedEncodeQuality() const +{ + RangeMock quality; + if (videoCaps_ != nullptr) { + quality.minVal = videoCaps_->GetSupportedEncodeQuality().minVal; + quality.maxVal = videoCaps_->GetSupportedEncodeQuality().maxVal; + } + return quality; +} + +bool VideoCapsNativeMock::IsSizeSupported(int32_t width, int32_t height) const +{ + if (videoCaps_ != nullptr) { + return videoCaps_->IsSizeSupported(width, height); + } + return false; +} + +RangeMock VideoCapsNativeMock::GetSupportedFrameRate() const +{ + RangeMock frameRates; + if (videoCaps_ != nullptr) { + frameRates.minVal = videoCaps_->GetSupportedFrameRate().minVal; + frameRates.maxVal = videoCaps_->GetSupportedFrameRate().maxVal; + } + return frameRates; +} + +RangeMock VideoCapsNativeMock::GetSupportedFrameRatesFor(int32_t width, int32_t height) const +{ + RangeMock frameRates; + if (videoCaps_ != nullptr) { + frameRates.minVal = videoCaps_->GetSupportedFrameRatesFor(width, height).minVal; + frameRates.maxVal = videoCaps_->GetSupportedFrameRatesFor(width, height).maxVal; + } + return frameRates; +} + +bool VideoCapsNativeMock::IsSizeAndRateSupported(int32_t width, int32_t height, double frameRate) const +{ + if (videoCaps_ != nullptr) { + return videoCaps_->IsSizeAndRateSupported(width, height, frameRate); + } + return false; +} + +RangeMock VideoCapsNativeMock::GetPreferredFrameRate(int32_t width, int32_t height) const +{ + RangeMock frameRate; + if (videoCaps_ != nullptr) { + frameRate.minVal = videoCaps_->GetPreferredFrameRate(width, height).minVal; + frameRate.maxVal = videoCaps_->GetPreferredFrameRate(width, height).maxVal; + } + return frameRate; +} + +std::vector VideoCapsNativeMock::GetSupportedBitrateMode() const +{ + std::vector bitrateMode; + if (videoCaps_ != nullptr) { + bitrateMode = videoCaps_->GetSupportedBitrateMode(); + } + return bitrateMode; +} + +RangeMock VideoCapsNativeMock::GetSupportedQuality() const +{ + RangeMock quality; + if (videoCaps_ != nullptr) { + quality.minVal = videoCaps_->GetSupportedQuality().minVal; + quality.maxVal = videoCaps_->GetSupportedQuality().maxVal; + } + return quality; +} + +RangeMock VideoCapsNativeMock::GetSupportedComplexity() const +{ + RangeMock complexity; + if (videoCaps_ != nullptr) { + complexity.minVal = videoCaps_->GetSupportedComplexity().minVal; + complexity.maxVal = videoCaps_->GetSupportedComplexity().maxVal; + } + return complexity; +} + +bool VideoCapsNativeMock::IsSupportDynamicIframe() const +{ + if (videoCaps_ != nullptr) { + return videoCaps_->IsSupportDynamicIframe(); + } + return false; +} + +std::shared_ptr AudioCapsNativeMock::GetCodecInfo() const +{ + if (audioCaps_ != nullptr) { + return std::make_shared(audioCaps_->GetCodecInfo()); + } + return nullptr; +} + +RangeMock AudioCapsNativeMock::GetSupportedBitrate() const +{ + RangeMock bitrate; + if (audioCaps_ != nullptr) { + bitrate.minVal = audioCaps_->GetSupportedBitrate().minVal; + bitrate.maxVal = audioCaps_->GetSupportedBitrate().maxVal; + } + return bitrate; +} + +RangeMock AudioCapsNativeMock::GetSupportedChannel() const +{ + RangeMock channel; + if (audioCaps_ != nullptr) { + channel.minVal = audioCaps_->GetSupportedChannel().minVal; + channel.maxVal = audioCaps_->GetSupportedChannel().maxVal; + } + return channel; +} + +std::vector AudioCapsNativeMock::GetSupportedFormats() const +{ + std::vector formats; + if (audioCaps_ != nullptr) { + formats = audioCaps_->GetSupportedFormats(); + } + return formats; +} + +std::vector AudioCapsNativeMock::GetSupportedSampleRates() const +{ + std::vector sampleRates; + if (audioCaps_ != nullptr) { + sampleRates = audioCaps_->GetSupportedSampleRates(); + } + return sampleRates; +} + +std::vector AudioCapsNativeMock::GetSupportedProfiles() const +{ + std::vector profiles; + if (audioCaps_ != nullptr) { + profiles = audioCaps_->GetSupportedProfiles(); + } + return profiles; +} + +std::vector AudioCapsNativeMock::GetSupportedLevels() const +{ + std::vector levels; + if (audioCaps_ != nullptr) { + levels = audioCaps_->GetSupportedLevels(); + } + return levels; +} + +RangeMock AudioCapsNativeMock::GetSupportedComplexity() const +{ + RangeMock complexity; + if (audioCaps_ != nullptr) { + complexity.minVal = audioCaps_->GetSupportedComplexity().minVal; + complexity.maxVal = audioCaps_->GetSupportedComplexity().maxVal; + } + return complexity; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.h b/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..ead60d4c28ae432a9d34b64f047ba22dfc483a93 --- /dev/null +++ b/test/unittest/avcodec_test/native/avcodec_info/avcodec_info_native_mock.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +#ifndef AVFCODEC_INFO_NATIVE_MOCK_H +#define AVFCODEC_INFO_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +const std::map AVCODEC_TYPE_INFOS = { + {AVCODEC_TYPE_MOCK_NONE, AVCODEC_TYPE_NONE}, + {AVCODEC_TYPE_MOCK_VIDEO_ENCODER, AVCODEC_TYPE_VIDEO_ENCODER}, + {AVCODEC_TYPE_MOCK_VIDEO_DECODER, AVCODEC_TYPE_VIDEO_DECODER}, + {AVCODEC_TYPE_MOCK_AUDIO_ENCODER, AVCODEC_TYPE_AUDIO_ENCODER}, + {AVCODEC_TYPE_MOCK_AUDIO_DECODER, AVCODEC_TYPE_AUDIO_DECODER}, +}; + +class AVCodecInfoNativeMock : public AVCodecInfoMock { +public: + explicit AVCodecInfoNativeMock(std::shared_ptr codecInfo) : codecInfo_(codecInfo) {} + AVCodecInfoNativeMock() = default; + std::string GetName() const override; + int32_t GetType() const override; + std::string GetMimeType() const override; + bool IsHardwareAccelerated() const override; + bool IsSoftwareOnly() const override; + bool IsVendor() const override; + +private: + std::shared_ptr codecInfo_ = nullptr; +}; + +class VideoCapsNativeMock : public VideoCapsMock { +public: + explicit VideoCapsNativeMock(std::shared_ptr videoCaps) : videoCaps_(videoCaps) {} + VideoCapsNativeMock() = default; + std::shared_ptr GetCodecInfo() const override; + RangeMock GetSupportedBitrate() const override; + std::vector GetSupportedFormats() const override; + int32_t GetSupportedHeightAlignment() const override; + int32_t GetSupportedWidthAlignment() const override; + RangeMock GetSupportedWidth() const override; + RangeMock GetSupportedHeight() const override; + std::vector GetSupportedProfiles() const override; + std::vector GetSupportedLevels() const override; + RangeMock GetSupportedEncodeQuality() const override; + bool IsSizeSupported(int32_t width, int32_t height) const override; + RangeMock GetSupportedFrameRate() const override; + RangeMock GetSupportedFrameRatesFor(int32_t width, int32_t height) const override; + bool IsSizeAndRateSupported(int32_t width, int32_t height, double frameRate) const override; + RangeMock GetPreferredFrameRate(int32_t width, int32_t height) const override; + std::vector GetSupportedBitrateMode() const override; + RangeMock GetSupportedQuality() const override; + RangeMock GetSupportedComplexity() const override; + bool IsSupportDynamicIframe() const override; + +private: + std::shared_ptr videoCaps_ = nullptr; +}; + +class AudioCapsNativeMock : public AudioCapsMock { +public: + explicit AudioCapsNativeMock(std::shared_ptr audioCaps) : audioCaps_(audioCaps) {} + AudioCapsNativeMock() = default; + std::shared_ptr GetCodecInfo() const override; + RangeMock GetSupportedBitrate() const override; + RangeMock GetSupportedChannel() const override; + std::vector GetSupportedFormats() const override; + std::vector GetSupportedSampleRates() const override; + std::vector GetSupportedProfiles() const override; + std::vector GetSupportedLevels() const override; + RangeMock GetSupportedComplexity() const override; +private: + std::shared_ptr audioCaps_ = nullptr; +}; +} // Media +} // OHOS +#endif // AVFCODEC_INFO_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.cpp b/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cfade4f5324c3f49aaa3f72aba14e9533341262 --- /dev/null +++ b/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.cpp @@ -0,0 +1,135 @@ +/* + * 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 "avcodec_info_native_mock.h" +#include "avformat_native_mock.h" +#include "avcodec_list_native_mock.h" + +namespace OHOS { +namespace Media { +std::string AVCodecListNativeMock::FindVideoDecoder(std::shared_ptr format) const +{ + std::string ret; + if (avCodecList_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + ret = avCodecList_->FindVideoDecoder(fmt->GetFormat()); + } + return ret; +} + +std::string AVCodecListNativeMock::FindVideoEncoder(std::shared_ptr format) const +{ + std::string ret; + if (avCodecList_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + ret = avCodecList_->FindVideoEncoder(fmt->GetFormat()); + } + return ret; +} + +std::string AVCodecListNativeMock::FindAudioDecoder(std::shared_ptr format) const +{ + std::string ret; + if (avCodecList_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + ret = avCodecList_->FindAudioDecoder(fmt->GetFormat()); + } + return ret; +} + +std::string AVCodecListNativeMock::FindAudioEncoder(std::shared_ptr format) const +{ + std::string ret; + if (avCodecList_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + ret = avCodecList_->FindAudioEncoder(fmt->GetFormat()); + } + return ret; +} + + +std::vector> AVCodecListNativeMock::GetVideoDecoderCaps() const +{ + std::vector> videoCapsArray; + std::vector> retVideoCapsArray; + if (avCodecList_ == nullptr) { + return retVideoCapsArray; + } + videoCapsArray = avCodecList_->GetVideoDecoderCaps(); + for (auto iter = videoCapsArray.begin(); iter != videoCapsArray.end(); iter++) { + std::shared_ptr pVideoCaps = *iter; + if (pVideoCaps == nullptr) { + break; + } + retVideoCapsArray.push_back(std::make_shared(pVideoCaps)); + } + return retVideoCapsArray; +} + +std::vector> AVCodecListNativeMock::GetVideoEncoderCaps() const +{ + std::vector> videoCapsArray; + std::vector> retVideoCapsArray; + if (avCodecList_ == nullptr) { + return retVideoCapsArray; + } + videoCapsArray = avCodecList_->GetVideoEncoderCaps(); + for (auto iter = videoCapsArray.begin(); iter != videoCapsArray.end(); iter++) { + std::shared_ptr pVideoCaps = *iter; + if (pVideoCaps == nullptr) { + break; + } + retVideoCapsArray.push_back(std::make_shared(pVideoCaps)); + } + return retVideoCapsArray; +} + +std::vector> AVCodecListNativeMock::GetAudioDecoderCaps() const +{ + std::vector> audioCapsArray; + std::vector> retAudioCapsArray; + if (avCodecList_ == nullptr) { + return retAudioCapsArray; + } + audioCapsArray = avCodecList_->GetAudioDecoderCaps(); + for (auto iter = audioCapsArray.begin(); iter != audioCapsArray.end(); iter++) { + std::shared_ptr pAudioCaps = *iter; + if (pAudioCaps == nullptr) { + break; + } + retAudioCapsArray.push_back(std::make_shared(pAudioCaps)); + } + return retAudioCapsArray; +} + +std::vector> AVCodecListNativeMock::GetAudioEncoderCaps() const +{ + std::vector> audioCapsArray; + std::vector> retAudioCapsArray; + if (avCodecList_ == nullptr) { + return retAudioCapsArray; + } + audioCapsArray = avCodecList_->GetAudioEncoderCaps(); + for (auto iter = audioCapsArray.begin(); iter != audioCapsArray.end(); iter++) { + std::shared_ptr pAudioCaps = *iter; + if (pAudioCaps == nullptr) { + break; + } + retAudioCapsArray.push_back(std::make_shared(pAudioCaps)); + } + return retAudioCapsArray; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.h b/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..90d586f21dd18f05cdc401a1b77b4f649dc8f328 --- /dev/null +++ b/test/unittest/avcodec_test/native/avcodec_list/avcodec_list_native_mock.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef AVCODEC_LIST_NATIVE_MOCK_H +#define AVCODEC_LIST_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_list.h" + +namespace OHOS { +namespace Media { +class AVCodecListNativeMock : public AVCodecListMock { +public: + explicit AVCodecListNativeMock(std::shared_ptr avCodecList) : avCodecList_(avCodecList) {} + AVCodecListNativeMock() = default; + std::string FindVideoDecoder(std::shared_ptr format) const override; + std::string FindVideoEncoder(std::shared_ptr format) const override; + std::string FindAudioDecoder(std::shared_ptr format) const override; + std::string FindAudioEncoder(std::shared_ptr format) const override; + std::vector> GetVideoDecoderCaps() const override; + std::vector> GetVideoEncoderCaps() const override; + std::vector> GetAudioDecoderCaps() const override; + std::vector> GetAudioEncoderCaps() const override; + +private: + std::shared_ptr avCodecList_ = nullptr; +}; +} // Media +} // OHOS +#endif // AVCODEC_LIST_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avcodec_mock_factory.cpp b/test/unittest/avcodec_test/native/avcodec_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4e1281d75a24cdc6e586e447235482d23cd3fbe3 --- /dev/null +++ b/test/unittest/avcodec_test/native/avcodec_mock_factory.cpp @@ -0,0 +1,136 @@ +/* + * 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 "avcodec_mock.h" +#include "avcodec_list_native_mock.h" +#include "enum_native_mock.h" +#include "avcodec_info_native_mock.h" +#include "avformat_native_mock.h" +#include "avmemory_native_mock.h" +#include "surface_native_mock.h" +#include "audiodec_native_mock.h" +#include "audioenc_native_mock.h" +#include "videodec_native_mock.h" +#include "videoenc_native_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr AVCodecMockFactory::CreateVideoDecMockByMime(const std::string &mime) +{ + auto videoDec = VideoDecoderFactory::CreateByMime(mime); + if (videoDec != nullptr) { + return std::make_shared(videoDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoDecMockByName(const std::string &name) +{ + auto videoDec = VideoDecoderFactory::CreateByName(name); + if (videoDec != nullptr) { + return std::make_shared(videoDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoEncMockByMime(const std::string &mime) +{ + auto videoEnc = VideoEncoderFactory::CreateByMime(mime); + if (videoEnc != nullptr) { + return std::make_shared(videoEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateVideoEncMockByName(const std::string &name) +{ + auto videoEnc = VideoEncoderFactory::CreateByName(name); + if (videoEnc != nullptr) { + return std::make_shared(videoEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioDecMockByMime(const std::string &mime) +{ + auto audioDec = AudioDecoderFactory::CreateByMime(mime); + if (audioDec != nullptr) { + return std::make_shared(audioDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioDecMockByName(const std::string &name) +{ + auto audioDec = AudioDecoderFactory::CreateByName(name); + if (audioDec != nullptr) { + return std::make_shared(audioDec); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioEncMockByMime(const std::string &mime) +{ + auto audioEnc = AudioEncoderFactory::CreateByMime(mime); + if (audioEnc != nullptr) { + return std::make_shared(audioEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateAudioEncMockByName(const std::string &name) +{ + auto audioEnc = AudioEncoderFactory::CreateByName(name); + if (audioEnc != nullptr) { + return std::make_shared(audioEnc); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateFormat() +{ + return std::make_shared(); +} + +std::shared_ptr AVCodecMockFactory::CreateSurface() +{ + return std::make_shared(); +} + +std::shared_ptr AVCodecMockFactory::CreateAVCodecInfo() +{ + return std::make_shared(); +} + +std::shared_ptr AVCodecMockFactory::CreateVideoCaps() +{ + return std::make_shared(); +} + +std::shared_ptr AVCodecMockFactory::CreateAVCodecList() +{ + auto avCodecList = AVCodecListFactory::CreateAVCodecList(); + if (avCodecList != nullptr) { + return std::make_shared(avCodecList); + } + return nullptr; +} + +std::shared_ptr AVCodecMockFactory::CreateEnum() +{ + return std::make_shared(); +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avformat/avformat_native_mock.cpp b/test/unittest/avcodec_test/native/avformat/avformat_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d64d09a822c54f5e6ca83f42fe9358df262aae1 --- /dev/null +++ b/test/unittest/avcodec_test/native/avformat/avformat_native_mock.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 "avformat_native_mock.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +bool AVFormatNativeMock::PutIntValue(const std::string_view &key, int32_t value) +{ + return format_.PutIntValue(key, value); +} + +bool AVFormatNativeMock::GetIntValue(const std::string_view &key, int32_t &value) +{ + return format_.GetIntValue(key, value); +} + +bool AVFormatNativeMock::PutStringValue(const std::string_view &key, const std::string_view &value) +{ + return format_.PutStringValue(key, value); +} + +bool AVFormatNativeMock::GetStringValue(const std::string_view &key, std::string &value) +{ + return format_.GetStringValue(key, value); +} + +void AVFormatNativeMock::Destroy() +{ + if (dumpInfo_ != nullptr) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + return; +} + +Format &AVFormatNativeMock::GetFormat() +{ + return format_; +} + +bool AVFormatNativeMock::PutLongValue(const std::string_view &key, int64_t value) +{ + return format_.PutLongValue(key, value); +} + +bool AVFormatNativeMock::GetLongValue(const std::string_view &key, int64_t &value) +{ + return format_.GetLongValue(key, value); +} + +bool AVFormatNativeMock::PutFloatValue(const std::string_view &key, float value) +{ + return format_.PutFloatValue(key, value); +} + +bool AVFormatNativeMock::GetFloatValue(const std::string_view &key, float &value) +{ + return format_.GetFloatValue(key, value); +} + +bool AVFormatNativeMock::PutDoubleValue(const std::string_view &key, double value) +{ + return format_.PutDoubleValue(key, value); +} + +bool AVFormatNativeMock::GetDoubleValue(const std::string_view &key, double &value) +{ + return format_.GetDoubleValue(key, value); +} + +bool AVFormatNativeMock::GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) +{ + return format_.GetBuffer(key, addr, size); +} + +bool AVFormatNativeMock::PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) +{ + return format_.PutBuffer(key, addr, size); +} + +const char *AVFormatNativeMock::DumpInfo() +{ + if (dumpInfo_ != nullptr) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + std::string info = format_.Stringify(); + if (info.empty()) { + return nullptr; + } + constexpr uint32_t maxDumpLength = 1024; + uint32_t bufLength = info.size() > maxDumpLength ? maxDumpLength : info.size(); + dumpInfo_ = static_cast(malloc((bufLength + 1) * sizeof(char))); + if (dumpInfo_ == nullptr) { + return nullptr; + } + if (strcpy_s(dumpInfo_, bufLength + 1, info.c_str()) != 0) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + return dumpInfo_; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avformat/avformat_native_mock.h b/test/unittest/avcodec_test/native/avformat/avformat_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..e4d12792f0c72610ef6b0c5d16f43db03a622afe --- /dev/null +++ b/test/unittest/avcodec_test/native/avformat/avformat_native_mock.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef AVFORMAT_NATIVE_MOCK_H +#define AVFORMAT_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class AVFormatNativeMock : public FormatMock { +public: + explicit AVFormatNativeMock(const Format &format) : format_(format) {} + AVFormatNativeMock() = default; + bool PutIntValue(const std::string_view &key, int32_t value) override; + bool GetIntValue(const std::string_view &key, int32_t &value) override; + bool PutStringValue(const std::string_view &key, const std::string_view &value) override; + bool GetStringValue(const std::string_view &key, std::string &value) override; + void Destroy() override; + bool PutLongValue(const std::string_view &key, int64_t value) override; + bool GetLongValue(const std::string_view &key, int64_t &value) override; + bool PutFloatValue(const std::string_view &key, float value) override; + bool GetFloatValue(const std::string_view &key, float &value) override; + bool PutDoubleValue(const std::string_view &key, double value) override; + bool GetDoubleValue(const std::string_view &key, double &value) override; + bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) override; + bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) override; + const char *DumpInfo() override; + Format &GetFormat(); + +private: + Format format_; + char *dumpInfo_ = nullptr; +}; +} // Media +} // OHOS +#endif // AVFORMAT_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.cpp b/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d40015b4c944d537a5a3dc88338e70200c2fb51 --- /dev/null +++ b/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.cpp @@ -0,0 +1,44 @@ +/* + * 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 "avmemory_native_mock.h" + +namespace OHOS { +namespace Media { +uint8_t *AVMemoryNativeMock::GetAddr() const +{ + if (memory_ != nullptr) { + return memory_->GetBase(); + } + return nullptr; +} + +int32_t AVMemoryNativeMock::GetSize() const +{ + if (memory_ != nullptr) { + return memory_->GetSize(); + } + return -1; +} + +uint32_t AVMemoryNativeMock::GetFlags() const +{ + if (memory_ != nullptr) { + return memory_->GetFlags(); + } + return 0; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.h b/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..a22ac59d973e10d35afb1402433b7985e8114f56 --- /dev/null +++ b/test/unittest/avcodec_test/native/avmemory/avmemory_native_mock.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef AVMEMORY_NATIVE_MOCK_H +#define AVMEMORY_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avsharedmemory.h" + +namespace OHOS { +namespace Media { +class AVMemoryNativeMock : public AVMemoryMock { +public: + explicit AVMemoryNativeMock(std::shared_ptr mem) : memory_(mem) {} + uint8_t *GetAddr() const override; + int32_t GetSize() const override; + uint32_t GetFlags() const override; + +private: + std::shared_ptr memory_ = nullptr; +}; +} // Media +} // OHOS +#endif // AVMEMORY_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/enum/enum_native_mock.cpp b/test/unittest/avcodec_test/native/enum/enum_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..681bd38e0ff2ff4a8d33d2dfde06c1158f53b0bc --- /dev/null +++ b/test/unittest/avcodec_test/native/enum/enum_native_mock.cpp @@ -0,0 +1,47 @@ +/* + * 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 "enum_native_mock.h" + +namespace OHOS { +namespace Media { +std::string EnumNativeMock::GetMediaDescriptionKey(const MediaDescriptionKeyMock &key) const +{ + std::string ret; + if (MEDIA_DESCRIPTION_KEY_INFOS.find(key) != MEDIA_DESCRIPTION_KEY_INFOS.end()) { + ret = MEDIA_DESCRIPTION_KEY_INFOS.find(key)->second; + } + return ret; +} + +int32_t EnumNativeMock::GetVideoPixelFormat(const VideoPixelFormatMock &key) const +{ + int32_t ret = 0; + if (VIDEO_PIXEL_FORMAT_INFOS.find(key) != VIDEO_PIXEL_FORMAT_INFOS.end()) { + ret = VIDEO_PIXEL_FORMAT_INFOS.find(key)->second; + } + return ret; +} + +std::string EnumNativeMock::GetCodecMimeType(const CodecMimeTypeMock &key) const +{ + std::string ret; + if (CODEC_MIME_INFOS.find(key) != CODEC_MIME_INFOS.end()) { + ret = CODEC_MIME_INFOS.find(key)->second; + } + return ret; +} +} // Media +} // OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/enum/enum_native_mock.h b/test/unittest/avcodec_test/native/enum/enum_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..268453da915088ff79fa7e5ec52e449fa40dd084 --- /dev/null +++ b/test/unittest/avcodec_test/native/enum/enum_native_mock.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef ENUM_NATIVE_MOCK_H +#define ENUM_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "enum_mock.h" +#include "media_description.h" +#include "av_common.h" +#include "avcodec_info.h" + +namespace OHOS { +namespace Media { +const std::mapMEDIA_DESCRIPTION_KEY_INFOS = { + {MOCK_MD_KEY_TRACK_INDEX, MediaDescriptionKey::MD_KEY_TRACK_INDEX}, + {MOCK_MD_KEY_TRACK_TYPE, MediaDescriptionKey::MD_KEY_TRACK_TYPE}, + {MOCK_MD_KEY_CODEC_MIME, MediaDescriptionKey::MD_KEY_CODEC_MIME}, + {MOCK_MD_KEY_DURATION, MediaDescriptionKey::MD_KEY_DURATION}, + {MOCK_MD_KEY_BITRATE, MediaDescriptionKey::MD_KEY_BITRATE}, + {MOCK_MD_KEY_WIDTH, MediaDescriptionKey::MD_KEY_WIDTH}, + {MOCK_MD_KEY_HEIGHT, MediaDescriptionKey::MD_KEY_HEIGHT}, + {MOCK_MD_KEY_PIXEL_FORMAT, MediaDescriptionKey::MD_KEY_PIXEL_FORMAT}, + {MOCK_MD_KEY_FRAME_RATE, MediaDescriptionKey::MD_KEY_FRAME_RATE}, + {MOCK_MD_KEY_CHANNEL_COUNT, MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}, + {MOCK_MD_KEY_SAMPLE_RATE, MediaDescriptionKey::MD_KEY_SAMPLE_RATE}, +}; + +const std::map VIDEO_PIXEL_FORMAT_INFOS = { + {MOCK_YUVI420, YUVI420}, + {MOCK_NV12, NV12}, + {MOCK_NV21, NV21}, + {MOCK_SURFACE_FORMAT, SURFACE_FORMAT}, + {MOCK_RGBA, RGBA}, +}; + +const std::map CODEC_MIME_INFOS = { + {VIDEO_H263, CodecMimeType::VIDEO_H263}, + {VIDEO_AVC, CodecMimeType::VIDEO_AVC}, + {VIDEO_MPEG2, CodecMimeType::VIDEO_MPEG2}, + {VIDEO_HEVC, CodecMimeType::VIDEO_HEVC}, + {VIDEO_MPEG4, CodecMimeType::VIDEO_MPEG4}, + {VIDEO_VP8, CodecMimeType::VIDEO_VP8}, + {VIDEO_VP9, CodecMimeType::VIDEO_VP9}, + {AUDIO_AMR_NB, CodecMimeType::AUDIO_AMR_NB}, + {AUDIO_AMR_WB, CodecMimeType::AUDIO_AMR_WB}, + {AUDIO_MPEG, CodecMimeType::AUDIO_MPEG}, + {AUDIO_AAC, CodecMimeType::AUDIO_AAC}, + {AUDIO_VORBIS, CodecMimeType::AUDIO_VORBIS}, + {AUDIO_OPUS, CodecMimeType::AUDIO_OPUS}, + {AUDIO_FLAC, CodecMimeType::AUDIO_FLAC}, + {AUDIO_RAW, CodecMimeType::AUDIO_RAW}, +}; + +class EnumNativeMock : public EnumMock { +public: + EnumNativeMock() = default; + std::string GetMediaDescriptionKey(const MediaDescriptionKeyMock &key) const override; + int32_t GetVideoPixelFormat(const VideoPixelFormatMock &key) const override; + std::string GetCodecMimeType(const CodecMimeTypeMock &key) const override; +}; +} // Media +} // OHOS +#endif // ENUM_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/surface/surface_native_mock.cpp b/test/unittest/avcodec_test/native/surface/surface_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b04fb35bb1b79ff90c2f8596937c00f64e114210 --- /dev/null +++ b/test/unittest/avcodec_test/native/surface/surface_native_mock.cpp @@ -0,0 +1,50 @@ +/* + * 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 "surface_native_mock.h" +#include "ui/rs_surface_node.h" +#include "window_option.h" + +namespace OHOS { +namespace Media { +namespace { +constexpr uint32_t DEFAULT_WIDTH = 480; +constexpr uint32_t DEFAULT_HEIGHT = 360; +} // namespace +SurfaceNativeMock::~SurfaceNativeMock() +{ + if (window_ != nullptr) { + window_->Destroy(); + window_ = nullptr; + } +} +sptr SurfaceNativeMock::GetSurface() +{ + if (surface_ == nullptr) { + sptr option = new Rosen::WindowOption(); + option->SetWindowRect({0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT}); + option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_LAUNCHING); + option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING); + window_ = Rosen::Window::Create("avcodec_unittest", option); + if (window_ == nullptr || window_->GetSurfaceNode() == nullptr) { + return nullptr; + } + window_->Show(); + surface_ = window_->GetSurfaceNode()->GetSurface(); + } + return surface_; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/surface/surface_native_mock.h b/test/unittest/avcodec_test/native/surface/surface_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..556538112f47918c6e3305e461af3c6b28c985f6 --- /dev/null +++ b/test/unittest/avcodec_test/native/surface/surface_native_mock.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef SURFACE_NATIVE_MOCK_H +#define SURFACE_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "surface.h" +#include "window.h" + +namespace OHOS { +namespace Media { +class SurfaceNativeMock : public SurfaceMock { +public: + explicit SurfaceNativeMock(sptr surface) : surface_(surface) {} + SurfaceNativeMock() = default; + ~SurfaceNativeMock(); + sptr GetSurface(); + +private: + sptr surface_ = nullptr; + sptr window_ = nullptr; +}; +} // Media +} // OHOS +#endif // SURFACE_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.cpp b/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ec3b09ff219eac50095f01023966e333db20afd --- /dev/null +++ b/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.cpp @@ -0,0 +1,199 @@ +/* + * 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 "videodec_native_mock.h" +#include "avcodec_info_native_mock.h" +#include "avformat_native_mock.h" +#include "avmemory_native_mock.h" +#include "surface_native_mock.h" +#include "avcodec_errors.h" + +namespace OHOS { +namespace Media { +VideoDecCallbackMock::VideoDecCallbackMock(std::shared_ptr cb, + std::weak_ptr vd) + : mockCb_(cb), videoDec_(vd) +{ +} + +void VideoDecCallbackMock::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + if (mockCb_ != nullptr) { + mockCb_->OnError(errorCode); + } +} + +void VideoDecCallbackMock::OnOutputFormatChanged(const Format &format) +{ + if (mockCb_ != nullptr) { + auto formatMock = std::make_shared(format); + mockCb_->OnStreamChanged(formatMock); + } +} + +void VideoDecCallbackMock::OnInputBufferAvailable(uint32_t index) +{ + auto videoDec = videoDec_.lock(); + if (mockCb_ != nullptr && videoDec != nullptr) { + std::shared_ptr mem = videoDec->GetInputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + mockCb_->OnNeedInputData(index, memMock); + } + } +} + +void VideoDecCallbackMock::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + if (mockCb_ != nullptr) { + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = info.presentationTimeUs; + bufferInfo.size = info.size; + bufferInfo.offset = info.offset; + bufferInfo.flags = flag; + return mockCb_->OnNewOutputData(index, nullptr, bufferInfo); + } +} + +int32_t VideoDecNativeMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr) { + auto callback = std::make_shared(cb, videoDec_); + if (videoDec_ != nullptr && callback != nullptr) { + return videoDec_->SetCallback(callback); + } + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::SetOutputSurface(std::shared_ptr surface) +{ + if (surface != nullptr) { + auto decSurface = std::static_pointer_cast(surface); + sptr nativeSurface = decSurface->GetSurface(); + if (videoDec_ != nullptr && nativeSurface != nullptr) { + return videoDec_->SetOutputSurface(nativeSurface); + } + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Configure(std::shared_ptr format) +{ + if (videoDec_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return videoDec_->Configure(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Prepare() +{ + if (videoDec_ != nullptr) { + return videoDec_->Prepare(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Start() +{ + if (videoDec_ != nullptr) { + return videoDec_->Start(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Stop() +{ + if (videoDec_ != nullptr) { + return videoDec_->Stop(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Flush() +{ + if (videoDec_ != nullptr) { + return videoDec_->Flush(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Reset() +{ + if (videoDec_ != nullptr) { + return videoDec_->Reset(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::Release() +{ + if (videoDec_ != nullptr) { + return videoDec_->Release(); + } + return MSERR_INVALID_OPERATION; +} + +std::shared_ptr VideoDecNativeMock::GetOutputMediaDescription() +{ + if (videoDec_ != nullptr) { + Format format; + (void)videoDec_->GetOutputFormat(format); + return std::make_shared(format); + } + return nullptr; +} + +int32_t VideoDecNativeMock::SetParameter(std::shared_ptr format) +{ + if (videoDec_ != nullptr && format != nullptr) { + auto fmt = std::static_pointer_cast(format); + return videoDec_->SetParameter(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (videoDec_ != nullptr) { + AVCodecBufferInfo info; + info.presentationTimeUs = attr.pts; + info.size = attr.size; + info.offset = attr.offset; + AVCodecBufferFlag flags = static_cast(attr.flags); + return videoDec_->QueueInputBuffer(index, info, flags); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::RenderOutputData(uint32_t index) +{ + if (videoDec_ != nullptr) { + return videoDec_->ReleaseOutputBuffer(index, true); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoDecNativeMock::FreeOutputData(uint32_t index) +{ + if (videoDec_ != nullptr) { + return videoDec_->ReleaseOutputBuffer(index, false); + } + return MSERR_INVALID_OPERATION; +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.h b/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..e126f7ed22ecb88fc42161c02861394fa1892cef --- /dev/null +++ b/test/unittest/avcodec_test/native/videodecoder/videodec_native_mock.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef VIDEO_DEC_NATIVE_MOCK_H +#define VIDEO_DEC_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_common.h" +#include "avcodec_video_decoder.h" + +namespace OHOS { +namespace Media { +class VideoDecNativeMock : public VideoDecMock { +public: + explicit VideoDecNativeMock(std::shared_ptr videoDec) : videoDec_(videoDec) {} + ~VideoDecNativeMock() = default; + int32_t SetCallback(std::shared_ptr cb) override; + int32_t SetOutputSurface(std::shared_ptr surface) override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) override; + int32_t RenderOutputData(uint32_t index) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + std::shared_ptr videoDec_ = nullptr; +}; + +class VideoDecCallbackMock : public AVCodecCallback { +public: + VideoDecCallbackMock(std::shared_ptr cb, std::weak_ptr vd); + ~VideoDecCallbackMock() = default; + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr mockCb_ = nullptr; + std::weak_ptr videoDec_; +}; +} // namespace Media +} // namespace OHOS +#endif // VIDEO_DEC_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.cpp b/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..637b7aba834d27a47641ca76ef13f03916d86ef0 --- /dev/null +++ b/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.cpp @@ -0,0 +1,185 @@ +/* + * 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 "avcodec_info_native_mock.h" +#include "avformat_native_mock.h" +#include "avmemory_native_mock.h" +#include "surface_native_mock.h" +#include "avcodec_errors.h" +#include "videoenc_native_mock.h" + +namespace OHOS { +namespace Media { +VideoEncCallbackMock::VideoEncCallbackMock(std::shared_ptr cb, + std::weak_ptr vd) + : mockCb_(cb), videoEnc_(vd) +{ +} + +void VideoEncCallbackMock::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + if (mockCb_ != nullptr) { + mockCb_->OnError(errorCode); + } +} + +void VideoEncCallbackMock::OnOutputFormatChanged(const Format &format) +{ + if (mockCb_ != nullptr) { + auto formatMock = std::make_shared(format); + mockCb_->OnStreamChanged(formatMock); + } +} + +void VideoEncCallbackMock::OnInputBufferAvailable(uint32_t index) +{ + if (mockCb_ != nullptr) { + mockCb_->OnNeedInputData(index, nullptr); + } +} + +void VideoEncCallbackMock::OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + auto videoEnc = videoEnc_.lock(); + if (mockCb_ != nullptr && videoEnc != nullptr) { + std::shared_ptr mem = videoEnc->GetOutputBuffer(index); + if (mem != nullptr) { + std::shared_ptr memMock = std::make_shared(mem); + struct AVCodecBufferAttrMock bufferInfo; + bufferInfo.pts = info.presentationTimeUs; + bufferInfo.size = info.size; + bufferInfo.offset = info.offset; + bufferInfo.flags = flag; + return mockCb_->OnNewOutputData(index, memMock, bufferInfo); + } + } +} + +int32_t VideoEncNativeMock::SetCallback(std::shared_ptr cb) +{ + if (cb != nullptr) { + auto callback = std::make_shared(cb, videoEnc_); + if (videoEnc_ != nullptr && callback != nullptr) { + return videoEnc_->SetCallback(callback); + } + } + return MSERR_INVALID_OPERATION; +} + +std::shared_ptr VideoEncNativeMock::GetInputSurface() +{ + if (videoEnc_ != nullptr) { + sptr surface = videoEnc_->CreateInputSurface(); + if (surface != nullptr) { + return std::make_shared(surface); + } + } + return nullptr; +} + +int32_t VideoEncNativeMock::Configure(std::shared_ptr format) +{ + if (videoEnc_ != nullptr) { + auto fmt = std::static_pointer_cast(format); + return videoEnc_->Configure(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Prepare() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Prepare(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Start() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Start(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Stop() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Stop(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Flush() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Flush(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Reset() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Reset(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::Release() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->Release(); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::NotifyEos() +{ + if (videoEnc_ != nullptr) { + return videoEnc_->NotifyEos(); + } + return MSERR_INVALID_OPERATION; +} + +std::shared_ptr VideoEncNativeMock::GetOutputMediaDescription() +{ + if (videoEnc_ != nullptr) { + Format format; + (void)videoEnc_->GetOutputFormat(format); + return std::make_shared(format); + } + return nullptr; +} + +int32_t VideoEncNativeMock::SetParameter(std::shared_ptr format) +{ + if (videoEnc_ != nullptr) { + auto fmt = std::static_pointer_cast(format); + return videoEnc_->SetParameter(fmt->GetFormat()); + } + return MSERR_INVALID_OPERATION; +} + +int32_t VideoEncNativeMock::FreeOutputData(uint32_t index) +{ + if (videoEnc_ != nullptr) { + return videoEnc_->ReleaseOutputBuffer(index); + } + return MSERR_INVALID_OPERATION; +} +} +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.h b/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..1e2f9f5ff53d5b57c88dec8970158ea09ffa846b --- /dev/null +++ b/test/unittest/avcodec_test/native/videoencoder/videoenc_native_mock.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef VIDEO_ENC_NATIVE_MOCK_H +#define VIDEO_ENC_NATIVE_MOCK_H + +#include "avcodec_mock.h" +#include "avcodec_video_encoder.h" + +namespace OHOS { +namespace Media { +class VideoEncNativeMock : public VideoEncMock { +public: + explicit VideoEncNativeMock(std::shared_ptr videoEnc) : videoEnc_(videoEnc) {} + int32_t SetCallback(std::shared_ptr cb) override; + std::shared_ptr GetInputSurface() override; + int32_t Configure(std::shared_ptr format) override; + int32_t Prepare() override; + int32_t Start() override; + int32_t Stop() override; + int32_t Flush() override; + int32_t Reset() override; + int32_t Release() override; + int32_t NotifyEos() override; + std::shared_ptr GetOutputMediaDescription() override; + int32_t SetParameter(std::shared_ptr format) override; + int32_t FreeOutputData(uint32_t index) override; + +private: + std::shared_ptr videoEnc_ = nullptr; +}; + +class VideoEncCallbackMock : public AVCodecCallback { +public: + VideoEncCallbackMock(std::shared_ptr cb, std::weak_ptr ve); + void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + void OnOutputFormatChanged(const Format &format) override; + void OnInputBufferAvailable(uint32_t index) override; + void OnOutputBufferAvailable(uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; + +private: + std::shared_ptr mockCb_ = nullptr; + std::weak_ptr videoEnc_; +}; +} // namespace Media +} // namespace OHOS +#endif // VIDEO_ENC_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.cpp b/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb3d185591e955d701e0b6bce58e0b8ca66e9815 --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.cpp @@ -0,0 +1,567 @@ +/* + * 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 "gtest/gtest.h" +#include "avcodec_errors.h" +#include "vcodec_unit_test.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::Media; +using namespace testing::ext; +using namespace OHOS::Media::VCodecTestParam; + +void VCodecUnitTest::SetUpTestCase(void) {} + +void VCodecUnitTest::TearDownTestCase(void) {} + +void VCodecUnitTest::SetUp(void) +{ + createCodecSuccess_ = false; + std::shared_ptr vdecSignal = std::make_shared(); + vdecCallback_ = std::make_shared(vdecSignal); + ASSERT_NE(nullptr, vdecCallback_); + videoDec_ = std::make_shared(vdecSignal); + + std::shared_ptr vencSignal = std::make_shared(); + vencCallback_ = std::make_shared(vencSignal); + ASSERT_NE(nullptr, vencCallback_); + videoEnc_ = std::make_shared(vencSignal); + + testInfo_ = ::testing::UnitTest::GetInstance()->current_test_info(); + string prefix = "/data/test/media/"; + string fileName = testInfo_->name(); + string suffix = ".es"; + videoEnc_->SetOutPath(prefix + fileName + suffix); +} + +bool VCodecUnitTest::CreateVideoCodecByMime(const std::string &decMime, const std::string &encMime) +{ + if (videoDec_->CreateVideoDecMockByMime(decMime) == false || + videoEnc_->CreateVideoEncMockByMime(encMime) == false || + videoDec_->SetCallback(vdecCallback_) != AVCS_ERR_OK || + videoEnc_->SetCallback(vencCallback_) != AVCS_ERR_OK) { + return false; + } + createCodecSuccess_ = true; + return true; +} + +bool VCodecUnitTest::CreateVideoCodecByName(const std::string &decName, const std::string &encName) +{ + if (videoDec_->CreateVideoDecMockByName(decName) == false || + videoEnc_->CreateVideoEncMockByName(encName) == false || + videoDec_->SetCallback(vdecCallback_) != AVCS_ERR_OK || + videoEnc_->SetCallback(vencCallback_) != AVCS_ERR_OK) { + return false; + } + createCodecSuccess_ = true; + return true; +} + +void VCodecUnitTest::TearDown(void) +{ + if (videoDec_ != nullptr && createCodecSuccess_) { + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Reset()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Release()); + } + + if (videoEnc_ != nullptr && createCodecSuccess_) { + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Reset()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Release()); + } +} + +/** + * @tc.name: video_codec_create_0100 + * @tc.desc: video create + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_create_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByName("avdec_h264", "avenc_mpeg4")); +} + +/** + * @tc.name: video_codec_Configure_0100 + * @tc.desc: video codec Configure + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_Configure_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + string maxInputSize = "max_input_size"; + string rotationAngle = "rotation_angle"; + string videoEncodeBitrateMode = "video_encode_bitrate_mode"; + string iFrameInterval = "i_frame_interval"; + string codecQuality = "codec_quality"; + string codecProfile = "codec_profile"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + (void)format->PutIntValue(rotationAngle.c_str(), 0); // set rotation_angle 0 + (void)format->PutIntValue(maxInputSize.c_str(), 15000); // set max input size 15000 + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + (void)format->PutIntValue(videoEncodeBitrateMode.c_str(), 0); // CBR + (void)format->PutIntValue(iFrameInterval.c_str(), 1); // i_frame_interval 1ms + (void)format->PutIntValue(codecQuality.c_str(), 0); // set codec_quality 0 + (void)format->PutIntValue(codecProfile.c_str(), 0); // AVC_PROFILE_BASELINE + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_start_0100 + * @tc.desc: video decodec start + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_start_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_format_h264_h264_0100 + * @tc.desc: video decodec h264->h264 + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_format_h264_h264_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + system("hidumper -s 3002 -a codec"); + sleep(10); // start run 10s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_format_h265_h265_0100 + * @tc.desc: video codec h265->h265 + * @tc.type: FUNC + * @tc.require: issueI5OOKN issueI5OOKW issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_format_h265_h265_0100, TestSize.Level0) +{ + if (!CreateVideoCodecByName("OMX_hisi_video_decoder_hevc", "OMX_hisi_video_encoder_hevc")) { + std::cout << "This device does not support hard hevc" << std::endl; + createCodecSuccess_ = false; + return; + } + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H265_SRC_PATH, ES_H265, ES_LENGTH_H265); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(10); // start run 10s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_decode_Flush_0100 + * @tc.desc: video decodec flush + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_decode_Flush_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(3); // start run 3s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Flush()); + sleep(7); // start run 7s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_encode_Flush_0100 + * @tc.desc: video encodec flush + * @tc.type: FUNC + * @tc.require: issueI5NYCP issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_encode_Flush_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(3); // start run 3s + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Flush()); + sleep(7); // start run 7s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + + +/** + * @tc.name: video_codec_abnormal_0100 + * @tc.desc: video codec abnormal func + * @tc.type: FUNC + * @tc.require: issueI5NYCP issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_abnormal_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + string maxInputSize = "max_input_size"; + string rotationAngle = "rotation_angle"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + (void)format->PutIntValue(rotationAngle.c_str(), 20); // invalid rotation_angle 20 + (void)format->PutIntValue(maxInputSize.c_str(), -1); // invalid max input size -1 + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + videoEnc_->Configure(format); + videoDec_->Configure(format); + videoDec_->Prepare(); + videoEnc_->Prepare(); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Reset()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Reset()); + ASSERT_NE(AVCS_ERR_OK, videoDec_->Start()); + ASSERT_NE(AVCS_ERR_OK, videoEnc_->Start()); + ASSERT_NE(AVCS_ERR_OK, videoDec_->Flush()); + ASSERT_NE(AVCS_ERR_OK, videoEnc_->Flush()); + ASSERT_NE(AVCS_ERR_OK, videoDec_->Stop()); + ASSERT_NE(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_SetParameter_0100 + * @tc.desc: video codec SetParameter + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_SetParameter_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + string suspendInputSurface = "suspend_input_surface"; + string maxEncoderFps = "max_encoder_fps"; + string repeatFrameAfter = "repeat_frame_after"; + string reqIFrame = "req_i_frame"; + string bitrate = "bitrate"; + string vendorCustom = "vendor.custom"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + (void)format->PutIntValue(suspendInputSurface.c_str(), 0); // set suspend_input_surface value 0 + (void)format->PutIntValue(maxEncoderFps.c_str(), DEFAULT_FRAME_RATE); + (void)format->PutIntValue(repeatFrameAfter.c_str(), 1); // set repeat_frame_after 1ms + (void)format->PutIntValue(reqIFrame.c_str(), 0); // set request i frame false + (void)format->PutIntValue(bitrate.c_str(), 1000000); // set bitrate 1Mbps + uint8_t *addr = nullptr; + size_t size = 0; + (void)format->PutBuffer(vendorCustom, addr, size); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->SetParameter(format)); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->SetParameter(format)); + sleep(5); // start run 5s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_GetOutputMediaDescription_0100 + * @tc.desc: video codec GetOutputMediaDescription + * @tc.type: FUNC + * @tc.require: issueI5NYCP issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_GetOutputMediaDescription_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(2); // start run 2s + EXPECT_NE(nullptr, videoDec_->GetOutputMediaDescription()); + EXPECT_NE(nullptr, videoEnc_->GetOutputMediaDescription()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_NotifyEos_0100 + * @tc.desc: video encodec NotifyEos + * @tc.type: FUNC + * @tc.require: issueI5NYCF issueI5OX06 issueI5P8N0 +*/ +HWTEST_F(VCodecUnitTest, video_NotifyEos_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/avc", "video/avc")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(H264_SRC_PATH, ES_H264, ES_LENGTH_H264); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(10); // start run 10s + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->NotifyEos()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_format_none_0100 + * @tc.desc: video format none + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 +*/ +HWTEST_F(VCodecUnitTest, video_codec_format_none_0100, TestSize.Level0) +{ + CreateVideoCodecByMime("", ""); +} + +/** + * @tc.name: video_codec_format_mpeg2_mpeg4_0100 + * @tc.desc: video format decoder-mpeg2 encoder-mpeg4 + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_format_mpeg2_mpeg4_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/mpeg2", "video/mp4v-es")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), 720); // set width 720 + (void)format->PutIntValue(height.c_str(), 480); // set height 480 + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(MPEG2_SRC_PATH, ES_MPEG2, ES_LENGTH_MPEG2); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(5); // start run 5s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} + +/** + * @tc.name: video_codec_format_mpeg4_mpeg4_0100 + * @tc.desc: video format decoder-mpeg4 encoder-mpeg4 + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(VCodecUnitTest, video_codec_format_mpeg4_mpeg4_0100, TestSize.Level0) +{ + ASSERT_TRUE(CreateVideoCodecByMime("video/mp4v-es", "video/mp4v-es")); + std::shared_ptr format = AVCodecMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + string width = "width"; + string height = "height"; + string pixelFormat = "pixel_format"; + string frameRate = "frame_rate"; + (void)format->PutIntValue(width.c_str(), DEFAULT_WIDTH); + (void)format->PutIntValue(height.c_str(), DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormat.c_str(), NV12); + (void)format->PutIntValue(frameRate.c_str(), DEFAULT_FRAME_RATE); + videoDec_->SetSource(MPEG4_SRC_PATH, ES_MPEG4, ES_LENGTH_MPEG4); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->Configure(format)); + ASSERT_EQ(AVCS_ERR_OK, videoEnc_->Configure(format)); + std::shared_ptr surface = videoEnc_->GetInputSurface(); + ASSERT_NE(nullptr, surface); + ASSERT_EQ(AVCS_ERR_OK, videoDec_->SetOutputSurface(surface)); + + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Prepare()); + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Start()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Start()); + sleep(5); // start run 5s + EXPECT_EQ(AVCS_ERR_OK, videoDec_->Stop()); + EXPECT_EQ(AVCS_ERR_OK, videoEnc_->Stop()); + format->Destroy(); +} \ No newline at end of file diff --git a/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.h b/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..3e1872343e1e8c22a9254a77e585b019180f517b --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/vcodec_unit_test.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef VCODEC_UNIT_TEST_H +#define VCODEC_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "vdec_mock.h" +#include "venc_mock.h" +namespace OHOS { +namespace Media { +class VCodecUnitTest : 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); + bool CreateVideoCodecByName(const std::string &decName, const std::string &encName); + bool CreateVideoCodecByMime(const std::string &decMime, const std::string &encMime); +protected: + std::shared_ptr videoDec_ = nullptr; + std::shared_ptr vdecCallback_ = nullptr; + std::shared_ptr videoEnc_ = nullptr; + std::shared_ptr vencCallback_ = nullptr; + const ::testing::TestInfo *testInfo_ = nullptr; + bool createCodecSuccess_ = false; +}; +} // namespace Media +} // namespace OHOS +#endif // VCODEC_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/vcodec_test/vdec_mock.cpp b/test/unittest/avcodec_test/vcodec_test/vdec_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1aa5d42b0f73444e3499238a652c8324517e938 --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/vdec_mock.cpp @@ -0,0 +1,355 @@ +/* + * 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 "vdec_mock.h" +#include "nocopyable.h" +#include "avcodec_errors.h" +#include "avcodec_common.h" +using namespace std; +using namespace OHOS::Media::VCodecTestParam; +namespace OHOS { +namespace Media { +VDecCallbackTest::VDecCallbackTest(std::shared_ptr signal) + : signal_(signal) +{ +} + +VDecCallbackTest::~VDecCallbackTest() +{ +} + +void VDecCallbackTest::OnError(int32_t errorCode) +{ + cout << "VDec Error errorCode=" << errorCode << endl; +} + +void VDecCallbackTest::OnStreamChanged(std::shared_ptr format) +{ + cout << "VDec Format Changed" << endl; +} + +void VDecCallbackTest::OnNeedInputData(uint32_t index, std::shared_ptr data) +{ + if (signal_ == nullptr) { + return; + } + unique_lock lock(signal_->inMutex_); + if (!signal_->isRunning_.load()) { + return; + } + signal_->inIndexQueue_.push(index); + signal_->inBufferQueue_.push(data); + signal_->inCond_.notify_all(); +} + +void VDecCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) +{ + if (signal_ == nullptr) { + return; + } + unique_lock lock(signal_->outMutex_); + if (!signal_->isRunning_.load()) { + return; + } + signal_->outIndexQueue_.push(index); + + signal_->outSizeQueue_.push(attr.size); + signal_->outCond_.notify_all(); +} + +VDecMock::VDecMock(std::shared_ptr signal) + : signal_(signal) +{ +} + +VDecMock::~VDecMock() +{ +} + +bool VDecMock::CreateVideoDecMockByMime(const std::string &mime) +{ + videoDec_ = AVCodecMockFactory::CreateVideoDecMockByMime(mime); + return videoDec_ != nullptr; +} + +bool VDecMock::CreateVideoDecMockByName(const std::string &name) +{ + videoDec_ = AVCodecMockFactory::CreateVideoDecMockByName(name); + return videoDec_ != nullptr; +} + +int32_t VDecMock::SetCallback(std::shared_ptr cb) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->SetCallback(cb); +} + +int32_t VDecMock::SetOutputSurface(std::shared_ptr surface) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->SetOutputSurface(surface); +} + +int32_t VDecMock::Configure(std::shared_ptr format) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Configure(format); +} + +int32_t VDecMock::Prepare() +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Prepare(); +} + +int32_t VDecMock::Start() +{ + if (signal_ == nullptr || videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + signal_->isRunning_.store(true); + + testFile_ = std::make_unique(); + UNITTEST_CHECK_AND_RETURN_RET_LOG(testFile_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + testFile_->open(inpPath_, std::ios::in | std::ios::binary); + + inputLoop_ = make_unique(&VDecMock::InpLoopFunc, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(inputLoop_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + + outputLoop_ = make_unique(&VDecMock::OutLoopFunc, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(outputLoop_ != nullptr, AVCS_ERR_OK, "Fatal: No memory"); + return videoDec_->Start(); +} + +void VDecMock::FlushInner() +{ + if (signal_ == nullptr) { + return; + } + signal_->isRunning_.store(false); + if (inputLoop_ != nullptr && inputLoop_->joinable()) { + unique_lock queueLock(signal_->inMutex_); + signal_->inIndexQueue_.push(10000); // push 10000 to stop queue + signal_->inCond_.notify_all(); + queueLock.unlock(); + inputLoop_->join(); + inputLoop_.reset(); + std::queue temp; + std::swap(temp, signal_->inIndexQueue_); + } + if (outputLoop_ != nullptr && outputLoop_->joinable()) { + unique_lock lock(signal_->outMutex_); + signal_->outIndexQueue_.push(10000); // push 10000 to stop queue + signal_->outCond_.notify_all(); + lock.unlock(); + outputLoop_->join(); + outputLoop_.reset(); + std::queue temp; + std::swap(temp, signal_->outIndexQueue_); + } +} + +int32_t VDecMock::Stop() +{ + FlushInner(); + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Stop(); +} + +int32_t VDecMock::Flush() +{ + FlushInner(); + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Flush(); +} + +int32_t VDecMock::Reset() +{ + FlushInner(); + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Reset(); +} + +int32_t VDecMock::Release() +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->Release(); +} + +std::shared_ptr VDecMock::GetOutputMediaDescription() +{ + if (videoDec_ == nullptr) { + return nullptr; + } + return videoDec_->GetOutputMediaDescription(); +} + +int32_t VDecMock::SetParameter(std::shared_ptr format) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->SetParameter(format); +} + +int32_t VDecMock::PushInputData(uint32_t index, AVCodecBufferAttrMock &attr) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->PushInputData(index, attr); +} + +int32_t VDecMock::RenderOutputData(uint32_t index) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->RenderOutputData(index); +} + +int32_t VDecMock::FreeOutputData(uint32_t index) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoDec_->FreeOutputData(index); +} + +void VDecMock::SetSource(const std::string &path, const uint32_t es[], const uint32_t &size) +{ + inpPath_ = path; + es_ = es; + esLength_ = size; +} + +int32_t VDecMock::PushInputDataMock(uint32_t index, uint32_t bufferSize) +{ + if (videoDec_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + struct AVCodecBufferAttrMock attr; + attr.offset = 0; + if (frameCount_ == esLength_) { + attr.flags = AVCODEC_BUFFER_FLAG_EOS; + attr.size = 0; + attr.pts = 0; + cout << "EOS Frame, frameCount = " << frameCount_ << endl; + signal_->isRunning_.store(false); + } else { + if (isFirstFrame_) { + attr.flags = AVCODEC_BUFFER_FLAG_CODEC_DATA; + isFirstFrame_ = false; + } else { + attr.flags = AVCODEC_BUFFER_FLAG_NONE; + } + attr.size = bufferSize; + attr.pts = timestamp_; + } + return videoDec_->PushInputData(index, attr); +} + +void VDecMock::InpLoopFunc() +{ + if (signal_ == nullptr || videoDec_ == nullptr) { + return; + } + while (true) { + if (!signal_->isRunning_.load()) { + break; + } + + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return signal_->inIndexQueue_.size() > 0; }); + + if (!signal_->isRunning_.load()) { + break; + } + uint32_t index = signal_->inIndexQueue_.front(); + std::shared_ptr buffer = signal_->inBufferQueue_.front(); + UNITTEST_CHECK_AND_RETURN_LOG(buffer != nullptr, "Fatal: GetInputBuffer fail"); + UNITTEST_CHECK_AND_RETURN_LOG(testFile_ != nullptr && testFile_->is_open(), "Fatal: open file fail"); + + uint32_t bufferSize = 0; + + if (frameCount_ < esLength_) { + bufferSize = es_[frameCount_]; + char *fileBuffer = static_cast(malloc(sizeof(char) * bufferSize + 1)); + UNITTEST_CHECK_AND_RETURN_LOG(fileBuffer != nullptr, "Fatal: malloc fail."); + (void)testFile_->read(fileBuffer, bufferSize); + if (testFile_->eof()) { + cout << "Finish" << endl; + free(fileBuffer); + break; + } + + if (memcpy_s(buffer->GetAddr(), buffer->GetSize(), fileBuffer, bufferSize) != EOK) { + cout << "Fatal: memcpy fail" << endl; + free(fileBuffer); + break; + } + free(fileBuffer); + } + if (PushInputDataMock(index, bufferSize) != AVCS_ERR_OK) { + cout << "Fatal: PushInputData fail, exit" << endl; + } + timestamp_ += FRAME_DURATION_US; + frameCount_++; + signal_->inIndexQueue_.pop(); + signal_->inBufferQueue_.pop(); + } +} + +void VDecMock::OutLoopFunc() +{ + if (signal_ == nullptr || videoDec_ == nullptr) { + return; + } + while (true) { + if (!signal_->isRunning_.load()) { + break; + } + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return signal_->outIndexQueue_.size() > 0; }); + if (!signal_->isRunning_.load()) { + break; + } + uint32_t index = signal_->outIndexQueue_.front(); + if (index != EOS_INDEX && videoDec_->RenderOutputData(index) != AVCS_ERR_OK) { + cout << "Fatal: ReleaseOutputBuffer fail index" << index << endl; + break; + } + signal_->outIndexQueue_.pop(); + signal_->outSizeQueue_.pop(); + } +} +} // namespace Media +} // namespace OHOS diff --git a/test/unittest/avcodec_test/vcodec_test/vdec_mock.h b/test/unittest/avcodec_test/vcodec_test/vdec_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..1a0db37a2029745fe5125a719eb2e6f3cc15c433 --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/vdec_mock.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#ifndef VDEC_MOCK_H +#define VDEC_MOCK_H +#include +#include +#include +#include +#include +#include +#include "avcodec_mock.h" +#include "unittest_log.h" +#include "test_params_config.h" +#include "securec.h" +namespace OHOS { +namespace Media { +struct VDecSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inIndexQueue_; + std::queue outIndexQueue_; + std::queue inSizeQueue_; + std::queue outSizeQueue_; + std::queue> inBufferQueue_; + std::queue> outBufferQueue_; + std::atomic isRunning_ = false; +}; + +class VDecCallbackTest : public AVCodecCallbackMock { +public: + explicit VDecCallbackTest(std::shared_ptr signal); + virtual ~VDecCallbackTest(); + void OnError(int32_t errorCode) override; + void OnStreamChanged(std::shared_ptr format) override; + void OnNeedInputData(uint32_t index, std::shared_ptr data) override; + void OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) override; +private: + std::shared_ptr signal_ = nullptr; +}; + +class VDecMock : public NoCopyable { +public: + explicit VDecMock(std::shared_ptr signal); + virtual ~VDecMock(); + bool CreateVideoDecMockByMime(const std::string &mime); + bool CreateVideoDecMockByName(const std::string &name); + int32_t SetCallback(std::shared_ptr cb); + int32_t SetOutputSurface(std::shared_ptr surface); + int32_t Configure(std::shared_ptr format); + int32_t Prepare(); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + std::shared_ptr GetOutputMediaDescription(); + int32_t SetParameter(std::shared_ptr format); + int32_t PushInputData(uint32_t index, AVCodecBufferAttrMock &attr); + int32_t RenderOutputData(uint32_t index); + int32_t FreeOutputData(uint32_t index); + void SetSource(const std::string &path, const uint32_t es[], const uint32_t &size); +private: + void FlushInner(); + std::unique_ptr testFile_; + std::unique_ptr inputLoop_; + std::unique_ptr outputLoop_; + std::shared_ptr videoDec_ = nullptr; + std::shared_ptr signal_ = nullptr; + int32_t PushInputDataMock(uint32_t index, uint32_t bufferSize); + void InpLoopFunc(); + void OutLoopFunc(); + bool isFirstFrame_ = true; + int64_t timestamp_ = 0; + uint32_t frameCount_ = 0; + const uint32_t *es_; + uint32_t esLength_; + std::string inpPath_; +}; +} // namespace Media +} // namespace OHOS +#endif // VDEC_MOCK_H \ No newline at end of file diff --git a/test/unittest/avcodec_test/vcodec_test/venc_mock.cpp b/test/unittest/avcodec_test/vcodec_test/venc_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89ea9417b6f45b6a439c34b2ec5a5ed5b4602c36 --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/venc_mock.cpp @@ -0,0 +1,266 @@ +/* + * 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 "venc_mock.h" +#include +#include "nocopyable.h" +#include "avcodec_errors.h" +using namespace std; +using namespace OHOS::Media::VCodecTestParam; + +namespace OHOS { +namespace Media { +VEncCallbackTest::VEncCallbackTest(std::shared_ptr signal) + : signal_(signal) +{ +} + +VEncCallbackTest::~VEncCallbackTest() +{ +} + +void VEncCallbackTest::OnError(int32_t errorCode) +{ + cout << "VEnc Error errorCode=" << errorCode << endl; +} + +void VEncCallbackTest::OnStreamChanged(std::shared_ptr format) +{ + cout << "VEnc Format Changed" << endl; +} + +void VEncCallbackTest::OnNeedInputData(uint32_t index, std::shared_ptr data) +{ +} + +void VEncCallbackTest::OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) +{ + if (signal_ == nullptr) { + return; + } + unique_lock lock(signal_->outMutex_); + if (!signal_->isRunning_.load()) { + return; + } + signal_->outIndexQueue_.push(index); + signal_->outSizeQueue_.push(attr.size); + signal_->outBufferQueue_.push(data); + signal_->outCond_.notify_all(); +} + +VEncMock::VEncMock(std::shared_ptr signal) + : signal_(signal) +{ +} + +VEncMock::~VEncMock() +{ +} + +bool VEncMock::CreateVideoEncMockByMime(const std::string &mime) +{ + videoEnc_ = AVCodecMockFactory::CreateVideoEncMockByMime(mime); + return videoEnc_ != nullptr; +} + +bool VEncMock::CreateVideoEncMockByName(const std::string &name) +{ + videoEnc_ = AVCodecMockFactory::CreateVideoEncMockByName(name); + return videoEnc_ != nullptr; +} + +int32_t VEncMock::SetCallback(std::shared_ptr cb) +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->SetCallback(cb); +} + +std::shared_ptr VEncMock::GetInputSurface() +{ + if (videoEnc_ == nullptr) { + return nullptr; + } + surface_ = videoEnc_->GetInputSurface(); + return surface_; +} + +int32_t VEncMock::Configure(std::shared_ptr format) +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Configure(format); +} + +int32_t VEncMock::Prepare() +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Prepare(); +} + +int32_t VEncMock::Start() +{ + if (signal_ == nullptr || videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + signal_->isRunning_.store(true); + outLoop_ = make_unique(&VEncMock::OutLoopFunc, this); + UNITTEST_CHECK_AND_RETURN_RET_LOG(outLoop_ != nullptr, AVCS_ERR_UNKNOWN, "Fatal: No memory"); + return videoEnc_->Start(); +} + +void VEncMock::FlushInner() +{ + if (signal_ == nullptr || videoEnc_ == nullptr) { + return; + } + signal_->isRunning_.store(false); + if (outLoop_ != nullptr && outLoop_->joinable()) { + unique_lock queueLock(signal_->mutex_); + signal_->outIndexQueue_.push(10000); // push 10000 to stop queue + signal_->outCond_.notify_all(); + queueLock.unlock(); + outLoop_->join(); + outLoop_.reset(); + std::queue temp; + std::swap(temp, signal_->outIndexQueue_); + } +} + +int32_t VEncMock::Stop() +{ + FlushInner(); + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Stop(); +} + +int32_t VEncMock::Flush() +{ + FlushInner(); + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Flush(); +} + +int32_t VEncMock::Reset() +{ + FlushInner(); + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Reset(); +} + +int32_t VEncMock::Release() +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->Release(); +} + +int32_t VEncMock::NotifyEos() +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->NotifyEos(); +} + +std::shared_ptr VEncMock::GetOutputMediaDescription() +{ + if (videoEnc_ == nullptr) { + return nullptr; + } + return videoEnc_->GetOutputMediaDescription(); +} + +int32_t VEncMock::SetParameter(std::shared_ptr format) +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->SetParameter(format); +} + +int32_t VEncMock::FreeOutputData(uint32_t index) +{ + if (videoEnc_ == nullptr) { + return AVCS_ERR_INVALID_VAL; + } + return videoEnc_->FreeOutputData(index); +} + +void VEncMock::SetOutPath(const std::string &path) +{ + outPath_ = path; +} + +void VEncMock::OutLoopFunc() +{ + if (signal_ == nullptr || videoEnc_ == nullptr) { + return; + } + while (true) { + if (!signal_->isRunning_.load()) { + break; + } + + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return signal_->outIndexQueue_.size() > 0; }); + + if (!signal_->isRunning_.load()) { + break; + } + + uint32_t index = signal_->outIndexQueue_.front(); + auto buffer = signal_->outBufferQueue_.front(); + uint32_t size = signal_->outSizeQueue_.front(); + + if (buffer == nullptr) { + cout << "Fatal: GetOutputBuffer fail, exit" << endl; + break; + } + frameCount_++; + + if (NEED_DUMP) { + FILE *outFile; + const char *savepath = outPath_.c_str(); + outFile = fopen(savepath, "a"); + if (outFile == nullptr) { + cout << "dump data fail" << endl; + } else { + fwrite(buffer->GetAddr(), 1, size, outFile); + fclose(outFile); + } + } + if (index != EOS_INDEX && videoEnc_->FreeOutputData(index) != AVCS_ERR_OK) { + cout << "Fatal: FreeOutputData fail, exit" << endl; + break; + } + signal_->outIndexQueue_.pop(); + signal_->outSizeQueue_.pop(); + signal_->outBufferQueue_.pop(); + } +} +} // namespace Media +} // namespace OHOS diff --git a/test/unittest/avcodec_test/vcodec_test/venc_mock.h b/test/unittest/avcodec_test/vcodec_test/venc_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..579ef710272a590eca2d3c7223a238d9f0d1e8a4 --- /dev/null +++ b/test/unittest/avcodec_test/vcodec_test/venc_mock.h @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#ifndef VENC_MOCK_H +#define VENC_MOCK_H +#include +#include +#include +#include +#include +#include +#include "avcodec_mock.h" +#include "test_params_config.h" +#include "unittest_log.h" +#include "securec.h" +namespace OHOS { +namespace Media { +struct VEncSignal { +public: + std::mutex mutex_; + std::mutex outMutex_; + std::condition_variable outCond_; + std::queue> outBufferQueue_; + std::queue outIndexQueue_; + std::queue outSizeQueue_; + std::atomic isRunning_ = false; +}; + +class VEncCallbackTest : public AVCodecCallbackMock { +public: + explicit VEncCallbackTest(std::shared_ptr signal); + virtual ~VEncCallbackTest(); + void OnError(int32_t errorCode) override; + void OnStreamChanged(std::shared_ptr format) override; + void OnNeedInputData(uint32_t index, std::shared_ptr data) override; + void OnNewOutputData(uint32_t index, std::shared_ptr data, AVCodecBufferAttrMock attr) override; +private: + std::shared_ptr signal_; +}; + +class VEncMock : public NoCopyable { +public: + explicit VEncMock(std::shared_ptr signal); + virtual ~VEncMock(); + bool CreateVideoEncMockByMime(const std::string &mime); + bool CreateVideoEncMockByName(const std::string &name); + int32_t SetCallback(std::shared_ptr cb); + std::shared_ptr GetInputSurface(); + int32_t Configure(std::shared_ptr format); + int32_t Prepare(); + int32_t Start(); + int32_t Stop(); + int32_t Flush(); + int32_t Reset(); + int32_t Release(); + int32_t NotifyEos(); + std::shared_ptr GetOutputMediaDescription(); + int32_t SetParameter(std::shared_ptr format); + int32_t FreeOutputData(uint32_t index); + void SetOutPath(const std::string &path); + void OutLoopFunc(); +private: + void FlushInner(); + std::unique_ptr outLoop_; + std::shared_ptr videoEnc_ = nullptr; + std::shared_ptr signal_ = nullptr; + std::shared_ptr surface_ = nullptr; + uint32_t frameCount_ = 0; + std::string outPath_ = "/data/test/media/vout.es"; +}; +} // namespace Media +} // namespace OHOS +#endif // VENC_MOCK_H \ No newline at end of file diff --git a/test/unittest/avmuxer_test/BUILD.gn b/test/unittest/avmuxer_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..fb4f610f37969bc7518f32f2f18a93ad6a9b1d95 --- /dev/null +++ b/test/unittest/avmuxer_test/BUILD.gn @@ -0,0 +1,103 @@ +# 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") + +module_output_path = "av_codec" + +avmuxer_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", +] + +#################################################################################################################muxer +ohos_unittest("avmuxer_capi_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./capi", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/test/unittest/format_test", + "$av_codec_root_dir/test/unittest/format_test/capi", + ] + + cflags = avmuxer_unittest_cflags + + if (multimedia_av_codec_support_muxer) { + sources = [ + "$av_codec_root_dir/test/unittest/format_test/capi/avformat_capi_mock.cpp", + "$av_codec_root_dir/test/unittest/format_test/capi/avformat_capi_mock_factory.cpp", + "./avmuxer_sample.cpp", + "./avmuxer_unit_test.cpp", + "./capi/avmuxer_capi_mock.cpp", + "./capi/avmuxer_capi_mock_factory.cpp", + ] + } + + defines = [ "AVMUXER_UNITTEST_CAPI" ] + + deps = [ "$av_codec_root_dir/interfaces/kits/c:capi_packages" ] + external_deps = [ "av_codec:av_codec_client" ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + +#################################################################################################################muxer +ohos_unittest("avmuxer_inner_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./inner", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/test/unittest/format_test", + "$av_codec_root_dir/test/unittest/format_test/inner", + ] + + cflags = avmuxer_unittest_cflags + + if (multimedia_av_codec_support_muxer) { + sources = [ + "$av_codec_root_dir/test/unittest/format_test/inner/avformat_inner_mock.cpp", + "$av_codec_root_dir/test/unittest/format_test/inner/avformat_inner_mock_factory.cpp", + "./avmuxer_sample.cpp", + "./avmuxer_unit_test.cpp", + "./inner/avmuxer_inner_mock.cpp", + "./inner/avmuxer_inner_mock_factory.cpp", + ] + } + external_deps = [ "av_codec:av_codec_client" ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} diff --git a/test/unittest/avmuxer_test/avmuxer_mock.h b/test/unittest/avmuxer_test/avmuxer_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..71add42500f9f817765a8bec5417f1906ea556b7 --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_mock.h @@ -0,0 +1,51 @@ +/* + * 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_MOCK_H +#define AVMUXER_MOCK_H + +#include +#include "avcodec_info.h" +#include "native_averrors.h" +#include "avformat_mock.h" +#include "native_avcodec_base.h" +#include "avcodec_common.h" +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +class AVMuxerMock : public NoCopyable { +public: + virtual ~AVMuxerMock() = default; + virtual int32_t Destroy() = 0; + virtual int32_t Start() = 0; + virtual int32_t Stop() = 0; + virtual int32_t AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) = 0; + virtual int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, + const AVCodecBufferAttrMock &info) = 0; + virtual int32_t SetLocation(float latitude, float longitude) = 0; + virtual int32_t SetRotation(int32_t rotation) = 0; +}; + +class __attribute__((visibility("default"))) AVMuxerMockFactory { +public: + static std::shared_ptr CreateMuxer(int32_t fd, const OutputFormat &format); +private: + AVMuxerMockFactory() = delete; + ~AVMuxerMockFactory() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_MOCK_H \ No newline at end of file diff --git a/test/unittest/avmuxer_test/avmuxer_sample.cpp b/test/unittest/avmuxer_test/avmuxer_sample.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afe22a65821f970cebfee82771f096eada98be4f --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_sample.cpp @@ -0,0 +1,91 @@ +/* + * 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_sample.h" +#include "nocopyable.h" +using namespace std; +namespace OHOS { +namespace Media { +AVMuxerSample::AVMuxerSample() +{ +} + +AVMuxerSample::~AVMuxerSample() +{ +} + +bool AVMuxerSample::CreateMuxer(int32_t fd, const OutputFormat format) +{ + muxer_ = AVMuxerMockFactory::CreateMuxer(fd, format); + return muxer_ != nullptr; +} + +int32_t AVMuxerSample::Destroy() +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->Destroy(); +} + +int32_t AVMuxerSample::Start() +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->Start(); +} + +int32_t AVMuxerSample::Stop() +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->Stop(); +} + +int32_t AVMuxerSample::AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->AddTrack(trackIndex, trackFormat); +} + +int32_t AVMuxerSample::WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info) +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->WriteSampleBuffer(trackIndex, sampleBuffer, info); +} + +int32_t AVMuxerSample::SetLocation(float latitude, float longitude) +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->SetLocation(latitude, longitude); +} + +int32_t AVMuxerSample::SetRotation(int32_t rotation) +{ + if (muxer_ == nullptr) { + return AV_ERR_INVALID_VAL; + } + return muxer_->SetRotation(rotation); +} +} // namespace Media +} // namespace OHOS diff --git a/test/unittest/avmuxer_test/avmuxer_sample.h b/test/unittest/avmuxer_test/avmuxer_sample.h new file mode 100644 index 0000000000000000000000000000000000000000..4beb9234c8742a02aa542ded821eb77a56ef9c42 --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_sample.h @@ -0,0 +1,41 @@ +/* + * 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_SAMPLE +#define AVMUXER_SAMPLE +#include +#include "avformat_mock.h" +#include "avmuxer_mock.h" + +namespace OHOS { +namespace Media { +class AVMuxerSample : public NoCopyable { +public: + explicit AVMuxerSample(); + virtual ~AVMuxerSample(); + bool CreateMuxer(int32_t fd, const OutputFormat format); + int32_t Destroy(); + int32_t Start(); + int32_t Stop(); + int32_t AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat); + int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info); + int32_t SetLocation(float latitude, float longitude); + int32_t SetRotation(int32_t rotation); +private: + std::shared_ptr muxer_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_SAMPLE \ No newline at end of file diff --git a/test/unittest/avmuxer_test/avmuxer_unit_test.cpp b/test/unittest/avmuxer_test/avmuxer_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b9997ac897ac5d0ccf52e77326032ef29c2a687 --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_unit_test.cpp @@ -0,0 +1,1168 @@ +/* + * 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 +#include "avmuxer.h" +#include "avcodec_info.h" +#include "avmuxer_unit_test.h" +#ifdef AVMUXER_UNITTEST_CAPI +#include "native_avmuxer.h" +#include "native_avformat.h" +#endif + +using namespace testing::ext; +using namespace OHOS::Media; + +static const std::string TEST_FILE_PATH = "./"; + + +void AVMuxerUnitTest::SetUpTestCase() {} + +void AVMuxerUnitTest::TearDownTestCase() {} + +void AVMuxerUnitTest::SetUp() +{ + avmuxer_ = std::make_shared(); + avDataFile_ = std::make_shared(); + avDataFile_->open("avDataMpegMpeg4.bin", std::ios::in | std::ios::binary); + if (avDataFile_ == nullptr) { + std::cout<<"open avDataMpegMpeg4.bin failed!"<(); + vDataFile_->open("mpeg4_720_480.bin", std::ios::in | std::ios::binary); + if (vDataFile_ == nullptr) { + std::cout<<"open mpeg4_720_480.bin failed!"<close(); + avDataFile_ = nullptr; + } + + if (vDataFile_ != nullptr) { + vDataFile_->close(); + vDataFile_ = nullptr; + } + + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } + + if (avmuxer_ != nullptr) { + avmuxer_->Destroy(); + avmuxer_ = nullptr; + } +} + +/** + * @tc.name: Muxer_Create_001 + * @tc.desc: Muxer Create + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Create_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Create.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); +} + +/** + * @tc.name: Muxer_Create_002 + * @tc.desc: Muxer Create write only + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Create_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Create.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_FALSE(isCreated); +} + +/** + * @tc.name: Muxer_Create_003 + * @tc.desc: Muxer Create read only + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Create_003, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Create.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_FALSE(isCreated); +} + +/** + * @tc.name: Muxer_Create_004 + * @tc.desc: Muxer Create rand fd + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Create_004, TestSize.Level0) +{ + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(999999, outputFormat); + ASSERT_FALSE(isCreated); + + avmuxer_->Destroy(); + isCreated = avmuxer_->CreateMuxer(0xfffffff, outputFormat); + ASSERT_FALSE(isCreated); + + avmuxer_->Destroy(); + isCreated = avmuxer_->CreateMuxer(-1, outputFormat); + ASSERT_FALSE(isCreated); + + avmuxer_->Destroy(); + isCreated = avmuxer_->CreateMuxer(-999, outputFormat); + ASSERT_FALSE(isCreated); +} + +/** + * @tc.name: Muxer_Create_005 + * @tc.desc: Muxer Create outputFormat + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Create_005, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Create.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + avmuxer_->Destroy(); + outputFormat = OUTPUT_FORMAT_M4A; + isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + avmuxer_->Destroy(); + outputFormat = OUTPUT_FORMAT_DEFAULT; + isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + avmuxer_->Destroy(); + isCreated = avmuxer_->CreateMuxer(fd_, static_cast(-99)); + ASSERT_TRUE(isCreated); +} + +/** + * @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.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr audioParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); + EXPECT_GE(audioTrackId, 0); + + audioParams = FormatMockFactory::CreateFormat(); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + audioParams->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + ret = avmuxer_->AddTrack(audioTrackId, audioParams); + EXPECT_NE(ret, AV_ERR_OK); + + audioParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); + + audioParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); +} + +/** + * @tc.name: Muxer_AddTrack_002 + * @tc.desc: Muxer AddTrack add video track + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_AddTrack_002, TestSize.Level0) +{ + int32_t videoTrackId = -1; + int32_t ret = AV_ERR_INVALID_VAL; + std::string outputFile = TEST_FILE_PATH + std::string("avmuxer_AddTrack_002.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); + EXPECT_GE(videoTrackId, 0); + + videoParams = FormatMockFactory::CreateFormat(); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + videoParams->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + ret = avmuxer_->AddTrack(videoTrackId, videoParams); + EXPECT_NE(ret, AV_ERR_OK); + + videoParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); + + videoParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); +} + +/** + * @tc.name: Muxer_AddTrack_003 + * @tc.desc: Muxer AddTrack after Start() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_AddTrack_003, TestSize.Level0) +{ + int32_t audioTrackId = -1; + int32_t videoTrackId = -1; + int32_t ret = AV_ERR_INVALID_VAL; + std::string outputFile = TEST_FILE_PATH + std::string("avmuxer_AddTrack_003.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + ret = avmuxer_->AddTrack(videoTrackId, videoParams); + EXPECT_EQ(ret, AV_ERR_OK); + EXPECT_GE(videoTrackId, 0); + + avmuxer_->Start(); + std::shared_ptr audioParams = FormatMockFactory::CreateFormat(); + 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, AV_ERR_OK); +} + +/** + * @tc.name: Muxer_AddTrack_004 + * @tc.desc: Muxer AddTrack mimeType test + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_AddTrack_004, TestSize.Level0) +{ + int trackId = -1; + int ret = 0; + const std::vector testMp4MimeTypeList = + { + CodecMimeType::AUDIO_MPEG, + // CodecMimeType::AUDIO_FLAC, + // CodecMimeType::AUDIO_RAW, + CodecMimeType::AUDIO_AAC, + // CodecMimeType::AUDIO_VORBIS, + // CodecMimeType::AUDIO_OPUS, + // CodecMimeType::AUDIO_AMR_NB, + // CodecMimeType::AUDIO_AMR_WB, + CodecMimeType::VIDEO_AVC, + CodecMimeType::VIDEO_MPEG4, + CodecMimeType::IMAGE_JPG, + CodecMimeType::IMAGE_PNG, + CodecMimeType::IMAGE_BMP, + }; + + const std::vector testM4aMimeTypeList = + { + CodecMimeType::AUDIO_AAC, + CodecMimeType::VIDEO_AVC, + CodecMimeType::VIDEO_MPEG4, + CodecMimeType::IMAGE_JPG, + CodecMimeType::IMAGE_PNG, + CodecMimeType::IMAGE_BMP, + }; + + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_AddTrack.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 avParam = FormatMockFactory::CreateFormat(); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + for (uint32_t i = 0; i < testMp4MimeTypeList.size(); ++i) { + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + avParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, testMp4MimeTypeList[i]); + ret = avmuxer_->AddTrack(trackId, avParam); + EXPECT_EQ(ret, AV_ERR_OK) << "AddTrack filed: i:" << i << " mimeType:"<Destroy(); + outputFormat = OUTPUT_FORMAT_M4A; + for (uint32_t i = 0; i < testM4aMimeTypeList.size(); ++i) { + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + avParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, testM4aMimeTypeList[i]); + ret = avmuxer_->AddTrack(trackId, avParam); + EXPECT_EQ(ret, AV_ERR_OK) << "AddTrack filed: i:" << i << " mimeType:"<CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr avParam = FormatMockFactory::CreateFormat(); + avParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::AUDIO_MPEG); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, 44100); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, 2); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + avParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, avParam); + ASSERT_EQ(ret, 0); + + avParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_MPEG4); + ret = avmuxer_->AddTrack(trackId, avParam); + ASSERT_EQ(ret, 0); +} + +/** + * @tc.name: Muxer_Start_001 + * @tc.desc: Muxer Start normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Start_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Start.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + EXPECT_EQ(avmuxer_->Start(), 0); +} + +/** + * @tc.name: Muxer_Start_002 + * @tc.desc: Muxer Start twice + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Start_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Start.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + EXPECT_NE(avmuxer_->Start(), 0); +} + +/** + * @tc.name: Muxer_Start_003 + * @tc.desc: Muxer Start after Create() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Start_003, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Start.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + EXPECT_NE(avmuxer_->Start(), 0); +} + +/** + * @tc.name: Muxer_Start_004 + * @tc.desc: Muxer Start after Stop() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Start_004, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Start.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + + EXPECT_NE(avmuxer_->Start(), 0); +} + +/** + * @tc.name: Muxer_Start_005 + * @tc.desc: Muxer Start normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Start_005, TestSize.Level0) +{ + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(-1, outputFormat); + ASSERT_FALSE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_NE(ret, AV_ERR_OK); + ASSERT_LT(videoTrackId, 0); + ASSERT_NE(avmuxer_->Start(), 0); +} + +/** + * @tc.name: Muxer_Stop_001 + * @tc.desc: Muxer Stop() normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Stop.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + EXPECT_EQ(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_Stop_002 + * @tc.desc: Muxer Stop() after Create() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Stop.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + EXPECT_NE(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_Stop_003 + * @tc.desc: Muxer Stop() after AddTrack() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_003, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Stop.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + EXPECT_NE(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_Stop_004 + * @tc.desc: Muxer Stop() multiple times + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_004, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Stop.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + + ASSERT_EQ(avmuxer_->Stop(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_Stop_005 + * @tc.desc: Muxer Stop() before Start + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_005, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Stop.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + EXPECT_GE(videoTrackId, 0); + EXPECT_NE(avmuxer_->Stop(), 0); + EXPECT_EQ(avmuxer_->Start(), 0); + EXPECT_EQ(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_Stop_006 + * @tc.desc: Muxer Stop() while Create failed! + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Stop_006, TestSize.Level0) +{ + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(-1, outputFormat); + ASSERT_FALSE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_NE(ret, AV_ERR_OK); + ASSERT_LT(videoTrackId, 0); + ASSERT_NE(avmuxer_->Start(), 0); + ASSERT_NE(avmuxer_->Stop(), 0); +} + +/** + * @tc.name: Muxer_writeSample_001 + * @tc.desc: Muxer Write Sample normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_writeSample_001, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_WriteSample.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId, (uint8_t*)buffer_, info); + ASSERT_EQ(ret, 0); +} + +/** + * @tc.name: Muxer_writeSample_002 + * @tc.desc: Muxer Write Sample while Create failed! + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_writeSample_002, TestSize.Level0) +{ + int trackId = -1; + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + bool isCreated = avmuxer_->CreateMuxer(-1, outputFormat); + ASSERT_FALSE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_NE(ret, 0); + ASSERT_LT(trackId, 0); + ASSERT_NE(avmuxer_->Start(), 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_writeSample_003 + * @tc.desc: Muxer Write Sample without Start() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_writeSample_003, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_WriteSample.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_writeSample_004 + * @tc.desc: Muxer Write Sample unexisting track + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_writeSample_004, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_WriteSample.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId + 1, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); + + ret = avmuxer_->WriteSampleBuffer(-2, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); + + ret = avmuxer_->WriteSampleBuffer(99999, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_writeSample_005 + * @tc.desc: Muxer Write Sample after Stop() + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_writeSample_005, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_WriteSample.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId, (uint8_t*)buffer_, info); + ASSERT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_SetRotation_001 + * @tc.desc: Muxer SetLocation SetRotation after Create + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_001, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + + ret = avmuxer_->SetLocation(22.38, 114.05); + ASSERT_EQ(ret, 0); + + ret = avmuxer_->SetLocation(-22.38, -114.05); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_EQ(ret, 0); +} + + +/** + * @tc.name: Muxer_SetLocation_SetRotation_002 + * @tc.desc: Muxer SetLocation SetRotation after Create + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + int ret = avmuxer_->SetLocation(22.38, 114.05); + ASSERT_EQ(ret, 0); + + ret = avmuxer_->SetLocation(-22.38, -114.05); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_SetRotation_003 + * @tc.desc: Muxer SetLocation SetRotation after Start + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_003, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + + ret = avmuxer_->SetLocation(22.38, 114.05); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_SetRotation_004 + * @tc.desc: Muxer SetLocation SetRotation after Stop + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_004, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + + ret = avmuxer_->SetLocation(22.38, 114.05); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_SetRotation_005 + * @tc.desc: Muxer SetLocation SetRotation after WriteSample + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_005, TestSize.Level0) +{ + int trackId = -1; + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr vParam = FormatMockFactory::CreateFormat(); + vParam->PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, CodecMimeType::VIDEO_AVC); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 352); + vParam->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 288); + + int ret = avmuxer_->AddTrack(trackId, vParam); + ASSERT_EQ(ret, 0); + ASSERT_GE(trackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + + AVCodecBufferAttrMock info; + info.pts = 0; + info.size = sizeof(buffer_); + ret = avmuxer_->WriteSampleBuffer(trackId, (uint8_t*)buffer_, info); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetLocation(22.38, 114.05); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_SetRotation_006 + * @tc.desc: Muxer SetLocation SetRotation while Create failed! + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_SetRotation_006, TestSize.Level0) +{ + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + bool isCreated = avmuxer_->CreateMuxer(-1, outputFormat); + ASSERT_FALSE(isCreated); + + int ret = avmuxer_->SetLocation(22.38, 114.05); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetLocation(-22.38, -114.05); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetRotation(90); + ASSERT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetRotation_001 + * @tc.desc: Muxer SetRotation expected value + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetRotation_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + int ret = avmuxer_->SetRotation(0); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetRotation(90); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetRotation(180); + EXPECT_EQ(ret, 0); + + ret = avmuxer_->SetRotation(270); + EXPECT_EQ(ret, 0); +} + +/** + * @tc.name: Muxer_SetRotation_002 + * @tc.desc: Muxer SetRotation unexpected value + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetRotation_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetRotation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + int ret = avmuxer_->SetRotation(1); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(91); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(360); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(-1); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(-90); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(-180); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(-270); + EXPECT_NE(ret, 0); + + ret = avmuxer_->SetRotation(-360); + EXPECT_NE(ret, 0); +} + +/** + * @tc.name: Muxer_SetLocation_001 + * @tc.desc: Muxer SetLocation unexpected value + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_SetLocation_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_SetLocation.mp4"); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + int ret = avmuxer_->SetLocation(90.1, 50); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetLocation(-90.1, 50); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetLocation(50, 180.1); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetLocation(50, -180.1); + ASSERT_NE(ret, 0); + + ret = avmuxer_->SetLocation(90, 180); + ASSERT_EQ(ret, 0); + + ret = avmuxer_->SetLocation(-90, -180); + ASSERT_EQ(ret, 0); +} + +#ifdef AVMUXER_UNITTEST_CAPI +/** + * @tc.name: Muxer_Destroy_001 + * @tc.desc: Muxer Destroy normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Destroy_001, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Destro.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + bool isCreated = avmuxer_->CreateMuxer(fd_, outputFormat); + ASSERT_TRUE(isCreated); + + std::shared_ptr videoParams = FormatMockFactory::CreateFormat(); + 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_, sizeof(buffer_)); + int32_t videoTrackId = -1; + int32_t ret = avmuxer_->AddTrack(videoTrackId, videoParams); + ASSERT_EQ(ret, AV_ERR_OK); + ASSERT_GE(videoTrackId, 0); + ASSERT_EQ(avmuxer_->Start(), 0); + ASSERT_EQ(avmuxer_->Stop(), 0); + ASSERT_EQ(avmuxer_->Destroy(), 0); +} + +/** + * @tc.name: Muxer_Destroy_002 + * @tc.desc: Muxer Destroy normal + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Destroy_002, TestSize.Level0) +{ + std::string outputFile = TEST_FILE_PATH + std::string("Muxer_Destroy.mp4"); + fd_ = open(outputFile.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + OutputFormat outputFormat = OUTPUT_FORMAT_MPEG_4; + OH_AVMuxer *muxer = OH_AVMuxer_Create(fd_, static_cast(outputFormat)); + int ret = OH_AVMuxer_Destroy(muxer); + ASSERT_EQ(ret, 0); + muxer = nullptr; +} + +/** + * @tc.name: Muxer_Destroy_003 + * @tc.desc: Muxer Destroy nullptr + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Destroy_003, TestSize.Level0) +{ + int ret = OH_AVMuxer_Destroy(nullptr); + ASSERT_EQ(ret, AV_ERR_INVALID_VAL); +} + +/** + * @tc.name: Muxer_Destroy_004 + * @tc.desc: Muxer Destroy other class + * @tc.type: FUNC + */ +HWTEST_F(AVMuxerUnitTest, Muxer_Destroy_004, TestSize.Level0) +{ + OH_AVFormat *format = OH_AVFormat_Create(); + int ret = OH_AVMuxer_Destroy((OH_AVMuxer *)format); + ASSERT_EQ(ret, AV_ERR_INVALID_VAL); + OH_AVFormat_Destroy(format); +} +#endif // AVMUXER_UNITTEST_CAPI \ No newline at end of file diff --git a/test/unittest/avmuxer_test/avmuxer_unit_test.h b/test/unittest/avmuxer_test/avmuxer_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..c4bab5339e3464a1ebf39ce0c461209b74932017 --- /dev/null +++ b/test/unittest/avmuxer_test/avmuxer_unit_test.h @@ -0,0 +1,44 @@ +/* + * 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_UNIT_TEST_H +#define AVMUXER_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "avmuxer_sample.h" + +namespace OHOS { +namespace Media { +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: + std::shared_ptr avmuxer_ {nullptr}; + int32_t fd_ {-1}; + std::shared_ptr avDataFile_ {nullptr}; + std::shared_ptr vDataFile_ {nullptr}; + uint8_t buffer_[10] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.cpp b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..efab500a0124657e0711abb451d2736b17cd7fcb --- /dev/null +++ b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.cpp @@ -0,0 +1,67 @@ +/* + * 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_capi_mock.h" + +namespace OHOS { +namespace Media { +int32_t AVMuxerCapiMock::Destroy() +{ + int ret = OH_AVMuxer_Destroy(muxer_); + if (ret != AV_ERR_OK) { + return ret; + } + muxer_ = nullptr; + return AV_ERR_OK; +} + +int32_t AVMuxerCapiMock::Start() +{ + return OH_AVMuxer_Start(muxer_); +} + +int32_t AVMuxerCapiMock::Stop() +{ + return OH_AVMuxer_Stop(muxer_); +} + +int32_t AVMuxerCapiMock::AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) +{ + auto formatMock = std::static_pointer_cast(trackFormat); + return OH_AVMuxer_AddTrack(muxer_, &trackIndex, formatMock->GetFormat()); +} + +int32_t AVMuxerCapiMock::WriteSampleBuffer(uint32_t trackIndex, + uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info) +{ + OH_AVCodecBufferAttr bufferAttr; + bufferAttr.pts = info.pts; + bufferAttr.size = info.size; + bufferAttr.offset = info.offset; + bufferAttr.flags = info.flags; + return OH_AVMuxer_WriteSampleBuffer(muxer_, trackIndex, sampleBuffer, bufferAttr); +} + +int32_t AVMuxerCapiMock::SetLocation(float latitude, float longitude) +{ + return OH_AVMuxer_SetLocation(muxer_, latitude, longitude); +} + +int32_t AVMuxerCapiMock::SetRotation(int32_t rotation) +{ + return OH_AVMuxer_SetRotation(muxer_, rotation); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.h b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..b15391f4b9299316917d6916c87e12bd1423e741 --- /dev/null +++ b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock.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_CAPI_MOCK_H +#define AVMUXER_CAPI_MOCK_H + +#include "avmuxer_mock.h" +#include "avformat_capi_mock.h" +#include "avcodec_common.h" +#include "native_avmuxer.h" + +namespace OHOS { +namespace Media { +class AVMuxerCapiMock : public AVMuxerMock { +public: + explicit AVMuxerCapiMock(OH_AVMuxer *muxer) : muxer_(muxer) {} + ~AVMuxerCapiMock() = default; + int32_t Destroy() override; + int32_t Start() override; + int32_t Stop() override; + int32_t AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) override; + int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info) override; + int32_t SetLocation(float latitude, float longitude) override; + int32_t SetRotation(int32_t rotation) override; +private: + OH_AVMuxer *muxer_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVMUXER_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/avmuxer_test/capi/avmuxer_capi_mock_factory.cpp b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2800095ffdea141361e8a80f2074176dde7bfc2 --- /dev/null +++ b/test/unittest/avmuxer_test/capi/avmuxer_capi_mock_factory.cpp @@ -0,0 +1,30 @@ +/* + * 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_mock.h" +#include "avmuxer_capi_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr AVMuxerMockFactory::CreateMuxer(int32_t fd, const OutputFormat &format) +{ + OH_AVMuxer *muxer = OH_AVMuxer_Create(fd, static_cast(format)); + if (muxer != nullptr) { + return std::make_shared(muxer); + } + return nullptr; +} +} +} \ No newline at end of file diff --git a/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.cpp b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f804e8b02802375fbbd16575e579024220e727f --- /dev/null +++ b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.cpp @@ -0,0 +1,84 @@ +/* + * 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_inner_mock.h" + +namespace OHOS { +namespace Media { +int32_t AVMuxerInnerMock::Destroy() +{ + if (muxer_ != nullptr) { + muxer_ = nullptr; + return AV_ERR_OK; + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::Start() +{ + if (muxer_ != nullptr) { + return muxer_->Start(); + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::Stop() +{ + if (muxer_ != nullptr) { + return muxer_->Stop(); + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) +{ + if (muxer_ != nullptr) { + auto formatMock = std::static_pointer_cast(trackFormat); + return muxer_->AddTrack(trackIndex, static_cast(formatMock->GetFormat())); + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::WriteSampleBuffer(uint32_t trackIndex, + uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info) +{ + if (muxer_ != nullptr) { + TrackSampleInfo sampleInfo; + sampleInfo.trackIndex = trackIndex; + sampleInfo.timeUs = info.pts; + sampleInfo.size = info.size; + sampleInfo.flags = info.flags; + return muxer_->WriteSampleBuffer(sampleBuffer, sampleInfo); + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::SetLocation(float latitude, float longitude) +{ + if (muxer_ != nullptr) { + return muxer_->SetLocation(latitude, longitude); + } + return AV_ERR_UNKNOWN; +} + +int32_t AVMuxerInnerMock::SetRotation(int32_t rotation) +{ + if (muxer_ != nullptr) { + return muxer_->SetRotation(rotation); + } + return AV_ERR_UNKNOWN; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.h b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..068ec8ca8e312a690b99acacd4cdacba08615909 --- /dev/null +++ b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock.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 MUXER_INNER_MOCK_H +#define MUXER_INNER_MOCK_H + +#include "avmuxer_mock.h" +#include "avformat_inner_mock.h" +#include "avcodec_common.h" +#include "avmuxer.h" + +namespace OHOS { +namespace Media { +class AVMuxerInnerMock : public AVMuxerMock { +public: + explicit AVMuxerInnerMock(std::shared_ptr muxer) : muxer_(muxer) {} + ~AVMuxerInnerMock() = default; + int32_t Destroy() override; + int32_t Start() override; + int32_t Stop() override; + int32_t AddTrack(int32_t &trackIndex, std::shared_ptr &trackFormat) override; + int32_t WriteSampleBuffer(uint32_t trackIndex, uint8_t *sampleBuffer, const AVCodecBufferAttrMock &info) override; + int32_t SetLocation(float latitude, float longitude) override; + int32_t SetRotation(int32_t rotation) override; +private: + std::shared_ptr muxer_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // MUXER_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/avmuxer_test/inner/avmuxer_inner_mock_factory.cpp b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b454ff7bbed4ad90e5d14b1a2ade71ce62d8c45 --- /dev/null +++ b/test/unittest/avmuxer_test/inner/avmuxer_inner_mock_factory.cpp @@ -0,0 +1,30 @@ +/* + * 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_mock.h" +#include "avmuxer_inner_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr AVMuxerMockFactory::CreateMuxer(int32_t fd, const OutputFormat &format) +{ + auto muxer = AVMuxerFactory::CreateAVMuxer(fd, format); + if (muxer != nullptr) { + return std::make_shared(muxer); + } + return nullptr; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/codeclist_test/BUILD.gn b/test/unittest/codeclist_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..79e7f0d428cdf94db04344911252b0313588930d --- /dev/null +++ b/test/unittest/codeclist_test/BUILD.gn @@ -0,0 +1,107 @@ +# 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") + +module_output_path = "av_codec" + +codeclist_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", +] + +#################################################################################################################codeclist +ohos_unittest("codeclist_capi_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./capi", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/test/unittest/common/include", + "$av_codec_root_dir/test/unittest/format_test", + "$av_codec_root_dir/test/unittest/format_test/capi", + ] + + cflags = codeclist_unittest_cflags + + if (multimedia_av_codec_support_codeclist) { + sources = [ + "$av_codec_root_dir/test/unittest/format_test/capi/avformat_capi_mock.cpp", + "$av_codec_root_dir/test/unittest/format_test/capi/avformat_capi_mock_factory.cpp", + "./capi/codeclist_capi_mock.cpp", + "./capi/codeclist_capi_mock_factory.cpp", + "./codeclist_unit_test.cpp", + ] + } + deps = [ + "$av_codec_root_dir/interfaces/kits/c:capi_packages" , + ] + external_deps = [ + "av_codec:av_codec_client" + ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + +#################################################################################################################codeclist +ohos_unittest("codeclist_inner_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./codeclist_test", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + "$av_codec_root_dir/test/unittest/common/include", + "$av_codec_root_dir/test/unittest/format_test", + "$av_codec_root_dir/test/unittest/format_test/inner", + ] + + cflags = codeclist_unittest_cflags + + if (multimedia_av_codec_support_codeclist) { + sources = [ + "$av_codec_root_dir/test/unittest/format_test/inner/avformat_inner_mock.cpp", + "$av_codec_root_dir/test/unittest/format_test/inner/avformat_inner_mock_factory.cpp", + "./codeclist_unit_test.cpp", + "./inner/codeclist_inner_mock.cpp", + "./inner/codeclist_inner_mock_factory.cpp", + ] + } + + external_deps = [ + "av_codec:av_codec_client" + ] + + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} diff --git a/test/unittest/codeclist_test/capi/codeclist_capi_mock.cpp b/test/unittest/codeclist_test/capi/codeclist_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76997fa70a3754bc8f0e4830e0d13806d1696178 --- /dev/null +++ b/test/unittest/codeclist_test/capi/codeclist_capi_mock.cpp @@ -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. + */ + +#include "codeclist_capi_mock.h" +#include "native_avcodec_list.h" + +namespace OHOS { +namespace Media { +std::string CodecListCapiMock::FindDecoder(std::shared_ptr &format) +{ + auto formatMock = std::static_pointer_cast(format); + std::string codecName = OH_AVCodec_FindDecoder(formatMock->GetFormat()); + return codecName; +} + +std::string CodecListCapiMock::FindEncoder(std::shared_ptr &format) +{ + auto formatMock = std::static_pointer_cast(format); + std::string codecName = OH_AVCodec_FindEncoder(formatMock->GetFormat()); + return codecName; +} + +CapabilityData CodecListCapiMock::CreateCapability(const std::string codecName) +{ + // 接口还在评审: *OH_AVCodec_CreateCapability(codecName.c_str()); + CapabilityData capability; + return capability; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/codeclist_test/capi/codeclist_capi_mock.h b/test/unittest/codeclist_test/capi/codeclist_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..784e9a7eb6853dd887fa117c09773e8109f181f6 --- /dev/null +++ b/test/unittest/codeclist_test/capi/codeclist_capi_mock.h @@ -0,0 +1,36 @@ +/* + * 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 CODECLIST_CAPI_MOCK_H +#define CODECLIST_CAPI_MOCK_H + +#include "codeclist_mock.h" +#include "avformat_capi_mock.h" +#include "avcodec_common.h" +#include "avcodec_list.h" + +namespace OHOS { +namespace Media { +class CodecListCapiMock : public CodecListMock { +public: + explicit CodecListCapiMock() = default; + ~CodecListCapiMock() = default; + std::string FindDecoder(std::shared_ptr &format) override; + std::string FindEncoder(std::shared_ptr &format) override; + CapabilityData CreateCapability(const std::string codecName) override; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/codeclist_test/capi/codeclist_capi_mock_factory.cpp b/test/unittest/codeclist_test/capi/codeclist_capi_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63ea3bbe253e8105ee2b3bc65807a2343d1af7f2 --- /dev/null +++ b/test/unittest/codeclist_test/capi/codeclist_capi_mock_factory.cpp @@ -0,0 +1,29 @@ +/* + * 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 "codeclist_capi_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr CodecListMockFactory::CreateCodecList() +{ + auto codeclist = std::make_shared(); + if (codeclist != nullptr) { + return codeclist; + } + return nullptr; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/codeclist_test/codeclist_mock.h b/test/unittest/codeclist_test/codeclist_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..ab23198a4c08af630a3f129aae3f46fcaa10637b --- /dev/null +++ b/test/unittest/codeclist_test/codeclist_mock.h @@ -0,0 +1,48 @@ +/* + * 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 CODECLIST_MOCK_H +#define CODECLIST_MOCK_H + +#include +#include "avcodec_list.h" +#include "avcodec_info.h" +#include "native_averrors.h" +#include "avformat_mock.h" +#include "native_avcodec_base.h" +#include "avcodec_common.h" +#include "nocopyable.h" +#include "avformat_mock.h" + +namespace OHOS { +namespace Media { +class CodecListMock : public NoCopyable { +public: + virtual ~CodecListMock() = default; + virtual std::string FindDecoder(std::shared_ptr &format) = 0; + virtual std::string FindEncoder(std::shared_ptr &format) = 0; + virtual CapabilityData CreateCapability(const std::string codecName) = 0; +}; + +class __attribute__((visibility("default"))) CodecListMockFactory { +public: + static std::shared_ptr CreateCodecList(); +private: + CodecListMockFactory() = delete; + ~CodecListMockFactory() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_MOCK_H \ No newline at end of file diff --git a/test/unittest/codeclist_test/codeclist_unit_test.cpp b/test/unittest/codeclist_test/codeclist_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..56fcdbba48f84ff9bcf161bc6534f27001a9e4c1 --- /dev/null +++ b/test/unittest/codeclist_test/codeclist_unit_test.cpp @@ -0,0 +1,318 @@ +/* + * 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 "codeclist_unit_test.h" +#include +#include +#include +#include +#include +#include +#include "test_params_config.h" + + +using namespace testing::ext; +using namespace OHOS::Media; +using namespace OHOS::Media::CodecListTestParam; + +template +void ReleaseCodec(vector &codecLst) +{ + uint32_t ret; + for (auto &codec : codecLst) { + if (codec != nullptr) { + ret = codec->Destroy(); + EXPECT_EQ(AV_ERR_OK, ret); + codec = nullptr; + } + } + codecLst.swap(vector()); +} + +void CodecListUnitTest::SetUpTestCase() {} + +void CodecListUnitTest::TearDownTestCase() {} + +void CodecListUnitTest::SetUp() +{ + codeclist_ = CodecListMockFactory::CreateCodecList(); + EXPECT_NE(codeclist_, nullptr); +} + +void CodecListUnitTest::TearDown() {} + +/** + * @tc.name: CodecList_FindVideoDecoder_001 + * @tc.desc: CodecList FindVideoDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindVideoDecoder_001, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::VIDEO_AVC); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, DEFAULT_WIDTH); + (void)format->PutIntValue(heightKey_, DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormatKey_, VideoPixelFormat::NV12); + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("video_decoder.avc", codecName); +} + +/** + * @tc.name: CodecList_FindVideoDecoder_002 + * @tc.desc: CodecList FindVideoDecoder, Negative PixelFormat + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindVideoDecoder_002, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::VIDEO_AVC); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, DEFAULT_WIDTH); + (void)format->PutIntValue(heightKey_, DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormatKey_, VideoPixelFormat::SURFACE_FORMAT); // Negative parameters + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("", codecName); +} + +/** + * @tc.name: CodecList_FindVideoDecoder_003 + * @tc.desc: CodecList FindVideoDecoder, Negative Width + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindVideoDecoder_003, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::VIDEO_AVC); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, 15361); + (void)format->PutIntValue(heightKey_, DEFAULT_HEIGHT); + (void)format->PutIntValue(pixelFormatKey_, VideoPixelFormat::SURFACE_FORMAT); // Negative parameters + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("", codecName); +} + +/** + * @tc.name: CodecList_FindVideoDecoder_004 + * @tc.desc: CodecList FindVideoDecoder, Negative Height + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindVideoDecoder_004, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::VIDEO_AVC); + (void)format->PutIntValue(bitrateKey_, MAX_VIDEO_BITRATE); + (void)format->PutIntValue(widthKey_, DEFAULT_WIDTH); + (void)format->PutIntValue(heightKey_, 31); + (void)format->PutIntValue(pixelFormatKey_, VideoPixelFormat::SURFACE_FORMAT); // Negative parameters + (void)format->PutIntValue(frameRateKey_, MAX_FRAME_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_001 + * @tc.desc: CodecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_001, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_MPEG); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("avdec_mp3", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_002 + * @tc.desc: CodecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_002, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_AAC); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("avdec_aac", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_003 + * @tc.desc: CodecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_003, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_VORBIS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("avdec_vorbis", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_004 + * @tc.desc: CodecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_004, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_FLAC); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("avdec_flac", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_005 + * @tc.desc: CodecList FindAudioDecoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_005, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_OPUS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, 48000); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("avdec_opus", codecName); +} + +/** + * @tc.name: CodecList_FindAudioDecoder_006 + * @tc.desc: CodecList FindAudioDecoder, Negative ChannelCount + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioDecoder_006, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_OPUS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT + 1); // Negative parameters + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindDecoder(format); + EXPECT_EQ("", codecName); +} + +/** + * @tc.name: CodecList_FindAudioEncoder_001 + * @tc.desc: CodecList FindAudioEncoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioEncoder_001, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_AAC); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); + codecName = codeclist_->FindEncoder(format); + EXPECT_EQ("avenc_aac", codecName); +} + +/** + * @tc.name: CodecList_FindAudioEncoder_002 + * @tc.desc: CodecList FindAudioEncoder + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioEncoder_002, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_OPUS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, 48000); + codecName = codeclist_->FindEncoder(format); + EXPECT_EQ("avenc_opus", codecName); +} + +/** + * @tc.name: CodecList_FindAudioEncoder_003 + * @tc.desc: CodecList FindAudioEncoder, Negative SampleRate + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioEncoder_003, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_OPUS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE); + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, DEFAULT_SAMPLE_RATE); // Negative parameters + codecName = codeclist_->FindEncoder(format); + EXPECT_EQ("", codecName); +} + +/** + * @tc.name: CodecList_FindAudioEncoder_004 + * @tc.desc: CodecList FindAudioEncoder, Negative Bitrate + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(CodecListUnitTest, CodecList_FindAudioEncoder_004, TestSize.Level0) +{ + std::string codecName; + std::shared_ptr format = FormatMockFactory::CreateFormat(); + (void)format->PutStringValue(codecMimeKey_, CodecMimeType::AUDIO_OPUS); + (void)format->PutIntValue(bitrateKey_, MAX_AUDIO_BITRATE + 1); // Negative parameters + (void)format->PutIntValue(channelCountKey_, MAX_CHANNEL_COUNT); + (void)format->PutIntValue(sampleRateKey_, 48000); + codecName = codeclist_->FindEncoder(format); + EXPECT_EQ("", codecName); +} diff --git a/test/unittest/codeclist_test/codeclist_unit_test.h b/test/unittest/codeclist_test/codeclist_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..a5b55f5ba453f973455d145b5b7c8fb34be2c62c --- /dev/null +++ b/test/unittest/codeclist_test/codeclist_unit_test.h @@ -0,0 +1,52 @@ +/* + * 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 CODECLIST_UNIT_TEST_H +#define CODECLIST_UNIT_TEST_H + +#include +#include "gtest/gtest.h" +#include "avcodec_info.h" +#include "codeclist_mock.h" +#include "media_description.h" + +namespace OHOS { +namespace Media { +class CodecListUnitTest : 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: + std::string codecMimeKey_ {MediaDescriptionKey::MD_KEY_CODEC_MIME}; + std::string bitrateKey_ {MediaDescriptionKey::MD_KEY_BITRATE}; + std::string widthKey_ {MediaDescriptionKey::MD_KEY_WIDTH}; + std::string heightKey_ {MediaDescriptionKey::MD_KEY_HEIGHT}; + std::string pixelFormatKey_ {MediaDescriptionKey::MD_KEY_PIXEL_FORMAT}; + std::string frameRateKey_ {MediaDescriptionKey::MD_KEY_FRAME_RATE}; + std::string channelCountKey_ {MediaDescriptionKey::MD_KEY_CHANNEL_COUNT}; + std::string sampleRateKey_ {"samplerate"}; // MediaDescriptionKey::MD_KEY_SAMPLE_RATE + std::string bitDepthKey_ {MediaDescriptionKey::MD_KEY_SAMPLE_RATE}; + std::shared_ptr codeclist_ {nullptr}; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/codeclist_test/inner/codeclist_inner_mock.cpp b/test/unittest/codeclist_test/inner/codeclist_inner_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5284aa8ab4cd934da09f1ef10f3ac0e4a58d4f0 --- /dev/null +++ b/test/unittest/codeclist_test/inner/codeclist_inner_mock.cpp @@ -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. + */ + +#include "codeclist_inner_mock.h" + +namespace OHOS { +namespace Media { +std::string CodecListInnerMock::FindDecoder(std::shared_ptr &format) +{ + if (codeclist_ != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return codeclist_->FindDecoder(formatMock->GetFormat()); + } + return ""; +} + +std::string CodecListInnerMock::FindEncoder(std::shared_ptr &format) +{ + if (codeclist_ != nullptr) { + auto formatMock = std::static_pointer_cast(format); + return codeclist_->FindEncoder(formatMock->GetFormat()); + } + return ""; +} + +CapabilityData CodecListInnerMock::CreateCapability(const std::string codecName) +{ + CapabilityData capabilityData; + if (codeclist_ != nullptr) { + return codeclist_->CreateCapability(codecName); + } + return capabilityData; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/codeclist_test/inner/codeclist_inner_mock.h b/test/unittest/codeclist_test/inner/codeclist_inner_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..3e1c136607e23ae8d2e8bfc6777fa31a8ee6e1bd --- /dev/null +++ b/test/unittest/codeclist_test/inner/codeclist_inner_mock.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 CODECLIST_INNER_MOCK_H +#define CODECLIST_INNER_MOCK_H + +#include "codeclist_mock.h" +#include "avformat_inner_mock.h" +#include "avcodec_common.h" +#include "avcodec_list.h" + +namespace OHOS { +namespace Media { +class CodecListInnerMock : public CodecListMock { +public: + explicit CodecListInnerMock(std::shared_ptr codeclist) : codeclist_(codeclist) {} + ~CodecListInnerMock() = default; + std::string FindDecoder(std::shared_ptr &format) override; + std::string FindEncoder(std::shared_ptr &format) override; + CapabilityData CreateCapability(const std::string codecName) override; +private: + std::shared_ptr codeclist_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // CODECLIST_INNER_MOCK_H \ No newline at end of file diff --git a/test/unittest/codeclist_test/inner/codeclist_inner_mock_factory.cpp b/test/unittest/codeclist_test/inner/codeclist_inner_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cecc8f75e4e9b2185415e807b532006001fecc68 --- /dev/null +++ b/test/unittest/codeclist_test/inner/codeclist_inner_mock_factory.cpp @@ -0,0 +1,29 @@ +/* + * 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 "codeclist_inner_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr CodecListMockFactory::CreateCodecList() +{ + auto codeclist = AVCodecListFactory::CreateAVCodecList(); + if (codeclist != nullptr) { + return std::make_shared(codeclist); + } + return nullptr; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/common/include/test_params_config.h b/test/unittest/common/include/test_params_config.h new file mode 100644 index 0000000000000000000000000000000000000000..28653a8132436816a6fe9328a8da27e24c253f9e --- /dev/null +++ b/test/unittest/common/include/test_params_config.h @@ -0,0 +1,206 @@ +/* + * 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. + */ + +#ifndef TEST_PARAMS_CONFIG_H +#define TEST_PARAMS_CONFIG_H + +#include +#include +#include "av_common.h" + +namespace OHOS { +namespace Media { +namespace VCodecTestParam { +constexpr uint32_t DEFAULT_WIDTH = 320; +constexpr uint32_t DEFAULT_HEIGHT = 240; +constexpr uint32_t DEFAULT_FRAME_RATE = 60; +constexpr uint32_t FRAME_DURATION_US = 16670; +constexpr uint32_t EOS_INDEX = 1000; +const std::string MIME_TYPE = "video/mp4v-es"; +constexpr bool NEED_DUMP = true; +const uint32_t ES_H264[] = { // H264_FRAME_SIZE_240 + 2106, 11465, 321, 72, 472, 68, 76, 79, 509, 90, 677, 88, 956, 99, 347, 77, 452, 681, 81, 1263, 94, 106, 97, + 998, 97, 797, 93, 1343, 150, 116, 117, 926, 1198, 128, 110, 78, 1582, 158, 135, 112, 1588, 165, 132, + 128, 1697, 168, 149, 117, 1938, 170, 141, 142, 1830, 106, 161, 122, 1623, 160, 154, 156, 1998, 230, + 177, 139, 1650, 186, 128, 134, 1214, 122, 1411, 120, 1184, 128, 1591, 195, 145, 105, 1587, 169, 140, + 118, 1952, 177, 150, 161, 1437, 159, 123, 1758, 180, 165, 144, 1936, 214, 191, 175, 2122, 180, 179, + 160, 1927, 161, 184, 119, 1973, 218, 210, 129, 1962, 196, 127, 154, 2308, 173, 127, 1572, 142, 122, + 2065, 262, 159, 206, 2251, 269, 179, 170, 2056, 308, 168, 191, 2090, 303, 191, 110, 1932, 272, 162, + 122, 1877, 245, 167, 141, 1908, 294, 162, 118, 1493, 132, 1782, 273, 184, 133, 1958, 274, 180, 149, + 2070, 216, 169, 143, 1882, 224, 149, 139, 1749, 277, 184, 139, 2141, 197, 170, 140, 2002, 269, 162, + 140, 1862, 202, 179, 131, 1868, 214, 164, 140, 1546, 226, 150, 130, 1707, 162, 146, 1824, 181, 147, + 130, 1898, 209, 143, 131, 1805, 180, 148, 106, 1776, 147, 141, 1572, 177, 130, 105, 1776, 178, 144, + 122, 1557, 142, 124, 114, 1436, 143, 126, 1326, 127, 1755, 169, 127, 105, 1807, 177, 131, 134, 1613, + 187, 137, 136, 1314, 134, 118, 2005, 194, 129, 147, 1566, 185, 132, 131, 1236, 174, 137, 106, 11049, + 574, 126, 1242, 188, 130, 119, 1450, 187, 137, 141, 1116, 124, 1848, 138, 122, 1605, 186, 127, 140, + 1798, 170, 124, 121, 1666, 157, 128, 130, 1678, 135, 118, 1804, 169, 135, 125, 1837, 168, 124, 124, + 2049, 180, 122, 128, 1334, 143, 128, 1379, 116, 1884, 149, 122, 150, 1962, 176, 122, 122, 1197, 139, + 1853, 184, 151, 148, 1692, 209, 129, 126, 1736, 149, 135, 104, 1775, 165, 160, 121, 1653, 163, 123, + 112, 1907, 181, 129, 107, 1808, 177, 125, 111, 2405, 166, 144, 114, 1833, 198, 136, 113, 1960, 206, + 139, 116, 1791, 175, 130, 129, 1909, 194, 138, 119, 1807, 160, 156, 124, 1998, 184, 173, 114, 2069, 181, + 127, 139, 2212, 182, 138, 146, 1993, 214, 135, 139, 2286, 194, 137, 120, 2090, 196, 159, 132, 2294, 194, + 148, 137, 2312, 183, 163, 106, 2118, 201, 158, 127, 2291, 187, 144, 116, 2413, 139, 115, 2148, 178, 122, + 103, 2370, 207, 161, 117, 2291, 213, 159, 129, 2244, 243, 157, 133, 2418, 255, 171, 127, 2316, 185, 160, + 132, 2405, 220, 165, 155, 2539, 219, 172, 128, 2433, 199, 154, 119, 1681, 140, 1960, 143, 2682, 202, 153, + 127, 2794, 239, 158, 155, 2643, 229, 172, 125, 2526, 201, 181, 159, 2554, 233, 167, 125, 2809, 205, 164, + 117, 2707, 221, 156, 138, 2922, 240, 160, 146, 2952, 267, 177, 149, 3339, 271, 175, 136, 3006, 242, 168, + 141, 3068, 232, 194, 149, 2760, 214, 208, 143, 2811, 218, 184, 149, 137, 15486, 2116, 235, 167, 157, 2894, + 305, 184, 139, 3090, 345, 179, 155, 3226, 347, 160, 164, 3275, 321, 184, 174, 3240, 269, 166, 170, 3773, + 265, 169, 155, 3023, 301, 188, 161, 3343, 275, 174, 155, 3526, 309, 177, 173, 3546, 307, 183, 149, 3648, + 295, 213, 170, 3568, 305, 198, 166, 3641, 297, 172, 148, 3608, 301, 200, 159, 3693, 322, 209, 166, 3453, + 318, 206, 162, 3696, 341, 200, 176, 3386, 320, 192, 176, 3903, 373, 207, 187, 3305, 361, 200, 202, 3110, + 367, 220, 197, 2357, 332, 196, 201, 1827, 377, 187, 199, 860, 472, 173, 223, 238}; +constexpr uint32_t ES_LENGTH_H264 = sizeof(ES_H264) / sizeof(uint32_t); +const std::string H264_SRC_PATH = "/data/test/media/out_320_240_10s.h264"; + +const uint32_t ES_H265[] = {9900, 203, 57, 56, 51, 147, 57, 334, 42, 59, 66, 394, 66, 325, 58, 513, + 64, 52, 647, 43, 39, 40, 55, 608, 63, 55, 788, 52, 56, 53, 621, 57, 75, 65, 56, 737, 82, 40, 42, 69, 675}; +constexpr uint32_t ES_LENGTH_H265 = sizeof(ES_H264) / sizeof(uint32_t); +const std::string H265_SRC_PATH = "/data/test/media/hevc_320x240_60.h265"; + +const uint32_t ES_MPEG2[] = { + 38462, 55096, 8660, 3417, 1197, 2209, 984, 718, 783, 623, 659, 694, 14174, 580, 421, 495, 480, 476, 534, + 660, 699, 601, 603, 720, 12585, 555, 532, 776, 789, 762, 766, 732, 671, 735, 777, 948, 12650, 827, 766, + 835, 747, 847, 940, 1121, 1092, 1001, 980, 989, 12746, 945, 912, 1046, 1118, 1134, 1050, 1073, 1051, 1195, + 1085, 1182, 12874, 992, 1007, 985, 1040, 1143, 1157, 1150, 1247, 1149, 1246, 1145, 12870, 1041, 1066, 1314, + 1239, 1283, 1223, 1224, 1270, 1427, 1406, 1516, 12949, 1228, 1299, 1439, 1358, 1455, 1311, 1396, 1416, 1470, + 1393, 1502, 12999, 1232, 1400, 1348, 1335, 1461, 1404, 1412, 1426, 1548, 1481, 1488, 12840, 1229, 1342, 1323, + 1353, 1524, 1363, 1475, 1540, 1495, 1489, 1438, 12762, 1291, 1303, 1470, 1494, 1488, 1474, 1453, 1607, 1485, + 1589, 1762, 12548, 1363, 1317, 1435, 1411, 1338, 1373, 1605, 1639, 1429, 1392, 1543, 12332, 1255, 1200, 1291, + 1337, 1341, 1356, 1214, 1456, 1353, 1314, 1502, 12151, 1192, 1290, 1203, 1284, 1154, 1264, 1358, 1390, 1433, + 1194, 1325, 11904, 993, 1007, 1149, 1099, 1182, 1076, 1074, 1092, 1030, 1272, 1178, 11710, 966, 879, 860, 955, + 898, 967, 927, 1066, 997, 1083, 940, 11717, 648, 705, 901, 925, 930, 868, 798, 846, 781, 825, 1027, 11587, 785, + 733, 731, 848, 753, 806, 699, 837, 750, 762, 748, 11541, 678, 742, 667, 735, 702, 837, 695, 773, 849, 869, 769, + 11381, 664, 705, 714, 698, 814, 846, 757, 802, 857, 905, 772, 11265, 718, 643, 597, 687, 774, 843, 747, 785, + 683, 1135, 676, 11259, 616, 595, 773, 746, 798, 722, 798, 790, 959, 771, 907, 11234, 705, 675, 773, 764, 846, + 789, 840, 853, 828, 774, 842, 11263, 758, 758, 757, 820, 847, 834, 884, 842, 988, 750, 952, 11236, 776, 640, 727, + 832, 855, 733, 822, 827, 862, 697, 924, 11176, 675, 615, 688, 818, 783, 746, 901, 834, 892, 759, 923, 11181, 661, + 578, 720, 697}; +constexpr uint32_t ES_LENGTH_MPEG2 = sizeof(ES_MPEG2) / sizeof(uint32_t); +const std::string MPEG2_SRC_PATH = "/data/test/media/MPEG2_720_480.es"; + +const uint32_t ES_MPEG4[] = { + 11895, 8109, 1578, 1616, 1313, 572, 805, 837, 755, 706, 952, 879, 13193, 422, 389, 509, 725, 465, 479, 959, + 677, 364, 541, 696, 9306, 322, 318, 767, 590, 422, 530, 403, 505, 566, 445, 508, 7783, 460, 405, 343, 451, + 608, 431, 411, 543, 487, 527, 400, 6287, 385, 418, 391, 592, 434, 412, 398, 504, 492, 479, 561, 5413, 317, + 355, 422, 467, 452, 476, 460, 490, 492, 485, 451, 5036, 312, 408, 460, 432, 502, 388, 475, 407, 544, 401, + 487, 4404, 362, 378, 427, 416, 426, 456, 414, 438, 424, 442, 444, 4310, 362, 388, 393, 390, 441, 398, 423, + 369, 443, 406, 392, 4231, 343, 363, 355, 390, 459, 371, 378, 381, 405, 392, 426, 3975, 387, 337, 393, 439, + 378, 355, 374, 484, 381, 373, 423, 3869, 312, 350, 400, 345, 356, 320, 473, 431, 386, 338, 431, 3426, 268, + 315, 416, 383, 373, 381, 354, 383, 328, 348, 418, 3715, 324, 361, 331, 350, 302, 409, 377, 359, 384, 334, + 326, 3439, 266, 324, 329, 353, 405, 303, 357, 332, 292, 361, 333, 3542, 294, 284, 247, 331, 306, 322, 287, + 367, 341, 276, 258, 3980, 246, 245, 259, 309, 333, 250, 275, 334, 281, 253, 371, 3640, 213, 231, 301, 302, + 228, 289, 290, 281, 201, 284, 277, 4242, 205, 328, 237, 283, 295, 266, 230, 321, 348, 212, 308, 4103, 259, + 238, 245, 298, 330, 265, 271, 287, 267, 286, 290, 3856, 269, 242, 209, 314, 267, 278, 280, 314, 250, 433, + 238, 3654, 195, 246, 301, 298, 250, 270, 320, 269, 305, 258, 368, 3810, 231, 212, 279, 289, 252, 303, 287, + 295, 206, 264, 349, 4071, 242, 296, 271, 231, 307, 265, 254, 267, 317, 232, 348, 4077, 259, 222, 268, 235, + 324, 266, 256, 312, 246, 248, 325, 4000, 266, 201, 230, 293, 264, 265, 273, 301, 304, 253, 266, 3978, 228, + 232, 250, 248, 281, 219, 243, 293, 287, 253, 328, 3719}; +constexpr uint32_t ES_LENGTH_MPEG4 = sizeof(ES_MPEG4) / sizeof(uint32_t); +const std::string MPEG4_SRC_PATH = "/data/test/media/mpeg4_320_240.es"; +} // namespace VCodecTestParam +namespace ACodecTestParam { +constexpr int32_t MAX_CHANNEL = 2; // max channel count of avdec_mp3 +constexpr int32_t DEFAULT_SAMPLERATE = 44100; // one of sample_rate that meets avdec_mp3 +constexpr int32_t DEFAULT_BITRATE = 97496; // one of bitrate that meets avdec_mp3 +constexpr uint32_t SAMPLE_DURATION_US = 23000; +constexpr bool NEED_DUMP = true; +const std::string MIME_TYPE = "audio/mp4a-latm"; +constexpr uint32_t ES[] = { + 283, 336, 291, 405, 438, 411, 215, 215, 313, 270, 342, 641, 554, 545, 545, 546, + 541, 540, 542, 552, 537, 533, 498, 472, 445, 430, 445, 427, 414, 386, 413, 370, 380, + 401, 393, 369, 391, 367, 395, 396, 396, 385, 391, 384, 395, 392, 386, 388, 384, 379, + 376, 381, 375, 373, 349, 391, 357, 384, 395, 384, 380, 386, 372, 386, 383, 378, 385, + 385, 384, 342, 390, 379, 387, 386, 393, 397, 362, 393, 394, 391, 383, 385, 377, 379, + 381, 369, 375, 379, 346, 382, 356, 361, 366, 394, 393, 385, 362, 406, 399, 384, 377, + 385, 389, 375, 346, 396, 388, 381, 383, 352, 357, 397, 382, 395, 376, 388, 373, 374, + 353, 383, 384, 393, 379, 348, 364, 389, 380, 381, 388, 423, 392, 381, 368, 351, 391, + 355, 358, 395, 390, 385, 382, 383, 388, 388, 389, 376, 379, 376, 384, 369, 354, 390, + 389, 396, 393, 382, 385, 353, 383, 381, 377, 411, 387, 390, 377, 349, 381, 390, 378, + 373, 375, 381, 351, 392, 381, 380, 381, 378, 387, 379, 383, 348, 386, 364, 386, 371, + 399, 399, 385, 380, 355, 397, 395, 382, 380, 386, 352, 387, 390, 373, 372, 388, 378, + 385, 368, 385, 370, 378, 373, 383, 368, 373, 388, 351, 384, 391, 387, 389, 383, 355, + 361, 392, 386, 354, 394, 392, 397, 392, 352, 381, 395, 349, 383, 390, 392, 350, 393, + 393, 385, 389, 393, 382, 378, 384, 378, 375, 373, 375, 389, 377, 383, 387, 373, 344, + 388, 379, 391, 373, 384, 358, 361, 391, 394, 363, 350, 361, 395, 399, 389, 398, 375, + 398, 400, 381, 354, 363, 366, 400, 400, 356, 370, 400, 394, 398, 385, 378, 372, 354, + 359, 393, 381, 363, 396, 396, 355, 390, 356, 355, 371, 399, 367, 406, 375, 377, 405, + 401, 390, 393, 392, 384, 386, 374, 358, 397, 389, 393, 385, 345, 379, 357, 388, 356, + 381, 389, 367, 358, 391, 360, 394, 396, 357, 395, 388, 394, 383, 357, 383, 392, 394, + 376, 379, 356, 386, 395, 387, 377, 377, 389, 377, 385, 351, 387, 350, 388, 384, 345, + 358, 368, 399, 394, 385, 384, 395, 378, 387, 386, 386, 376, 375, 382, 351, 359, 356, + 401, 388, 363, 406, 363, 374, 435, 366, 400, 393, 392, 371, 391, 359, 359, 397, 388, + 390, 420, 411, 369, 384, 382, 383, 383, 375, 381, 361, 380, 348, 379, 386, 379, 379, + 386, 371, 352, 378, 378, 388, 384, 385, 352, 355, 387, 383, 379, 362, 386, 399, 376, + 390, 350, 387, 357, 403, 398, 397, 360, 351, 394, 400, 399, 393, 388, 395, 370, 377, + 395, 360, 346, 381, 370, 390, 380, 391, 387, 382, 384, 383, 354, 349, 394, 358, 387, + 400, 386, 402, 354, 396, 387, 391, 365, 377, 359, 361, 365, 395, 388, 388, 384, 388, + 378, 374, 382, 376, 377, 389, 378, 341, 390, 376, 381, 375, 414, 368, 369, 387, 411, + 396, 391, 378, 389, 349, 383, 344, 381, 387, 380, 353, 361, 391, 365, 390, 396, 382, + 386, 385, 385, 409, 387, 386, 378, 372, 372, 374, 349, 388, 389, 348, 395, 380, 382, + 388, 375, 347, 383, 359, 389, 368, 361, 405, 398, 393, 395, 359, 360, 395, 395, 362, + 354, 388, 348, 388, 386, 390, 350, 388, 356, 369, 364, 404, 404, 391, 394, 385, 439, + 432, 375, 366, 441, 362, 367, 382, 374, 346, 391, 371, 354, 376, 390, 373, 382, 385, + 389, 378, 377, 347, 414, 338, 348, 385, 352, 385, 386, 381, 388, 387, 364, 465, 405, + 443, 387, 339, 376, 337, 379, 387, 370, 374, 358, 354, 357, 393, 356, 381, 357, 407, + 361, 397, 362, 394, 394, 392, 394, 391, 381, 386, 379, 354, 351, 392, 408, 393, 389, + 388, 385, 375, 388, 375, 388, 375, 354, 384, 379, 386, 394, 383, 359, 405, 395, 352, + 345, 403, 427, 373, 380, 350, 415, 378, 434, 385, 388, 387, 400, 405, 329, 391, 356, + 419, 358, 359, 375, 367, 391, 359, 369, 361, 376, 378, 379, 348, 390, 345, 388, 390, + 406, 349, 368, 364, 391, 384, 401, 384, 391, 361, 399, 359, 386, 392, 382, 386, 380, + 383, 345, 376, 393, 400, 395, 343, 352, 354, 381, 388, 357, 393, 389, 384, 389, 388, + 384, 404, 372, 358, 381, 352, 355, 485, 393, 371, 376, 389, 377, 391, 387, 376, 342, + 390, 375, 379, 396, 376, 402, 353, 392, 382, 383, 387, 386, 372, 377, 382, 388, 381, + 387, 357, 393, 385, 346, 389, 388, 357, 362, 404, 398, 397, 402, 371, 351, 370, 362, + 350, 388, 399, 402, 406, 377, 396, 359, 372, 390, 392, 368, 383, 346, 384, 381, 379, + 367, 384, 389, 381, 371, 358, 422, 372, 382, 374, 444, 412, 369, 362, 373, 389, 401, + 383, 380, 366, 365, 361, 379, 372, 345, 382, 375, 376, 375, 382, 356, 395, 383, 384, + 391, 361, 396, 407, 365, 351, 385, 378, 403, 344, 352, 387, 397, 399, 377, 371, 381, + 415, 382, 388, 368, 383, 405, 390, 386, 384, 374, 375, 381, 371, 372, 374, 377, 346, + 358, 381, 377, 359, 385, 396, 385, 390, 389, 391, 375, 357, 389, 390, 377, 370, 379, + 351, 381, 381, 380, 371, 386, 389, 389, 383, 362, 393, 388, 355, 396, 383, 352, 384, + 352, 383, 362, 396, 385, 396, 357, 388, 382, 377, 373, 379, 383, 386, 350, 393, 355, + 380, 401, 392, 391, 402, 391, 427, 407, 394, 332, 398, 367, 373, 343, 381, 383, 386, + 382, 349, 353, 393, 378, 386, 375, 390, 356, 392, 384, 387, 380, 381, 385, 386, 383, + 378, 379, 359, 381, 382, 388, 357, 357, 397, 358, 424, 382, 352, 409, 374, 368, 365, + 399, 352, 393, 389, 385, 352, 380, 398, 389, 385, 387, 387, 353, 402, 396, 386, 357, + 395, 368, 369, 407, 394, 383, 362, 380, 385, 368, 375, 365, 379, 377, 388, 380, 346, + 383, 381, 399, 359, 386, 455, 368, 406, 377, 339, 381, 377, 373, 371, 338}; // replace of self frame length +constexpr uint32_t ES_LENGTH = sizeof(ES) / sizeof(uint32_t); +} // namespace ACodecTestParam + +namespace FormatTestParam { + constexpr float EPSINON_FLOAT = 0.0001; + constexpr double EPSINON_DOUBLE = 0.0001; +} // namespace FormatTestParam + +namespace CodecListTestParam { + constexpr uint32_t DEFAULT_WIDTH = 1920; + constexpr uint32_t DEFAULT_HEIGHT = 1080; + constexpr uint32_t MIN_WIDTH = 2; + constexpr uint32_t MIN_HEIGHT = 2; + constexpr uint32_t MAX_WIDTH = 3840; + constexpr uint32_t MAX_HEIGHT = 2160; + constexpr uint32_t MAX_FRAME_RATE = 30; + constexpr uint32_t MAX_VIDEO_BITRATE = 3000000; + constexpr uint32_t MAX_AUDIO_BITRATE = 384000; + constexpr uint32_t DEFAULT_SAMPLE_RATE = 8000; + constexpr uint32_t MAX_CHANNEL_COUNT = 2; + constexpr uint32_t MAX_CHANNEL_COUNT_VORBIS = 7; +} // namespace CodecListTestParam +} // namespace Media +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/test/unittest/common/include/unittest_log.h b/test/unittest/common/include/unittest_log.h new file mode 100644 index 0000000000000000000000000000000000000000..15251d89b2e797287c75ae7422dfbd7a44fb94dc --- /dev/null +++ b/test/unittest/common/include/unittest_log.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef UNITTEST_LOG_H +#define UNITTEST_LOG_H + +#include +#include "avcodec_log.h" +namespace { + constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "MediaUnitTest"}; +} +namespace OHOS { +#define LOG_MAX_SIZE 200 +#define UNITTEST_CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) + +#define UNITTEST_CHECK_AND_RETURN_LOG(cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + return; \ + } \ + } while (0) + +#define UNITTEST_CHECK_AND_BREAK_LOG(cond, fmt, ...) \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + break; \ + } + +#define UNITTEST_CHECK_AND_CONTINUE_LOG(cond, fmt, ...) \ + if (!(cond)) { \ + (void)printf("%s\n", fmt, ##__VA_ARGS__); \ + continue; \ + } +#define UNITTEST_INFO_LOG(fmt, ...) \ + do { \ + char ch[LOG_MAX_SIZE]; \ + (void)sprintf_s(ch, LOG_MAX_SIZE, fmt, ##__VA_ARGS__); \ + (void)printf("%s", ch); \ + (void)printf("\n"); \ + AVCODEC_LOG(::OHOS::HiviewDFX::HiLog::Info, "%{public}s", ch); \ + } while (0) +} + +#endif // UNITTEST_LOG_H \ No newline at end of file diff --git a/test/unittest/common/src/test_params_config.cpp b/test/unittest/common/src/test_params_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ece6d069ca70ea9ff9613607d7d82f07cf5b199c --- /dev/null +++ b/test/unittest/common/src/test_params_config.cpp @@ -0,0 +1,25 @@ +/* + * 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 "test_params_config.h" + +namespace OHOS { +namespace Media { +namespace PlayerTestParam { +} // namespace PlayerTestParam +namespace AVMetadataTestParam { +} // namespace AVMetadataTestParam +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/format_test/BUILD.gn b/test/unittest/format_test/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..9bf56d191bc41ee133044040dae9e0ce825de60c --- /dev/null +++ b/test/unittest/format_test/BUILD.gn @@ -0,0 +1,85 @@ +# 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") + +module_output_path = "av_codec" + +avcodec_unittest_cflags = [ + "-std=c++17", + "-frtti", + "-fexceptions", + "-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("avformat_capi_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./capi", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + ] + + cflags = avcodec_unittest_cflags + + if (multimedia_av_codec_support_codec) { + sources = [ + "./avformat_unit_test.cpp", + "./capi/avformat_capi_mock.cpp", + "./capi/avformat_capi_mock_factory.cpp", + ] + } + + deps = [ "$av_codec_root_dir/interfaces/kits/c:capi_packages" ] + public_deps = [ "$av_codec_root_dir/services/utils:av_codec_format" ] + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} + +################################################################################################################## +ohos_unittest("avformat_inner_unit_test") { + module_out_path = module_output_path + include_dirs = [ + "./", + "./inner", + "$av_codec_root_dir/interfaces/inner_api/native", + "$av_codec_root_dir/interfaces/kits/c", + ] + cflags = avcodec_unittest_cflags + sources = [ + "./avformat_unit_test.cpp", + "./inner/avformat_inner_mock.cpp", + "./inner/avformat_inner_mock_factory.cpp", + ] + public_deps = [ "$av_codec_root_dir/services/utils:av_codec_format" ] + resource_config_file = + "$av_codec_root_dir/test/unittest/resources/ohos_test.xml" +} diff --git a/test/unittest/format_test/avformat_mock.h b/test/unittest/format_test/avformat_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..6d4ede6e8fd94fd1828a008b1d3769b8b8d0e533 --- /dev/null +++ b/test/unittest/format_test/avformat_mock.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 AVFORMAT_MOCK_H +#define AVFORMAT_MOCK_H + +#include +#include "nocopyable.h" + +namespace OHOS { +namespace Media { +struct AVCodecBufferAttrMock { + int64_t pts = 0; + int32_t size = 0; + int32_t offset = 0; + uint32_t flags = 0; +}; + +class FormatMock : public NoCopyable { +public: + virtual ~FormatMock() = default; + virtual bool PutIntValue(const std::string_view &key, int32_t value) = 0; + virtual bool GetIntValue(const std::string_view &key, int32_t &value) = 0; + virtual bool PutLongValue(const std::string_view &key, int64_t value) = 0; + virtual bool GetLongValue(const std::string_view &key, int64_t &value) = 0; + virtual bool PutFloatValue(const std::string_view &key, float value) = 0; + virtual bool GetFloatValue(const std::string_view &key, float &value) = 0; + virtual bool PutDoubleValue(const std::string_view &key, double value) = 0; + virtual bool GetDoubleValue(const std::string_view &key, double &value) = 0; + virtual bool PutStringValue(const std::string_view &key, const std::string_view &value) = 0; + virtual bool GetStringValue(const std::string_view &key, std::string &value) = 0; + virtual bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) = 0; + virtual bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) = 0; + virtual const char *DumpInfo() = 0; + virtual void Destroy() = 0; +}; + +class __attribute__((visibility("default"))) FormatMockFactory { +public: + static std::shared_ptr CreateFormat(); +private: + FormatMockFactory() = delete; + ~FormatMockFactory() = delete; +}; +} // namespace Media +} // namespace OHOS +#endif // AVFORMAT_MOCK_H \ No newline at end of file diff --git a/test/unittest/format_test/avformat_unit_test.cpp b/test/unittest/format_test/avformat_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94f7c8c0d55eb23a1d585e01d94493df1e43b613 --- /dev/null +++ b/test/unittest/format_test/avformat_unit_test.cpp @@ -0,0 +1,121 @@ +/* + * 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 "avformat_unit_test.h" +#include +#include "gtest/gtest.h" +#include "avcodec_errors.h" +#include "securec.h" + +using namespace std; +using namespace OHOS; +using namespace OHOS::Media; +using namespace testing::ext; + +constexpr float EPSINON_FLOAT = 0.0001; +constexpr double EPSINON_DOUBLE = 0.0001; + +void AVFormatUnitTest::SetUpTestCase(void) {} + +void AVFormatUnitTest::TearDownTestCase(void) {} + +void AVFormatUnitTest::SetUp(void) +{ + format_ = FormatMockFactory::CreateFormat(); + ASSERT_NE(nullptr, format_); +} + +void AVFormatUnitTest::TearDown(void) +{ + if (format_ != nullptr) { + format_->Destroy(); + } +} + +/** + * @tc.name: Format_Value_001 + * @tc.desc: format put and get value + * @tc.type: FUNC + * @tc.require: issueI5OX06 issueI5P8N0 + */ +HWTEST_F(AVFormatUnitTest, Format_Value_001, 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 = ""; + + EXPECT_TRUE(format_->PutIntValue(intKey, intValue)); + EXPECT_TRUE(format_->GetIntValue(intKey, getIntValue)); + EXPECT_TRUE(intValue == getIntValue); + EXPECT_FALSE(format_->GetLongValue(intKey, getLongValue)); + + EXPECT_TRUE(format_->PutLongValue(longKey, intValue)); + EXPECT_TRUE(format_->GetLongValue(longKey, getLongValue)); + EXPECT_TRUE(longValue == getLongValue); + EXPECT_FALSE(format_->GetIntValue(longKey, getIntValue)); + + EXPECT_TRUE(format_->PutFloatValue(floatKey, floatValue)); + EXPECT_TRUE(format_->GetFloatValue(floatKey, getFloatValue)); + EXPECT_TRUE(fabs(floatValue - getFloatValue) < EPSINON_FLOAT); + EXPECT_FALSE(format_->GetDoubleValue(floatKey, getDoubleValue)); + + EXPECT_TRUE(format_->PutDoubleValue(doubleKey, doubleValue)); + EXPECT_TRUE(format_->GetDoubleValue(doubleKey, getDoubleValue)); + EXPECT_TRUE(fabs(doubleValue - getDoubleValue) < EPSINON_DOUBLE); + EXPECT_FALSE(format_->GetFloatValue(doubleKey, getFloatValue)); + + EXPECT_TRUE(format_->PutStringValue(stringKey, stringValue.c_str())); + EXPECT_TRUE(format_->GetStringValue(stringKey, getStringValue)); + EXPECT_TRUE(stringValue == getStringValue); +} + +/** + * @tc.name: Format_Buffer_001 + * @tc.desc: format put and get buffer + * @tc.type: FUNC + * @tc.require: issueI5OWXY issueI5OXCD + */ +HWTEST_F(AVFormatUnitTest, Format_Buffer_001, TestSize.Level0) +{ + constexpr size_t size = 3; + const std::string_view key = "BufferKey"; + uint8_t buffer[size] = {'a', 'b', 'b'}; + + EXPECT_TRUE(format_->PutBuffer(key, buffer, size)); + uint8_t *getBuffer; + size_t getSize; + EXPECT_TRUE(format_->GetBuffer(key, &getBuffer, getSize)); + EXPECT_TRUE(size == getSize); + for (int32_t i = 0; i < size; i++) { + EXPECT_TRUE(buffer[i] == getBuffer[i]); + } + + std::string getString; + EXPECT_FALSE(format_->GetStringValue(key, getString)); +} \ No newline at end of file diff --git a/test/unittest/format_test/avformat_unit_test.h b/test/unittest/format_test/avformat_unit_test.h new file mode 100644 index 0000000000000000000000000000000000000000..7746a02913497f70fa38619ef2f4da9d9bd4d95f --- /dev/null +++ b/test/unittest/format_test/avformat_unit_test.h @@ -0,0 +1,40 @@ +/* + * 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 FORMAT_UNIT_TEST_H +#define FORMAT_UNIT_TEST_H + +#include "gtest/gtest.h" +#include "avformat_mock.h" + +namespace OHOS { +namespace Media { +class AVFormatUnitTest : 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: + std::shared_ptr format_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // FORMAT_UNIT_TEST_H \ No newline at end of file diff --git a/test/unittest/format_test/capi/avformat_capi_mock.cpp b/test/unittest/format_test/capi/avformat_capi_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddd500b5c475ab5a8734b62c3567e253e1f0d8e9 --- /dev/null +++ b/test/unittest/format_test/capi/avformat_capi_mock.cpp @@ -0,0 +1,154 @@ +/* + * 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 "avformat_capi_mock.h" + +namespace OHOS { +namespace Media { +AVFormatCapiMock::AVFormatCapiMock() +{ + format_ = OH_AVFormat_Create(); +} + +AVFormatCapiMock::~AVFormatCapiMock() +{ +} + +bool AVFormatCapiMock::PutIntValue(const std::string_view &key, int32_t value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetIntValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetIntValue(const std::string_view &key, int32_t &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetIntValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutStringValue(const std::string_view &key, const std::string_view &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetStringValue(format_, std::string(key).c_str(), std::string(value).c_str()); + } + return false; +} + +bool AVFormatCapiMock::GetStringValue(const std::string_view &key, std::string &value) +{ + if (format_ != nullptr) { + const char *out = nullptr; + if (OH_AVFormat_GetStringValue(format_, std::string(key).c_str(), &out)) { + value = out; + return true; + } + } + return false; +} + +void AVFormatCapiMock::Destroy() +{ + if (format_ != nullptr) { + OH_AVFormat_Destroy(format_); + } +} + +OH_AVFormat *AVFormatCapiMock::GetFormat() +{ + return format_; +} + +bool AVFormatCapiMock::AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from) +{ + return OH_AVFormat_Copy(to, from); +} + +bool AVFormatCapiMock::PutLongValue(const std::string_view &key, int64_t value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetLongValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetLongValue(const std::string_view &key, int64_t &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetLongValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutFloatValue(const std::string_view &key, float value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetFloatValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetFloatValue(const std::string_view &key, float &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetFloatValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::PutDoubleValue(const std::string_view &key, double value) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetDoubleValue(format_, std::string(key).c_str(), value); + } + return false; +} + +bool AVFormatCapiMock::GetDoubleValue(const std::string_view &key, double &value) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetDoubleValue(format_, std::string(key).c_str(), &value); + } + return false; +} + +bool AVFormatCapiMock::GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) +{ + if (format_ != nullptr) { + return OH_AVFormat_GetBuffer(format_, std::string(key).c_str(), addr, &size); + } + return false; +} + +bool AVFormatCapiMock::PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) +{ + if (format_ != nullptr) { + return OH_AVFormat_SetBuffer(format_, std::string(key).c_str(), addr, size); + } + return false; +} + +const char *AVFormatCapiMock::DumpInfo() +{ + if (format_ != nullptr) { + return OH_AVFormat_DumpInfo(format_); + } + return nullptr; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/format_test/capi/avformat_capi_mock.h b/test/unittest/format_test/capi/avformat_capi_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..54678db0e89a3f1976d5f20bc200a825e987d969 --- /dev/null +++ b/test/unittest/format_test/capi/avformat_capi_mock.h @@ -0,0 +1,51 @@ +/* + * 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 AVFORMAT_CAPI_MOCK_H +#define AVFORMAT_CAPI_MOCK_H + +#include "avformat_mock.h" +#include "native_avformat.h" + +namespace OHOS { +namespace Media { +class AVFormatCapiMock : public FormatMock { +public: + explicit AVFormatCapiMock(OH_AVFormat *format) : format_(format) {} + AVFormatCapiMock(); + ~AVFormatCapiMock(); + bool PutIntValue(const std::string_view &key, int32_t value) override; + bool GetIntValue(const std::string_view &key, int32_t &value) override; + bool PutStringValue(const std::string_view &key, const std::string_view &value) override; + bool GetStringValue(const std::string_view &key, std::string &value) override; + void Destroy() override; + bool PutLongValue(const std::string_view &key, int64_t value) override; + bool GetLongValue(const std::string_view &key, int64_t &value) override; + bool PutFloatValue(const std::string_view &key, float value) override; + bool GetFloatValue(const std::string_view &key, float &value) override; + bool PutDoubleValue(const std::string_view &key, double value) override; + bool GetDoubleValue(const std::string_view &key, double &value) override; + bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) override; + bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) override; + const char *DumpInfo() override; + bool AVFormat_Copy(struct OH_AVFormat *to, struct OH_AVFormat *from); + OH_AVFormat *GetFormat(); + +private: + OH_AVFormat *format_; +}; +} // namespace Media +} // namespace OHOS +#endif // AVFORMAT_CAPI_MOCK_H \ No newline at end of file diff --git a/test/unittest/format_test/capi/avformat_capi_mock_factory.cpp b/test/unittest/format_test/capi/avformat_capi_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad5790ecd9e71997f881db2264ebf920f5962ce3 --- /dev/null +++ b/test/unittest/format_test/capi/avformat_capi_mock_factory.cpp @@ -0,0 +1,25 @@ +/* + * 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 "avformat_capi_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr FormatMockFactory::CreateFormat() +{ + return std::make_shared(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/format_test/inner/avformat_inner_mock.cpp b/test/unittest/format_test/inner/avformat_inner_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e415806d6467456ca9df34df686b0d54054d878 --- /dev/null +++ b/test/unittest/format_test/inner/avformat_inner_mock.cpp @@ -0,0 +1,118 @@ +/* + * 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 "avformat_inner_mock.h" +#include "securec.h" + +namespace OHOS { +namespace Media { +bool AVFormatInnerMock::PutIntValue(const std::string_view &key, int32_t value) +{ + return format_.PutIntValue(key, value); +} + +bool AVFormatInnerMock::GetIntValue(const std::string_view &key, int32_t &value) +{ + return format_.GetIntValue(key, value); +} + +bool AVFormatInnerMock::PutStringValue(const std::string_view &key, const std::string_view &value) +{ + return format_.PutStringValue(key, value); +} + +bool AVFormatInnerMock::GetStringValue(const std::string_view &key, std::string &value) +{ + return format_.GetStringValue(key, value); +} + +void AVFormatInnerMock::Destroy() +{ + if (dumpInfo_ != nullptr) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + return; +} + +Format &AVFormatInnerMock::GetFormat() +{ + return format_; +} + +bool AVFormatInnerMock::PutLongValue(const std::string_view &key, int64_t value) +{ + return format_.PutLongValue(key, value); +} + +bool AVFormatInnerMock::GetLongValue(const std::string_view &key, int64_t &value) +{ + return format_.GetLongValue(key, value); +} + +bool AVFormatInnerMock::PutFloatValue(const std::string_view &key, float value) +{ + return format_.PutFloatValue(key, value); +} + +bool AVFormatInnerMock::GetFloatValue(const std::string_view &key, float &value) +{ + return format_.GetFloatValue(key, value); +} + +bool AVFormatInnerMock::PutDoubleValue(const std::string_view &key, double value) +{ + return format_.PutDoubleValue(key, value); +} + +bool AVFormatInnerMock::GetDoubleValue(const std::string_view &key, double &value) +{ + return format_.GetDoubleValue(key, value); +} + +bool AVFormatInnerMock::GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) +{ + return format_.GetBuffer(key, addr, size); +} + +bool AVFormatInnerMock::PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) +{ + return format_.PutBuffer(key, addr, size); +} + +const char *AVFormatInnerMock::DumpInfo() +{ + if (dumpInfo_ != nullptr) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + std::string info = format_.Stringify(); + if (info.empty()) { + return nullptr; + } + constexpr uint32_t maxDumpLength = 1024; + uint32_t bufLength = info.size() > maxDumpLength ? maxDumpLength : info.size(); + dumpInfo_ = static_cast(malloc((bufLength + 1) * sizeof(char))); + if (dumpInfo_ == nullptr) { + return nullptr; + } + if (strcpy_s(dumpInfo_, bufLength + 1, info.c_str()) != 0) { + free(dumpInfo_); + dumpInfo_ = nullptr; + } + return dumpInfo_; +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/format_test/inner/avformat_inner_mock.h b/test/unittest/format_test/inner/avformat_inner_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..7dbe20f2b29a07af366875250a717c2398e008ca --- /dev/null +++ b/test/unittest/format_test/inner/avformat_inner_mock.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 AVFORMAT_INNER_MOCK_H +#define AVFORMAT_INNER_MOCK_H + +#include "avformat_mock.h" +#include "format.h" + +namespace OHOS { +namespace Media { +class AVFormatInnerMock : public FormatMock { +public: + explicit AVFormatInnerMock(const Format &format) : format_(format) {} + AVFormatInnerMock() = default; + bool PutIntValue(const std::string_view &key, int32_t value) override; + bool GetIntValue(const std::string_view &key, int32_t &value) override; + bool PutStringValue(const std::string_view &key, const std::string_view &value) override; + bool GetStringValue(const std::string_view &key, std::string &value) override; + void Destroy() override; + bool PutLongValue(const std::string_view &key, int64_t value) override; + bool GetLongValue(const std::string_view &key, int64_t &value) override; + bool PutFloatValue(const std::string_view &key, float value) override; + bool GetFloatValue(const std::string_view &key, float &value) override; + bool PutDoubleValue(const std::string_view &key, double value) override; + bool GetDoubleValue(const std::string_view &key, double &value) override; + bool GetBuffer(const std::string_view &key, uint8_t **addr, size_t &size) override; + bool PutBuffer(const std::string_view &key, const uint8_t *addr, size_t size) override; + const char *DumpInfo() override; + Format &GetFormat(); + +private: + Format format_; + char *dumpInfo_ = nullptr; +}; +} // namespace Media +} // namespace OHOS +#endif // AVFORMAT_NATIVE_MOCK_H \ No newline at end of file diff --git a/test/unittest/format_test/inner/avformat_inner_mock_factory.cpp b/test/unittest/format_test/inner/avformat_inner_mock_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..acde37dd12c8e274549c3d16c0831a59e1dbc5c3 --- /dev/null +++ b/test/unittest/format_test/inner/avformat_inner_mock_factory.cpp @@ -0,0 +1,25 @@ +/* + * 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 "avformat_inner_mock.h" + +namespace OHOS { +namespace Media { +std::shared_ptr FormatMockFactory::CreateFormat() +{ + return std::make_shared(); +} +} // namespace Media +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/resources/ohos_test.xml b/test/unittest/resources/ohos_test.xml new file mode 100644 index 0000000000000000000000000000000000000000..628356065f77ab1f802d64c6a7e1020d9a959959 --- /dev/null +++ b/test/unittest/resources/ohos_test.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/test/unittest/video_test/fcodec_unit_test.cpp b/test/unittest/video_test/fcodec_unit_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..415da628e70600c19684947fcddeb7f27dade1fc --- /dev/null +++ b/test/unittest/video_test/fcodec_unit_test.cpp @@ -0,0 +1,511 @@ +/* + * 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 "fcodec.h" + +extern "C" { +#include "libavutil/frame.h" +#include "libavutil/mem.h" +#include "libavcodec/avcodec.h" +} + +using namespace std; +using namespace testing::ext; +using namespace OHOS; +using namespace OHOS::Media; +using namespace OHOS::Media::Codec; +namespace { +const string CODEC_NAME = "video_decoder.avc"; +constexpr uint32_t DEFAULT_WIDTH = 480; +constexpr uint32_t DEFAULT_HEIGHT = 272; +} // namespace + +namespace OHOS { +namespace Media { +class VDecSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::queue inIdxQueue_; + std::queue outIdxQueue_; + std::queue infoQueue_; + std::queue flagQueue_; +}; + +class BufferCallback : public AVCodecCallback { +public: + explicit BufferCallback(VDecSignal *userData) : userData_(userData) {} + virtual ~BufferCallback() = default; + VDecSignal *userData_; + virtual void OnError(AVCodecErrorType errorType, int32_t errorCode) override; + virtual void OnOutputFormatChanged(const Format &format) override; + virtual void OnInputBufferAvailable(size_t index) override; + virtual void OnOutputBufferAvailable(size_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) override; +}; + +void BufferCallback::OnError(AVCodecErrorType errorType, int32_t errorCode) +{ + (void)errorType; + cout << "Error errorCode=" << errorCode << endl; +} + +void BufferCallback::OnOutputFormatChanged(const Format &format) +{ + (void)format; + cout << "Format Changed" << endl; +} + +void BufferCallback::OnInputBufferAvailable(size_t index) +{ + unique_lock lock(userData_->inMutex_); + userData_->inIdxQueue_.push(index); + userData_->inCond_.notify_all(); +} + +void BufferCallback::OnOutputBufferAvailable(size_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag) +{ + unique_lock lock(userData_->outMutex_); + userData_->outIdxQueue_.push(index); + userData_->infoQueue_.push(info); + userData_->flagQueue_.push(flag); + userData_->outCond_.notify_all(); + (void)flag; +} + +class FCodecUnitTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + int32_t ProceFunc(); + +protected: + int32_t index_; + int64_t timeStamp_ = 0; + + VDecSignal *signal_; + + FILE *inFile_ = nullptr; + FILE *dumpFd_ = nullptr; + + std::string codecName_; + Format format; + std::shared_ptr vdec_ = nullptr; +}; + +void FCodecUnitTest::SetUpTestCase(void) +{ + cout << "[SetUpTestCase]: " << endl; +} + +void FCodecUnitTest::TearDownTestCase(void) +{ + cout << "[TearDownTestCase]: " << endl; +} + +void FCodecUnitTest::SetUp(void) +{ + codecName_ = ""; + vdec_ = std::make_shared(codecName_); + ASSERT_EQ(nullptr, vdec_); + + codecName_ = CODEC_NAME; + vdec_ = std::make_shared(codecName_); + ASSERT_NE(nullptr, vdec_); + + signal_ = new VDecSignal(); + ASSERT_EQ(AVCS_ERR_OK, + vdec_->SetCallback(std::shared_ptr(std::make_shared(signal_)))); +} + +void FCodecUnitTest::TearDown(void) +{ + vdec_->Release(); + cout << "[TearDown]: over!!!" << endl; +} + +int32_t FCodecUnitTest::ProceFunc(void) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + + if (vdec_->Configure(format) != AVCS_ERR_OK) { + cout << "[Configure]: failed to Configure" << endl; + return AVCS_ERR_UNKNOWN; + } else if (vdec_->Start() != AVCS_ERR_OK) { + cout << "[Start]: failed Start" << endl; + return AVCS_ERR_UNKNOWN; + } + format = Format(); + return AVCS_ERR_OK; +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_01, TestSize.Level1) +{ + EXPECT_NE(AVCS_ERR_INVALID_STATE, vdec_->Configure(format)); +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_02, TestSize.Level1) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_03, TestSize.Level1) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_04, TestSize.Level1) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, 1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_05, TestSize.Level1) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, 1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_Configure_06, TestSize.Level1) +{ + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, 1); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_INVALID_STATE, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_02, TestSize.Level1) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + EXPECT_EQ(AVCS_ERR_OK, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_03, TestSize.Level2) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_04, TestSize.Level3) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, 1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_05, TestSize.Level4) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, 1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_SetParameter_06, TestSize.Level1) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, 1); + EXPECT_EQ(AVCS_ERR_OK, vdec_->SetParameter(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_GetInputbuffer_01, TestSize.Level1) +{ + EXPECT_EQ(ProceFunc(), AVCS_ERR_OK); + std::shared_ptr buffer = nullptr; + index_ = -1; + buffer = vdec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = 1024; + buffer = vdec_->GetInputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + index_ = signal_->inIdxQueue_.front(); + buffer = vdec_->GetInputBuffer(index_); + EXPECT_NE(nullptr, buffer); +} + +HWTEST_F(FCodecUnitTest, fcodec_QueueInputbuffer_01, TestSize.Level1) +{ + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + // case0 传参异常 + index_ = -1; + EXPECT_EQ(AVCS_ERR_INVALID_VAL, vdec_->QueueInputBuffer(index_, info, flag)); + // case1 info未赋值 + index_ = 1024; + EXPECT_EQ(AVCS_ERR_INVALID_VAL, vdec_->QueueInputBuffer(index_, info, flag)); + + // case2 EOS帧数据 + index_ = 0; + info.presentationTimeUs = 0; + info.size = -1; + info.offset = 0; + flag = AVCODEC_BUFFER_FLAG_EOS; + EXPECT_EQ(AVCS_ERR_OK, vdec_->QueueInputBuffer(index_, info, flag)); +} + +HWTEST_F(FCodecUnitTest, fcodec_QueueInputbuffer_02, TestSize.Level1) +{ + AVCodecBufferInfo info; + AVCodecBufferFlag flag; + + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + // case0 传参异常 + index_ = -1; + EXPECT_EQ(AVCS_ERR_INVALID_VAL, vdec_->QueueInputBuffer(index_, info, flag)); + // case1 info未赋值 + index_ = 1024; + EXPECT_EQ(AVCS_ERR_INVALID_VAL, vdec_->QueueInputBuffer(index_, info, flag)); + + // case3 正常帧数据 + index_ = 0; + info.presentationTimeUs = timeStamp_; + info.size = 1024; + info.offset = 0; + flag = AVCODEC_BUFFER_FLAG_NONE; + EXPECT_EQ(AVCS_ERR_OK, vdec_->QueueInputBuffer(index_, info, flag)); +} + +HWTEST_F(FCodecUnitTest, fcodec_GetOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + std::shared_ptr buffer = nullptr; + + // case1 传参异常 + index_ = -1; + buffer = vdec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + index_ = 1024; + buffer = vdec_->GetOutputBuffer(index_); + EXPECT_EQ(nullptr, buffer); + + // case2 传参正常 + index_ = 0; + buffer = vdec_->GetOutputBuffer(index_); + EXPECT_NE(nullptr, buffer); +} + +HWTEST_F(FCodecUnitTest, fcodec_ReleaseOutputBuffer_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + + // case1 传参异常 + index_ = -1; + EXPECT_NE(AVCS_ERR_INVALID_VAL, vdec_->ReleaseOutputBuffer(index_)); + index_ = 1024; + EXPECT_NE(AVCS_ERR_INVALID_VAL, vdec_->ReleaseOutputBuffer(index_)); + // case2 传参正常 + index_ = 0; + EXPECT_EQ(AVCS_ERR_INVALID_VAL, vdec_->ReleaseOutputBuffer(index_)); +} + +HWTEST_F(FCodecUnitTest, fcodec_GetOutputFormat_01, TestSize.Level1) +{ + // case1 传参异常 + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, 1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); + EXPECT_EQ(AVCS_ERR_OK, vdec_->GetOutputFormat(format)); + format = Format(); + + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, 0); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, -1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); + EXPECT_EQ(AVCS_ERR_OK, vdec_->GetOutputFormat(format)); + format = Format(); + + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, -1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, -1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, -1); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); + EXPECT_EQ(AVCS_ERR_OK, vdec_->GetOutputFormat(format)); + format = Format(); + + // case2 传参正常 + format.PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, DEFAULT_WIDTH); + format.PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, DEFAULT_HEIGHT); + format.PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, static_cast(Codec::VideoPixelFormat::BGRA)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, + static_cast(GraphicTransformType::GRAPHIC_ROTATE_90)); + format.PutIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, + static_cast(ScalingMode::SCALING_MODE_SCALE_TO_WINDOW)); + EXPECT_EQ(AVCS_ERR_OK, vdec_->Configure(format)); + format = Format(); + EXPECT_EQ(AVCS_ERR_OK, vdec_->GetOutputFormat(format)); + format = Format(); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_01, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Start()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Release()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_02, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Start()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Reset()); + ASSERT_EQ(AVCS_ERR_OK, + vdec_->SetCallback(std::shared_ptr(std::make_shared(signal_)))); + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Release()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_03, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Flush()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_04, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_INVALID_STATE, vdec_->Start()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_05, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_06, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Reset()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Reset()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_07, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Flush()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Flush()); +} + +HWTEST_F(FCodecUnitTest, fcodec_Operating_procedures_08, TestSize.Level1) +{ + EXPECT_EQ(AVCS_ERR_OK, ProceFunc()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Stop()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Release()); + ASSERT_EQ(AVCS_ERR_OK, vdec_->Release()); +} + +int main(int argc, char *argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +} +}