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.
9 #include "VideoPlayerCodec.h"
11 #include "ServiceBroker.h"
13 #include "cores/AudioEngine/AEResampleFactory.h"
14 #include "cores/AudioEngine/Interfaces/AE.h"
15 #include "cores/AudioEngine/Utils/AEUtil.h"
16 #include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h"
17 #include "cores/VideoPlayer/DVDDemuxers/DVDDemuxUtils.h"
18 #include "cores/VideoPlayer/DVDDemuxers/DVDFactoryDemuxer.h"
19 #include "cores/VideoPlayer/DVDInputStreams/DVDFactoryInputStream.h"
20 #include "cores/VideoPlayer/DVDStreamInfo.h"
21 #include "music/tags/TagLoaderTagLib.h"
22 #include "utils/StringUtils.h"
23 #include "utils/log.h"
25 VideoPlayerCodec::VideoPlayerCodec() : m_processInfo(CProcessInfo::CreateInstance())
27 m_CodecName
= "VideoPlayer";
30 VideoPlayerCodec::~VideoPlayerCodec()
35 AEAudioFormat
VideoPlayerCodec::GetFormat()
40 format
= m_pAudioCodec
->GetFormat();
45 void VideoPlayerCodec::SetContentType(const std::string
&strContent
)
47 m_strContentType
= strContent
;
48 StringUtils::ToLower(m_strContentType
);
51 void VideoPlayerCodec::SetPassthroughStreamType(CAEStreamInfo::DataType streamType
)
53 m_srcFormat
.m_streamInfo
.m_type
= streamType
;
56 bool VideoPlayerCodec::Init(const CFileItem
&file
, unsigned int filecache
)
58 // take precaution if Init()ialized earlier
61 // keep things as is if Init() was done with known strFile
62 if (m_strFileName
== file
.GetDynPath())
65 // got differing filename, so cleanup before starting over
71 CFileItem
fileitem(file
);
72 fileitem
.SetMimeType(m_strContentType
);
73 fileitem
.SetMimeTypeForInternetFile();
74 m_pInputStream
= CDVDFactoryInputStream::CreateInputStream(NULL
, fileitem
);
77 CLog::Log(LOGERROR
, "{}: Error creating input stream for {}", __FUNCTION__
, file
.GetDynPath());
82 //! convey CFileItem::ContentLookup() into Open()
83 if (!m_pInputStream
->Open())
85 CLog::Log(LOGERROR
, "{}: Error opening file {}", __FUNCTION__
, file
.GetDynPath());
86 if (m_pInputStream
.use_count() > 1)
87 throw std::runtime_error("m_pInputStream reference count is greater than 1");
88 m_pInputStream
.reset();
96 m_pDemuxer
= CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream
);
99 if (m_pInputStream
.use_count() > 1)
100 throw std::runtime_error("m_pInputStream reference count is greater than 1");
101 m_pInputStream
.reset();
102 CLog::Log(LOGERROR
, "{}: Error creating demuxer", __FUNCTION__
);
108 CLog::Log(LOGERROR
, "{}: Exception thrown when opening demuxer", __FUNCTION__
);
117 CDemuxStream
* pStream
= NULL
;
119 int64_t demuxerId
= -1;
120 for (auto stream
: m_pDemuxer
->GetStreams())
122 if (stream
&& stream
->type
== STREAM_AUDIO
)
124 m_nAudioStream
= stream
->uniqueId
;
125 demuxerId
= stream
->demuxerId
;
131 if (m_nAudioStream
== -1)
133 CLog::Log(LOGERROR
, "{}: Could not find audio stream", __FUNCTION__
);
136 if (m_pInputStream
.use_count() > 1)
137 throw std::runtime_error("m_pInputStream reference count is greater than 1");
138 m_pInputStream
.reset();
142 CDVDStreamInfo
hint(*pStream
, true);
144 CAEStreamInfo::DataType ptStreamTye
=
145 GetPassthroughStreamType(hint
.codec
, hint
.samplerate
, hint
.profile
);
146 m_pAudioCodec
= CDVDFactoryCodec::CreateAudioCodec(hint
, *m_processInfo
, true, true, ptStreamTye
);
149 CLog::Log(LOGERROR
, "{}: Could not create audio codec", __FUNCTION__
);
152 if (m_pInputStream
.use_count() > 1)
153 throw std::runtime_error("m_pInputStream reference count is greater than 1");
154 m_pInputStream
.reset();
158 // Extract ReplayGain info
159 // tagLoaderTagLib.Load will try to determine tag type by file extension, so set fallback by contentType
160 std::string strFallbackFileExtension
= "";
161 if (m_strContentType
== "audio/aacp" ||
162 m_strContentType
== "audio/aac")
163 strFallbackFileExtension
= "m4a";
164 else if (m_strContentType
== "audio/x-ms-wma")
165 strFallbackFileExtension
= "wma";
166 else if (m_strContentType
== "audio/x-ape" ||
167 m_strContentType
== "audio/ape")
168 strFallbackFileExtension
= "ape";
169 CTagLoaderTagLib tagLoaderTagLib
;
170 tagLoaderTagLib
.Load(file
.GetDynPath(), m_tag
, strFallbackFileExtension
);
172 // we have to decode initial data in order to get channels/samplerate
173 // for sanity - we read no more than 10 packets
175 for (int nPacket
= 0;
176 nPacket
< 10 && (m_channels
== 0 || m_format
.m_sampleRate
== 0 || m_format
.m_frameSize
== 0);
181 if (ReadPCM(dummy
, nSize
, &nSize
) == READ_ERROR
)
184 m_srcFormat
= m_pAudioCodec
->GetFormat();
185 m_format
= m_srcFormat
;
186 m_channels
= m_srcFormat
.m_channelLayout
.Count();
187 m_bitsPerSample
= CAEUtil::DataFormatToBits(m_srcFormat
.m_dataFormat
);
188 m_bitsPerCodedSample
= static_cast<CDemuxStreamAudio
*>(pStream
)->iBitsPerSample
;
192 CLog::Log(LOGDEBUG
, "{}: Could not decode data", __FUNCTION__
);
196 // test if seeking is supported
198 if (m_pInputStream
->Seek(0, SEEK_POSSIBLE
))
202 // rewind stream to beginning
208 m_pInputStream
->Seek(0, SEEK_SET
);
209 if (!m_pDemuxer
->Reset())
214 if (m_channels
== 0) // no data - just guess and hope for the best
216 m_srcFormat
.m_channelLayout
= CAEChannelInfo(AE_CH_LAYOUT_2_0
);
217 m_channels
= m_srcFormat
.m_channelLayout
.Count();
220 if (m_srcFormat
.m_sampleRate
== 0)
221 m_srcFormat
.m_sampleRate
= 44100;
223 m_TotalTime
= m_pDemuxer
->GetStreamLength();
224 m_bitRate
= m_pAudioCodec
->GetBitRate();
225 if (!m_bitRate
&& m_TotalTime
)
227 m_bitRate
= (int)(((m_pInputStream
->GetLength()*1000) / m_TotalTime
) * 8);
229 m_CodecName
= m_pDemuxer
->GetStreamCodecName(demuxerId
, m_nAudioStream
);
231 m_needConvert
= false;
232 if (NeedConvert(m_srcFormat
.m_dataFormat
))
234 m_needConvert
= true;
235 // if we don't know the framesize yet, we will fail when converting
236 if (m_srcFormat
.m_frameSize
== 0)
239 m_pResampler
= ActiveAE::CAEResampleFactory::Create();
241 SampleConfig dstConfig
, srcConfig
;
242 dstConfig
.channel_layout
= CAEUtil::GetAVChannelLayout(m_srcFormat
.m_channelLayout
);
243 dstConfig
.channels
= m_channels
;
244 dstConfig
.sample_rate
= m_srcFormat
.m_sampleRate
;
245 dstConfig
.fmt
= CAEUtil::GetAVSampleFormat(AE_FMT_FLOAT
);
246 dstConfig
.bits_per_sample
= CAEUtil::DataFormatToUsedBits(AE_FMT_FLOAT
);
247 dstConfig
.dither_bits
= CAEUtil::DataFormatToDitherBits(AE_FMT_FLOAT
);
249 srcConfig
.channel_layout
= CAEUtil::GetAVChannelLayout(m_srcFormat
.m_channelLayout
);
250 srcConfig
.channels
= m_channels
;
251 srcConfig
.sample_rate
= m_srcFormat
.m_sampleRate
;
252 srcConfig
.fmt
= CAEUtil::GetAVSampleFormat(m_srcFormat
.m_dataFormat
);
253 srcConfig
.bits_per_sample
= CAEUtil::DataFormatToUsedBits(m_srcFormat
.m_dataFormat
);
254 srcConfig
.dither_bits
= CAEUtil::DataFormatToDitherBits(m_srcFormat
.m_dataFormat
);
256 m_pResampler
->Init(dstConfig
, srcConfig
, false, false, M_SQRT1_2
, NULL
, AE_QUALITY_UNKNOWN
,
259 m_planes
= AE_IS_PLANAR(m_srcFormat
.m_dataFormat
) ? m_channels
: 1;
260 m_format
= m_srcFormat
;
261 m_format
.m_dataFormat
= AE_FMT_FLOAT
;
262 m_bitsPerSample
= CAEUtil::DataFormatToBits(m_format
.m_dataFormat
);
265 m_strFileName
= file
.GetDynPath();
271 void VideoPlayerCodec::DeInit()
273 if (m_pDemuxer
!= NULL
)
279 if (m_pInputStream
.use_count() > 1)
280 throw std::runtime_error("m_pInputStream reference count is greater than 1");
281 m_pInputStream
.reset();
283 m_pAudioCodec
.reset();
285 m_pResampler
.reset();
287 // cleanup format information
292 m_format
.m_dataFormat
= AE_FMT_INVALID
;
300 bool VideoPlayerCodec::Seek(int64_t iSeekTime
)
302 // default to announce backwards seek if !m_pPacket to not make FFmpeg
303 // skip mpeg audio frames at playback start
304 bool seekback
= true;
306 bool ret
= m_pDemuxer
->SeekTime((int)iSeekTime
, seekback
);
307 m_pAudioCodec
->Reset();
314 int VideoPlayerCodec::ReadPCM(uint8_t* pBuffer
, size_t size
, size_t* actualsize
)
316 if (m_nDecodedLen
> 0)
318 size_t nLen
= (size
< m_nDecodedLen
) ? size
: m_nDecodedLen
;
322 int samples
= *actualsize
/ (m_bitsPerSample
>>3);
323 int frames
= samples
/ m_channels
;
324 m_pResampler
->Resample(&pBuffer
, frames
, m_audioFrame
.data
, frames
, 1.0);
325 for (int i
=0; i
<m_planes
; i
++)
327 m_audioFrame
.data
[i
] += frames
*m_srcFormat
.m_frameSize
/m_planes
;
332 memcpy(pBuffer
, m_audioFrame
.data
[0], *actualsize
);
333 m_audioFrame
.data
[0] += (*actualsize
);
335 m_nDecodedLen
-= nLen
;
340 m_pAudioCodec
->GetData(m_audioFrame
);
341 int bytes
= m_audioFrame
.nb_frames
* m_audioFrame
.framesize
;
345 DemuxPacket
* pPacket
= nullptr;
349 CDVDDemuxUtils::FreeDemuxPacket(pPacket
);
350 pPacket
= m_pDemuxer
->Read();
351 } while (pPacket
&& pPacket
->iStreamId
!= m_nAudioStream
);
358 pPacket
->pts
= DVD_NOPTS_VALUE
;
359 pPacket
->dts
= DVD_NOPTS_VALUE
;
361 int ret
= m_pAudioCodec
->AddData(*pPacket
);
362 CDVDDemuxUtils::FreeDemuxPacket(pPacket
);
368 m_pAudioCodec
->GetData(m_audioFrame
);
369 bytes
= m_audioFrame
.nb_frames
* m_audioFrame
.framesize
;
372 m_nDecodedLen
= bytes
;
373 // scale decoded bytes to destination format
375 m_nDecodedLen
*= (m_bitsPerSample
>>3) / (m_srcFormat
.m_frameSize
/ m_channels
);
377 *actualsize
= (m_nDecodedLen
<= size
) ? m_nDecodedLen
: size
;
382 int samples
= *actualsize
/ (m_bitsPerSample
>>3);
383 int frames
= samples
/ m_channels
;
384 m_pResampler
->Resample(&pBuffer
, frames
, m_audioFrame
.data
, frames
, 1.0);
385 for (int i
=0; i
<m_planes
; i
++)
387 m_audioFrame
.data
[i
] += frames
*m_srcFormat
.m_frameSize
/m_planes
;
392 memcpy(pBuffer
, m_audioFrame
.data
[0], *actualsize
);
393 m_audioFrame
.data
[0] += *actualsize
;
395 m_nDecodedLen
-= *actualsize
;
401 int VideoPlayerCodec::ReadRaw(uint8_t **pBuffer
, int *bufferSize
)
403 DemuxPacket
* pPacket
;
406 DVDAudioFrame audioframe
;
408 m_pAudioCodec
->GetData(audioframe
);
409 if (audioframe
.nb_frames
)
416 pPacket
= m_pDemuxer
->Read();
417 } while (pPacket
&& pPacket
->iStreamId
!= m_nAudioStream
);
423 pPacket
->pts
= DVD_NOPTS_VALUE
;
424 pPacket
->dts
= DVD_NOPTS_VALUE
;
425 int ret
= m_pAudioCodec
->AddData(*pPacket
);
426 CDVDDemuxUtils::FreeDemuxPacket(pPacket
);
432 m_pAudioCodec
->GetData(audioframe
);
433 if (audioframe
.nb_frames
)
435 *bufferSize
= audioframe
.nb_frames
;
436 *pBuffer
= audioframe
.data
[0];
446 bool VideoPlayerCodec::CanInit()
451 bool VideoPlayerCodec::CanSeek()
456 bool VideoPlayerCodec::NeedConvert(AEDataFormat fmt
)
458 if (fmt
== AE_FMT_RAW
)
474 CAEStreamInfo::DataType
VideoPlayerCodec::GetPassthroughStreamType(AVCodecID codecId
,
478 AEAudioFormat format
;
479 format
.m_dataFormat
= AE_FMT_RAW
;
480 format
.m_sampleRate
= samplerate
;
481 format
.m_streamInfo
.m_type
= CAEStreamInfo::DataType::STREAM_TYPE_NULL
;
484 case AV_CODEC_ID_AC3
:
485 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_AC3
;
486 format
.m_streamInfo
.m_sampleRate
= samplerate
;
489 case AV_CODEC_ID_EAC3
:
490 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_EAC3
;
491 format
.m_streamInfo
.m_sampleRate
= samplerate
;
494 case AV_CODEC_ID_DTS
:
495 if (profile
== FF_PROFILE_DTS_HD_HRA
)
496 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_DTSHD
;
497 else if (profile
== FF_PROFILE_DTS_HD_MA
)
498 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_DTSHD_MA
;
500 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
;
501 format
.m_streamInfo
.m_sampleRate
= samplerate
;
504 case AV_CODEC_ID_TRUEHD
:
505 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_TRUEHD
;
506 format
.m_streamInfo
.m_sampleRate
= samplerate
;
510 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_NULL
;
513 bool supports
= CServiceBroker::GetActiveAE()->SupportsRaw(format
);
515 if (!supports
&& codecId
== AV_CODEC_ID_DTS
&&
516 format
.m_streamInfo
.m_type
!= CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
&&
517 CServiceBroker::GetActiveAE()->UsesDtsCoreFallback())
519 format
.m_streamInfo
.m_type
= CAEStreamInfo::STREAM_TYPE_DTSHD_CORE
;
520 supports
= CServiceBroker::GetActiveAE()->SupportsRaw(format
);
524 return format
.m_streamInfo
.m_type
;
526 return CAEStreamInfo::DataType::STREAM_TYPE_NULL
;