1fa7767c5Sopenharmony_ci/* 2fa7767c5Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3fa7767c5Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fa7767c5Sopenharmony_ci * you may not use this file except in compliance with the License. 5fa7767c5Sopenharmony_ci * You may obtain a copy of the License at 6fa7767c5Sopenharmony_ci * 7fa7767c5Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fa7767c5Sopenharmony_ci * 9fa7767c5Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fa7767c5Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fa7767c5Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fa7767c5Sopenharmony_ci * See the License for the specific language governing permissions and 13fa7767c5Sopenharmony_ci * limitations under the License. 14fa7767c5Sopenharmony_ci */ 15fa7767c5Sopenharmony_ci#include "foundation/log.h" 16fa7767c5Sopenharmony_ci#include "plugin/convert/ffmpeg_convert.h" 17fa7767c5Sopenharmony_ci#include "securec.h" 18fa7767c5Sopenharmony_ci 19fa7767c5Sopenharmony_cinamespace OHOS { 20fa7767c5Sopenharmony_cinamespace Media { 21fa7767c5Sopenharmony_cinamespace Plugin { 22fa7767c5Sopenharmony_cinamespace Ffmpeg { 23fa7767c5Sopenharmony_ciStatus Resample::Init(const ResamplePara& resamplePara) 24fa7767c5Sopenharmony_ci{ 25fa7767c5Sopenharmony_ci resamplePara_ = resamplePara; 26fa7767c5Sopenharmony_ci#if defined(_WIN32) || !defined(OHOS_LITE) 27fa7767c5Sopenharmony_ci if (resamplePara_.bitsPerSample != 8 && resamplePara_.bitsPerSample != 24) { // 8 24 28fa7767c5Sopenharmony_ci auto destFrameSize = av_samples_get_buffer_size(nullptr, resamplePara_.channels, 29fa7767c5Sopenharmony_ci resamplePara_.destSamplesPerFrame, resamplePara_.destFmt, 0); 30fa7767c5Sopenharmony_ci resampleCache_.reserve(destFrameSize); 31fa7767c5Sopenharmony_ci resampleChannelAddr_.reserve(resamplePara_.channels); 32fa7767c5Sopenharmony_ci auto tmp = resampleChannelAddr_.data(); 33fa7767c5Sopenharmony_ci av_samples_fill_arrays(tmp, nullptr, resampleCache_.data(), resamplePara_.channels, 34fa7767c5Sopenharmony_ci resamplePara_.destSamplesPerFrame, resamplePara_.destFmt, 0); 35fa7767c5Sopenharmony_ci auto swrContext = swr_alloc(); 36fa7767c5Sopenharmony_ci if (swrContext == nullptr) { 37fa7767c5Sopenharmony_ci MEDIA_LOG_E("cannot allocate swr context"); 38fa7767c5Sopenharmony_ci return Status::ERROR_NO_MEMORY; 39fa7767c5Sopenharmony_ci } 40fa7767c5Sopenharmony_ci swrContext = swr_alloc_set_opts(swrContext, resamplePara_.channelLayout, resamplePara_.destFmt, 41fa7767c5Sopenharmony_ci resamplePara_.sampleRate, resamplePara_.channelLayout, 42fa7767c5Sopenharmony_ci resamplePara_.srcFfFmt, resamplePara_.sampleRate, 0, nullptr); 43fa7767c5Sopenharmony_ci if (swr_init(swrContext) != 0) { 44fa7767c5Sopenharmony_ci MEDIA_LOG_E("swr init error"); 45fa7767c5Sopenharmony_ci return Status::ERROR_UNKNOWN; 46fa7767c5Sopenharmony_ci } 47fa7767c5Sopenharmony_ci swrCtx_ = std::shared_ptr<SwrContext>(swrContext, [](SwrContext *ptr) { 48fa7767c5Sopenharmony_ci if (ptr) { 49fa7767c5Sopenharmony_ci swr_free(&ptr); 50fa7767c5Sopenharmony_ci } 51fa7767c5Sopenharmony_ci }); 52fa7767c5Sopenharmony_ci } 53fa7767c5Sopenharmony_ci#endif 54fa7767c5Sopenharmony_ci return Status::OK; 55fa7767c5Sopenharmony_ci} 56fa7767c5Sopenharmony_ci 57fa7767c5Sopenharmony_ciStatus Resample::Convert(const uint8_t* srcBuffer, const size_t srcLength, uint8_t*& destBuffer, size_t& destLength) 58fa7767c5Sopenharmony_ci{ 59fa7767c5Sopenharmony_ci#if defined(_WIN32) || !defined(OHOS_LITE) 60fa7767c5Sopenharmony_ci if (resamplePara_.bitsPerSample == 8) { // 8 61fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG(resamplePara_.destFmt == AV_SAMPLE_FMT_S16, Status::ERROR_UNIMPLEMENTED, 62fa7767c5Sopenharmony_ci "resample 8bit to other format can not support"); 63fa7767c5Sopenharmony_ci destLength = srcLength * 2; // 2 64fa7767c5Sopenharmony_ci resampleCache_.reserve(destLength); 65fa7767c5Sopenharmony_ci resampleCache_.assign(destLength, 0); 66fa7767c5Sopenharmony_ci for (size_t i {0}; i < destLength / 2; i++) { // 2 67fa7767c5Sopenharmony_ci auto resCode = memcpy_s(&resampleCache_[0] + i * 2 + 1, sizeof(uint8_t), srcBuffer + i, 1); // 0 2 1 68fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG_E(resCode == EOK, Status::ERROR_INVALID_OPERATION, "Memcpy failed at 8 bits/sample."); 69fa7767c5Sopenharmony_ci *(&resampleCache_[0] + i * 2 + 1) += 0x80; // 2 0x80 70fa7767c5Sopenharmony_ci } 71fa7767c5Sopenharmony_ci destBuffer = resampleCache_.data(); 72fa7767c5Sopenharmony_ci } else if (resamplePara_.bitsPerSample == 24) { // 24 73fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG(resamplePara_.destFmt == AV_SAMPLE_FMT_S16, Status::ERROR_UNIMPLEMENTED, 74fa7767c5Sopenharmony_ci "resample 24bit to other format can not support"); 75fa7767c5Sopenharmony_ci destLength = srcLength / 3 * 2; // 3 2 76fa7767c5Sopenharmony_ci resampleCache_.reserve(destLength); 77fa7767c5Sopenharmony_ci resampleCache_.assign(destLength, 0); 78fa7767c5Sopenharmony_ci for (size_t i = 0; i < destLength / 2; i++) { // 2 79fa7767c5Sopenharmony_ci auto resCode 80fa7767c5Sopenharmony_ci = memcpy_s(&resampleCache_[0] + i * 2, sizeof(uint8_t) * 2, srcBuffer + i * 3 + 1, 2); // 2 3 1 81fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG_E(resCode == EOK, Status::ERROR_INVALID_OPERATION, "Memcpy failed at 24 bits/sample."); 82fa7767c5Sopenharmony_ci } 83fa7767c5Sopenharmony_ci destBuffer = resampleCache_.data(); 84fa7767c5Sopenharmony_ci } else { 85fa7767c5Sopenharmony_ci size_t lineSize = srcLength / resamplePara_.channels; 86fa7767c5Sopenharmony_ci std::vector<const uint8_t*> tmpInput(resamplePara_.channels); 87fa7767c5Sopenharmony_ci tmpInput[0] = srcBuffer; 88fa7767c5Sopenharmony_ci if (av_sample_fmt_is_planar(resamplePara_.srcFfFmt)) { 89fa7767c5Sopenharmony_ci for (size_t i = 1; i < tmpInput.size(); ++i) { 90fa7767c5Sopenharmony_ci tmpInput[i] = tmpInput[i-1] + lineSize; 91fa7767c5Sopenharmony_ci } 92fa7767c5Sopenharmony_ci } 93fa7767c5Sopenharmony_ci auto samples = lineSize / static_cast<size_t>(av_get_bytes_per_sample(resamplePara_.srcFfFmt)); 94fa7767c5Sopenharmony_ci auto res = swr_convert(swrCtx_.get(), resampleChannelAddr_.data(), resamplePara_.destSamplesPerFrame, 95fa7767c5Sopenharmony_ci tmpInput.data(), samples); 96fa7767c5Sopenharmony_ci if (res < 0) { 97fa7767c5Sopenharmony_ci MEDIA_LOG_E("resample input failed"); 98fa7767c5Sopenharmony_ci destLength = 0; 99fa7767c5Sopenharmony_ci } else { 100fa7767c5Sopenharmony_ci destBuffer = resampleCache_.data(); 101fa7767c5Sopenharmony_ci size_t bytesPerSample = static_cast<size_t>(av_get_bytes_per_sample(resamplePara_.destFmt)); 102fa7767c5Sopenharmony_ci destLength = static_cast<size_t>(res) * bytesPerSample * resamplePara_.channels; 103fa7767c5Sopenharmony_ci } 104fa7767c5Sopenharmony_ci } 105fa7767c5Sopenharmony_ci#endif 106fa7767c5Sopenharmony_ci return Status::OK; 107fa7767c5Sopenharmony_ci} 108fa7767c5Sopenharmony_ci 109fa7767c5Sopenharmony_ci#if defined(VIDEO_SUPPORT) 110fa7767c5Sopenharmony_ciStatus Scale::Init(const ScalePara& scalePara, uint8_t** dstData, int32_t* dstLineSize) 111fa7767c5Sopenharmony_ci{ 112fa7767c5Sopenharmony_ci scalePara_ = scalePara; 113fa7767c5Sopenharmony_ci if (swsCtx_ != nullptr) { 114fa7767c5Sopenharmony_ci return Status::OK; 115fa7767c5Sopenharmony_ci } 116fa7767c5Sopenharmony_ci auto swsContext = sws_getContext(scalePara_.srcWidth, scalePara_.srcHeight, scalePara_.srcFfFmt, 117fa7767c5Sopenharmony_ci scalePara_.dstWidth, scalePara_.dstHeight, scalePara_.dstFfFmt, 118fa7767c5Sopenharmony_ci SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); 119fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG_E(swsContext != nullptr, Status::ERROR_UNKNOWN, "sws_getContext fail"); 120fa7767c5Sopenharmony_ci swsCtx_ = std::shared_ptr<SwsContext>(swsContext, [](struct SwsContext *ptr) { 121fa7767c5Sopenharmony_ci if (ptr != nullptr) { 122fa7767c5Sopenharmony_ci sws_freeContext(ptr); 123fa7767c5Sopenharmony_ci } 124fa7767c5Sopenharmony_ci }); 125fa7767c5Sopenharmony_ci auto ret = av_image_alloc(dstData, dstLineSize, scalePara_.dstWidth, scalePara_.dstHeight, 126fa7767c5Sopenharmony_ci scalePara_.dstFfFmt, scalePara_.align); 127fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN, "could not allocate destination image" PUBLIC_LOG_D32, ret); 128fa7767c5Sopenharmony_ci MEDIA_LOG_D("av_image_alloc call, ret: " PUBLIC_LOG_U32 "dstPixelFormat_: " PUBLIC_LOG_U32, 129fa7767c5Sopenharmony_ci ret, scalePara_.dstFfFmt); 130fa7767c5Sopenharmony_ci // av_image_alloc can make sure that dstLineSize last element is 0 131fa7767c5Sopenharmony_ci for (int32_t i = 0; dstLineSize[i] > 0; i++) { 132fa7767c5Sopenharmony_ci MEDIA_LOG_D("dstLineSize[" PUBLIC_LOG_D32 "]: " PUBLIC_LOG_D32, i, dstLineSize[i]); 133fa7767c5Sopenharmony_ci if (dstData[i] && !dstLineSize[i]) { 134fa7767c5Sopenharmony_ci MEDIA_LOG_E("scale frame is broken, i: " PUBLIC_LOG_D32, i); 135fa7767c5Sopenharmony_ci return Status::ERROR_UNKNOWN; 136fa7767c5Sopenharmony_ci } 137fa7767c5Sopenharmony_ci } 138fa7767c5Sopenharmony_ci return Status::OK; 139fa7767c5Sopenharmony_ci} 140fa7767c5Sopenharmony_ci 141fa7767c5Sopenharmony_ciStatus Scale::Convert(uint8_t** srcData, const int32_t* srcLineSize, uint8_t** dstData, int32_t* dstLineSize) 142fa7767c5Sopenharmony_ci{ 143fa7767c5Sopenharmony_ci auto res = sws_scale(swsCtx_.get(), srcData, srcLineSize, 0, scalePara_.srcHeight, 144fa7767c5Sopenharmony_ci dstData, dstLineSize); 145fa7767c5Sopenharmony_ci FALSE_RETURN_V_MSG_E(res >= 0, Status::ERROR_UNKNOWN, "sws_scale fail: " PUBLIC_LOG_D32, res); 146fa7767c5Sopenharmony_ci return Status::OK; 147fa7767c5Sopenharmony_ci} 148fa7767c5Sopenharmony_ci#endif 149fa7767c5Sopenharmony_ci} // namespace Ffmpeg 150fa7767c5Sopenharmony_ci} // namespace Plugin 151fa7767c5Sopenharmony_ci} // namespace Media 152fa7767c5Sopenharmony_ci} // namespace OHOS