903 changes: 0 additions & 903 deletions mythtv/libs/libmyth/audio/audiooutput_omx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,50 +42,6 @@ using namespace omxcontext;
/*
* Types
*/
class AudioDecoderOMX : public OMXComponentCtx
{
// No copying
AudioDecoderOMX(const AudioDecoderOMX&);
AudioDecoderOMX & operator =(const AudioDecoderOMX&);

public:
explicit AudioDecoderOMX(OMXComponent&);
virtual ~AudioDecoderOMX();

// OMXComponentCtx overrides
virtual OMX_ERRORTYPE EmptyBufferDone(OMXComponent&, OMX_BUFFERHEADERTYPE*);
virtual OMX_ERRORTYPE FillBufferDone(OMXComponent&, OMX_BUFFERHEADERTYPE*);
virtual void ReleaseBuffers(OMXComponent&);

// Implementation
void Stop() { m_audiodecoder.Shutdown(); m_bIsStarted = false; }
bool Start(AVCodecID, AudioFormat, int chnls, int sps);
bool IsStarted() { return m_bIsStarted; }
int DecodeAudio(AVCodecContext*, uint8_t*, int&, const AVPacket*);

protected:
int GetBufferedFrame(uint8_t *buffer);
int ProcessPacket(const AVPacket *pkt);

private:
OMX_ERRORTYPE FillOutputBuffers();

// OMXComponentCB actions
typedef OMX_ERRORTYPE ComponentCB();
ComponentCB FreeBuffersCB, AllocBuffersCB;
ComponentCB AllocInputBuffers, AllocOutputBuffers;

private:
OMXComponent &m_audiorender;
OMXComponent m_audiodecoder;
bool m_bIsStarted;

QSemaphore m_ibufs_sema; // EmptyBufferDone signal
QSemaphore m_obufs_sema; // FillBufferDone signal
QMutex mutable m_lock; // Protects data following
QList<OMX_BUFFERHEADERTYPE*> m_ibufs;
QList<OMX_BUFFERHEADERTYPE*> m_obufs;
};


/*
Expand All @@ -94,7 +50,6 @@ class AudioDecoderOMX : public OMXComponentCtx
AudioOutputOMX::AudioOutputOMX(const AudioSettings &settings) :
AudioOutputBase(settings),
m_audiorender(gCoreContext->GetSetting("OMXAudioRender", AUDIO_RENDER), *this),
m_audiodecoder(0),
m_lock(QMutex::Recursive)
{
if (m_audiorender.GetState() != OMX_StateLoaded)
Expand Down Expand Up @@ -125,9 +80,6 @@ AudioOutputOMX::AudioOutputOMX(const AudioSettings &settings) :
if (0) m_audiorender.ShowFormats(port, LOG_DEBUG, VB_AUDIO);
}

// Create the OMX audio decoder
m_audiodecoder = new AudioDecoderOMX(m_audiorender);

InitSettings(settings);
if (settings.init)
Reconfigure(settings);
Expand All @@ -140,7 +92,6 @@ AudioOutputOMX::~AudioOutputOMX()

// Must shutdown the OMX components now before our state becomes invalid.
// When the component's dtor is called our state has already been destroyed.
delete m_audiodecoder, m_audiodecoder = 0;
m_audiorender.Shutdown();
}

Expand Down Expand Up @@ -239,7 +190,6 @@ bool AudioOutputOMX::OpenDevice(void)
}

m_audiorender.Shutdown();
if (m_audiodecoder) m_audiodecoder->Stop();

OMX_ERRORTYPE e;
unsigned nBitPerSample = 0;
Expand Down Expand Up @@ -460,10 +410,6 @@ bool AudioOutputOMX::OpenDevice(void)
}
#endif

// Setup the audio decoder
if (!passthru && m_audiodecoder)
m_audiodecoder->Start(AVCodecID(codec), output_format, channels, samplerate);

// Goto OMX_StateIdle & allocate buffers
OMXComponentCB<AudioOutputOMX> cb(this, &AudioOutputOMX::AllocBuffersCB);
e = m_audiorender.SetState(OMX_StateIdle, 500, &cb);
Expand Down Expand Up @@ -587,7 +533,6 @@ AudioOutputSettings* AudioOutputOMX::GetOutputSettings(bool passthrough)
}

m_audiorender.Shutdown();
if (m_audiodecoder) m_audiodecoder->Stop();

OMX_ERRORTYPE e;
OMX_AUDIO_PARAM_PORTFORMATTYPE fmt;
Expand Down Expand Up @@ -750,28 +695,6 @@ bool AudioOutputOMX::OpenMixer()
return true;
}

// virtual
int AudioOutputOMX::DecodeAudio(AVCodecContext *ctx, uint8_t *buffer,
int &data_size, const AVPacket *pkt)
{
if (m_audiodecoder && m_audiodecoder->IsStarted())
{
static int s_bShown;
if (!s_bShown)
{
s_bShown = 1;
LOG(VB_GENERAL, LOG_CRIT, LOC +
"AudioDecoderOMX::DecodeAudio is available but untested.");
}

static int s_enable = gCoreContext->GetNumSetting("OMXAudioDecoderEnable", 0);
if (s_enable)
return m_audiodecoder->DecodeAudio(ctx, buffer, data_size, pkt);
}

return AudioOutputBase::DecodeAudio(ctx, buffer, data_size, pkt);
}

// virtual
OMX_ERRORTYPE AudioOutputOMX::EmptyBufferDone(
OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
Expand Down Expand Up @@ -870,830 +793,4 @@ OMX_ERRORTYPE AudioOutputOMX::AllocBuffersCB()
return OMX_ErrorNone;
}

/*******************************************************************************
* AudioDecoder
******************************************************************************/
#undef LOC
#define LOC QString("ADOMX:%1 ").arg(m_audiodecoder.Id())

