1/* 2 * Copyright (C) 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 16#include "audio_resample.h" 17#include "avcodec_log.h" 18#include "securec.h" 19#include "ffmpeg_converter.h" 20 21namespace { 22constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-AudioResample"}; 23} // namespace 24 25namespace OHOS { 26namespace MediaAVCodec { 27int32_t AudioResample::Init(const ResamplePara& resamplePara) 28{ 29 auto ret = InitSwrContext(resamplePara); 30 if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) { 31 return ret; 32 } 33 auto destFrameSize = av_samples_get_buffer_size(nullptr, resamplePara_.channels, 34 resamplePara_.destSamplesPerFrame, resamplePara_.destFmt, 0); 35 resampleCache_.reserve(destFrameSize); 36 resampleChannelAddr_.reserve(resamplePara_.channels); 37 auto tmp = resampleChannelAddr_.data(); 38 av_samples_fill_arrays(tmp, nullptr, resampleCache_.data(), resamplePara_.channels, 39 resamplePara_.destSamplesPerFrame, resamplePara_.destFmt, 0); 40 return AVCodecServiceErrCode::AVCS_ERR_OK; 41} 42 43int32_t AudioResample::InitSwrContext(const ResamplePara& resamplePara) 44{ 45 resamplePara_ = resamplePara; 46 SwrContext *swrContext = swr_alloc(); 47 if (swrContext == nullptr) { 48 AVCODEC_LOGE("cannot allocate swr context"); 49 return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; 50 } 51 int error = 52 swr_alloc_set_opts2(&swrContext, &resamplePara_.channelLayout, resamplePara_.destFmt, resamplePara_.sampleRate, 53 &resamplePara_.channelLayout, resamplePara_.srcFmt, resamplePara_.sampleRate, 0, nullptr); 54 if (error < 0) { 55 AVCODEC_LOGE("swr init error"); 56 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; 57 } 58 if (swr_init(swrContext) != 0) { 59 AVCODEC_LOGE("swr init error"); 60 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; 61 } 62 swrCtx_ = std::shared_ptr<SwrContext>(swrContext, [](SwrContext *ptr) { 63 if (ptr) { 64 swr_free(&ptr); 65 } 66 }); 67 return AVCodecServiceErrCode::AVCS_ERR_OK; 68} 69 70int32_t AudioResample::Convert(const uint8_t* srcBuffer, const size_t srcLength, uint8_t*& destBuffer, 71 size_t& destLength) 72{ 73 size_t lineSize = srcLength / resamplePara_.channels; 74 std::vector<const uint8_t*> tmpInput(resamplePara_.channels); 75 tmpInput[0] = srcBuffer; 76 if (av_sample_fmt_is_planar(resamplePara_.srcFmt)) { 77 for (size_t i = 1; i < tmpInput.size(); ++i) { 78 tmpInput[i] = tmpInput[i-1] + lineSize; 79 } 80 } 81 int32_t samples = lineSize / av_get_bytes_per_sample(resamplePara_.srcFmt); 82 auto res = swr_convert(swrCtx_.get(), resampleChannelAddr_.data(), resamplePara_.destSamplesPerFrame, 83 tmpInput.data(), samples); 84 if (res < 0) { 85 AVCODEC_LOGE("resample input failed"); 86 destLength = 0; 87 } else { 88 destBuffer = resampleCache_.data(); 89 destLength = static_cast<size_t>(res * av_get_bytes_per_sample(resamplePara_.destFmt) * resamplePara_.channels); 90 } 91 return AVCodecServiceErrCode::AVCS_ERR_OK; 92} 93 94int32_t AudioResample::ConvertFrame(AVFrame *outputFrame, const AVFrame *inputFrame) 95{ 96 if (outputFrame == nullptr || inputFrame == nullptr) { 97 AVCODEC_LOGE("Frame null pointer"); 98 return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; 99 } 100 int planar = av_sample_fmt_is_planar(static_cast<AVSampleFormat>(inputFrame->format)); 101 if (planar) { 102 for (auto i = 0; i < inputFrame->channels; i++) { 103 if (inputFrame->extended_data[i] == nullptr) { 104 AVCODEC_LOGE("this is a planar audio, inputFrame->channels: %{public}d, " 105 "but inputFrame->extended_data[%{public}d] is nullptr", inputFrame->channels, i); 106 return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; 107 } 108 } 109 } else { 110 if (inputFrame->extended_data[0] == nullptr) { 111 AVCODEC_LOGE("inputFrame->extended_data[0] is nullptr"); 112 return AVCodecServiceErrCode::AVCS_ERR_NO_MEMORY; 113 } 114 } 115 116 outputFrame->ch_layout = resamplePara_.channelLayout; 117 outputFrame->format = resamplePara_.destFmt; 118 outputFrame->sample_rate = resamplePara_.sampleRate; 119 120 auto ret = swr_convert_frame(swrCtx_.get(), outputFrame, inputFrame); 121 if (ret < 0) { 122 AVCODEC_LOGE("convert frame failed, %{public}s", FFMpegConverter::AVStrError(ret).c_str()); 123 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN; 124 } 125 return AVCodecServiceErrCode::AVCS_ERR_OK; 126} 127} // namespace MediaAVCodec 128} // namespace OHOS 129