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