Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2026 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "aacencoder.h"
24 :
25 : #include <algorithm>
26 : #include <vector>
27 :
28 : #include "aacenc_lib.h"
29 : #include "FDK_audio.h"
30 :
31 : #include "global/io/iodevice.h"
32 :
33 : #include "../dsp/audiomathutils.h"
34 :
35 : #include "log.h"
36 :
37 : using namespace muse::audio;
38 : using namespace muse::audio::encode;
39 :
40 : namespace muse::audio::encode {
41 : struct AacEncoderHandler
42 : {
43 : HANDLE_AACENCODER handle = nullptr;
44 : AACENC_InfoStruct info = {};
45 : std::vector<INT_PCM> inputBuffer;
46 : std::vector<unsigned char> outputBuffer;
47 : size_t frameLength = 0;
48 : int channels = 0;
49 :
50 0 : ~AacEncoderHandler()
51 : {
52 0 : if (handle) {
53 0 : aacEncClose(&handle);
54 : }
55 0 : }
56 :
57 0 : bool init(const SoundTrackFormat& format)
58 : {
59 0 : channels = format.outputSpec.audioChannelCount;
60 0 : if (aacEncOpen(&handle, 0, channels) != AACENC_OK) {
61 0 : LOGE() << "Failed to open AAC encoder";
62 0 : return false;
63 : }
64 :
65 0 : if (aacEncoder_SetParam(handle, AACENC_AOT, AOT_AAC_LC) != AACENC_OK) {
66 0 : LOGE() << "Failed to set AAC AOT";
67 0 : return false;
68 : }
69 :
70 0 : if (aacEncoder_SetParam(handle, AACENC_SAMPLERATE, format.outputSpec.sampleRate) != AACENC_OK) {
71 0 : LOGE() << "Failed to set sample rate";
72 0 : return false;
73 : }
74 :
75 0 : CHANNEL_MODE mode = MODE_1;
76 0 : switch (channels) {
77 0 : case 1: mode = MODE_1;
78 0 : break;
79 0 : case 2: mode = MODE_2;
80 0 : break;
81 0 : case 3: mode = MODE_1_2;
82 0 : break;
83 0 : case 4: mode = MODE_1_2_1;
84 0 : break;
85 0 : case 5: mode = MODE_1_2_2;
86 0 : break;
87 0 : case 6: mode = MODE_1_2_2_1;
88 0 : break;
89 0 : default:
90 0 : LOGE() << "Unsupported channel count:" << channels;
91 0 : return false;
92 : }
93 :
94 0 : if (aacEncoder_SetParam(handle, AACENC_CHANNELMODE, mode) != AACENC_OK) {
95 0 : LOGE() << "Failed to set channel mode";
96 0 : return false;
97 : }
98 :
99 0 : if (aacEncoder_SetParam(handle, AACENC_CHANNELORDER, 1) != AACENC_OK) {
100 0 : LOGE() << "Failed to set channel order (WAV)";
101 0 : return false;
102 : }
103 :
104 0 : if (aacEncoder_SetParam(handle, AACENC_BITRATE, format.bitRate * 1000) != AACENC_OK) {
105 0 : LOGE() << "Failed to set bitrate";
106 0 : return false;
107 : }
108 :
109 0 : if (aacEncoder_SetParam(handle, AACENC_TRANSMUX, TT_MP4_ADTS) != AACENC_OK) {
110 0 : LOGE() << "Failed to set ADTS transport";
111 0 : return false;
112 : }
113 :
114 0 : if (aacEncoder_SetParam(handle, AACENC_AFTERBURNER, 1) != AACENC_OK) {
115 0 : LOGE() << "Failed to set afterburner";
116 0 : return false;
117 : }
118 :
119 0 : if (aacEncEncode(handle, nullptr, nullptr, nullptr, nullptr) != AACENC_OK) {
120 0 : LOGE() << "Failed to initialize AAC encoder";
121 0 : return false;
122 : }
123 :
124 0 : if (aacEncInfo(handle, &info) != AACENC_OK) {
125 0 : LOGE() << "Failed to get AAC encoder info";
126 0 : return false;
127 : }
128 :
129 0 : frameLength = info.frameLength;
130 0 : outputBuffer.resize(info.maxOutBufBytes);
131 0 : inputBuffer.resize(channels * frameLength);
132 :
133 0 : return true;
134 : }
135 : };
136 : }
137 :
138 0 : AacEncoder::AacEncoder(const SoundTrackFormat& format, io::IODevice& dstDevice)
139 0 : : AbstractAudioEncoder(format), m_handler{std::make_unique<AacEncoderHandler>()}, m_dstDevice{&dstDevice}
140 : {
141 0 : DO_ASSERT(m_dstDevice);
142 0 : }
143 :
144 0 : AacEncoder::~AacEncoder() noexcept = default;
145 :
146 0 : bool AacEncoder::begin(const samples_t /*totalSamplesNumber*/)
147 : {
148 0 : if (!m_format.isValid()) {
149 0 : return false;
150 : }
151 :
152 0 : return m_handler->init(m_format);
153 : }
154 :
155 0 : size_t AacEncoder::encode(samples_t samplesPerChannel, const float* input)
156 : {
157 0 : IF_ASSERT_FAILED(m_handler && m_dstDevice) {
158 0 : return 0;
159 : }
160 :
161 0 : const int channels = m_handler->channels;
162 0 : const size_t frameLength = m_handler->frameLength;
163 0 : const size_t samplesPerFrame = frameLength * channels;
164 :
165 0 : size_t inputOffset = 0;
166 0 : const size_t totalSamples = samplesPerChannel * static_cast<size_t>(channels);
167 :
168 0 : while (inputOffset < totalSamples) {
169 0 : const size_t samplesToProcess = std::min(samplesPerFrame, totalSamples - inputOffset);
170 :
171 0 : for (size_t i = 0; i < samplesToProcess; ++i) {
172 0 : m_handler->inputBuffer[i] = dsp::convertFloatSamples<INT_PCM>(input[inputOffset + i], 16);
173 : }
174 :
175 0 : AACENC_BufDesc inBufDesc = {};
176 0 : AACENC_BufDesc outBufDesc = {};
177 0 : AACENC_InArgs inArgs = {};
178 0 : AACENC_OutArgs outArgs = {};
179 :
180 0 : int inIdentifier = IN_AUDIO_DATA;
181 0 : int inSize = static_cast<int>(samplesToProcess * sizeof(INT_PCM));
182 0 : int inElemSize = sizeof(INT_PCM);
183 0 : void* inPtr = m_handler->inputBuffer.data();
184 :
185 0 : int outIdentifier = OUT_BITSTREAM_DATA;
186 0 : int outSize = static_cast<int>(m_handler->outputBuffer.size());
187 0 : int outElemSize = 1;
188 0 : void* outPtr = m_handler->outputBuffer.data();
189 :
190 0 : inBufDesc.numBufs = 1;
191 0 : inBufDesc.bufs = &inPtr;
192 0 : inBufDesc.bufferIdentifiers = &inIdentifier;
193 0 : inBufDesc.bufSizes = &inSize;
194 0 : inBufDesc.bufElSizes = &inElemSize;
195 :
196 0 : outBufDesc.numBufs = 1;
197 0 : outBufDesc.bufs = &outPtr;
198 0 : outBufDesc.bufferIdentifiers = &outIdentifier;
199 0 : outBufDesc.bufSizes = &outSize;
200 0 : outBufDesc.bufElSizes = &outElemSize;
201 :
202 0 : inArgs.numInSamples = static_cast<int>(samplesToProcess);
203 :
204 0 : const AACENC_ERROR err = aacEncEncode(m_handler->handle, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
205 :
206 0 : if (err == AACENC_ENCODE_EOF) {
207 0 : LOGE() << "AAC encoding unexpected EOF";
208 0 : return 0;
209 : }
210 0 : if (err != AACENC_OK) {
211 0 : LOGE() << "AAC encoding failed:" << err;
212 0 : return 0;
213 : }
214 :
215 0 : if (outArgs.numOutBytes > 0) {
216 0 : const size_t written = m_dstDevice->write(m_handler->outputBuffer.data(), static_cast<size_t>(outArgs.numOutBytes));
217 0 : if (written != static_cast<size_t>(outArgs.numOutBytes)) {
218 0 : return 0;
219 : }
220 : }
221 :
222 0 : inputOffset += samplesToProcess;
223 :
224 0 : if (samplesToProcess < samplesPerFrame) {
225 0 : break;
226 : }
227 : }
228 :
229 0 : if (inputOffset != totalSamples) {
230 0 : return 0;
231 : }
232 :
233 0 : return static_cast<size_t>(samplesPerChannel) * static_cast<size_t>(channels);
234 : }
235 :
236 0 : size_t AacEncoder::end()
237 : {
238 0 : IF_ASSERT_FAILED(m_handler && m_dstDevice) {
239 0 : return 0;
240 : }
241 :
242 0 : size_t totalBytesWritten = 0;
243 :
244 0 : AACENC_BufDesc inBufDesc = {};
245 0 : AACENC_BufDesc outBufDesc = {};
246 0 : AACENC_InArgs inArgs = {};
247 0 : AACENC_OutArgs outArgs = {};
248 :
249 0 : int inIdentifier = IN_AUDIO_DATA;
250 0 : int inSize = 0;
251 0 : int inElemSize = sizeof(INT_PCM);
252 0 : void* inPtr = nullptr;
253 :
254 0 : int outIdentifier = OUT_BITSTREAM_DATA;
255 0 : int outSize = static_cast<int>(m_handler->outputBuffer.size());
256 0 : int outElemSize = 1;
257 0 : void* outPtr = m_handler->outputBuffer.data();
258 :
259 0 : inBufDesc.numBufs = 1;
260 0 : inBufDesc.bufs = &inPtr;
261 0 : inBufDesc.bufferIdentifiers = &inIdentifier;
262 0 : inBufDesc.bufSizes = &inSize;
263 0 : inBufDesc.bufElSizes = &inElemSize;
264 :
265 0 : outBufDesc.numBufs = 1;
266 0 : outBufDesc.bufs = &outPtr;
267 0 : outBufDesc.bufferIdentifiers = &outIdentifier;
268 0 : outBufDesc.bufSizes = &outSize;
269 0 : outBufDesc.bufElSizes = &outElemSize;
270 :
271 0 : inArgs.numInSamples = -1;
272 :
273 : while (true) {
274 0 : AACENC_ERROR err = aacEncEncode(m_handler->handle, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
275 :
276 0 : if (err == AACENC_ENCODE_EOF) {
277 0 : break;
278 : }
279 0 : if (err != AACENC_OK) {
280 0 : break;
281 : }
282 :
283 0 : if (outArgs.numOutBytes > 0) {
284 0 : const size_t written = m_dstDevice->write(m_handler->outputBuffer.data(), static_cast<size_t>(outArgs.numOutBytes));
285 0 : totalBytesWritten += written;
286 : }
287 0 : }
288 :
289 0 : return totalBytesWritten;
290 : }
|