AudioDecoderOMX::AudioDecoderOMX(OMXComponent &render) :
m_audiorender(render),
m_audiodecoder(gCoreContext->GetSetting("OMXAudioDecode", AUDIO_DECODE), *this),
m_bIsStarted(false), m_lock(QMutex::Recursive)
{
if (m_audiodecoder.GetState() != OMX_StateLoaded)
return;

if (OMX_ErrorNone != m_audiodecoder.Init(OMX_IndexParamAudioInit))
return;

if (!m_audiodecoder.IsValid())
return;

// Show default port definitions and audio formats supported
for (unsigned port = 0; port < m_audiodecoder.Ports(); ++port)
{
m_audiodecoder.ShowPortDef(port, LOG_DEBUG, VB_AUDIO);
if (0) m_audiodecoder.ShowFormats(port, LOG_DEBUG, VB_AUDIO);
}
}

// virtual
AudioDecoderOMX::~AudioDecoderOMX()
{
// Must shutdown the OMX components now before our state becomes invalid.
// When the component's dtor is called our state has already been destroyed.
m_audiodecoder.Shutdown();
}

static const char *toString(OMX_AUDIO_CHANNELMODETYPE mode)
{
switch (mode)
{
CASE2STR(OMX_AUDIO_ChannelModeStereo);
CASE2STR(OMX_AUDIO_ChannelModeJointStereo);
CASE2STR(OMX_AUDIO_ChannelModeDual);
CASE2STR(OMX_AUDIO_ChannelModeMono);
}
static char buf[32];
return strcpy(buf, qPrintable(QString("ChannelMode 0x%1").arg(mode,0,16)));
}

static const char *toString(OMX_AUDIO_MP3STREAMFORMATTYPE type)
{
switch (type)
{
CASE2STR(OMX_AUDIO_MP3StreamFormatMP1Layer3);
CASE2STR(OMX_AUDIO_MP3StreamFormatMP2Layer3);
CASE2STR(OMX_AUDIO_MP3StreamFormatMP2_5Layer3);
}
static char buf[32];
return strcpy(buf, qPrintable(QString("StreamFormat 0x%1").arg(type,0,16)));
}

