diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp index 229282d1bcbc5..344006332a1ca 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.cpp @@ -64,7 +64,7 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, CProces } // platform specifig video decoders - if (!(hint.codecOptions & CODEC_FORCE_SOFTWARE)) + if (!m_hwVideoCodecs.empty() && !(hint.codecOptions & CODEC_FORCE_SOFTWARE)) { for (auto &codec : m_hwVideoCodecs) { diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h index 690f6800a1d60..e25fe18db2e67 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h @@ -235,6 +235,19 @@ class CDVDVideoCodec */ virtual void Reopen() {}; + /** + * Return true, if codec parses stream to detect mid stream changes + * If false, demuxer tries to parse the stream and notifies VideoPlayer on changes. + */ + virtual bool HasCodecParser() const { return true; } + + /** + * Get the framerate calculated by decoder. + * The return value could be different to what provided in hints for interlaced media + * Return 0.0f for default handling + */ + virtual float GetFramerate() const { return 0.0f; } + protected: CProcessInfo &m_processInfo; }; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index f6f0a574bc4c4..a92d19623e25d 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -1042,6 +1042,16 @@ unsigned CDVDVideoCodecAndroidMediaCodec::GetAllowedReferences() return 4; } +float CDVDVideoCodecAndroidMediaCodec::GetFramerate() const +{ + int fpsRate = m_hints.fpsrate; + if (m_hints.fieldOrder > AV_FIELD_PROGRESSIVE) + fpsRate *= 2; + + return (fpsRate > 0 && m_hints.fpsscale > 0) ? static_cast(fpsRate) / m_hints.fpsscale + : 0.0f; +} + void CDVDVideoCodecAndroidMediaCodec::FlushInternal() { SignalEndOfStream(); @@ -1445,14 +1455,21 @@ void CDVDVideoCodecAndroidMediaCodec::ReleaseSurfaceTexture(void) void CDVDVideoCodecAndroidMediaCodec::UpdateFpsDuration() { - if (m_hints.fpsrate > 0 && m_hints.fpsscale > 0) - m_fpsDuration = static_cast(static_cast(DVD_TIME_BASE) * m_hints.fpsscale / m_hints.fpsrate); + int fpsRate = m_hints.fpsrate; + if (m_hints.fieldOrder > AV_FIELD_PROGRESSIVE) + fpsRate *= 2; + + if (fpsRate > 0 && m_hints.fpsscale > 0) + { + m_fpsDuration = + static_cast(static_cast(DVD_TIME_BASE) * m_hints.fpsscale / fpsRate); + m_processInfo.SetVideoFps(static_cast(fpsRate) / m_hints.fpsscale); + } else m_fpsDuration = 1; - - m_processInfo.SetVideoFps(static_cast(m_hints.fpsrate) / m_hints.fpsscale); - - CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::UpdateFpsDuration fpsRate:%u fpsscale:%u, fpsDur:%u", m_hints.fpsrate, m_hints.fpsscale, m_fpsDuration); + CLog::Log(LOGDEBUG, + "CDVDVideoCodecAndroidMediaCodec::UpdateFpsDuration fpsRate:%u fpsscale:%u, fpsDur:%u", + fpsRate, m_hints.fpsscale, m_fpsDuration); } void CDVDVideoCodecAndroidMediaCodec::surfaceChanged(CJNISurfaceHolder holder, int format, int width, int height) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h index 944fa805dc43e..1aa23b9a6f58d 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h @@ -141,6 +141,8 @@ class CDVDVideoCodecAndroidMediaCodec : public CDVDVideoCodec, public CJNISurfac virtual const char* GetName() override { return m_formatname.c_str(); }; virtual void SetCodecControl(int flags) override; virtual unsigned GetAllowedReferences() override; + bool HasCodecParser() const override { return false; } + float GetFramerate() const override; protected: void Dispose(); diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h index df8c0727a5bbb..af0bfd780a6dc 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h @@ -69,53 +69,37 @@ enum StreamSource class CDemuxStream { public: - CDemuxStream() - { - uniqueId = 0; - dvdNavId = 0; - demuxerId = -1; - codec = (AVCodecID)0; // AV_CODEC_ID_NONE - codec_fourcc = 0; - profile = FF_PROFILE_UNKNOWN; - level = FF_LEVEL_UNKNOWN; - type = STREAM_NONE; - source = STREAM_SOURCE_NONE; - iDuration = 0; - pPrivate = NULL; - ExtraData = NULL; - ExtraSize = 0; - disabled = false; - changes = 0; - flags = StreamFlags::FLAG_NONE; - } - + CDemuxStream() = default; virtual ~CDemuxStream() { delete[] ExtraData; } virtual std::string GetStreamName(); - int uniqueId; // unique stream id - int dvdNavId; - int64_t demuxerId; // id of the associated demuxer - AVCodecID codec; - unsigned int codec_fourcc; // if available - int profile; // encoder profile of the stream reported by the decoder. used to qualify hw decoders. - int level; // encoder level of the stream reported by the decoder. used to qualify hw decoders. - StreamType type; - int source; - - int iDuration; // in mseconds - void* pPrivate; // private pointer for the demuxer - uint8_t* ExtraData; // extra data for codec to use - unsigned int ExtraSize; // size of extra data - - StreamFlags flags; + int uniqueId = 0; // unique stream id + int dvdNavId = 0; + int64_t demuxerId = -1; // id of the associated demuxer + AVCodecID codec = AV_CODEC_ID_NONE; + unsigned int codec_fourcc = 0; // if available + int profile = + FF_PROFILE_UNKNOWN; // encoder profile of the stream reported by the decoder. used to qualify hw decoders. + int level = + FF_LEVEL_UNKNOWN; // encoder level of the stream reported by the decoder. used to qualify hw decoders. + StreamType type = STREAM_NONE; + int source = STREAM_SOURCE_NONE; + + int iDuration = 0; // in mseconds + void* pPrivate = nullptr; // private pointer for the demuxer + uint8_t* ExtraData = nullptr; // extra data for codec to use + unsigned int ExtraSize = 0; // size of extra data + + StreamFlags flags = StreamFlags::FLAG_NONE; std::string language; // RFC 5646 language code (empty string if undefined) - bool disabled; // set when stream is disabled. (when no decoder exists) + bool disabled = false; // set when stream is disabled. (when no decoder exists) std::string name; std::string codecName; - int changes; // increment on change which player may need to know about + bool checkStreamChange = false; + int changes = 0; // increment on change which player may need to know about std::shared_ptr cryptoSession; std::shared_ptr externalInterfaces; @@ -138,6 +122,7 @@ class CDemuxStreamVideo : public CDemuxStream int iOrientation = 0; // orientation of the video in degrees counter clockwise int iBitsPerPixel = 0; int iBitRate = 0; + AVFieldOrder fieldOrder = AV_FIELD_UNKNOWN; AVColorSpace colorSpace = AVCOL_SPC_UNSPECIFIED; AVColorRange colorRange = AVCOL_RANGE_UNSPECIFIED; @@ -349,6 +334,11 @@ class CDVDDemux */ virtual void SetVideoResolution(int width, int height){}; + /* + * Enable ParsePacket to detect mid stream changes + */ + virtual void EnableParsePacket(int64_t demuxerId, bool enable){}; + /* * return the id of the demuxer */ diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp index 3b4b2b7b65247..15701660430b4 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp @@ -15,6 +15,13 @@ #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - AV_INPUT_BUFFER_PADDING_SIZE) +static int GetStartcodeLength(uint8_t* buf) +{ + if (buf && !buf[0] && !buf[1]) + return buf[2] == 1 ? 3 : (buf[2] == 0 && buf[3] == 1 ? 4 : 0); + return 0; +} + class CDemuxStreamClientInternal { public: @@ -35,11 +42,16 @@ class CDemuxStreamClientInternal avcodec_free_context(&m_context); m_context = nullptr; } + m_parser_split = false; + m_parser_keep_running = false; + m_codec = nullptr; } AVCodecParserContext *m_parser = nullptr; AVCodecContext *m_context = nullptr; + AVCodec* m_codec = nullptr; bool m_parser_split = false; + bool m_parser_keep_running = false; }; template @@ -119,26 +131,25 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) bool change = false; CDemuxStream* st = GetStream(pkt->iStreamId); - if (st == nullptr || st->changes < 0 || st->ExtraSize || !CodecHasExtraData(st->codec)) + if (!st || !CodecHasExtraData(st->codec)) return change; CDemuxStreamClientInternal* stream = dynamic_cast(st); - if (stream == nullptr || - stream->m_parser == nullptr) + if (!stream || !stream->m_parser || !stream->m_parser_split) return change; if (stream->m_context == nullptr) { - AVCodec *codec = avcodec_find_decoder(st->codec); - if (codec == nullptr) + stream->m_codec = avcodec_find_decoder(st->codec); + if (stream->m_codec == nullptr) { CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__); stream->DisposeParser(); return change; } - stream->m_context = avcodec_alloc_context3(codec); + stream->m_context = avcodec_alloc_context3(stream->m_codec); if (stream->m_context == nullptr) { CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__); @@ -152,42 +163,60 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) if (stream->m_parser_split && stream->m_parser->parser->split) { int len = stream->m_parser->parser->split(stream->m_context, pkt->pData, pkt->iSize); - if (len > 0 && len < FF_MAX_EXTRADATA_SIZE) + if (len > 3 && len < FF_MAX_EXTRADATA_SIZE) { - if (st->ExtraData) - delete[] st->ExtraData; - st->changes++; - st->disabled = false; - st->ExtraSize = len; - st->ExtraData = new uint8_t[len+AV_INPUT_BUFFER_PADDING_SIZE]; - memcpy(st->ExtraData, pkt->pData, len); - memset(st->ExtraData + len, 0 , AV_INPUT_BUFFER_PADDING_SIZE); - stream->m_parser_split = false; - change = true; - CLog::Log(LOGDEBUG, "CDVDDemuxClient::ParsePacket - split extradata"); - - // Allow ffmpeg to transport codec information to stream->m_context - if (!avcodec_open2(stream->m_context, stream->m_context->codec, nullptr)) + int startcur = GetStartcodeLength(pkt->pData); + int startold = GetStartcodeLength(st->ExtraData); + + if (len - startcur != st->ExtraSize - startold || + memcmp(pkt->pData + startcur, st->ExtraData + startold, st->ExtraSize - startold) != 0) { - AVPacket avpkt; - av_init_packet(&avpkt); - avpkt.data = pkt->pData; - avpkt.size = pkt->iSize; - avpkt.dts = avpkt.pts = AV_NOPTS_VALUE; - avcodec_send_packet(stream->m_context, &avpkt); - avcodec_close(stream->m_context); + CLog::Log(LOGDEBUG, + "CDVDDemuxClient::ParsePacket (%d) - split extradata. Old: %d -> New: %d", + pkt->iStreamId, st->ExtraSize, len); + if (st->ExtraData) + delete[] st->ExtraData; + st->changes++; + st->disabled = false; + st->ExtraSize = len; + st->ExtraData = new uint8_t[len + AV_INPUT_BUFFER_PADDING_SIZE]; + memcpy(st->ExtraData, pkt->pData, len); + memset(st->ExtraData + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + stream->m_parser_split = false; + change = true; + + // Allow ffmpeg to transport codec information to stream->m_context + if (!avcodec_open2(stream->m_context, stream->m_codec, nullptr)) + { + AVPacket avpkt; + av_init_packet(&avpkt); + avpkt.data = pkt->pData; + avpkt.size = pkt->iSize; + avpkt.dts = avpkt.pts = AV_NOPTS_VALUE; + avcodec_send_packet(stream->m_context, &avpkt); + avcodec_close(stream->m_context); + } } + if (!stream->m_parser_keep_running) + stream->m_parser_split = false; } } - uint8_t *outbuf = nullptr; + uint8_t* outbuf = nullptr; int outbuf_size = 0; + uint8_t* extradataOld = stream->m_context->extradata; + int extradata_sizeOld = stream->m_context->extradata_size; + + stream->m_context->extradata = st->ExtraData; + stream->m_context->extradata_size = st->ExtraSize; int len = av_parser_parse2(stream->m_parser, stream->m_context, &outbuf, &outbuf_size, pkt->pData, pkt->iSize, (int64_t)(pkt->pts * DVD_TIME_BASE), (int64_t)(pkt->dts * DVD_TIME_BASE), 0); + stream->m_context->extradata = extradataOld; + stream->m_context->extradata_size = extradata_sizeOld; // our parse is setup to parse complete frames, so we don't care about outbufs if (len >= 0) @@ -230,8 +259,8 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) sta->changes++; sta->disabled = false; } - if (stream->m_context->channels) - st->changes = -1; // stop parsing + if (stream->m_context->channels && !stream->m_parser_keep_running) + stream->m_parser_split = false; break; } case STREAM_VIDEO: @@ -267,7 +296,7 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) stv->disabled = false; } } - if (stream->m_context->framerate.num && + if (stream->m_context->framerate.num && !stv->iFpsRate && (stv->iFpsRate != stream->m_context->framerate.num || stv->iFpsScale != stream->m_context->framerate.den)) { @@ -279,10 +308,14 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) stv->changes++; stv->disabled = false; } - + if (stream->m_context->field_order != stv->fieldOrder) + { + stv->fieldOrder = stream->m_context->field_order; + stv->changes++; + stv->disabled = false; + } break; } - default: break; } @@ -321,7 +354,6 @@ DemuxPacket* CDVDDemuxClient::Read() { if (ParsePacket(m_packet.get())) { - RequestStreams(); DemuxPacket *pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0); pPacket->iStreamId = DMX_SPECIALID_STREAMCHANGE; pPacket->demuxerId = m_demuxerId; @@ -383,11 +415,12 @@ void CDVDDemuxClient::RequestStreams() { std::map> newStreamMap; for (auto stream : m_IDemux->GetStreams()) - SetStreamProps(stream, newStreamMap, false); + SetStreamProps(stream, newStreamMap); m_streams = newStreamMap; } -void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::map> &map, bool forceInit) +void CDVDDemuxClient::SetStreamProps(CDemuxStream* stream, + std::map>& map) { if (!stream) { @@ -412,19 +445,11 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::map> streamAudio; if (currentStream) streamAudio = std::dynamic_pointer_cast>(currentStream); - if (forceInit || !streamAudio || streamAudio->codec != source->codec) - { - streamAudio.reset(new CDemuxStreamClientInternalTpl()); - streamAudio->m_parser = av_parser_init(source->codec); - if (streamAudio->m_parser) - streamAudio->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - streamAudio->iSampleRate = source->iSampleRate; - streamAudio->iChannels = source->iChannels; - } + streamAudio.reset(new CDemuxStreamClientInternalTpl()); + streamAudio->m_parser = av_parser_init(source->codec); + if (streamAudio->m_parser) + streamAudio->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - streamAudio->iBlockAlign = source->iBlockAlign; - streamAudio->iBitRate = source->iBitRate; - streamAudio->iBitsPerSample = source->iBitsPerSample; if (source->ExtraSize > 0 && source->ExtraData) { delete[] streamAudio->ExtraData; @@ -433,7 +458,12 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapExtraSize; j++) streamAudio->ExtraData[j] = source->ExtraData[j]; } - streamAudio->m_parser_split = true; + streamAudio->iSampleRate = source->iSampleRate; + streamAudio->iChannels = source->iChannels; + streamAudio->iBlockAlign = source->iBlockAlign; + streamAudio->iBitRate = source->iBitRate; + streamAudio->iBitsPerSample = source->iBitsPerSample; + streamAudio->m_parser_split = streamAudio->ExtraSize == 0; streamAudio->changes++; map[stream->uniqueId] = streamAudio; toStream = streamAudio; @@ -452,19 +482,10 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::map> streamVideo; if (currentStream) streamVideo = std::dynamic_pointer_cast>(currentStream); - if (forceInit || !streamVideo || streamVideo->codec != source->codec) - { - streamVideo.reset(new CDemuxStreamClientInternalTpl()); - streamVideo->m_parser = av_parser_init(source->codec); - if (streamVideo->m_parser) - streamVideo->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - streamVideo->iHeight = source->iHeight; - streamVideo->iWidth = source->iWidth; - streamVideo->fAspect = source->fAspect; - streamVideo->iFpsScale = source->iFpsScale; - streamVideo->iFpsRate = source->iFpsRate; - } - streamVideo->iBitRate = source->iBitRate; + streamVideo.reset(new CDemuxStreamClientInternalTpl()); + streamVideo->m_parser = av_parser_init(source->codec); + if (streamVideo->m_parser) + streamVideo->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; if (source->ExtraSize > 0 && source->ExtraData) { delete[] streamVideo->ExtraData; @@ -473,6 +494,14 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapExtraSize; j++) streamVideo->ExtraData[j] = source->ExtraData[j]; } + streamVideo->iHeight = source->iHeight; + streamVideo->iWidth = source->iWidth; + streamVideo->fAspect = source->fAspect; + streamVideo->iFpsScale = source->iFpsScale; + streamVideo->iFpsRate = source->iFpsRate; + streamVideo->fieldOrder = source->fieldOrder; + + streamVideo->iBitRate = source->iBitRate; streamVideo->colorPrimaries = source->colorPrimaries; streamVideo->colorRange = source->colorRange; streamVideo->colorSpace = source->colorSpace; @@ -480,7 +509,7 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapmasteringMetaData = source->masteringMetaData; streamVideo->contentLightMetaData = source->contentLightMetaData; - streamVideo->m_parser_split = true; + streamVideo->m_parser_split = streamVideo->ExtraSize == 0; streamVideo->changes++; map[stream->uniqueId] = streamVideo; toStream = streamVideo; @@ -505,16 +534,17 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapm_parser = av_parser_init(source->codec); if (streamSubtitle->m_parser) streamSubtitle->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; - } - if (source->ExtraSize == 4) - { - delete[] streamSubtitle->ExtraData; - streamSubtitle->ExtraData = new uint8_t[4]; - streamSubtitle->ExtraSize = 4; - for (int j=0; j<4; j++) - streamSubtitle->ExtraData[j] = source->ExtraData[j]; + if (source->ExtraSize == 4) + { + delete[] streamSubtitle->ExtraData; + streamSubtitle->ExtraData = new uint8_t[4]; + streamSubtitle->ExtraSize = 4; + for (int j = 0; j < 4; j++) + streamSubtitle->ExtraData[j] = source->ExtraData[j]; + } } + map[stream->uniqueId] = streamSubtitle; toStream = streamSubtitle; } @@ -585,6 +615,7 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapcryptoSession = stream->cryptoSession; toStream->externalInterfaces = stream->externalInterfaces; toStream->language = stream->language; + toStream->checkStreamChange = stream->checkStreamChange; CLog::Log(LOGDEBUG,"CDVDDemuxClient::RequestStream(): added/updated stream %d with codec_id %d", toStream->uniqueId, @@ -706,7 +737,7 @@ void CDVDDemuxClient::OpenStream(int id) m_videoStreamPlaying = id; if (bOpenStream) - SetStreamProps(stream, m_streams, true); + SetStreamProps(stream, m_streams); } } @@ -718,6 +749,21 @@ void CDVDDemuxClient::SetVideoResolution(int width, int height) } } +void CDVDDemuxClient::EnableParsePacket(int64_t demuxerId, bool enable) +{ + std::shared_ptr stream = GetStreamInternal(static_cast(demuxerId)); + if (stream && stream->checkStreamChange) + { + std::shared_ptr> streamCI = + std::dynamic_pointer_cast>(stream); + if (streamCI) + { + streamCI->m_parser_keep_running = enable; + CLog::Log(LOGDEBUG, "CDVDDemuxClient::EnableParsePacket: %d", enable); + } + } +} + bool CDVDDemuxClient::CodecHasExtraData(AVCodecID id) { switch (id) diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h index 5f680a3553ba7..484c0f56fc1c0 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h @@ -43,10 +43,11 @@ class CDVDDemuxClient : public CDVDDemux void EnableStream(int id, bool enable) override; void OpenStream(int id) override; void SetVideoResolution(int width, int height) override; + void EnableParsePacket(int64_t demuxerId, bool enable) override; protected: void RequestStreams(); - void SetStreamProps(CDemuxStream *stream, std::map> &map, bool forceInit); + void SetStreamProps(CDemuxStream* stream, std::map>& map); bool ParsePacket(DemuxPacket* pPacket); void DisposeStreams(); std::shared_ptr GetStreamInternal(int iStreamId); diff --git a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp index d706bc30d7980..329cd7b88b96b 100644 --- a/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp +++ b/xbmc/cores/VideoPlayer/DVDInputStreams/InputStreamPVRBase.cpp @@ -344,6 +344,9 @@ void CInputStreamPVRBase::UpdateStreamMap() dStream = std::make_shared(); dStream->codec = (AVCodecID)stream.iCodecId; + if (dStream->codec == AV_CODEC_ID_MPEG2VIDEO) + dStream->checkStreamChange = true; + dStream->uniqueId = stream.iPID; dStream->language = stream.strLanguage; diff --git a/xbmc/cores/VideoPlayer/DVDStreamInfo.cpp b/xbmc/cores/VideoPlayer/DVDStreamInfo.cpp index e0b5b5315a9eb..0aa732f9edfed 100644 --- a/xbmc/cores/VideoPlayer/DVDStreamInfo.cpp +++ b/xbmc/cores/VideoPlayer/DVDStreamInfo.cpp @@ -55,6 +55,7 @@ void CDVDStreamInfo::Clear() ptsinvalid = false; forced_aspect = false; bitsperpixel = 0; + fieldOrder = AV_FIELD_UNKNOWN; colorSpace = AVCOL_SPC_UNSPECIFIED; colorRange = AVCOL_RANGE_UNSPECIFIED; colorPrimaries = AVCOL_PRI_UNSPECIFIED; @@ -93,22 +94,15 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata) } // VIDEO - if( fpsscale != right.fpsscale - || fpsrate != right.fpsrate - || height != right.height - || width != right.width - || stills != right.stills - || level != right.level - || profile != right.profile - || ptsinvalid != right.ptsinvalid - || forced_aspect != right.forced_aspect - || bitsperpixel != right.bitsperpixel - || vfr != right.vfr - || colorSpace != right.colorSpace - || colorRange != right.colorRange - || colorPrimaries != right.colorPrimaries - || colorTransferCharacteristic != right.colorTransferCharacteristic - || stereo_mode != right.stereo_mode ) return false; + if (fpsscale != right.fpsscale || fpsrate != right.fpsrate || height != right.height || + width != right.width || stills != right.stills || level != right.level || + profile != right.profile || ptsinvalid != right.ptsinvalid || + forced_aspect != right.forced_aspect || bitsperpixel != right.bitsperpixel || + fieldOrder != right.fieldOrder || vfr != right.vfr || colorSpace != right.colorSpace || + colorRange != right.colorRange || colorPrimaries != right.colorPrimaries || + colorTransferCharacteristic != right.colorTransferCharacteristic || + stereo_mode != right.stereo_mode) + return false; if (masteringMetadata && right.masteringMetadata) { @@ -219,6 +213,7 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata) forced_aspect = right.forced_aspect; orientation = right.orientation; bitsperpixel = right.bitsperpixel; + fieldOrder = right.fieldOrder; vfr = right.vfr; codecOptions = right.codecOptions; colorSpace = right.colorSpace; @@ -288,6 +283,7 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata) forced_aspect = stream->bForcedAspect; orientation = stream->iOrientation; bitsperpixel = stream->iBitsPerPixel; + fieldOrder = stream->fieldOrder; colorSpace = stream->colorSpace; colorRange = stream->colorRange; colorPrimaries = stream->colorPrimaries; diff --git a/xbmc/cores/VideoPlayer/DVDStreamInfo.h b/xbmc/cores/VideoPlayer/DVDStreamInfo.h index ad32bcd88b419..4b04eb512e2e6 100644 --- a/xbmc/cores/VideoPlayer/DVDStreamInfo.h +++ b/xbmc/cores/VideoPlayer/DVDStreamInfo.h @@ -59,6 +59,7 @@ class CDVDStreamInfo bool forced_aspect; // aspect is forced from container int orientation; // orientation of the video in degrees counter clockwise int bitsperpixel; + AVFieldOrder fieldOrder; AVColorSpace colorSpace; AVColorRange colorRange; AVColorPrimaries colorPrimaries; diff --git a/xbmc/cores/VideoPlayer/IVideoPlayer.h b/xbmc/cores/VideoPlayer/IVideoPlayer.h index d8130fce5222a..9d4787af78a2d 100644 --- a/xbmc/cores/VideoPlayer/IVideoPlayer.h +++ b/xbmc/cores/VideoPlayer/IVideoPlayer.h @@ -44,6 +44,7 @@ class IDVDStreamPlayer virtual bool IsInited() const = 0; virtual bool AcceptsData() const = 0; virtual bool IsStalled() const = 0; + virtual bool HasCodecParser() const { return true; } enum ESyncState { diff --git a/xbmc/cores/VideoPlayer/VideoPlayer.cpp b/xbmc/cores/VideoPlayer/VideoPlayer.cpp index 5cdf85afaf31e..36e24e022c93c 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -1985,6 +1985,7 @@ void CVideoPlayer::HandlePlaySpeed() if (!m_State.streamsReady) { + CLog::Log(LOGDEBUG, "VideoPlayer::Sync - streams are ready"); if (m_playerOptions.fullscreen) { CApplicationMessenger::GetInstance().PostMsg(TMSG_SWITCHTOFULLSCREEN); @@ -3572,19 +3573,6 @@ bool CVideoPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) if (hint.flags & AV_DISPOSITION_ATTACHED_PIC) return false; - // set desired refresh rate - if (m_playerOptions.fullscreen && CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot() && - hint.fpsrate != 0 && hint.fpsscale != 0) - { - if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF) - { - double framerate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * hint.fpsscale / hint.fpsrate); - RESOLUTION res = CResolutionUtils::ChooseBestResolution(static_cast(framerate), hint.width, hint.height, !hint.stereo_mode.empty()); - CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(res, false); - m_renderManager.TriggerUpdateResolution(framerate, hint.width, hint.height, hint.stereo_mode); - } - } - IDVDStreamPlayer* player = GetStreamPlayer(m_CurrentVideo.player); if(player == nullptr) return false; @@ -3598,6 +3586,31 @@ bool CVideoPlayer::OpenVideoStream(CDVDStreamInfo& hint, bool reset) if (!player->OpenStream(hint)) return false; + if (m_pDemuxer) + m_pDemuxer->EnableParsePacket(hint.uniqueId, !player->HasCodecParser()); + + // set desired refresh rate + if (m_playerOptions.fullscreen && + CServiceBroker::GetWinSystem()->GetGfxContext().IsFullScreenRoot() && + m_CurrentVideo.id < 0 && hint.fpsrate != 0 && hint.fpsscale != 0) + { + if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt( + CSettings::SETTING_VIDEOPLAYER_ADJUSTREFRESHRATE) != ADJUST_REFRESHRATE_OFF) + { + float framerate = m_processInfo->GetVideoFps(); + CLog::Log(LOGDEBUG, "%s - ProcessInfo reports fps: %0.4f.", __FUNCTION__, framerate); + if (framerate < 1.0E-6) + framerate = static_cast( + DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * + hint.fpsscale / hint.fpsrate)); + RESOLUTION res = CResolutionUtils::ChooseBestResolution(framerate, hint.width, hint.height, + !hint.stereo_mode.empty()); + CServiceBroker::GetWinSystem()->GetGfxContext().SetVideoResolution(res, false); + m_renderManager.TriggerUpdateResolution(framerate, hint.width, hint.height, + hint.stereo_mode); + } + } + player->SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_PAUSE, m_displayLost), 1); // look for any EDL files diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp index a4e95e6e7dbc5..83d19f073b7dd 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp @@ -161,7 +161,10 @@ void CVideoPlayerVideo::OpenStream(CDVDStreamInfo &hint, CDVDVideoCodec* codec) //reported fps is usually not completely correct if (hint.fpsrate && hint.fpsscale) { - m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * hint.fpsscale / hint.fpsrate); + m_fFrameRate = codec ? codec->GetFramerate() : 0.0f; + if (m_fFrameRate < 1.0E-6) + m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration( + (double)DVD_TIME_BASE * hint.fpsscale / hint.fpsrate); m_bFpsInvalid = false; m_processInfo.SetVideoFps(static_cast(m_fFrameRate)); } diff --git a/xbmc/cores/VideoPlayer/VideoPlayerVideo.h b/xbmc/cores/VideoPlayer/VideoPlayerVideo.h index 1087682c94b90..db67837464b5d 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.h +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.h @@ -66,6 +66,10 @@ class CVideoPlayerVideo : public CThread, public IDVDStreamPlayerVideo double GetSubtitleDelay() override { return m_iSubtitleDelay; } void SetSubtitleDelay(double delay) override { m_iSubtitleDelay = delay; } bool IsStalled() const override { return m_stalled; } + bool HasCodecParser() const override + { + return m_pVideoCodec ? m_pVideoCodec->HasCodecParser() : false; + } bool IsRewindStalled() const override { return m_rewindStalled; } double GetCurrentPts() override; double GetOutputDelay() override; /* returns the expected delay, from that a packet is put in queue */