vdr-plugin-softhddevice-drm-gles 1.6.7
codec_audio.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
17#include <cstdint>
18#include <mutex>
19#include <string>
20#include <vector>
21#include <unistd.h>
22
23extern "C" {
24#include <libavcodec/avcodec.h>
25#include <libavformat/avformat.h>
26}
27
28#include "audio.h"
29#include "codec_audio.h"
30#include "logger.h"
31#include "misc.h"
32
40static std::string GetPassthroughMaskString(int mask)
41{
42 std::string passthrough = "";
43
44 if (mask) {
45 passthrough += " (passthrough mask:";
46 if (mask & CODEC_AC3) passthrough += " AC3";
47 if (mask & CODEC_EAC3) passthrough += " E-AC-3";
48 if (mask & CODEC_DTS) passthrough += " DTS";
49 passthrough += ")";
50 }
51
52 return passthrough;
53}
54
61 : m_pAudio(audio),
62 m_passthroughMask(m_pAudio->GetPassthroughMask() & (CODEC_AC3 | CODEC_EAC3 | CODEC_DTS))
63{
64 if (!(m_pFrame = av_frame_alloc()))
65 LOGFATAL("audiocodec: %s: can't allocate audio decoder frame buffer", __FUNCTION__);
66
68}
69
76
87{
88 std::lock_guard<std::mutex> lock(m_mutex);
89
90 const AVCodec *codec;
91
92 m_codecId = codecId;
93
94 switch (codecId) {
95 case AV_CODEC_ID_AC3:
96 if (!(codec = avcodec_find_decoder_by_name("ac3_fixed")))
97 LOGFATAL("audiocodec: %s: codec ac3_fixed ID %#06x not found", __FUNCTION__, codecId);
98 break;
99 case AV_CODEC_ID_AAC:
100 if (!(codec = avcodec_find_decoder_by_name("aac_fixed")))
101 LOGFATAL("audiocodec: %s: codec aac_fixed ID %#06x not found", __FUNCTION__, codecId);
102 break;
103 default:
104 if (!(codec = avcodec_find_decoder(codecId))) {
105 LOGFATAL("audiocodec: %s: codec %s ID %#06x not found", __FUNCTION__,
106 avcodec_get_name(codecId), codecId);
107 }
108 break;
109 }
110
112 LOGFATAL("audiocodec: %s: can't allocate audio codec context", __FUNCTION__);
113
114 m_pAudioCtx->pkt_timebase = timebase;
115
117 LOGERROR("audiocodec: %s: insert parameters to context failed!", __FUNCTION__);
118
119 if (avcodec_open2(m_pAudioCtx, m_pAudioCtx->codec, NULL) < 0)
120 LOGFATAL("audiocodec: %s: can't open audio codec", __FUNCTION__);
121
122 LOGDEBUG2(L_CODEC, "audiocodec: %s: Codec %s found%s", __FUNCTION__, m_pAudioCtx->codec->long_name, GetPassthroughMaskString(m_passthroughMask).c_str());
123
129}
130
135{
136 std::lock_guard<std::mutex> lock(m_mutex);
137
138 if (!m_pAudioCtx)
139 return;
140
142
143 LOGDEBUG2(L_CODEC, "audiocodec: %s", __FUNCTION__);
144
146
149}
150
157#if LIBAVFORMAT_VERSION_MAJOR >= 61
158int cAudioDecoder::SpdifWriteCallback(void *opaque, const uint8_t *buffer, int bufferSize)
159#else
161#endif
162{
163 auto &output = *static_cast<std::vector<uint8_t> *>(opaque);
164 output.insert(output.end(), buffer, buffer + bufferSize);
165
166 return bufferSize;
167}
168
179{
181
182 if (avformat_alloc_output_context2(&m_spdifFmtCtx, nullptr, "spdif", nullptr) < 0 || !m_spdifFmtCtx) {
183 LOGERROR("audiocodec: %s: failed to allocate spdif muxer", __FUNCTION__);
184 return false;
185 }
186
188 if (!m_spdifFmtCtx->pb) {
190 m_spdifFmtCtx = nullptr;
191 return false;
192 }
193
195 if (!stream) {
197 return false;
198 }
199
200 stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
201 stream->codecpar->codec_id = codecId;
202 stream->codecpar->sample_rate = sampleRate;
203 av_channel_layout_default(&stream->codecpar->ch_layout, 2);
204 stream->time_base = AVRational{1, sampleRate};
205
206 if (avformat_write_header(m_spdifFmtCtx, nullptr) < 0) {
207 LOGERROR("audiocodec: %s: failed to write avformat header", __FUNCTION__);
209 return false;
210 }
211
212 LOGDEBUG2(L_CODEC, "audiocodec: %s: opened spdif muxer for %s @ %dHz", __FUNCTION__, avcodec_get_name(codecId), sampleRate);
213
214 return true;
215}
216
221{
222 if (m_spdifFmtCtx) {
223 LOGDEBUG2(L_CODEC, "audiocodec: %s: close spdif muxer", __FUNCTION__);
224 if (m_spdifFmtCtx->pb) {
225 m_spdifFmtCtx->pb->buffer = nullptr;
227 }
229 m_spdifFmtCtx = nullptr;
230 }
231
232 m_spdifOutputBuf.clear();
233}
234
242const std::vector<uint8_t> &cAudioDecoder::BuildIEC61937(const AVPacket *avpkt)
243{
244 if (!m_spdifFmtCtx || !avpkt || !avpkt->data || avpkt->size <= 0) {
245 m_spdifOutputBuf.clear();
246 return m_spdifOutputBuf;
247 }
248
249 m_spdifOutputBuf.clear();
250
251 AVPacket pkt = {};
252 int ret = av_packet_ref(&pkt, avpkt);
253 if (ret < 0) {
254 LOGERROR("audiocodec: %s: av_packet_ref failed: %s", __FUNCTION__, av_err2str(ret));
255 return m_spdifOutputBuf;
256 }
257
258 pkt.stream_index = 0;
259
262 if (ret < 0) {
263 LOGERROR("audiocodec: %s: av_write_frame failed: %s", __FUNCTION__, av_err2str(ret));
264 m_spdifOutputBuf.clear();
265 return m_spdifOutputBuf;
266 }
267
268 // always flush to see, if new output is ready
270
271 return m_spdifOutputBuf;
272}
273
289
297{
301 return 0;
302
303 m_currentHwSampleRate = m_pAudioCtx->sample_rate;
304 m_currentHwNumChannels = m_pAudioCtx->ch_layout.nb_channels;
305
306 if (passthrough) {
310
311 // E-AC3 over HDMI: some receivers need HBR
312 if (m_pAudioCtx->codec_id == AV_CODEC_ID_EAC3)
314 }
315
316 int err = 0;
318 // E-AC3 over HDMI: try without HBR
320
321 if (m_pAudioCtx->codec_id != AV_CODEC_ID_EAC3 ||
323 LOGERROR("audiocodec: %s: format change update error", __FUNCTION__);
326 return err;
327 }
328 }
329
330 // remember for next update check
334
335 // audio was newly set up (err == 0)
336 if (!err)
337 LOGDEBUG2(L_SOUND, "audiocodec: %s: format changed %s %dHz *%d channels%s", __FUNCTION__,
340
341 return 0;
342}
343
350{
351 std::lock_guard<std::mutex> lock(m_mutex);
352
355 else
357}
358
371{
372 if (CheckUpdateFormat(true)) {
373 LOGERROR("audiocodec: %s: unsupported format!", __FUNCTION__);
374 return 0;
375 }
376
378 LOGERROR("audiocodec: %s: failed to open spdif muxer for codec %s @ %dHz!", __FUNCTION__, avcodec_get_name(m_pAudioCtx->codec_id), m_currentHwSampleRate);
379 return 0;
380 }
381
382 m_pAudio->SetTimebase(m_pAudioCtx->pkt_timebase);
383
384 const auto &burst = BuildIEC61937(avpkt);
385
386 if (burst.empty())
387 return 0;
388
389 m_pAudio->EnqueueSpdif(reinterpret_cast<const uint16_t *>(burst.data()), burst.size(), avpkt->pts);
390 return 1;
391}
392
399{
400 int retSend, retRec;
401 AVFrame *frame;
402
403 frame = m_pFrame;
404 av_frame_unref(frame);
405
406 do {
408 if (retSend < 0 && retSend != AVERROR(EAGAIN))
409 LOGERROR("audiocodec: %s: avcodec_send_packet error: %s", __FUNCTION__, av_err2str(retSend));
410
411 do {
413
414 if (retRec < 0) {
415 if (retRec != AVERROR(EAGAIN))
416 LOGERROR("audiocodec: %s: avcodec_receive_frame error: %s", __FUNCTION__, av_err2str(retRec));
417 continue;
418 }
419
420 if (m_lastPts == AV_NOPTS_VALUE && avpkt->pts == AV_NOPTS_VALUE) {
421 // the first AVPacket has no valid PTS, if its PES packet has been truncated while searching for the sync word
422 av_frame_unref(frame);
423 continue;
424 }
425
426 // update audio clock and remember last PTS or guess the next PTS
427 if (frame->pts != AV_NOPTS_VALUE) {
428 m_lastPts = frame->pts;
429 } else if (m_lastPts != AV_NOPTS_VALUE) {
430 frame->pts = m_lastPts +
431 av_rescale_q(frame->nb_samples, (AVRational){1, frame->sample_rate}, m_pAudioCtx->pkt_timebase);
432 m_lastPts = frame->pts;
433 }
434
435 if (CheckUpdateFormat(false)) {
436 LOGERROR("audiocodec: %s: unsupported format!", __FUNCTION__);
437 av_frame_unref(frame);
438 return;
439 }
440
441 m_pAudio->Filter(frame, m_pAudioCtx);
442
443 } while (retRec == 0);
444 } while (retSend == AVERROR(EAGAIN));
445}
446
453{
454 std::lock_guard<std::mutex> lock(m_mutex);
455
456 LOGDEBUG2(L_CODEC, "audiocodec: %s", __FUNCTION__);
457 if (m_pAudioCtx)
459
462}
463
Audio Interface Header File.
AVFormatContext * m_spdifFmtCtx
spdif muxer context
Definition codec_audio.h:85
bool ShouldTryPassthrough(void)
Test, if passthrough audio should be tried.
AVCodecContext * m_pAudioCtx
ffmpeg audio codec context
Definition codec_audio.h:72
int m_currentHwSampleRate
current hw sample rate
Definition codec_audio.h:80
void FlushBuffers(void)
Flush the audio decoder buffers.
int m_currentHwNumChannels
current number of hw channels
Definition codec_audio.h:81
void Decode(const AVPacket *)
Forward an audio packet either to the decoder or passthrough.
AVFrame * m_pFrame
decoded ffmpeg audio frame
Definition codec_audio.h:74
int m_currentPassthroughMask
current passthrough mask
Definition codec_audio.h:77
void CloseSpdifMuxer(void)
Close the spdif muxer and free the resources.
int m_passthroughMask
passthrough mask to be set
Definition codec_audio.h:76
AVCodecID m_codecId
current codec id
Definition codec_audio.h:73
static int SpdifWriteCallback(void *, uint8_t *, int)
Callback for the spdif muxer.
int Passthrough(const AVPacket *)
Passthrough audio data.
void DecodePCM(const AVPacket *)
Decode an audio packet.
cAudioDecoder(cSoftHdAudio *)
Create a new audio decoder for the given audio context.
int CheckUpdateFormat(bool)
Handle audio format changes and setup audio, if format changed.
void SetPassthroughMask(int)
Set audio pass-through mask.
bool OpenSpdifMuxer(AVCodecID, int)
Open the spdif muxer.
static constexpr int AUDIO_PASSTHROUGH_NUM_CHANNELS
fixed passthrough channel number
Definition codec_audio.h:88
std::vector< uint8_t > m_spdifOutputBuf
spdif muxer output
Definition codec_audio.h:86
std::mutex m_mutex
decoder mutex
Definition codec_audio.h:82
int64_t m_lastPts
last seen PTS
Definition codec_audio.h:75
int m_currentSampleRate
current sample rate
Definition codec_audio.h:78
static constexpr int AUDIO_PASSTHROUGH_RATE_HZ
fixed passthrough sample rate
Definition codec_audio.h:89
cSoftHdAudio * m_pAudio
audio module
Definition codec_audio.h:71
int m_currentNumChannels
current number of channels
Definition codec_audio.h:79
const std::vector< uint8_t > & BuildIEC61937(const AVPacket *)
Prepend an IEC61937 header to the raw audio data by sending the avpkt to the spdif muxer.
std::array< uint8_t, 32768 > m_spdifIoBuffer
spdif I/O buffer
Definition codec_audio.h:84
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open and initiate the audio decoder.
void Close(void)
Close the audio decoder.
Audio Interface.
Definition audio.h:51
void Filter(AVFrame *, AVCodecContext *)
Send audio frame to filter and enqueue it.
Definition audio.cpp:679
void SetTimebase(AVRational timebase)
Definition audio.h:85
int Setup(AVRational, int, int, bool)
Alsa setup wrapper.
Definition audio.cpp:582
void EnqueueSpdif(const uint16_t *, int, int64_t pts)
Enqueue prepared spdif bursts in audio output queue.
Definition audio.cpp:511
static std::string GetPassthroughMaskString(int mask)
Build a passthrough mask logging string.
Audio Decoder Header File.
@ CODEC_EAC3
E-AC-3 bit mask.
Definition codec_audio.h:42
@ CODEC_AC3
AC-3 bit mask.
Definition codec_audio.h:41
@ CODEC_DTS
DTS bit mask.
Definition codec_audio.h:43
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:47
#define LOGERROR
log to LOG_ERR
Definition logger.h:39
#define AV_NOPTS_VALUE
Definition misc.h:74
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:37
#define av_err2str(err)
Definition misc.h:112
@ L_CODEC
codec logs
Definition logger.h:61
@ L_SOUND
sound logs
Definition logger.h:58
Logger Header File.
Misc Functions.