bool AudioDecoderOMX::Start(AVCodecID codec, AudioFormat format, int chnls, int sps)
{
if (!m_audiodecoder.IsValid())
return false;

Stop();

if (m_audiodecoder.Ports() < 2)
{
LOG(VB_AUDIO, LOG_ERR, LOC + __func__ + ": missing output port");
return false;
}

OMX_ERRORTYPE e;
OMX_AUDIO_PARAM_PORTFORMATTYPE fmt;
OMX_DATA_INIT(fmt);

// Map Ffmpeg audio codec ID to OMX coding
switch (codec)
{
case AV_CODEC_ID_NONE:
return false;
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_U16LE:
case AV_CODEC_ID_PCM_U16BE:
case AV_CODEC_ID_PCM_S8:
case AV_CODEC_ID_PCM_U8:
case AV_CODEC_ID_PCM_S32LE:
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_U32LE:
case AV_CODEC_ID_PCM_U32BE:
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_U24LE:
case AV_CODEC_ID_PCM_U24BE:
fmt.eEncoding = OMX_AUDIO_CodingPCM;
break;
case AV_CODEC_ID_MP1:
case AV_CODEC_ID_MP2:
case AV_CODEC_ID_MP3:
fmt.eEncoding = OMX_AUDIO_CodingMP3;
break;
case AV_CODEC_ID_AAC:
fmt.eEncoding = OMX_AUDIO_CodingAAC;
break;
#ifdef OMX_AUDIO_CodingDDP_Supported
case AV_CODEC_ID_AC3:
case AV_CODEC_ID_EAC3:
fmt.eEncoding = OMX_AUDIO_CodingDDP;
break;
#endif
#ifdef OMX_AUDIO_CodingDTS_Supported
case AV_CODEC_ID_DTS:
fmt.eEncoding = OMX_AUDIO_CodingDTS;
break;
#endif
case AV_CODEC_ID_VORBIS:
case AV_CODEC_ID_FLAC:
fmt.eEncoding = OMX_AUDIO_CodingVORBIS;
break;
case AV_CODEC_ID_WMAV1:
case AV_CODEC_ID_WMAV2:
fmt.eEncoding = OMX_AUDIO_CodingWMA;
break;
#ifdef OMX_AUDIO_CodingATRAC3_Supported
case AV_CODEC_ID_ATRAC3:
case AV_CODEC_ID_ATRAC3P:
fmt.eEncoding = OMX_AUDIO_CodingATRAC3;
break;
#endif
default:
LOG(VB_AUDIO, LOG_NOTICE, LOC + __func__ +
QString(" codec %1 not supported").arg(ff_codec_id_string(codec)));
return false;
}

// Set input encoding
fmt.nPortIndex = m_audiodecoder.Base();
e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPortFormat, &fmt);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter input AudioPortFormat error %1")
.arg(Error2String(e)));
return false;
}

// Set input parameters
switch (fmt.eEncoding)
{
case OMX_AUDIO_CodingPCM:
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
OMX_DATA_INIT(pcm);
pcm.nPortIndex = m_audiodecoder.Base();

e = m_audiodecoder.GetParameter(OMX_IndexParamAudioPcm, &pcm);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"GetParameter input AudioPcm error %1")
.arg(Error2String(e)));
return false;
}

// TODO: Anything other than zeroes here causes bad parameter
pcm.nChannels = chnls;
pcm.nSamplingRate = sps;
if (!::Format2Pcm(pcm, format))
{
LOG(VB_AUDIO, LOG_ERR, LOC + __func__ + QString(
" Unsupported PCM input format %1")
.arg(AudioOutputSettings::FormatToString(format)));
return false;
}

::SetupChannels(pcm);

LOG(VB_AUDIO, LOG_INFO, LOC + QString(
"Input PCM %1 chnls @ %2 sps %3 %4 bits")
.arg(pcm.nChannels).arg(pcm.nSamplingRate).arg(pcm.nBitPerSample)
.arg(pcm.eNumData == OMX_NumericalDataSigned ? "signed" : "unsigned") );

e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPcm, &pcm);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter input AudioPcm error %1")
.arg(Error2String(e)));
return false;
}
break;

case OMX_AUDIO_CodingMP3:
OMX_AUDIO_PARAM_MP3TYPE mp3type;
OMX_DATA_INIT(mp3type);
mp3type.nPortIndex = m_audiodecoder.Base();

e = m_audiodecoder.GetParameter(OMX_IndexParamAudioMp3, &mp3type);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"GetParameter input AudioMp3 error %1")
.arg(Error2String(e)));
return false;
}

mp3type.nChannels = chnls;
mp3type.nBitRate = 0;
mp3type.nSampleRate = sps;
mp3type.nAudioBandWidth = 0;
mp3type.eChannelMode = (chnls == 1) ? OMX_AUDIO_ChannelModeMono :
OMX_AUDIO_ChannelModeStereo;
mp3type.eFormat = (codec == AV_CODEC_ID_MP1) ?
OMX_AUDIO_MP3StreamFormatMP1Layer3 :
OMX_AUDIO_MP3StreamFormatMP2Layer3;
// or OMX_AUDIO_MP3StreamFormatMP2_5Layer3

LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input %1 %2 chnls @ %3 sps %4")
.arg(toString(mp3type.eFormat)).arg(mp3type.nChannels)
.arg(mp3type.nSampleRate).arg(toString(mp3type.eChannelMode)) );

e = m_audiodecoder.SetParameter(OMX_IndexParamAudioMp3, &mp3type);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter output AudioMp3 error %1")
.arg(Error2String(e)));
return false;
}
break;

#ifdef OMX_AUDIO_CodingDDP_Supported
case OMX_AUDIO_CodingDDP:
OMX_AUDIO_PARAM_DDPTYPE ddp;
OMX_DATA_INIT(ddp);
ddp.nPortIndex = m_audiodecoder.Base();
e = m_audiodecoder.GetParameter(OMX_IndexParamAudioDdp, &ddp);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"GetParameter AudioDdp error %1")
.arg(Error2String(e)));
return false;
}

ddp.nChannels = chnls;
ddp.nBitRate = 0;
ddp.nSampleRate = sps;
ddp.eBitStreamId = (AV_CODEC_ID_AC3 == codec) ?
OMX_AUDIO_DDPBitStreamIdAC3 :
OMX_AUDIO_DDPBitStreamIdEAC3;
ddp.eBitStreamMode = OMX_AUDIO_DDPBitStreamModeCM;
ddp.eDolbySurroundMode = OMX_AUDIO_DDPDolbySurroundModeNotIndicated;
::SetupChannels(ddp);

LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input %1 %2 chnls @ %3 sps")
.arg(toString(ddp.eBitStreamId)).arg(ddp.nChannels)
.arg(ddp.nSampleRate) );

e = m_audiodecoder.SetParameter(OMX_IndexParamAudioDdp, &ddp);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter AudioDdp error %1")
.arg(Error2String(e)));
return false;
}
break;
#endif //def OMX_AUDIO_CodingDDP_Supported

case OMX_AUDIO_CodingVORBIS:
OMX_AUDIO_PARAM_VORBISTYPE vorbis;
OMX_DATA_INIT(vorbis);
vorbis.nPortIndex = m_audiodecoder.Base();
e = m_audiodecoder.GetParameter(OMX_IndexParamAudioVorbis, &vorbis);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"GetParameter AudioVorbis error %1")
.arg(Error2String(e)));
return false;
}

vorbis.nChannels = chnls;
vorbis.nBitRate = 0;
vorbis.nMinBitRate = 0;
vorbis.nMaxBitRate = 0;
vorbis.nSampleRate = sps;
vorbis.nAudioBandWidth = 0;
vorbis.nQuality = 0;
vorbis.bManaged = OMX_FALSE;
vorbis.bDownmix = OMX_FALSE;

LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input Vorbis %1 chnls @ %2 sps")
.arg(vorbis.nChannels).arg(vorbis.nSampleRate) );

e = m_audiodecoder.SetParameter(OMX_IndexParamAudioVorbis, &vorbis);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter AudioVorbis error %1")
.arg(Error2String(e)));
return false;
}
break;

#ifdef OMX_AUDIO_CodingDTS_Supported
case OMX_AUDIO_CodingDTS:
OMX_AUDIO_PARAM_DTSTYPE dts;
OMX_DATA_INIT(dts);
dts.nPortIndex = m_audiodecoder.Base();
e = m_audiorender.GetParameter(OMX_IndexParamAudioDts, &dts);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"GetParameter AudioDts error %1")
.arg(Error2String(e)));
return false;
}

dts.nChannels = chnls;
dts.nBitRate = 0;
dts.nSampleRate = sps;
// TODO
//dts.nDtsType; // OMX_U32 DTS type 1, 2, or 3
//dts.nFormat; // OMX_U32 DTS stream is either big/little endian and 16/14 bit packing
//dts.nDtsFrameSizeBytes; // OMX_U32 DTS frame size in bytes
::SetupChannels(dts);

LOG(VB_AUDIO, LOG_INFO, LOC + QString("Input DTS %1 chnls @ %2 sps")
.arg(dts.nChannels).arg(dts.nSampleRate) );

