Merge pull request #25762 from CastagnaIT/gui_menu_tracks
[xbmc.git] / xbmc / cores / paplayer / VideoPlayerCodec.cpp
blob13037229080b9d09732095f8f218ad6dcdbb3ebb
1 /*
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.
7 */
9 #include "VideoPlayerCodec.h"
11 #include "ServiceBroker.h"
12 #include "URL.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()
32 DeInit();
35 AEAudioFormat VideoPlayerCodec::GetFormat()
37 AEAudioFormat format;
38 if (m_pAudioCodec)
40 format = m_pAudioCodec->GetFormat();
42 return format;
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
59 if (m_bInited)
61 // keep things as is if Init() was done with known strFile
62 if (m_strFileName == file.GetDynPath())
63 return true;
65 // got differing filename, so cleanup before starting over
66 DeInit();
69 m_nDecodedLen = 0;
71 CFileItem fileitem(file);
72 fileitem.SetMimeType(m_strContentType);
73 fileitem.SetMimeTypeForInternetFile();
74 m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, fileitem);
75 if (!m_pInputStream)
77 CLog::Log(LOGERROR, "{}: Error creating input stream for {}", __FUNCTION__, file.GetDynPath());
78 return false;
81 //! @todo
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();
89 return false;
92 m_pDemuxer = NULL;
94 try
96 m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
97 if (!m_pDemuxer)
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__);
103 return false;
106 catch(...)
108 CLog::Log(LOGERROR, "{}: Exception thrown when opening demuxer", __FUNCTION__);
109 if (m_pDemuxer)
111 delete m_pDemuxer;
112 m_pDemuxer = NULL;
114 return false;
117 CDemuxStream* pStream = NULL;
118 m_nAudioStream = -1;
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;
126 pStream = stream;
127 break;
131 if (m_nAudioStream == -1)
133 CLog::Log(LOGERROR, "{}: Could not find audio stream", __FUNCTION__);
134 delete m_pDemuxer;
135 m_pDemuxer = NULL;
136 if (m_pInputStream.use_count() > 1)
137 throw std::runtime_error("m_pInputStream reference count is greater than 1");
138 m_pInputStream.reset();
139 return false;
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);
147 if (!m_pAudioCodec)
149 CLog::Log(LOGERROR, "{}: Could not create audio codec", __FUNCTION__);
150 delete m_pDemuxer;
151 m_pDemuxer = NULL;
152 if (m_pInputStream.use_count() > 1)
153 throw std::runtime_error("m_pInputStream reference count is greater than 1");
154 m_pInputStream.reset();
155 return false;
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
174 int nErrors = 0;
175 for (int nPacket = 0;
176 nPacket < 10 && (m_channels == 0 || m_format.m_sampleRate == 0 || m_format.m_frameSize == 0);
177 nPacket++)
179 uint8_t dummy[256];
180 size_t nSize = 256;
181 if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
182 ++nErrors;
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;
190 if (nErrors >= 10)
192 CLog::Log(LOGDEBUG, "{}: Could not decode data", __FUNCTION__);
193 return false;
196 // test if seeking is supported
197 m_bCanSeek = false;
198 if (m_pInputStream->Seek(0, SEEK_POSSIBLE))
200 if (Seek(1))
202 // rewind stream to beginning
203 Seek(0);
204 m_bCanSeek = true;
206 else
208 m_pInputStream->Seek(0, SEEK_SET);
209 if (!m_pDemuxer->Reset())
210 return false;
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)
237 return false;
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,
257 false, 0.0f);
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();
266 m_bInited = true;
268 return true;
271 void VideoPlayerCodec::DeInit()
273 if (m_pDemuxer != NULL)
275 delete m_pDemuxer;
276 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
288 m_TotalTime = 0;
289 m_bitsPerSample = 0;
290 m_bitRate = 0;
291 m_channels = 0;
292 m_format.m_dataFormat = AE_FMT_INVALID;
294 m_nDecodedLen = 0;
296 m_strFileName = "";
297 m_bInited = false;
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();
309 m_nDecodedLen = 0;
311 return ret;
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;
319 *actualsize = nLen;
320 if (m_needConvert)
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;
330 else
332 memcpy(pBuffer, m_audioFrame.data[0], *actualsize);
333 m_audioFrame.data[0] += (*actualsize);
335 m_nDecodedLen -= nLen;
336 return READ_SUCCESS;
339 m_nDecodedLen = 0;
340 m_pAudioCodec->GetData(m_audioFrame);
341 int bytes = m_audioFrame.nb_frames * m_audioFrame.framesize;
343 if (!bytes)
345 DemuxPacket* pPacket = nullptr;
348 if (pPacket)
349 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
350 pPacket = m_pDemuxer->Read();
351 } while (pPacket && pPacket->iStreamId != m_nAudioStream);
353 if (!pPacket)
355 return READ_EOF;
358 pPacket->pts = DVD_NOPTS_VALUE;
359 pPacket->dts = DVD_NOPTS_VALUE;
361 int ret = m_pAudioCodec->AddData(*pPacket);
362 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
363 if (ret < 0)
365 return READ_ERROR;
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
374 if (m_needConvert)
375 m_nDecodedLen *= (m_bitsPerSample>>3) / (m_srcFormat.m_frameSize / m_channels);
377 *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
378 if (*actualsize > 0)
380 if (m_needConvert)
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;
390 else
392 memcpy(pBuffer, m_audioFrame.data[0], *actualsize);
393 m_audioFrame.data[0] += *actualsize;
395 m_nDecodedLen -= *actualsize;
398 return READ_SUCCESS;
401 int VideoPlayerCodec::ReadRaw(uint8_t **pBuffer, int *bufferSize)
403 DemuxPacket* pPacket;
405 m_nDecodedLen = 0;
406 DVDAudioFrame audioframe;
408 m_pAudioCodec->GetData(audioframe);
409 if (audioframe.nb_frames)
411 return READ_SUCCESS;
416 pPacket = m_pDemuxer->Read();
417 } while (pPacket && pPacket->iStreamId != m_nAudioStream);
419 if (!pPacket)
421 return READ_EOF;
423 pPacket->pts = DVD_NOPTS_VALUE;
424 pPacket->dts = DVD_NOPTS_VALUE;
425 int ret = m_pAudioCodec->AddData(*pPacket);
426 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
427 if (ret < 0)
429 return READ_ERROR;
432 m_pAudioCodec->GetData(audioframe);
433 if (audioframe.nb_frames)
435 *bufferSize = audioframe.nb_frames;
436 *pBuffer = audioframe.data[0];
438 else
440 *bufferSize = 0;
443 return READ_SUCCESS;
446 bool VideoPlayerCodec::CanInit()
448 return true;
451 bool VideoPlayerCodec::CanSeek()
453 return m_bCanSeek;
456 bool VideoPlayerCodec::NeedConvert(AEDataFormat fmt)
458 if (fmt == AE_FMT_RAW)
459 return false;
461 switch(fmt)
463 case AE_FMT_U8:
464 case AE_FMT_S16NE:
465 case AE_FMT_S32NE:
466 case AE_FMT_FLOAT:
467 case AE_FMT_DOUBLE:
468 return false;
469 default:
470 return true;
474 CAEStreamInfo::DataType VideoPlayerCodec::GetPassthroughStreamType(AVCodecID codecId,
475 int samplerate,
476 int profile)
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;
482 switch (codecId)
484 case AV_CODEC_ID_AC3:
485 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_AC3;
486 format.m_streamInfo.m_sampleRate = samplerate;
487 break;
489 case AV_CODEC_ID_EAC3:
490 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3;
491 format.m_streamInfo.m_sampleRate = samplerate;
492 break;
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;
499 else
500 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD_CORE;
501 format.m_streamInfo.m_sampleRate = samplerate;
502 break;
504 case AV_CODEC_ID_TRUEHD:
505 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_TRUEHD;
506 format.m_streamInfo.m_sampleRate = samplerate;
507 break;
509 default:
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);
523 if (supports)
524 return format.m_streamInfo.m_type;
525 else
526 return CAEStreamInfo::DataType::STREAM_TYPE_NULL;