2 * Copyright (C) 2005-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 #include "EncoderFFmpeg.h"
11 #include "ServiceBroker.h"
12 #include "addons/Addon.h"
13 #include "addons/AddonManager.h"
14 #include "cores/FFmpeg.h"
15 #include "settings/Settings.h"
16 #include "settings/SettingsComponent.h"
17 #include "utils/StringUtils.h"
18 #include "utils/SystemInfo.h"
19 #include "utils/URIUtils.h"
20 #include "utils/log.h"
22 using namespace KODI::CDRIP
;
23 using FFMPEG_HELP_TOOLS::FFMpegErrorToString
;
24 using FFMPEG_HELP_TOOLS::FFMpegException
;
26 bool CEncoderFFmpeg::Init()
30 ADDON::AddonPtr addon
;
31 const std::string addonId
= CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
32 CSettings::SETTING_AUDIOCDS_ENCODER
);
34 CServiceBroker::GetAddonMgr().GetAddon(addonId
, addon
, ADDON::OnlyEnabled::CHOICE_YES
);
38 addon
->GetSettingInt("bitrate", bitrate
);
39 bitrate
*= 1000; /* Multiply as on settings as kbps */
43 throw FFMpegException("Could not get add-on: {}", addonId
);
46 // Hack fix about PTS on generated files.
47 // - AAC need to multiply with sample rate
48 // - Note: Within Kodi it can still played without use of sample rate, only becomes by VLC the problem visible,
49 // - WMA need only the multiply with 1000
50 if (addonId
== "audioencoder.kodi.builtin.aac")
51 m_samplesCountMultiply
= m_iInSampleRate
;
52 else if (addonId
== "audioencoder.kodi.builtin.wma")
53 m_samplesCountMultiply
= 1000;
55 throw FFMpegException("Internal add-on id \"{}\" not known as usable", addonId
);
57 const std::string filename
= URIUtils::GetFileName(m_strFile
);
59 m_formatCtx
= avformat_alloc_context();
61 throw FFMpegException("Could not allocate output format context");
63 auto buffer
= static_cast<uint8_t*>(av_malloc(BUFFER_SIZE
+ AV_INPUT_BUFFER_PADDING_SIZE
));
65 throw FFMpegException("Could not allocate buffer");
67 m_formatCtx
->pb
= avio_alloc_context(buffer
, BUFFER_SIZE
, AVIO_FLAG_WRITE
, this, nullptr,
68 avio_write_callback
, avio_seek_callback
);
72 throw FFMpegException("Failed to allocate ByteIOContext");
75 /* Guess the desired container format based on the file extension. */
76 m_formatCtx
->oformat
= av_guess_format(nullptr, filename
.c_str(), nullptr);
77 if (!m_formatCtx
->oformat
)
78 throw FFMpegException("Could not find output file format");
80 m_formatCtx
->url
= av_strdup(filename
.c_str());
81 if (!m_formatCtx
->url
)
82 throw FFMpegException("Could not allocate url");
84 /* Find the encoder to be used by its name. */
85 const AVCodec
* codec
= avcodec_find_encoder(m_formatCtx
->oformat
->audio_codec
);
87 throw FFMpegException("Unable to find a suitable FFmpeg encoder");
89 /* Create a new audio stream in the output file container. */
90 m_stream
= avformat_new_stream(m_formatCtx
, nullptr);
92 throw FFMpegException("Failed to allocate AVStream context");
94 m_codecCtx
= avcodec_alloc_context3(codec
);
96 throw FFMpegException("Failed to allocate the encoder context");
98 /* Set the basic encoder parameters.
99 * The input file's sample rate is used to avoid a sample rate conversion. */
100 av_channel_layout_uninit(&m_codecCtx
->ch_layout
);
101 av_channel_layout_default(&m_codecCtx
->ch_layout
, m_iInChannels
);
102 m_codecCtx
->sample_rate
= m_iInSampleRate
;
103 m_codecCtx
->sample_fmt
= codec
->sample_fmts
[0];
104 m_codecCtx
->bit_rate
= bitrate
;
106 /* Allow experimental encoders (like FFmpeg builtin AAC encoder) */
107 m_codecCtx
->strict_std_compliance
= FF_COMPLIANCE_EXPERIMENTAL
;
109 /* Set the sample rate for the container. */
110 m_codecCtx
->time_base
.num
= 1;
111 m_codecCtx
->time_base
.den
= m_iInSampleRate
;
113 /* Some container formats (like MP4) require global headers to be present.
114 * Mark the encoder so that it behaves accordingly. */
115 if (m_formatCtx
->oformat
->flags
& AVFMT_GLOBALHEADER
)
116 m_codecCtx
->flags
|= AV_CODEC_FLAG_GLOBAL_HEADER
;
118 int err
= avcodec_open2(m_codecCtx
, codec
, nullptr);
120 throw FFMpegException("Failed to open the codec {} (error '{}')",
121 codec
->long_name
? codec
->long_name
: codec
->name
,
122 FFMpegErrorToString(err
));
124 err
= avcodec_parameters_from_context(m_stream
->codecpar
, m_codecCtx
);
126 throw FFMpegException("Failed to copy encoder parameters to output stream (error '{}')",
127 FFMpegErrorToString(err
));
129 m_inFormat
= GetInputFormat(m_iInBitsPerSample
);
130 m_outFormat
= m_codecCtx
->sample_fmt
;
131 m_needConversion
= (m_outFormat
!= m_inFormat
);
133 /* calculate how many bytes we need per frame */
134 m_neededFrames
= m_codecCtx
->frame_size
;
136 av_samples_get_buffer_size(nullptr, m_iInChannels
, m_neededFrames
, m_inFormat
, 0);
137 m_buffer
= static_cast<uint8_t*>(av_malloc(m_neededBytes
));
140 m_bufferFrame
= av_frame_alloc();
141 if (!m_bufferFrame
|| !m_buffer
)
142 throw FFMpegException("Failed to allocate necessary buffers");
144 m_bufferFrame
->nb_samples
= m_codecCtx
->frame_size
;
145 m_bufferFrame
->format
= m_inFormat
;
147 av_channel_layout_uninit(&m_bufferFrame
->ch_layout
);
148 av_channel_layout_copy(&m_bufferFrame
->ch_layout
, &m_codecCtx
->ch_layout
);
150 m_bufferFrame
->sample_rate
= m_codecCtx
->sample_rate
;
152 err
= av_frame_get_buffer(m_bufferFrame
, 0);
154 throw FFMpegException("Could not allocate output frame samples (error '{}')",
155 FFMpegErrorToString(err
));
157 avcodec_fill_audio_frame(m_bufferFrame
, m_iInChannels
, m_inFormat
, m_buffer
, m_neededBytes
, 0);
159 if (m_needConversion
)
161 int ret
= swr_alloc_set_opts2(&m_swrCtx
, &m_codecCtx
->ch_layout
, m_outFormat
,
162 m_codecCtx
->sample_rate
, &m_codecCtx
->ch_layout
, m_inFormat
,
163 m_codecCtx
->sample_rate
, 0, nullptr);
164 if (ret
|| swr_init(m_swrCtx
) < 0)
165 throw FFMpegException("Failed to initialize the resampler");
167 m_resampledBufferSize
=
168 av_samples_get_buffer_size(nullptr, m_iInChannels
, m_neededFrames
, m_outFormat
, 0);
169 m_resampledBuffer
= static_cast<uint8_t*>(av_malloc(m_resampledBufferSize
));
170 m_resampledFrame
= av_frame_alloc();
171 if (!m_resampledBuffer
|| !m_resampledFrame
)
172 throw FFMpegException("Failed to allocate a frame for resampling");
174 m_resampledFrame
->nb_samples
= m_neededFrames
;
175 m_resampledFrame
->format
= m_outFormat
;
176 av_channel_layout_uninit(&m_resampledFrame
->ch_layout
);
177 av_channel_layout_copy(&m_resampledFrame
->ch_layout
, &m_codecCtx
->ch_layout
);
178 m_resampledFrame
->sample_rate
= m_codecCtx
->sample_rate
;
180 err
= av_frame_get_buffer(m_resampledFrame
, 0);
182 throw FFMpegException("Could not allocate output resample frame samples (error '{}')",
183 FFMpegErrorToString(err
));
185 avcodec_fill_audio_frame(m_resampledFrame
, m_iInChannels
, m_outFormat
, m_resampledBuffer
,
186 m_resampledBufferSize
, 0);
190 SetTag("album", m_strAlbum
);
191 SetTag("album_artist", m_strArtist
);
192 SetTag("genre", m_strGenre
);
193 SetTag("title", m_strTitle
);
194 SetTag("track", m_strTrack
);
195 SetTag("encoder", CSysInfo::GetAppName() + " FFmpeg Encoder");
197 /* write the header */
198 err
= avformat_write_header(m_formatCtx
, nullptr);
200 throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err
));
202 CLog::Log(LOGDEBUG
, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}",
204 m_formatCtx
->oformat
->long_name
? m_formatCtx
->oformat
->long_name
205 : m_formatCtx
->oformat
->name
,
206 codec
->long_name
? codec
->long_name
: codec
->name
);
208 catch (const FFMpegException
& caught
)
210 CLog::Log(LOGERROR
, "CEncoderFFmpeg::{} - {}", __func__
, caught
.what());
213 av_channel_layout_uninit(&m_bufferFrame
->ch_layout
);
214 av_frame_free(&m_bufferFrame
);
216 av_channel_layout_uninit(&m_resampledFrame
->ch_layout
);
217 av_frame_free(&m_resampledFrame
);
218 av_freep(&m_resampledBuffer
);
219 av_channel_layout_uninit(&m_codecCtx
->ch_layout
);
220 avcodec_free_context(&m_codecCtx
);
223 av_freep(&m_formatCtx
->pb
->buffer
);
224 av_freep(&m_formatCtx
->pb
);
225 avformat_free_context(m_formatCtx
);
233 void CEncoderFFmpeg::SetTag(const std::string
& tag
, const std::string
& value
)
235 av_dict_set(&m_formatCtx
->metadata
, tag
.c_str(), value
.c_str(), 0);
238 int CEncoderFFmpeg::avio_write_callback(void* opaque
, uint8_t* buf
, int buf_size
)
240 CEncoderFFmpeg
* enc
= static_cast<CEncoderFFmpeg
*>(opaque
);
241 if (enc
->Write(buf
, buf_size
) != buf_size
)
243 CLog::Log(LOGERROR
, "CEncoderFFmpeg::{} - Error writing FFmpeg buffer to file", __func__
);
249 int64_t CEncoderFFmpeg::avio_seek_callback(void* opaque
, int64_t offset
, int whence
)
251 CEncoderFFmpeg
* enc
= static_cast<CEncoderFFmpeg
*>(opaque
);
252 return enc
->Seek(offset
, whence
);
255 ssize_t
CEncoderFFmpeg::Encode(uint8_t* pbtStream
, size_t nNumBytesRead
)
257 while (nNumBytesRead
> 0)
259 size_t space
= m_neededBytes
- m_bufferSize
;
260 size_t copy
= nNumBytesRead
> space
? space
: nNumBytesRead
;
262 memcpy(&m_buffer
[m_bufferSize
], pbtStream
, copy
);
263 m_bufferSize
+= copy
;
265 nNumBytesRead
-= copy
;
267 /* only write full packets */
268 if (m_bufferSize
== m_neededBytes
)
278 bool CEncoderFFmpeg::WriteFrame()
280 int err
= AVERROR_UNKNOWN
;
281 AVPacket
* pkt
= av_packet_alloc();
284 CLog::Log(LOGERROR
, "CEncoderFFmpeg::{} - av_packet_alloc failed: {}", __func__
,
292 if (m_needConversion
)
294 //! @bug libavresample isn't const correct
295 if (swr_convert(m_swrCtx
, m_resampledFrame
->data
, m_neededFrames
,
296 const_cast<const uint8_t**>(m_bufferFrame
->extended_data
),
298 throw FFMpegException("Error resampling audio");
300 frame
= m_resampledFrame
;
303 frame
= m_bufferFrame
;
307 /* To fix correct length on wma files */
308 frame
->pts
= m_samplesCount
;
309 m_samplesCount
+= frame
->nb_samples
* m_samplesCountMultiply
/ m_codecCtx
->time_base
.den
;
313 err
= avcodec_send_frame(m_codecCtx
, frame
);
315 throw FFMpegException("Error sending a frame for encoding (error '{}')",
316 FFMpegErrorToString(err
));
320 err
= avcodec_receive_packet(m_codecCtx
, pkt
);
321 if (err
== AVERROR(EAGAIN
) || err
== AVERROR_EOF
)
323 av_packet_free(&pkt
);
324 return (err
== AVERROR(EAGAIN
)) ? false : true;
328 throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err
));
331 err
= av_write_frame(m_formatCtx
, pkt
);
333 throw FFMpegException("Failed to write the frame data (error '{}')",
334 FFMpegErrorToString(err
));
336 av_packet_unref(pkt
);
339 catch (const FFMpegException
& caught
)
341 CLog::Log(LOGERROR
, "CEncoderFFmpeg::{} - {}", __func__
, caught
.what());
344 av_packet_free(&pkt
);
346 return (err
) ? false : true;
349 bool CEncoderFFmpeg::Close()
353 /* if there is anything still in the buffer */
354 if (m_bufferSize
> 0)
356 /* zero the unused space so we dont encode random junk */
357 memset(&m_buffer
[m_bufferSize
], 0, m_neededBytes
- m_bufferSize
);
358 /* write any remaining data */
362 /* Flush if needed */
364 av_channel_layout_uninit(&m_bufferFrame
->ch_layout
);
365 av_frame_free(&m_bufferFrame
);
367 av_channel_layout_uninit(&m_resampledFrame
->ch_layout
);
368 av_frame_free(&m_resampledFrame
);
369 av_freep(&m_resampledBuffer
);
370 m_needConversion
= false;
374 /* write the trailer */
375 av_write_trailer(m_formatCtx
);
378 av_channel_layout_uninit(&m_codecCtx
->ch_layout
);
379 avcodec_free_context(&m_codecCtx
);
380 av_freep(&m_formatCtx
->pb
->buffer
);
381 av_freep(&m_formatCtx
->pb
);
382 avformat_free_context(m_formatCtx
);
390 AVSampleFormat
CEncoderFFmpeg::GetInputFormat(int inBitsPerSample
)
392 switch (inBitsPerSample
)
395 return AV_SAMPLE_FMT_U8
;
397 return AV_SAMPLE_FMT_S16
;
399 return AV_SAMPLE_FMT_S32
;
401 throw FFMpegException("Invalid input bits per sample");