e = m_audiorender.SetParameter(OMX_IndexParamAudioDts, &dts);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter AudioDts error %1")
.arg(Error2String(e)));
return false;
}
break;
#endif //def OMX_AUDIO_CodingDTS_Supported

case OMX_AUDIO_CodingAAC: // TODO
case OMX_AUDIO_CodingWMA: // TODO
//case OMX_AUDIO_CodingATRAC3: // TODO
default:
LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Unhandled codec %1")
.arg(Coding2String(fmt.eEncoding)));
return false;
}

// Setup input buffer size & count
m_audiodecoder.GetPortDef();
OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef();
//def.nBufferSize = 1024;
def.nBufferCountActual = std::max(OMX_U32(2), def.nBufferCountMin);
assert(def.eDomain == OMX_PortDomainAudio);
assert(def.format.audio.eEncoding == fmt.eEncoding);
e = m_audiodecoder.SetParameter(OMX_IndexParamPortDefinition, &def);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter PortDefinition error %1")
.arg(Error2String(e)));
return false;
}

#if 0
// Setup pass through
OMX_CONFIG_BOOLEANTYPE boolType;
OMX_DATA_INIT(boolType);
boolType.bEnabled = OMX_FALSE;
e = m_audiodecoder.SetParameter(OMX_IndexParamBrcmDecoderPassThrough, &boolType);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter BrcmDecoderPassThrough error %1")
.arg(Error2String(e)));
}
#endif

// Setup output encoding
m_audiodecoder.GetPortDef(1);
OMX_PARAM_PORTDEFINITIONTYPE &odef = m_audiodecoder.PortDef(1);
assert(odef.eDomain == OMX_PortDomainAudio);
if (odef.format.audio.eEncoding != OMX_AUDIO_CodingPCM)
{
// Set output encoding
OMX_AUDIO_PARAM_PORTFORMATTYPE ofmt;
OMX_DATA_INIT(ofmt);
ofmt.nPortIndex = odef.nPortIndex;
ofmt.eEncoding = OMX_AUDIO_CodingPCM;
e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPortFormat, &ofmt);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter output AudioPortFormat error %1")
.arg(Error2String(e)));
return false;
}
}

// Setup output PCM format
OMX_AUDIO_PARAM_PCMMODETYPE pcm;
OMX_DATA_INIT(pcm);
pcm.nPortIndex = odef.nPortIndex;
pcm.nChannels = chnls;
pcm.nSamplingRate = sps;
if (!::Format2Pcm(pcm, format))
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString("Unsupported PCM output format %1")
.arg(AudioOutputSettings::FormatToString(format)));
return false;
}
::SetupChannels(pcm);

LOG(VB_AUDIO, LOG_INFO, LOC + QString("Output PCM %1 chnls @ %2 sps %3 %4 bits")
.arg(pcm.nChannels).arg(pcm.nSamplingRate).arg(pcm.nBitPerSample)
.arg(pcm.eNumData == OMX_NumericalDataSigned ? "signed" : "unsigned") );

e = m_audiodecoder.SetParameter(OMX_IndexParamAudioPcm, &pcm);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter output AudioPcm error %1")
.arg(Error2String(e)));
return false;
}

m_audiodecoder.GetPortDef(1);
assert(odef.format.audio.eEncoding == OMX_AUDIO_CodingPCM);

// Setup output buffer size & count
// NB the OpenMAX spec requires PCM buffer size >= 5mS data
//odef.nBufferSize = 16384;
odef.nBufferCountActual = std::max(OMX_U32(4), odef.nBufferCountMin);
e = m_audiodecoder.SetParameter(OMX_IndexParamPortDefinition, &odef);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"SetParameter output PortDefinition error %1")
.arg(Error2String(e)));
return false;
}

