10#include <QtCore/qloggingcategory.h>
23 qCDebug(qLcFFmpegAudioEncoder) <<
"AudioEncoder" <<
settings.audioCodec();
25 m_format =
input->device.preferredFormat();
27 Q_ASSERT(avformat_query_codec(recordingEngine.avFormatContext()->oformat, codecID,
28 FF_COMPLIANCE_NORMAL));
37 qCDebug(qLcFFmpegAudioEncoder) <<
"found audio codec" << m_avCodec->name;
41 m_stream = avformat_new_stream(recordingEngine.avFormatContext(),
nullptr);
42 m_stream->id = recordingEngine.avFormatContext()->nb_streams - 1;
43 m_stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
44 m_stream->codecpar->codec_id = codecID;
45#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
46 m_stream->codecpar->channel_layout =
48 m_stream->codecpar->channels =
qPopulationCount(m_stream->codecpar->channel_layout);
50 m_stream->codecpar->ch_layout =
53 const auto sampleRate =
54 adjustSampleRate(m_avCodec->supported_samplerates, requestedAudioFormat.sampleRate);
56 m_stream->codecpar->sample_rate = sampleRate;
57 m_stream->codecpar->frame_size = 1024;
58 m_stream->codecpar->format =
61 m_stream->time_base = AVRational{ 1, sampleRate };
63 qCDebug(qLcFFmpegAudioEncoder) <<
"set stream time_base" << m_stream->time_base.num <<
"/"
64 << m_stream->time_base.den;
69 m_codecContext.reset(avcodec_alloc_context3(m_avCodec));
71 if (m_stream->time_base.num != 1 || m_stream->time_base.den != m_format.
sampleRate()) {
72 qCDebug(qLcFFmpegAudioEncoder) <<
"Most likely, av_format_write_header changed time base from"
74 << m_stream->time_base;
77 m_codecContext->time_base = m_stream->time_base;
79 avcodec_parameters_to_context(m_codecContext.get(), m_stream->codecpar);
85 int res = avcodec_open2(m_codecContext.get(), m_avCodec, opts);
86 qCDebug(qLcFFmpegAudioEncoder) <<
"audio codec opened" <<
res;
87 qCDebug(qLcFFmpegAudioEncoder) <<
"audio codec params: fmt=" << m_codecContext->sample_fmt
88 <<
"rate=" << m_codecContext->sample_rate;
93 if (requestedAudioFormat != codecAudioFormat)
100 const std::chrono::microseconds bufferDuration(
buffer.duration());
108 m_audioBufferQueue.push(
buffer);
109 m_queueDuration += bufferDuration;
119 m_queueDuration -= std::chrono::microseconds(
result.duration());
129 qCDebug(qLcFFmpegAudioEncoder) <<
"AudioEncoder::init started audio device thread.";
134 while (!m_audioBufferQueue.empty())
136 while (avcodec_send_frame(m_codecContext.get(),
nullptr) == AVERROR(EAGAIN))
143 return !m_audioBufferQueue.empty();
146void AudioEncoder::retrievePackets()
150 int ret = avcodec_receive_packet(m_codecContext.get(), packet.get());
152 if (
ret != AVERROR(EOF))
154 if (
ret != AVERROR(EAGAIN)) {
156 av_strerror(
ret, errStr, 1024);
157 qCDebug(qLcFFmpegAudioEncoder) <<
"receive packet" <<
ret << errStr;
164 packet->stream_index = m_stream->id;
175 if (
buffer.format() != m_format) {
177 qWarning() <<
"Get invalid audio format:" <<
buffer.format() <<
", expected:" << m_format;
186 frame->format = m_codecContext->sample_fmt;
187#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
188 frame->channel_layout = m_codecContext->channel_layout;
189 frame->channels = m_codecContext->channels;
191 frame->ch_layout = m_codecContext->ch_layout;
193 frame->sample_rate = m_codecContext->sample_rate;
195 if (
frame->nb_samples)
196 av_frame_get_buffer(
frame.get(), 0);
199 const uint8_t *
data =
buffer.constData<uint8_t>();
200 swr_convert(m_resampler.get(),
frame->extended_data,
frame->nb_samples, &
data,
206 const auto &timeBase = m_stream->time_base;
207 const auto pts = timeBase.den && timeBase.num
208 ? timeBase.den * m_samplesWritten / (m_codecContext->sample_rate * timeBase.num)
211 m_samplesWritten +=
buffer.frameCount();
219 int ret = avcodec_send_frame(m_codecContext.get(),
frame.get());
222 av_strerror(
ret, errStr, 1024);
230 return m_audioBufferQueue.size() <= 1 || m_queueDuration < m_maxQueueDuration;
232 return m_audioBufferQueue.empty();
void addBuffer(const QAudioBuffer &buffer)
void cleanup() override
Called on this thread before thread exits.
bool hasData() const override
Must return true when data is available for processing.
void processOne() override
Process one work item.
AudioEncoder(RecordingEngine &recordingEngine, QFFmpegAudioInput *input, const QMediaEncoderSettings &settings)
bool checkIfCanPushFrame() const override
void init() override
Called on this thread when thread starts.
void dataReady()
Wake thread from sleep and process data until hasData() returns false.
RecordingEngine & m_recordingEngine
void addPacket(AVPacketUPtr packet)
void newTimeStamp(qint64 time)
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
AVFrameUPtr makeAVFrame()
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
AVSampleFormat adjustSampleFormat(const AVSampleFormat *supportedFormats, AVSampleFormat requested)
void setAVFrameTime(AVFrame &frame, int64_t pts, const AVRational &timeBase)
T dequeueIfPossible(std::queue< T > &queue)
AVChannelLayout adjustChannelLayout(const AVChannelLayout *supportedLayouts, const AVChannelLayout &requested)
int adjustSampleRate(const int *supportedRates, int requested)
void applyExperimentalCodecOptions(const AVCodec *codec, AVDictionary **opts)
void applyAudioEncoderOptions(const QMediaEncoderSettings &settings, const QByteArray &codecName, AVCodecContext *codec, AVDictionary **opts)
SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat, const AVAudioFormat &outputFormat)
std::unique_ptr< AVPacket, AVDeleter< decltype(&av_packet_free), &av_packet_free > > AVPacketUPtr
Combined button and popup list for selecting options.
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum input
QLatin1StringView QLatin1String
QSettings settings("MySoft", "Star Runner")
[0]