2 * Copyright (C) 2010-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #define AC3_ENCODE_BITRATE 640000
10 #define DTS_ENCODE_BITRATE 1411200
12 #include "cores/AudioEngine/Encoders/AEEncoderFFmpeg.h"
14 #include "ServiceBroker.h"
15 #include "cores/AudioEngine/Utils/AEUtil.h"
16 #include "cores/FFmpeg.h"
17 #include "settings/Settings.h"
18 #include "settings/SettingsComponent.h"
19 #include "utils/log.h"
23 #include <libavutil/channel_layout.h>
29 using FFMPEG_HELP_TOOLS::FFMpegErrorToString
;
30 using FFMPEG_HELP_TOOLS::FFMpegException
;
32 CAEEncoderFFmpeg::CAEEncoderFFmpeg() : m_CodecCtx(NULL
), m_SwrCtx(NULL
)
36 CAEEncoderFFmpeg::~CAEEncoderFFmpeg()
40 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
41 avcodec_free_context(&m_CodecCtx
);
44 bool CAEEncoderFFmpeg::IsCompatible(const AEAudioFormat
& format
)
50 format
.m_dataFormat
== m_CurrentFormat
.m_dataFormat
&&
51 format
.m_sampleRate
== m_CurrentFormat
.m_sampleRate
56 CAEChannelInfo layout
;
57 BuildChannelLayout(AV_CH_LAYOUT_5POINT1_BACK
, layout
); /* hard coded for AC3 & DTS currently */
58 match
= (m_CurrentFormat
.m_channelLayout
== layout
);
64 unsigned int CAEEncoderFFmpeg::BuildChannelLayout(const int64_t ffmap
, CAEChannelInfo
& layout
)
66 /* build the channel layout and count the channels */
68 if (ffmap
& AV_CH_FRONT_LEFT
) layout
+= AE_CH_FL
;
69 if (ffmap
& AV_CH_FRONT_RIGHT
) layout
+= AE_CH_FR
;
70 if (ffmap
& AV_CH_FRONT_CENTER
) layout
+= AE_CH_FC
;
71 if (ffmap
& AV_CH_LOW_FREQUENCY
) layout
+= AE_CH_LFE
;
72 if (ffmap
& AV_CH_BACK_LEFT
) layout
+= AE_CH_BL
;
73 if (ffmap
& AV_CH_BACK_RIGHT
) layout
+= AE_CH_BR
;
74 if (ffmap
& AV_CH_FRONT_LEFT_OF_CENTER
) layout
+= AE_CH_FLOC
;
75 if (ffmap
& AV_CH_FRONT_RIGHT_OF_CENTER
) layout
+= AE_CH_FROC
;
76 if (ffmap
& AV_CH_BACK_CENTER
) layout
+= AE_CH_BC
;
77 if (ffmap
& AV_CH_SIDE_LEFT
) layout
+= AE_CH_SL
;
78 if (ffmap
& AV_CH_SIDE_RIGHT
) layout
+= AE_CH_SR
;
79 if (ffmap
& AV_CH_TOP_CENTER
) layout
+= AE_CH_TC
;
80 if (ffmap
& AV_CH_TOP_FRONT_LEFT
) layout
+= AE_CH_TFL
;
81 if (ffmap
& AV_CH_TOP_FRONT_CENTER
) layout
+= AE_CH_TFC
;
82 if (ffmap
& AV_CH_TOP_FRONT_RIGHT
) layout
+= AE_CH_TFR
;
83 if (ffmap
& AV_CH_TOP_BACK_LEFT
) layout
+= AE_CH_TBL
;
84 if (ffmap
& AV_CH_TOP_BACK_CENTER
) layout
+= AE_CH_TBC
;
85 if (ffmap
& AV_CH_TOP_BACK_RIGHT
) layout
+= AE_CH_TBR
;
87 return layout
.Count();
90 bool CAEEncoderFFmpeg::Initialize(AEAudioFormat
&format
, bool allow_planar_input
)
94 bool ac3
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_AUDIOOUTPUT_AC3PASSTHROUGH
);
96 const AVCodec
* codec
= nullptr;
98 /* fallback to ac3 if we support it, we might not have DTS support */
102 m_CodecID
= AV_CODEC_ID_AC3
;
103 m_BitRate
= AC3_ENCODE_BITRATE
;
104 codec
= avcodec_find_encoder(m_CodecID
);
107 /* check we got the codec */
111 m_CodecCtx
= avcodec_alloc_context3(codec
);
115 m_CodecCtx
->bit_rate
= m_BitRate
;
116 m_CodecCtx
->sample_rate
= format
.m_sampleRate
;
117 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
118 av_channel_layout_from_mask(&m_CodecCtx
->ch_layout
, AV_CH_LAYOUT_5POINT1_BACK
);
120 /* select a suitable data format */
121 if (codec
->sample_fmts
)
123 bool hasFloat
= false;
124 bool hasDouble
= false;
128 bool hasFloatP
= false;
129 bool hasUnknownFormat
= false;
131 for(int i
= 0; codec
->sample_fmts
[i
] != AV_SAMPLE_FMT_NONE
; ++i
)
133 switch (codec
->sample_fmts
[i
])
135 case AV_SAMPLE_FMT_FLT
: hasFloat
= true; break;
136 case AV_SAMPLE_FMT_DBL
: hasDouble
= true; break;
137 case AV_SAMPLE_FMT_S32
: hasS32
= true; break;
138 case AV_SAMPLE_FMT_S16
: hasS16
= true; break;
139 case AV_SAMPLE_FMT_U8
: hasU8
= true; break;
140 case AV_SAMPLE_FMT_FLTP
:
141 if (allow_planar_input
)
144 hasUnknownFormat
= true;
146 case AV_SAMPLE_FMT_NONE
: return false;
147 default: hasUnknownFormat
= true; break;
153 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_FLT
;
154 format
.m_dataFormat
= AE_FMT_FLOAT
;
158 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_FLTP
;
159 format
.m_dataFormat
= AE_FMT_FLOATP
;
163 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_DBL
;
164 format
.m_dataFormat
= AE_FMT_DOUBLE
;
168 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_S32
;
169 format
.m_dataFormat
= AE_FMT_S32NE
;
173 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_S16
;
174 format
.m_dataFormat
= AE_FMT_S16NE
;
178 m_CodecCtx
->sample_fmt
= AV_SAMPLE_FMT_U8
;
179 format
.m_dataFormat
= AE_FMT_U8
;
181 else if (hasUnknownFormat
)
183 m_CodecCtx
->sample_fmt
= codec
->sample_fmts
[0];
184 format
.m_dataFormat
= AE_FMT_FLOAT
;
185 m_NeedConversion
= true;
187 "CAEEncoderFFmpeg::Initialize - Unknown audio format, it will be resampled.");
193 "CAEEncoderFFmpeg::Initialize - Unable to find a suitable data format for the codec ({})",
195 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
196 avcodec_free_context(&m_CodecCtx
);
201 uint64_t mask
= m_CodecCtx
->ch_layout
.u
.mask
;
202 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
203 av_channel_layout_from_mask(&m_CodecCtx
->ch_layout
, mask
);
204 m_CodecCtx
->ch_layout
.nb_channels
= BuildChannelLayout(mask
, m_Layout
);
207 if (avcodec_open2(m_CodecCtx
, codec
, NULL
))
209 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
210 avcodec_free_context(&m_CodecCtx
);
214 format
.m_frames
= m_CodecCtx
->frame_size
;
215 int channels
= m_CodecCtx
->ch_layout
.nb_channels
;
216 format
.m_frameSize
= channels
* (CAEUtil::DataFormatToBits(format
.m_dataFormat
) >> 3);
217 format
.m_channelLayout
= m_Layout
;
219 m_CurrentFormat
= format
;
220 m_NeededFrames
= format
.m_frames
;
221 m_OutputRatio
= (double)m_NeededFrames
/ m_OutputSize
;
222 m_SampleRateMul
= 1.0 / (double)m_CodecCtx
->sample_rate
;
224 if (m_NeedConversion
)
226 int ret
= swr_alloc_set_opts2(&m_SwrCtx
, &m_CodecCtx
->ch_layout
, m_CodecCtx
->sample_fmt
,
227 m_CodecCtx
->sample_rate
, &m_CodecCtx
->ch_layout
,
228 AV_SAMPLE_FMT_FLT
, m_CodecCtx
->sample_rate
, 0, NULL
);
229 if (ret
|| swr_init(m_SwrCtx
) < 0)
231 CLog::Log(LOGERROR
, "CAEEncoderFFmpeg::Initialize - Failed to initialise resampler.");
233 av_channel_layout_uninit(&m_CodecCtx
->ch_layout
);
234 avcodec_free_context(&m_CodecCtx
);
238 CLog::Log(LOGINFO
, "CAEEncoderFFmpeg::Initialize - {} encoder ready", m_CodecName
);
242 void CAEEncoderFFmpeg::Reset()
247 unsigned int CAEEncoderFFmpeg::GetBitRate()
252 AVCodecID
CAEEncoderFFmpeg::GetCodecID()
257 unsigned int CAEEncoderFFmpeg::GetFrames()
259 return m_NeededFrames
;
262 int CAEEncoderFFmpeg::Encode(uint8_t *in
, int in_size
, uint8_t *out
, int out_size
)
265 int err
= AVERROR_UNKNOWN
;
266 AVFrame
* frame
= nullptr;
267 AVPacket
* pkt
= nullptr;
274 /* allocate the input frame and output packet
275 * sadly, we have to alloc/dealloc it everytime since we have no guarantee the
276 * data argument will be constant over iterated calls and the frame needs to
277 * setup pointers inside data */
278 frame
= av_frame_alloc();
279 pkt
= av_packet_alloc();
281 throw FFMpegException(
282 "Failed to allocate \"AVFrame\" or \"AVPacket\" for encoding (error '{}')",
285 frame
->nb_samples
= m_CodecCtx
->frame_size
;
286 frame
->format
= m_CodecCtx
->sample_fmt
;
287 av_channel_layout_uninit(&frame
->ch_layout
);
288 av_channel_layout_copy(&frame
->ch_layout
, &m_CodecCtx
->ch_layout
);
289 int channelNum
= m_CodecCtx
->ch_layout
.nb_channels
;
291 avcodec_fill_audio_frame(frame
, channelNum
, m_CodecCtx
->sample_fmt
, in
, in_size
, 0);
294 err
= avcodec_send_frame(m_CodecCtx
, frame
);
296 throw FFMpegException("Error sending a frame for encoding (error '{}')",
297 FFMpegErrorToString(err
));
299 err
= avcodec_receive_packet(m_CodecCtx
, pkt
);
300 //! @TODO: This is a workaround for our current design. The caller should be made
301 // aware of the potential error values to use the ffmpeg API in a proper way, which means
302 // copying with EAGAIN and multiple packet output.
303 // For the current situation there is a relationship implicitely assumed of:
304 // 1 frame in - 1 packet out. This holds true in practice but the API does not guarantee it.
307 if (pkt
->size
<= out_size
)
309 memset(out
, 0, out_size
);
310 memcpy(out
, pkt
->data
, pkt
->size
);
315 CLog::LogF(LOGERROR
, "Encoded pkt size ({}) is bigger than buffer ({})", pkt
->size
,
318 av_packet_unref(pkt
);
322 CLog::LogF(LOGERROR
, "Error receiving encoded paket ({})", err
);
325 catch (const FFMpegException
& caught
)
327 CLog::Log(LOGERROR
, "CAEEncoderFFmpeg::{} - {}", __func__
, caught
.what());
330 av_channel_layout_uninit(&frame
->ch_layout
);
332 /* free temporary data */
333 av_frame_free(&frame
);
335 /* free the packet */
336 av_packet_free(&pkt
);
338 /* return the number of frames used */
342 int CAEEncoderFFmpeg::GetData(uint8_t **data
)
351 double CAEEncoderFFmpeg::GetDelay(unsigned int bufferSize
)
356 int frames
= m_CodecCtx
->delay
;
358 frames
+= m_NeededFrames
;
360 return ((double)frames
+ ((double)bufferSize
* m_OutputRatio
)) * m_SampleRateMul
;