#if 0
// Goto OMX_StateIdle & allocate buffers
OMXComponentCB<AudioDecoderOMX> cb(this, &AudioDecoderOMX::AllocBuffersCB);
e = m_audiodecoder.SetState(OMX_StateIdle, 500, &cb);
switch (e)
{
case OMX_ErrorNone:
break;
case OMX_ErrorUnsupportedSetting:
// lvr: only OMX_AUDIO_CodingPCM is currently (17-Dec-2015) supported
LOG(VB_AUDIO, LOG_WARNING, LOC + QString("%1 is not supported")
.arg(Coding2String(fmt.eEncoding)));
return false;
default:
LOG(VB_AUDIO, LOG_ERR, LOC + QString("SetState idle error %1")
.arg(Error2String(e)));
return false;
}
#else
// A disabled port is not populated with buffers on a transition to IDLE
if (m_audiodecoder.PortDisable(0, 500) != OMX_ErrorNone)
return false;
if (m_audiodecoder.PortDisable(1, 500) != OMX_ErrorNone)
return false;

// Goto OMX_StateIdle
e = m_audiodecoder.SetState(OMX_StateIdle, 500);
if (e != OMX_ErrorNone)
return false;

// Enable input port
OMXComponentCB<AudioDecoderOMX> cb(this, &AudioDecoderOMX::AllocInputBuffers);
e = m_audiodecoder.PortEnable(0, 500, &cb);
switch (e)
{
case OMX_ErrorNone:
break;
case OMX_ErrorUnsupportedSetting:
// lvr: only OMX_AUDIO_CodingPCM is currently (17-Dec-2015) supported
LOG(VB_AUDIO, LOG_WARNING, LOC + QString("%1 is not supported")
.arg(Coding2String(fmt.eEncoding)));
return false;
default:
LOG(VB_AUDIO, LOG_ERR, LOC + QString("SetState idle error %1")
.arg(Error2String(e)));
return false;
}

OMXComponentCB<AudioDecoderOMX> cb2(this, &AudioDecoderOMX::AllocOutputBuffers);
e = m_audiodecoder.PortEnable(1, 500, &cb2);
if (e != OMX_ErrorNone)
return false;
#endif

// Goto OMX_StateExecuting
e = m_audiodecoder.SetState(OMX_StateExecuting, 500);
if (e != OMX_ErrorNone)
return false;

e = FillOutputBuffers();
if (e != OMX_ErrorNone)
return false;

m_bIsStarted = true;
return true;
}

/**
* Decode an audio packet, and compact it if data is planar
* Return negative error code if an error occurred during decoding
* or the number of bytes consumed from the input AVPacket
* data_size contains the size of decoded data copied into buffer
* data decoded will be S16 samples if class instance can't handle HD audio
* or S16 and above otherwise. No U8 PCM format can be returned
*/
int AudioDecoderOMX::DecodeAudio(AVCodecContext *ctx, uint8_t *buffer,
int &data_size, const AVPacket *pkt)
{
if (!m_audiodecoder.IsValid())
return -1;

// Check for decoded data
int ret = GetBufferedFrame(buffer);
if (ret < 0)
return ret;
if (ret > 0)
data_size = ret;

// Submit a packet for decoding
return (pkt && pkt->size) ? ProcessPacket(pkt) : 0;
}

int AudioDecoderOMX::GetBufferedFrame(uint8_t *buffer)
{
if (!buffer)
return 0;

if (!m_obufs_sema.tryAcquire())
return 0;

m_lock.lock();
assert(!m_obufs.isEmpty());
OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
m_lock.unlock();

int ret = hdr->nFilledLen;
memcpy(buffer, &hdr->pBuffer[hdr->nOffset], hdr->nFilledLen);

hdr->nFlags = 0;
hdr->nFilledLen = 0;
OMX_ERRORTYPE e = OMX_FillThisBuffer(m_audiodecoder.Handle(), hdr);
if (e != OMX_ErrorNone)
LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
"OMX_FillThisBuffer reQ error %1").arg(Error2String(e)) );

return ret;
}

int AudioDecoderOMX::ProcessPacket(const AVPacket *pkt)
{
uint8_t *buf = pkt->data;
int size = pkt->size;
int ret = pkt->size;

while (size > 0)
{
if (!m_ibufs_sema.tryAcquire(1, 5))
{
LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + " - no input buffers");
ret = 0;
break;
}
m_lock.lock();
assert(!m_ibufs.isEmpty());
OMX_BUFFERHEADERTYPE *hdr = m_ibufs.takeFirst();
m_lock.unlock();

int free = int(hdr->nAllocLen) - int(hdr->nFilledLen + hdr->nOffset);
int cnt = (free > size) ? size : free;
memcpy(&hdr->pBuffer[hdr->nOffset + hdr->nFilledLen], buf, cnt);
hdr->nFilledLen += cnt;
buf += cnt;
size -= cnt;
free -= cnt;

hdr->nFlags = 0;
OMX_ERRORTYPE e = OMX_EmptyThisBuffer(m_audiodecoder.Handle(), hdr);
if (e != OMX_ErrorNone)
{
LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
"OMX_EmptyThisBuffer error %1").arg(Error2String(e)) );
m_lock.lock();
m_ibufs.append(hdr);
m_lock.unlock();
m_ibufs_sema.release();
ret = -1;
break;
}
}

