HephAudio v3.0.6
A cross-platform C++ library for recording, playing, and processing audio on Windows, Android, Linux, iOS, and macOS.
Loading...
Searching...
No Matches
FFmpegAudioShared.h
Go to the documentation of this file.
1#pragma once
2#include "HephAudioShared.h"
3#include "AudioFormatInfo.h"
4#include <string>
5
8extern "C"
9{
10#include <libavcodec/avcodec.h>
11#include <libavformat/avformat.h>
12#include <libavutil/opt.h>
13#include <libswresample/swresample.h>
14}
15
16#if defined(_WIN32) && defined(_MSVC_LANG)
17#pragma comment(lib, "ffmpeg/lib/windows/avcodec.lib")
18#pragma comment(lib, "ffmpeg/lib/windows/avformat.lib")
19#pragma comment(lib, "ffmpeg/lib/windows/avutil.lib")
20#pragma comment(lib, "ffmpeg/lib/windows/swresample.lib")
21#endif
22
23
24#if LIBAVFORMAT_VERSION_MAJOR < 60
25#error unsupported libavformat version.
26#endif
27
28#if LIBAVCODEC_VERSION_MAJOR < 60
29#error unsupported libavcodec version.
30#endif
31
32#if LIBAVUTIL_VERSION_MAJOR < 58
33#error unsupported libavutil version.
34#endif
35
36#if LIBSWRESAMPLE_VERSION_MAJOR < 4
37#error unsupported libswresample version.
38#endif
39
40
41
42#if !defined(HEPHAUDIO_INTERNAL_SAMPLE_FMT)
43
44namespace HephAudio
45{
46 inline std::string FFmpegGetErrorMessage(int errorCode)
47 {
48 char errorMessage[AV_ERROR_MAX_STRING_SIZE]{ };
49 if (av_strerror(errorCode, errorMessage, AV_ERROR_MAX_STRING_SIZE) < 0)
50 {
51 return "error message not found.";
52 }
53 return errorMessage;
54 }
55
56 inline AVCodecID CodecIdFromAudioFormatInfo(const AudioFormatInfo& audioFormatInfo)
57 {
58 switch (audioFormatInfo.formatTag)
59 {
60
61 case HEPHAUDIO_FORMAT_TAG_PCM:
62 {
63 if (audioFormatInfo.endian == Heph::Endian::Little)
64 {
65 switch (audioFormatInfo.bitsPerSample)
66 {
67 case 8:
68 return AV_CODEC_ID_PCM_U8;
69 case 16:
70 return AV_CODEC_ID_PCM_S16LE;
71 case 24:
72 return AV_CODEC_ID_PCM_S24LE;
73 case 32:
74 return AV_CODEC_ID_PCM_S32LE;
75 case 64:
76 return AV_CODEC_ID_PCM_S64LE;
77 default:
78 return AV_CODEC_ID_NONE;
79 }
80 }
81 else
82 {
83 switch (audioFormatInfo.bitsPerSample)
84 {
85 case 8:
86 return AV_CODEC_ID_PCM_U8;
87 case 16:
88 return AV_CODEC_ID_PCM_S16BE;
89 case 24:
90 return AV_CODEC_ID_PCM_S24BE;
91 case 32:
92 return AV_CODEC_ID_PCM_S32BE;
93 case 64:
94 return AV_CODEC_ID_PCM_S64BE;
95 default:
96 return AV_CODEC_ID_NONE;
97 }
98 }
99 }
100
101 case HEPHAUDIO_FORMAT_TAG_IEEE_FLOAT:
102 {
103 if (audioFormatInfo.endian == Heph::Endian::Little)
104 {
105 return audioFormatInfo.bitsPerSample == sizeof(double) ? AV_CODEC_ID_PCM_F64LE : AV_CODEC_ID_PCM_F32LE;
106 }
107 return audioFormatInfo.bitsPerSample == sizeof(double) ? AV_CODEC_ID_PCM_F64BE : AV_CODEC_ID_PCM_F32BE;
108 }
109
110 case HEPHAUDIO_FORMAT_TAG_ALAW:
111 return AV_CODEC_ID_PCM_ALAW;
112
113 case HEPHAUDIO_FORMAT_TAG_MULAW:
114 return AV_CODEC_ID_PCM_MULAW;
115
116 case HEPHAUDIO_FORMAT_TAG_WMA:
117 return AV_CODEC_ID_WMAV2;
118
119 case HEPHAUDIO_FORMAT_TAG_WMAUDIO_LOSSLESS:
120 return AV_CODEC_ID_WMALOSSLESS;
121
122 case HEPHAUDIO_FORMAT_TAG_WMAVOICE:
123 return AV_CODEC_ID_WMAVOICE;
124
125 case HEPHAUDIO_FORMAT_TAG_MPEG:
126 return AV_CODEC_ID_MP2;
127
128 case HEPHAUDIO_FORMAT_TAG_MP3:
129 return AV_CODEC_ID_MP3;
130
131 case HEPHAUDIO_FORMAT_TAG_AAC:
132 return AV_CODEC_ID_AAC;
133
134 case HEPHAUDIO_FORMAT_TAG_ALAC:
135 return AV_CODEC_ID_ALAC;
136
137 case HEPHAUDIO_FORMAT_TAG_FLAC:
138 return AV_CODEC_ID_FLAC;
139
140 case HEPHAUDIO_FORMAT_TAG_OPUS:
141 return AV_CODEC_ID_OPUS;
142
143 case HEPHAUDIO_FORMAT_TAG_VORBIS:
144 return AV_CODEC_ID_VORBIS;
145
146 default:
147 return AV_CODEC_ID_NONE;
148 }
149 }
150
151 inline AVSampleFormat ToAVSampleFormat(const AVCodec* avCodec, const AudioFormatInfo& formatInfo)
152 {
153 if (avCodec == nullptr || avCodec->sample_fmts == nullptr)
154 {
155 return AV_SAMPLE_FMT_NONE;
156 }
157
158 auto getFirstSupportedSampleFormat = [avCodec](std::vector<AVSampleFormat> possibleFormats) -> AVSampleFormat
159 {
160 for (size_t i = 0; i < possibleFormats.size(); ++i)
161 {
162 for (size_t j = 0; avCodec->sample_fmts[j] != AV_SAMPLE_FMT_NONE; ++j)
163 {
164 if (possibleFormats[i] == avCodec->sample_fmts[j])
165 {
166 return possibleFormats[i];
167 }
168 }
169 }
170 return AV_SAMPLE_FMT_NONE;
171 };
172
173 if (formatInfo.formatTag == HEPHAUDIO_FORMAT_TAG_IEEE_FLOAT)
174 {
175 if (formatInfo.bitsPerSample == sizeof(double))
176 {
177 return getFirstSupportedSampleFormat(
178 {
179 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
180 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
181 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
182 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
183 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P
184 });
185 }
186 return getFirstSupportedSampleFormat(
187 {
188 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
189 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
190 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
191 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
192 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P
193 });
194 }
195
196 switch (formatInfo.bitsPerSample)
197 {
198 case 8:
199 return getFirstSupportedSampleFormat(
200 {
201 AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P,
202 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
203 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
204 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
205 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
206 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP
207 });
208 case 16:
209 return getFirstSupportedSampleFormat(
210 {
211 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
212 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
213 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
214 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
215 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
216 AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P
217 });
218 case 24:
219 case 32:
220 return getFirstSupportedSampleFormat(
221 {
222 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
223 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
224 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
225 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
226 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
227 AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P
228 });
229 case 64:
230 return getFirstSupportedSampleFormat(
231 {
232 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
233 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
234 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
235 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
236 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
237 AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P
238 });
239 default:
240 return getFirstSupportedSampleFormat(
241 {
242 AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
243 AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
244 AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64P,
245 AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32P,
246 AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P,
247 AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8P
248 });
249 }
250 }
251
252 inline AVSampleFormat ToAVSampleFormat(const AudioFormatInfo& formatInfo)
253 {
254 const AVCodecID codecID = HephAudio::CodecIdFromAudioFormatInfo(formatInfo);
255 const AVCodec* avCodec = avcodec_find_encoder(codecID);
256 return HephAudio::ToAVSampleFormat(avCodec, formatInfo);
257 }
258
259 inline AVChannelLayout ToAVChannelLayout(const AudioChannelLayout& audioChannelLayout)
260 {
261 AVChannelLayout avChannelLayout{};
262 avChannelLayout.order = AV_CHANNEL_ORDER_NATIVE;
263 avChannelLayout.nb_channels = audioChannelLayout.count;
264 avChannelLayout.u.mask = (uint64_t)audioChannelLayout.mask;
265 return avChannelLayout;
266 }
267
268 inline AudioChannelLayout FromAVChannelLayout(const AVChannelLayout& avChannelLayout)
269 {
270 AudioChannelLayout audioChannelLayout;
271
272 audioChannelLayout.count = avChannelLayout.nb_channels;
273
274 uint32_t avChMask = (uint32_t)avChannelLayout.u.mask;
275 audioChannelLayout.mask = (AudioChannelMask)avChMask;
276
277 // some formats like WAV and AIFF do not set mono and stereo masks
278 if (audioChannelLayout.mask == AudioChannelMask::Unknown)
279 {
280 switch (audioChannelLayout.count)
281 {
282 case 1:
283 audioChannelLayout.mask = HEPHAUDIO_CH_MASK_MONO;
284 break;
285 case 2:
286 audioChannelLayout.mask = HEPHAUDIO_CH_MASK_STEREO;
287 break;
288 default:
289 break;
290 }
291 }
292
293 return audioChannelLayout;
294 }
295
296 inline uint32_t GetClosestSupportedSampleRate(const AVCodec* avCodec, uint32_t targetSampleRate)
297 {
298 if (avCodec->supported_samplerates != nullptr)
299 {
300 int32_t closestSampleRate = avCodec->supported_samplerates[0];
301 int32_t closestAbsDeltaSampleRate = abs((int)targetSampleRate - avCodec->supported_samplerates[0]);
302 for (size_t i = 1; avCodec->supported_samplerates[i] != 0; i++)
303 {
304 if (avCodec->supported_samplerates[i] == targetSampleRate)
305 {
306 return targetSampleRate;
307 }
308
309 const int32_t currentAbsDeltaSampleRate = abs((int)targetSampleRate - avCodec->supported_samplerates[i]);
310 if (currentAbsDeltaSampleRate < closestAbsDeltaSampleRate)
311 {
312 closestAbsDeltaSampleRate = currentAbsDeltaSampleRate;
313 closestSampleRate = avCodec->supported_samplerates[i];
314 }
315 else if (currentAbsDeltaSampleRate == closestAbsDeltaSampleRate && avCodec->supported_samplerates[i] > closestSampleRate) // choose the greater sample rate
316 {
317 closestSampleRate = avCodec->supported_samplerates[i];
318 }
319 }
320 return closestSampleRate;
321 }
322
323 return targetSampleRate;
324 }
325
326 inline uint32_t GetClosestSupportedSampleRate(const AudioFormatInfo& formatInfo)
327 {
328 const AVCodecID codecID = HephAudio::CodecIdFromAudioFormatInfo(formatInfo);
329 const AVCodec* avCodec = avcodec_find_encoder(codecID);
330 return HephAudio::GetClosestSupportedSampleRate(avCodec, formatInfo.sampleRate);
331 }
332}
333
334#define HEPHAUDIO_FFMPEG_GET_ERROR_MESSAGE(errorCode) HephAudio::FFmpegGetErrorMessage(errorCode)
335
336
337#if defined(HEPH_AUDIO_SAMPLE_TYPE_DBL)
338#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_DBL
339#elif defined(HEPH_AUDIO_SAMPLE_TYPE_FLT)
340#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_FLT
341#elif defined(HEPH_AUDIO_SAMPLE_TYPE_S64)
342#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_S64
343#elif defined(HEPH_AUDIO_SAMPLE_TYPE_S32)
344#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_S32
345#elif defined(HEPH_AUDIO_SAMPLE_TYPE_S16)
346#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_S16
347#else
348#define HEPHAUDIO_FFMPEG_INTERNAL_SAMPLE_FMT AV_SAMPLE_FMT_FLT
349#endif
350
351#endif
AudioChannelMask
Definition AudioChannelLayout.h:70
uint16_t count
Definition AudioChannelLayout.h:141