vdr-plugin-softhddevice-drm-gles 1.6.2
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 <unistd.h>
19
20extern "C" {
21#include <libavcodec/avcodec.h>
22}
23
24#include "audio.h"
25#include "codec_audio.h"
26#include "logger.h"
27#include "misc.h"
28
42 : m_pAudio(audio),
43 m_passthroughMask(m_pAudio->GetPassthrough() & (CODEC_AC3 | CODEC_EAC3 | CODEC_DTS))
44{
45 if (!(m_pFrame = av_frame_alloc()))
46 LOGFATAL("audiocodec: %s: can't allocate audio decoder frame buffer", __FUNCTION__);
47
48 LOGDEBUG2(L_CODEC, "audiocodec: %s: Set passthrough mask %d", __FUNCTION__, m_passthroughMask);
49}
50
57
68{
69 const AVCodec *codec;
70
71 m_codecId = codecId;
72
73 if (codecId == AV_CODEC_ID_AC3) {
74 if (!(codec = avcodec_find_decoder_by_name("ac3_fixed"))) {
75 LOGFATAL("audiocodec: %s: codec ac3_fixed ID %#06x not found", __FUNCTION__, codecId);
76 }
77 } else if (codecId == AV_CODEC_ID_AAC) {
78 if (!(codec = avcodec_find_decoder_by_name("aac_fixed"))) {
79 LOGFATAL("audiocodec: %s: codec aac_fixed ID %#06x not found", __FUNCTION__, codecId);
80 }
81 } else {
82 if (!(codec = avcodec_find_decoder(codecId))) {
83 LOGFATAL("audiocodec: %s: codec %s ID %#06x not found", __FUNCTION__,
84 avcodec_get_name(codecId), codecId);
85 }
86 }
87
89 LOGFATAL("audiocodec: %s: can't allocate audio codec context", __FUNCTION__);
90
91 m_pAudioCtx->pkt_timebase = timebase;
92
94 LOGERROR("audiocodec: %s: insert parameters to context failed!", __FUNCTION__);
95
96 if (avcodec_open2(m_pAudioCtx, m_pAudioCtx->codec, NULL) < 0)
97 LOGFATAL("audiocodec: %s: can't open audio codec", __FUNCTION__);
98
99 LOGDEBUG2(L_CODEC, "audiocodec: %s: Codec %s found, passthrough mask %d", __FUNCTION__, m_pAudioCtx->codec->long_name, m_passthroughMask);
100
106}
107
120
137{
138 m_pAudio->SetTimebase(&m_pAudioCtx->pkt_timebase);
139
140 // AC3 passthrough
143 int spdifSize = AC3_FRAME_SIZE * 4; // frames * channels * (samplesize / 8)
144
145 if (spdifSize < avpkt->size + 8) {
146 LOGERROR("audiocodec: %s: too much data for spdif buffer!", __FUNCTION__);
147 return -1;
148 }
149
150 if (avpkt->size < 6)
151 return -1;
152
153 // build SPDIF header and append AC3 audio data to it
154 int bitstreamMode = avpkt->data[5] & 0x07;
158 spdif[3] = htole16(avpkt->size * 8);
159 swab(avpkt->data, spdif + 4, avpkt->size);
160 memset((uint8_t *)(spdif + 4) + avpkt->size, 0, spdifSize - 8 - avpkt->size);
161
163 return 1;
164 }
165
166 // EAC3 passthrough
169 int spdifSize = EAC3_FRAME_SIZE * 4; // frames * channels * (samplesize / 8)
170 int repeat = 1;
171
172 // spdifSize is smaller, if we don't have 192000
173 if (m_currentHwSampleRate == 48000) {
174 spdifSize /= 4;
175 }
176
178 LOGERROR("audiocodec: %s: too much data for spdif buffer!", __FUNCTION__);
179 ResetSpdif();
180 return -1;
181 }
182
183 if (avpkt->size < 5) {
184 LOGERROR("audiocodec: %s: avpkt size too small!", __FUNCTION__);
185 ResetSpdif();
186 return -1;
187 }
188
189 // check if we need to pack multiple packets
190 int fscod = (avpkt->data[4] >> 6) & 0x3;
191 int numblkscod = 6;
192 if (fscod != 0x3) {
193 numblkscod = (avpkt->data[4] >> 4) & 0x3;
194 static const uint8_t eac3_repeat[4] = { 6, 3, 2, 1 };
196 }
197
198 if (repeat * avpkt->size > spdifSize - 8) {
199 LOGERROR("audiocodec: %s: spdif size too small!", __FUNCTION__);
200 ResetSpdif();
201 return -1;
202 }
203
204 // pack upto repeat EAC-3 pakets into one IEC 61937 burst
205 swab(avpkt->data, (uint8_t *)(spdif + 4) + m_spdifIndex, avpkt->size);
206 m_spdifIndex += avpkt->size;
207
208// LOGDEBUG2(L_CODEC, "audiocodec: %s: E-AC3: set repeat to %d (fscod = %d, numblkscode = %d) avpkt->size %d (spdifSize %d) (repeatCount gets %d) (m_spdifIndex = %d)",
209// __FUNCTION__, repeat, fscod, numblkscod, avpkt->size, spdifSize, m_spdifRepeatCount + 1, m_spdifIndex);
210
212 return 1;
213
214 if (m_spdifRepeatCount > 6) {
215 ResetSpdif();
216 return -1;
217 }
218
219 // build SPDIF header and append E-AC3 audio data to it
223 spdif[3] = htole16(m_spdifIndex * 8);
224 int pad = spdifSize - 8 - m_spdifIndex;
225 if (pad > 0)
226 memset((uint8_t *)(spdif + 4) + m_spdifIndex, 0, pad);
227
229 ResetSpdif();
230 return 1;
231 }
232
233 // DTS passthrough
236
237 uint8_t nbs;
238 int bsid;
239 int burstSz;
240
241 if (avpkt->size < 6) {
242 LOGERROR("audiocodec: %s: avpkt size too small!", __FUNCTION__);
243 return -1;
244 }
245
246 nbs = (uint8_t)((avpkt->data[4] & 0x01) << 6) |
247 ((avpkt->data[5] >> 2) & 0x3f);
248 switch(nbs) {
249 case 0x07:
250 bsid = 0x0a; // MPEG-2 layer 3 is used when?
251 burstSz = 1024;
252 break;
253 case 0x0f:
255 burstSz = DTS1_FRAME_SIZE * 4; // frames * channels * (samplesize / 8)
256 break;
257 case 0x1f:
259 burstSz = DTS2_FRAME_SIZE * 4; // frames * channels * (samplesize / 8)
260 break;
261 case 0x3f:
263 burstSz = DTS3_FRAME_SIZE * 4; // frames * channels * (samplesize / 8)
264 break;
265 default:
267 if (nbs < 5)
268 nbs = 127;
269 burstSz = (nbs + 1) * 32 * 2 + 2;
270 break;
271 }
272
273 // build SPDIF header and append DTS audio data to it
274 if (burstSz < avpkt->size + 8) {
275 LOGERROR("audiocodec: %s: too much data for spdif buffer!", __FUNCTION__);
276 return -1;
277 }
280 spdif[2] = htole16(bsid);
281 spdif[3] = htole16(avpkt->size * 8);
284 swab(avpkt->data, spdif + 6, avpkt->size);
285 memset((uint8_t *)(spdif + 6) + avpkt->size, 0, burstSz - 12 - avpkt->size);
286
288 return 1;
289 }
290
291 return 0;
292}
293
303{
304 int isPassthrough = 0;
305 int err = 0;
306
307 m_currentSampleRate = m_pAudioCtx->sample_rate;
308 m_currentHwSampleRate = m_pAudioCtx->sample_rate;
309 m_currentNumChannels = m_pAudioCtx->ch_layout.nb_channels;
310 m_currentHwNumChannels = m_pAudioCtx->ch_layout.nb_channels;
312
316
317 // E-AC3 over HDMI: some receivers need HBR
318 if (m_pAudioCtx->codec_id == AV_CODEC_ID_EAC3)
320
322 m_spdifIndex = 0;
324 isPassthrough = 1;
325 }
326
328 // E-AC3 over HDMI: try without HBR
330
331 if (m_pAudioCtx->codec_id != AV_CODEC_ID_EAC3 ||
333 LOGERROR("audiocodec: %s: format change update error", __FUNCTION__);
336 return err;
337 }
338 }
339
340 if (!err) {
341 LOGDEBUG2(L_SOUND, "audiocodec: %s: format change %s %dHz *%d channels%s%s%s%s%d", __FUNCTION__,
342 av_get_sample_fmt_name(m_pAudioCtx->sample_fmt), m_pAudioCtx->sample_rate, m_pAudioCtx->ch_layout.nb_channels,
343 m_passthroughMask & CODEC_AC3 ? " AC3" : "",
344 m_passthroughMask & CODEC_EAC3 ? " EAC3" : "",
345 m_passthroughMask & CODEC_DTS ? " DTS" : "",
346 m_passthroughMask ? " passthrough mask " : "",
348 }
349
350 return err;
351}
352
359{
360 int retSend, retRec;
361 AVFrame *frame;
362
363 // decoded frame is also needed for passthrough to set the PTS
364 frame = m_pFrame;
365 av_frame_unref(frame);
366
367 do {
369 if (retSend < 0)
370 LOGERROR("audiocodec: %s: avcodec_send_packet error: %s", __FUNCTION__, av_err2str(retSend));
371
373
374 if (retRec < 0) {
375 if (retRec != AVERROR(EAGAIN))
376 LOGERROR("audiocodec: %s: avcodec_receive_frame error: %s", __FUNCTION__, av_err2str(retRec));
377 } else {
378 if (m_lastPts == AV_NOPTS_VALUE && avpkt->pts == AV_NOPTS_VALUE) {
379 // the first AVPacket has no valid PTS, if its PES packet has been truncated while searching for the sync word
380 av_frame_unref(frame);
381 continue;
382 }
383
384 // update audio clock and remeber last PTS or guess the next PTS
385 if (frame->pts != AV_NOPTS_VALUE) {
386 m_lastPts = frame->pts;
387 } else if (m_lastPts != AV_NOPTS_VALUE) {
388 frame->pts = m_lastPts +
389 av_rescale_q(frame->nb_samples, (AVRational){1, frame->sample_rate}, m_pAudioCtx->pkt_timebase);
390 m_lastPts = frame->pts;
391 }
392
394 m_currentNumChannels != m_pAudioCtx->ch_layout.nb_channels ||
395 m_currentSampleRate != m_pAudioCtx->sample_rate) {
396 UpdateFormat();
397 }
398
400 LOGERROR("audiocodec: %s: unsupported format!", __FUNCTION__);
401 av_frame_unref(frame);
402 return;
403 }
404
405 if (DecodePassthrough(avpkt, frame)) {
406 av_frame_unref(frame);
407 return;
408 }
409
410 m_pAudio->Filter(frame, m_pAudioCtx);
411 }
412
413 } while (retSend == AVERROR(EAGAIN));
414}
415
432
434{
435 m_spdifIndex = 0;
437}
438
449
Audio and Alsa Interface Header File.
AVCodecContext * m_pAudioCtx
ffmpeg audio codec context
Definition codec_audio.h:94
int m_currentHwSampleRate
current hw sample rate
int m_currentHwNumChannels
current number of hw channels
AVFrame * m_pFrame
decoded ffmpeg audio frame
Definition codec_audio.h:96
int m_spdifIndex
index into SPDIF output buffer
int m_passthroughMask
passthrough mask to be set
Definition codec_audio.h:98
AVCodecID m_codecId
current codec id
Definition codec_audio.h:95
int m_currentPassthrough
current passthrough mask
Definition codec_audio.h:99
int m_spdifRepeatCount
SPDIF repeat counter.
uint16_t m_spdifOutput[(MAX_FRAME_SIZE *4+16)/2]
SPDIF output buffer.
int64_t m_lastPts
last seen PTS
Definition codec_audio.h:97
int m_currentSampleRate
current sample rate
cSoftHdAudio * m_pAudio
audio module
Definition codec_audio.h:93
int m_currentNumChannels
current number of channels
Audio Interface.
Definition audio.h:46
void SetTimebase(AVRational *timebase)
Definition audio.h:79
Audio Decoder Header File.
void Filter(AVFrame *, AVCodecContext *)
Send audio frame to filter and enqueue it.
Definition audio.cpp:818
int Setup(AVCodecContext *, int, int, int)
Alsa setup wrapper.
Definition audio.cpp:729
void EnqueueSpdif(uint16_t *, int, AVFrame *)
Enqueue prepared spdif bursts in audio output queue.
Definition audio.cpp:655
int DecodePassthrough(const AVPacket *, AVFrame *)
Passthrough audio data.
int UpdateFormat(void)
Handle audio format changes.
void FlushBuffers(void)
Flush the audio decoder buffers.
void Decode(const AVPacket *)
Decode an audio packet.
cAudioDecoder(cSoftHdAudio *)
Create a new audio decoder for the given audio context.
void SetPassthroughMask(int)
Set audio pass-through mask.
void ResetSpdif(void)
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open and initiate the audio decoder.
void Close(void)
Close the audio decoder.
@ EAC3_FRAME_SIZE
Definition codec_audio.h:72
@ AC3_FRAME_SIZE
Definition codec_audio.h:71
@ DTS3_FRAME_SIZE
Definition codec_audio.h:70
@ DTS2_FRAME_SIZE
Definition codec_audio.h:69
@ DTS1_FRAME_SIZE
Definition codec_audio.h:68
@ IEC61937_DTS3
DTS type III (2048 samples)
Definition codec_audio.h:49
@ IEC61937_DTS2
DTS type II (1024 samples)
Definition codec_audio.h:48
@ IEC61937_AC3
AC-3 data.
Definition codec_audio.h:45
@ IEC61937_NULL
no data
Definition codec_audio.h:44
@ IEC61937_EAC3
E-AC-3 data.
Definition codec_audio.h:46
@ IEC61937_DTS1
DTS type I (512 samples)
Definition codec_audio.h:47
@ IEC61937_PREAMBLE1
Definition codec_audio.h:58
@ DTS_PREAMBLE_16BE_2
Definition codec_audio.h:61
@ DTS_PREAMBLE_16BE_1
Definition codec_audio.h:60
@ IEC61937_PREAMBLE2
Definition codec_audio.h:59
@ CODEC_EAC3
E-AC-3 bit mask.
Definition codec_audio.h:36
@ CODEC_AC3
AC-3 bit mask.
Definition codec_audio.h:35
@ CODEC_DTS
DTS bit mask.
Definition codec_audio.h:37
#define LOGDEBUG2
log to LOG_DEBUG and add a prefix
Definition logger.h:42
#define LOGERROR
log to LOG_ERR
Definition logger.h:34
#define AV_NOPTS_VALUE
Definition misc.h:74
#define LOGFATAL
log to LOG_ERR and abort
Definition logger.h:32
#define av_err2str(err)
Definition misc.h:112
@ L_CODEC
codec logs
Definition logger.h:56
@ L_SOUND
sound logs
Definition logger.h:53
Logger Header File.
Misc Functions.