return ret;
}

// OMX_StateIdle callback
OMX_ERRORTYPE AudioDecoderOMX::AllocBuffersCB()
{
OMX_ERRORTYPE e = AllocInputBuffers();
return (e == OMX_ErrorNone) ? AllocOutputBuffers() : e;
}

// Allocate decoder input buffers
OMX_ERRORTYPE AudioDecoderOMX::AllocInputBuffers()
{
assert(m_audiodecoder.IsValid());
assert(m_ibufs_sema.available() == 0);
assert(m_ibufs.isEmpty());

const OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef();
OMX_U32 uBufs = def.nBufferCountActual;
LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + QString(" %1 x %2 bytes")
.arg(uBufs).arg(def.nBufferSize));
while (uBufs--)
{
OMX_BUFFERHEADERTYPE *hdr;
OMX_ERRORTYPE e = OMX_AllocateBuffer(m_audiodecoder.Handle(), &hdr,
def.nPortIndex, 0, def.nBufferSize);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"OMX_AllocateBuffer error %1").arg(Error2String(e)) );
return e;
}
if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
{
LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer header mismatch");
OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
return OMX_ErrorVersionMismatch;
}
if (hdr->nVersion.nVersion != OMX_VERSION)
{
LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer version mismatch");
OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
return OMX_ErrorVersionMismatch;
}
hdr->nFilledLen = 0;
hdr->nOffset = 0;
m_lock.lock();
m_ibufs.append(hdr);
m_lock.unlock();
m_ibufs_sema.release();
}
return OMX_ErrorNone;
}

// Allocate decoder output buffers
OMX_ERRORTYPE AudioDecoderOMX::AllocOutputBuffers()
{
assert(m_audiodecoder.IsValid());
assert(m_obufs_sema.available() == 0);
assert(m_obufs.isEmpty());

const OMX_PARAM_PORTDEFINITIONTYPE &def = m_audiodecoder.PortDef(1);
OMX_U32 uBufs = def.nBufferCountActual;
LOG(VB_AUDIO, LOG_DEBUG, LOC + __func__ + QString(" %1 x %2 bytes")
.arg(uBufs).arg(def.nBufferSize));
while (uBufs--)
{
OMX_BUFFERHEADERTYPE *hdr;
OMX_ERRORTYPE e = OMX_AllocateBuffer(m_audiodecoder.Handle(), &hdr,
def.nPortIndex, 0, def.nBufferSize);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"OMX_AllocateBuffer error %1").arg(Error2String(e)) );
return e;
}
if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
{
LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer header mismatch");
OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
return OMX_ErrorVersionMismatch;
}
if (hdr->nVersion.nVersion != OMX_VERSION)
{
LOG(VB_AUDIO, LOG_ERR, LOC + "OMX_AllocateBuffer version mismatch");
OMX_FreeBuffer(m_audiodecoder.Handle(), def.nPortIndex, hdr);
return OMX_ErrorVersionMismatch;
}
hdr->nFilledLen = 0;
hdr->nOffset = 0;
m_lock.lock();
m_obufs.append(hdr);
m_lock.unlock();
m_obufs_sema.release();
}
return OMX_ErrorNone;
}

// Shutdown OMX_StateIdle -> OMX_StateLoaded callback
// virtual
void AudioDecoderOMX::ReleaseBuffers(OMXComponent &cmpnt)
{
FreeBuffersCB();
}

