[XAudio2] avoid leak + fix voice creation for closest match
[xbmc.git] / xbmc / cdrip / EncoderFFmpeg.cpp
blob85f5fa412e9616b06c23211939648f81f0fc02f7
1 /*
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.
7 */
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()
28 try
30 ADDON::AddonPtr addon;
31 const std::string addonId = CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(
32 CSettings::SETTING_AUDIOCDS_ENCODER);
33 bool success =
34 CServiceBroker::GetAddonMgr().GetAddon(addonId, addon, ADDON::OnlyEnabled::CHOICE_YES);
35 int bitrate;
36 if (success && addon)
38 addon->GetSettingInt("bitrate", bitrate);
39 bitrate *= 1000; /* Multiply as on settings as kbps */
41 else
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;
54 else
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();
60 if (!m_formatCtx)
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));
64 if (!buffer)
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);
69 if (!m_formatCtx->pb)
71 av_free(buffer);
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);
86 if (!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);
91 if (!m_stream)
92 throw FFMpegException("Failed to allocate AVStream context");
94 m_codecCtx = avcodec_alloc_context3(codec);
95 if (!m_codecCtx)
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);
119 if (err < 0)
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);
125 if (err < 0)
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;
135 m_neededBytes =
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));
138 m_bufferSize = 0;
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);
153 if (err < 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);
181 if (err < 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);
189 /* set the tags */
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);
199 if (err != 0)
200 throw FFMpegException("Failed to write the header (error '{}')", FFMpegErrorToString(err));
202 CLog::Log(LOGDEBUG, "CEncoderFFmpeg::{} - Successfully initialized with muxer {} and codec {}",
203 __func__,
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());
212 av_freep(&m_buffer);
213 av_channel_layout_uninit(&m_bufferFrame->ch_layout);
214 av_frame_free(&m_bufferFrame);
215 swr_free(&m_swrCtx);
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);
221 if (m_formatCtx)
223 av_freep(&m_formatCtx->pb->buffer);
224 av_freep(&m_formatCtx->pb);
225 avformat_free_context(m_formatCtx);
227 return false;
230 return true;
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__);
244 return -1;
246 return buf_size;
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;
264 pbtStream += copy;
265 nNumBytesRead -= copy;
267 /* only write full packets */
268 if (m_bufferSize == m_neededBytes)
270 if (!WriteFrame())
271 return 0;
275 return 1;
278 bool CEncoderFFmpeg::WriteFrame()
280 int err = AVERROR_UNKNOWN;
281 AVPacket* pkt = av_packet_alloc();
282 if (!pkt)
284 CLog::Log(LOGERROR, "CEncoderFFmpeg::{} - av_packet_alloc failed: {}", __func__,
285 strerror(errno));
286 return false;
291 AVFrame* frame;
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),
297 m_neededFrames) < 0)
298 throw FFMpegException("Error resampling audio");
300 frame = m_resampledFrame;
302 else
303 frame = m_bufferFrame;
305 if (frame)
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;
312 m_bufferSize = 0;
313 err = avcodec_send_frame(m_codecCtx, frame);
314 if (err < 0)
315 throw FFMpegException("Error sending a frame for encoding (error '{}')",
316 FFMpegErrorToString(err));
318 while (err >= 0)
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;
326 else if (err < 0)
328 throw FFMpegException("Error during encoding (error '{}')", FFMpegErrorToString(err));
331 err = av_write_frame(m_formatCtx, pkt);
332 if (err < 0)
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()
351 if (m_formatCtx)
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 */
359 WriteFrame();
362 /* Flush if needed */
363 av_freep(&m_buffer);
364 av_channel_layout_uninit(&m_bufferFrame->ch_layout);
365 av_frame_free(&m_bufferFrame);
366 swr_free(&m_swrCtx);
367 av_channel_layout_uninit(&m_resampledFrame->ch_layout);
368 av_frame_free(&m_resampledFrame);
369 av_freep(&m_resampledBuffer);
370 m_needConversion = false;
372 WriteFrame();
374 /* write the trailer */
375 av_write_trailer(m_formatCtx);
377 /* cleanup */
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);
385 m_bufferSize = 0;
387 return true;
390 AVSampleFormat CEncoderFFmpeg::GetInputFormat(int inBitsPerSample)
392 switch (inBitsPerSample)
394 case 8:
395 return AV_SAMPLE_FMT_U8;
396 case 16:
397 return AV_SAMPLE_FMT_S16;
398 case 32:
399 return AV_SAMPLE_FMT_S32;
400 default:
401 throw FFMpegException("Invalid input bits per sample");