1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9 #include "VideoPlayerCodec.h"
10
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"
24
VideoPlayerCodec()25 VideoPlayerCodec::VideoPlayerCodec()
26 {
27 m_CodecName = "VideoPlayer";
28 m_pDemuxer = NULL;
29 m_pInputStream = NULL;
30 m_pAudioCodec = NULL;
31 m_nAudioStream = -1;
32 m_nDecodedLen = 0;
33 m_bInited = false;
34 m_pResampler = NULL;
35 m_needConvert = false;
36 m_channels = 0;
37
38 m_processInfo.reset(CProcessInfo::CreateInstance());
39 }
40
~VideoPlayerCodec()41 VideoPlayerCodec::~VideoPlayerCodec()
42 {
43 DeInit();
44 }
45
GetFormat()46 AEAudioFormat VideoPlayerCodec::GetFormat()
47 {
48 AEAudioFormat format;
49 if (m_pAudioCodec)
50 {
51 format = m_pAudioCodec->GetFormat();
52 }
53 return format;
54 }
55
SetContentType(const std::string & strContent)56 void VideoPlayerCodec::SetContentType(const std::string &strContent)
57 {
58 m_strContentType = strContent;
59 StringUtils::ToLower(m_strContentType);
60 }
61
SetPassthroughStreamType(CAEStreamInfo::DataType streamType)62 void VideoPlayerCodec::SetPassthroughStreamType(CAEStreamInfo::DataType streamType)
63 {
64 m_srcFormat.m_streamInfo.m_type = streamType;
65 }
66
Init(const CFileItem & file,unsigned int filecache)67 bool VideoPlayerCodec::Init(const CFileItem &file, unsigned int filecache)
68 {
69 // take precaution if Init()ialized earlier
70 if (m_bInited)
71 {
72 // keep things as is if Init() was done with known strFile
73 if (m_strFileName == file.GetDynPath())
74 return true;
75
76 // got differing filename, so cleanup before starting over
77 DeInit();
78 }
79
80 m_nDecodedLen = 0;
81
82 CFileItem fileitem(file);
83 fileitem.SetMimeType(m_strContentType);
84 fileitem.SetMimeTypeForInternetFile();
85 m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, fileitem);
86 if (!m_pInputStream)
87 {
88 CLog::Log(LOGERROR, "{}: Error creating input stream for {}", __FUNCTION__, file.GetDynPath());
89 return false;
90 }
91
92 //! @todo
93 //! convey CFileItem::ContentLookup() into Open()
94 if (!m_pInputStream->Open())
95 {
96 CLog::Log(LOGERROR, "{}: Error opening file {}", __FUNCTION__, file.GetDynPath());
97 if (m_pInputStream.use_count() > 1)
98 throw std::runtime_error("m_pInputStream reference count is greater than 1");
99 m_pInputStream.reset();
100 return false;
101 }
102
103 m_pDemuxer = NULL;
104
105 try
106 {
107 m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
108 if (!m_pDemuxer)
109 {
110 if (m_pInputStream.use_count() > 1)
111 throw std::runtime_error("m_pInputStream reference count is greater than 1");
112 m_pInputStream.reset();
113 CLog::Log(LOGERROR, "%s: Error creating demuxer", __FUNCTION__);
114 return false;
115 }
116 }
117 catch(...)
118 {
119 CLog::Log(LOGERROR, "%s: Exception thrown when opening demuxer", __FUNCTION__);
120 if (m_pDemuxer)
121 {
122 delete m_pDemuxer;
123 m_pDemuxer = NULL;
124 }
125 return false;
126 }
127
128 CDemuxStream* pStream = NULL;
129 m_nAudioStream = -1;
130 int64_t demuxerId = -1;
131 for (auto stream : m_pDemuxer->GetStreams())
132 {
133 if (stream && stream->type == STREAM_AUDIO)
134 {
135 m_nAudioStream = stream->uniqueId;
136 demuxerId = stream->demuxerId;
137 pStream = stream;
138 break;
139 }
140 }
141
142 if (m_nAudioStream == -1)
143 {
144 CLog::Log(LOGERROR, "%s: Could not find audio stream", __FUNCTION__);
145 delete m_pDemuxer;
146 m_pDemuxer = NULL;
147 if (m_pInputStream.use_count() > 1)
148 throw std::runtime_error("m_pInputStream reference count is greater than 1");
149 m_pInputStream.reset();
150 return false;
151 }
152
153 CDVDStreamInfo hint(*pStream, true);
154
155 CAEStreamInfo::DataType ptStreamTye =
156 GetPassthroughStreamType(hint.codec, hint.samplerate, hint.profile);
157 m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, *m_processInfo, true, true, ptStreamTye);
158 if (!m_pAudioCodec)
159 {
160 CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__);
161 delete m_pDemuxer;
162 m_pDemuxer = NULL;
163 if (m_pInputStream.use_count() > 1)
164 throw std::runtime_error("m_pInputStream reference count is greater than 1");
165 m_pInputStream.reset();
166 return false;
167 }
168
169 // Extract ReplayGain info
170 // tagLoaderTagLib.Load will try to determine tag type by file extension, so set fallback by contentType
171 std::string strFallbackFileExtension = "";
172 if (m_strContentType == "audio/aacp" ||
173 m_strContentType == "audio/aac")
174 strFallbackFileExtension = "m4a";
175 else if (m_strContentType == "audio/x-ms-wma")
176 strFallbackFileExtension = "wma";
177 else if (m_strContentType == "audio/x-ape" ||
178 m_strContentType == "audio/ape")
179 strFallbackFileExtension = "ape";
180 CTagLoaderTagLib tagLoaderTagLib;
181 tagLoaderTagLib.Load(file.GetDynPath(), m_tag, strFallbackFileExtension);
182
183 // we have to decode initial data in order to get channels/samplerate
184 // for sanity - we read no more than 10 packets
185 int nErrors = 0;
186 for (int nPacket=0; nPacket < 10 && (m_channels == 0 || m_format.m_sampleRate == 0); nPacket++)
187 {
188 unsigned char dummy[256];
189 int nSize = 256;
190 if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
191 ++nErrors;
192
193 m_srcFormat = m_pAudioCodec->GetFormat();
194 m_format = m_srcFormat;
195 m_channels = m_srcFormat.m_channelLayout.Count();
196 m_bitsPerSample = CAEUtil::DataFormatToBits(m_srcFormat.m_dataFormat);
197 m_bitsPerCodedSample = static_cast<CDemuxStreamAudio*>(pStream)->iBitsPerSample;
198 }
199 if (nErrors >= 10)
200 {
201 CLog::Log(LOGDEBUG, "%s: Could not decode data", __FUNCTION__);
202 return false;
203 }
204
205 // test if seeking is supported
206 m_bCanSeek = false;
207 if (m_pInputStream->Seek(0, SEEK_POSSIBLE))
208 {
209 if (Seek(1))
210 {
211 // rewind stream to beginning
212 Seek(0);
213 m_bCanSeek = true;
214 }
215 else
216 {
217 m_pInputStream->Seek(0, SEEK_SET);
218 if (!m_pDemuxer->Reset())
219 return false;
220 }
221 }
222
223 if (m_channels == 0) // no data - just guess and hope for the best
224 {
225 m_srcFormat.m_channelLayout = CAEChannelInfo(AE_CH_LAYOUT_2_0);
226 m_channels = m_srcFormat.m_channelLayout.Count();
227 }
228
229 if (m_srcFormat.m_sampleRate == 0)
230 m_srcFormat.m_sampleRate = 44100;
231
232 m_TotalTime = m_pDemuxer->GetStreamLength();
233 m_bitRate = m_pAudioCodec->GetBitRate();
234 if (!m_bitRate && m_TotalTime)
235 {
236 m_bitRate = (int)(((m_pInputStream->GetLength()*1000) / m_TotalTime) * 8);
237 }
238 m_CodecName = m_pDemuxer->GetStreamCodecName(demuxerId, m_nAudioStream);
239
240 m_needConvert = false;
241 if (NeedConvert(m_srcFormat.m_dataFormat))
242 {
243 m_needConvert = true;
244 m_pResampler = ActiveAE::CAEResampleFactory::Create();
245
246 SampleConfig dstConfig, srcConfig;
247 dstConfig.channel_layout = CAEUtil::GetAVChannelLayout(m_srcFormat.m_channelLayout);
248 dstConfig.channels = m_channels;
249 dstConfig.sample_rate = m_srcFormat.m_sampleRate;
250 dstConfig.fmt = CAEUtil::GetAVSampleFormat(AE_FMT_FLOAT);
251 dstConfig.bits_per_sample = CAEUtil::DataFormatToUsedBits(AE_FMT_FLOAT);
252 dstConfig.dither_bits = CAEUtil::DataFormatToDitherBits(AE_FMT_FLOAT);
253
254 srcConfig.channel_layout = CAEUtil::GetAVChannelLayout(m_srcFormat.m_channelLayout);
255 srcConfig.channels = m_channels;
256 srcConfig.sample_rate = m_srcFormat.m_sampleRate;
257 srcConfig.fmt = CAEUtil::GetAVSampleFormat(m_srcFormat.m_dataFormat);
258 srcConfig.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_srcFormat.m_dataFormat);
259 srcConfig.dither_bits = CAEUtil::DataFormatToDitherBits(m_srcFormat.m_dataFormat);
260
261 m_pResampler->Init(dstConfig, srcConfig,
262 false,
263 false,
264 M_SQRT1_2,
265 NULL,
266 AE_QUALITY_UNKNOWN,
267 false);
268
269 m_planes = AE_IS_PLANAR(m_srcFormat.m_dataFormat) ? m_channels : 1;
270 m_format = m_srcFormat;
271 m_format.m_dataFormat = AE_FMT_FLOAT;
272 m_bitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
273 }
274
275 m_strFileName = file.GetDynPath();
276 m_bInited = true;
277
278 return true;
279 }
280
DeInit()281 void VideoPlayerCodec::DeInit()
282 {
283 if (m_pDemuxer != NULL)
284 {
285 delete m_pDemuxer;
286 m_pDemuxer = NULL;
287 }
288
289 if (m_pInputStream.use_count() > 1)
290 throw std::runtime_error("m_pInputStream reference count is greater than 1");
291 m_pInputStream.reset();
292
293 if (m_pAudioCodec != NULL)
294 {
295 delete m_pAudioCodec;
296 m_pAudioCodec = NULL;
297 }
298
299 delete m_pResampler;
300 m_pResampler = NULL;
301
302 // cleanup format information
303 m_TotalTime = 0;
304 m_bitsPerSample = 0;
305 m_bitRate = 0;
306 m_channels = 0;
307 m_format.m_dataFormat = AE_FMT_INVALID;
308
309 m_nDecodedLen = 0;
310
311 m_strFileName = "";
312 m_bInited = false;
313 }
314
Seek(int64_t iSeekTime)315 bool VideoPlayerCodec::Seek(int64_t iSeekTime)
316 {
317 // default to announce backwards seek if !m_pPacket to not make FFmpeg
318 // skip mpeg audio frames at playback start
319 bool seekback = true;
320
321 bool ret = m_pDemuxer->SeekTime((int)iSeekTime, seekback);
322 m_pAudioCodec->Reset();
323
324 m_nDecodedLen = 0;
325
326 return ret;
327 }
328
ReadPCM(unsigned char * pBuffer,int size,int * actualsize)329 int VideoPlayerCodec::ReadPCM(unsigned char *pBuffer, int size, int *actualsize)
330 {
331 if (m_nDecodedLen > 0)
332 {
333 int nLen = (size<m_nDecodedLen)?size:m_nDecodedLen;
334 *actualsize = nLen;
335 if (m_needConvert)
336 {
337 int samples = *actualsize / (m_bitsPerSample>>3);
338 int frames = samples / m_channels;
339 m_pResampler->Resample(&pBuffer, frames, m_audioFrame.data, frames, 1.0);
340 for (int i=0; i<m_planes; i++)
341 {
342 m_audioFrame.data[i] += frames*m_srcFormat.m_frameSize/m_planes;
343 }
344 }
345 else
346 {
347 memcpy(pBuffer, m_audioFrame.data[0], *actualsize);
348 m_audioFrame.data[0] += (*actualsize);
349 }
350 m_nDecodedLen -= nLen;
351 return READ_SUCCESS;
352 }
353
354 m_nDecodedLen = 0;
355 m_pAudioCodec->GetData(m_audioFrame);
356 int bytes = m_audioFrame.nb_frames * m_audioFrame.framesize;
357
358 if (!bytes)
359 {
360 DemuxPacket* pPacket;
361 do
362 {
363 pPacket = m_pDemuxer->Read();
364 } while (pPacket && pPacket->iStreamId != m_nAudioStream);
365
366 if (!pPacket)
367 {
368 return READ_EOF;
369 }
370
371 pPacket->pts = DVD_NOPTS_VALUE;
372 pPacket->dts = DVD_NOPTS_VALUE;
373
374 int ret = m_pAudioCodec->AddData(*pPacket);
375 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
376 if (ret < 0)
377 {
378 return READ_ERROR;
379 }
380
381 m_pAudioCodec->GetData(m_audioFrame);
382 bytes = m_audioFrame.nb_frames * m_audioFrame.framesize;
383 }
384
385 m_nDecodedLen = bytes;
386 // scale decoded bytes to destination format
387 if (m_needConvert)
388 m_nDecodedLen *= (m_bitsPerSample>>3) / (m_srcFormat.m_frameSize / m_channels);
389
390 *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
391 if (*actualsize > 0)
392 {
393 if (m_needConvert)
394 {
395 int samples = *actualsize / (m_bitsPerSample>>3);
396 int frames = samples / m_channels;
397 m_pResampler->Resample(&pBuffer, frames, m_audioFrame.data, frames, 1.0);
398 for (int i=0; i<m_planes; i++)
399 {
400 m_audioFrame.data[i] += frames*m_srcFormat.m_frameSize/m_planes;
401 }
402 }
403 else
404 {
405 memcpy(pBuffer, m_audioFrame.data[0], *actualsize);
406 m_audioFrame.data[0] += *actualsize;
407 }
408 m_nDecodedLen -= *actualsize;
409 }
410
411 return READ_SUCCESS;
412 }
413
ReadRaw(uint8_t ** pBuffer,int * bufferSize)414 int VideoPlayerCodec::ReadRaw(uint8_t **pBuffer, int *bufferSize)
415 {
416 DemuxPacket* pPacket;
417
418 m_nDecodedLen = 0;
419 DVDAudioFrame audioframe;
420
421 m_pAudioCodec->GetData(audioframe);
422 if (audioframe.nb_frames)
423 {
424 return READ_SUCCESS;
425 }
426
427 do
428 {
429 pPacket = m_pDemuxer->Read();
430 } while (pPacket && pPacket->iStreamId != m_nAudioStream);
431
432 if (!pPacket)
433 {
434 return READ_EOF;
435 }
436 pPacket->pts = DVD_NOPTS_VALUE;
437 pPacket->dts = DVD_NOPTS_VALUE;
438 int ret = m_pAudioCodec->AddData(*pPacket);
439 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
440 if (ret < 0)
441 {
442 return READ_ERROR;
443 }
444
445 m_pAudioCodec->GetData(audioframe);
446 if (audioframe.nb_frames)
447 {
448 *bufferSize = audioframe.nb_frames;
449 *pBuffer = audioframe.data[0];
450 }
451 else
452 {
453 *bufferSize = 0;
454 }
455
456 return READ_SUCCESS;
457 }
458
CanInit()459 bool VideoPlayerCodec::CanInit()
460 {
461 return true;
462 }
463
CanSeek()464 bool VideoPlayerCodec::CanSeek()
465 {
466 return m_bCanSeek;
467 }
468
NeedConvert(AEDataFormat fmt)469 bool VideoPlayerCodec::NeedConvert(AEDataFormat fmt)
470 {
471 if (fmt == AE_FMT_RAW)
472 return false;
473
474 switch(fmt)
475 {
476 case AE_FMT_U8:
477 case AE_FMT_S16NE:
478 case AE_FMT_S32NE:
479 case AE_FMT_FLOAT:
480 case AE_FMT_DOUBLE:
481 return false;
482 default:
483 return true;
484 }
485 }
486
GetPassthroughStreamType(AVCodecID codecId,int samplerate,int profile)487 CAEStreamInfo::DataType VideoPlayerCodec::GetPassthroughStreamType(AVCodecID codecId,
488 int samplerate,
489 int profile)
490 {
491 AEAudioFormat format;
492 format.m_dataFormat = AE_FMT_RAW;
493 format.m_sampleRate = samplerate;
494 format.m_streamInfo.m_type = CAEStreamInfo::DataType::STREAM_TYPE_NULL;
495 switch (codecId)
496 {
497 case AV_CODEC_ID_AC3:
498 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_AC3;
499 format.m_streamInfo.m_sampleRate = samplerate;
500 break;
501
502 case AV_CODEC_ID_EAC3:
503 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_EAC3;
504 format.m_streamInfo.m_sampleRate = samplerate;
505 break;
506
507 case AV_CODEC_ID_DTS:
508 if (profile == FF_PROFILE_DTS_HD_HRA)
509 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD;
510 else
511 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD_MA;
512 format.m_streamInfo.m_sampleRate = samplerate;
513 break;
514
515 case AV_CODEC_ID_TRUEHD:
516 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_TRUEHD;
517 format.m_streamInfo.m_sampleRate = samplerate;
518 break;
519
520 default:
521 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_NULL;
522 }
523
524 bool supports = CServiceBroker::GetActiveAE()->SupportsRaw(format);
525
526 if (!supports && codecId == AV_CODEC_ID_DTS)
527 {
528 format.m_streamInfo.m_type = CAEStreamInfo::STREAM_TYPE_DTSHD_CORE;
529 supports = CServiceBroker::GetActiveAE()->SupportsRaw(format);
530 }
531
532 if (supports)
533 return format.m_streamInfo.m_type;
534 else
535 return CAEStreamInfo::DataType::STREAM_TYPE_NULL;
536 }
537