// Free all OMX buffers
// OMX_CommandPortDisable callback
OMX_ERRORTYPE AudioDecoderOMX::FreeBuffersCB()
{
assert(m_audiodecoder.IsValid());

// Free all input buffers
while (m_ibufs_sema.tryAcquire())
{
m_lock.lock();
assert(!m_ibufs.isEmpty());
OMX_BUFFERHEADERTYPE *hdr = m_ibufs.takeFirst();
m_lock.unlock();

assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
assert(hdr->nVersion.nVersion == OMX_VERSION);

OMX_ERRORTYPE e;
e = OMX_FreeBuffer(m_audiodecoder.Handle(), m_audiodecoder.Base(), hdr);
if (e != OMX_ErrorNone)
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"OMX_FreeBuffer 0x%1 error %2")
.arg(quintptr(hdr),0,16).arg(Error2String(e)));
}

// Free all output buffers
while (m_obufs_sema.tryAcquire())
{
m_lock.lock();
assert(!m_obufs.isEmpty());
OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
m_lock.unlock();

assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
assert(hdr->nVersion.nVersion == OMX_VERSION);

OMX_ERRORTYPE e;
e = OMX_FreeBuffer(m_audiodecoder.Handle(), m_audiodecoder.Base() + 1, hdr);
if (e != OMX_ErrorNone)
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"OMX_FreeBuffer 0x%1 error %2")
.arg(quintptr(hdr),0,16).arg(Error2String(e)));
}

return OMX_ErrorNone;
}

// virtual
OMX_ERRORTYPE AudioDecoderOMX::EmptyBufferDone(
OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
{
assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
assert(hdr->nVersion.nVersion == OMX_VERSION);
hdr->nFilledLen = 0;
hdr->nFlags = 0;
if (m_lock.tryLock(1000))
{
m_ibufs.append(hdr);
m_lock.unlock();
m_ibufs_sema.release();
}
else
LOG(VB_GENERAL, LOG_CRIT, LOC + "EmptyBufferDone deadlock");
return OMX_ErrorNone;
}

// virtual
OMX_ERRORTYPE AudioDecoderOMX::FillBufferDone(
OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
{
assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
assert(hdr->nVersion.nVersion == OMX_VERSION);
if (m_lock.tryLock(1000))
{
m_obufs.append(hdr);
m_lock.unlock();
m_obufs_sema.release();
}
else
LOG(VB_GENERAL, LOG_CRIT, LOC + "FillBufferDone deadlock");
return OMX_ErrorNone;
}

// Start filling the output buffers
OMX_ERRORTYPE AudioDecoderOMX::FillOutputBuffers()
{
while (m_obufs_sema.tryAcquire())
{
m_lock.lock();
assert(!m_obufs.isEmpty());
OMX_BUFFERHEADERTYPE *hdr = m_obufs.takeFirst();
m_lock.unlock();

assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
assert(hdr->nVersion.nVersion == OMX_VERSION);

hdr->nFlags = 0;
hdr->nFilledLen = 0;
OMX_ERRORTYPE e = OMX_FillThisBuffer(m_audiodecoder.Handle(), hdr);
if (e != OMX_ErrorNone)
{
LOG(VB_AUDIO, LOG_ERR, LOC + QString(
"OMX_FillThisBuffer error %1").arg(Error2String(e)) );
m_lock.lock();
m_obufs.append(hdr);
m_lock.unlock();
m_obufs_sema.release();
return e;
}
}

return OMX_ErrorNone;
}
// EOF
8 changes: 0 additions & 8 deletions mythtv/libs/libmyth/audio/audiooutput_omx.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@
#include "audiooutputbase.h"
#include "omxcontext.h"

class AudioDecoderOMX;

class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx
{
friend class AudioDecoderOMX;

// No copying
AudioOutputOMX(const AudioOutputOMX&);
AudioOutputOMX & operator =(const AudioOutputOMX&);
Expand All @@ -30,9 +26,6 @@ class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx
virtual int GetVolumeChannel(int channel) const; // Returns 0-100
virtual void SetVolumeChannel(int channel, int volume); // range 0-100 for vol

// AudioOutput overrides
virtual int DecodeAudio(AVCodecContext*, uint8_t*, int&, const AVPacket*);

protected:
// AudioOutputBase implementation
virtual bool OpenDevice(void);
Expand All @@ -58,7 +51,6 @@ class AudioOutputOMX : public AudioOutputBase, private OMXComponentCtx

private:
OMXComponent m_audiorender;
AudioDecoderOMX *m_audiodecoder;

QSemaphore m_ibufs_sema; // EmptyBufferDone signal
QMutex mutable m_lock; // Protects data following
Expand Down