From b3b0c49ed80176eaa779da4f420a170e8dce36be Mon Sep 17 00:00:00 2001 From: peak3d Date: Sun, 22 Sep 2019 22:14:20 +0200 Subject: [PATCH] [DemuxClient] Parse for mid stream changes (optional) --- .../DVDCodecs/Video/DVDVideoCodec.h | 5 ++ .../Video/DVDVideoCodecAndroidMediaCodec.cpp | 14 ++-- .../Video/DVDVideoCodecAndroidMediaCodec.h | 1 + xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemux.h | 66 +++++++-------- .../DVDDemuxers/DVDDemuxClient.cpp | 83 ++++++++++++------- .../VideoPlayer/DVDDemuxers/DVDDemuxClient.h | 1 + .../DVDInputStreams/InputStreamPVRBase.cpp | 3 + xbmc/cores/VideoPlayer/DVDStreamInfo.cpp | 6 +- xbmc/cores/VideoPlayer/DVDStreamInfo.h | 1 + xbmc/cores/VideoPlayer/IVideoPlayer.h | 1 + xbmc/cores/VideoPlayer/VideoPlayer.cpp | 31 ++++--- xbmc/cores/VideoPlayer/VideoPlayerVideo.h | 1 + 12 files changed, 127 insertions(+), 86 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h index 690f6800a1d60..ddbf81949f0e5 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodec.h @@ -235,6 +235,11 @@ 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; } protected: CProcessInfo &m_processInfo; }; diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index f6f0a574bc4c4..f5a2842493e96 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -1445,13 +1445,17 @@ 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); } diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h index 944fa805dc43e..41d28ef362381 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.h @@ -141,6 +141,7 @@ 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; } 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..31c71ad298034 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.cpp @@ -35,11 +35,14 @@ class CDemuxStreamClientInternal avcodec_free_context(&m_context); m_context = nullptr; } + m_parser_split = false; + m_parser_keep_running = false; } AVCodecParserContext *m_parser = nullptr; AVCodecContext *m_context = nullptr; bool m_parser_split = false; + bool m_parser_keep_running = false; }; template @@ -119,13 +122,12 @@ 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) @@ -154,29 +156,34 @@ bool CDVDDemuxClient::ParsePacket(DemuxPacket* pkt) int len = stream->m_parser->parser->split(stream->m_context, pkt->pData, pkt->iSize); if (len > 0 && 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)) + if (len != st->ExtraSize || memcmp(pkt->pData, st->ExtraData, st->ExtraSize) != 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); + 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)) + { + 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; } } @@ -230,8 +237,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 +274,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 +286,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; } @@ -463,6 +474,7 @@ void CDVDDemuxClient::SetStreamProps(CDemuxStream *stream, std::mapfAspect = source->fAspect; streamVideo->iFpsScale = source->iFpsScale; streamVideo->iFpsRate = source->iFpsRate; + streamVideo->fieldOrder = source->fieldOrder; } streamVideo->iBitRate = source->iBitRate; if (source->ExtraSize > 0 && source->ExtraData) @@ -585,6 +597,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, @@ -718,6 +731,18 @@ void CDVDDemuxClient::SetVideoResolution(int width, int height) } } +void CDVDDemuxClient::EnableParsePacket(int64_t demuxerId, bool enable) +{ + std::shared_ptr stream = GetStreamInternal(demuxerId); + if (stream && stream->checkStreamChange) + { + std::shared_ptr> streamCI = + std::dynamic_pointer_cast>(stream); + if (streamCI) + streamCI->m_parser_keep_running = 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..f0a62977da891 100644 --- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h +++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxClient.h @@ -43,6 +43,7 @@ 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(); 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..583779df859c0 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,7 +94,7 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata) } // VIDEO - if( fpsscale != right.fpsscale + if (fpsscale != right.fpsscale || fpsrate != right.fpsrate || height != right.height || width != right.width @@ -103,6 +104,7 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata) || ptsinvalid != right.ptsinvalid || forced_aspect != right.forced_aspect || bitsperpixel != right.bitsperpixel + || fieldOrder != right.fieldOrder || vfr != right.vfr || colorSpace != right.colorSpace || colorRange != right.colorRange @@ -219,6 +221,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 +291,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..e4a7c221b07c0 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayer.cpp +++ b/xbmc/cores/VideoPlayer/VideoPlayer.cpp @@ -3572,19 +3572,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 +3585,24 @@ 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(); + 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.h b/xbmc/cores/VideoPlayer/VideoPlayerVideo.h index 1087682c94b90..7c8c76550b164 100644 --- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.h +++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.h @@ -66,6 +66,7 @@ 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 { 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 */