Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions fragmentcollector_mpd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4535,9 +4535,50 @@ AAMPStatusType StreamAbstractionAAMP_MPD::Init(TuneType tuneType)
AAMPLOG_MIL("StreamAbstractionAAMP_MPD: fetch initialization fragments");
// We have decided on the first period, calculate the PTSoffset to be applied to
// all segments including the init segments for the GST buffer that goes with the init
// For seeks: set mNextPts to seekPosition so segments get PTS matching pipeline flush position
// UpdatePtsOffset will calculate: mPTSOffset = mNextPts - timelineStart
// This maps raw media PTS to the seek position for immediate playback
mPTSOffset = 0.0;
mNextPts = 0.0;
mNextPts = seekPosition;
UpdatePtsOffset(true);
// Adjust offset to account for raw media PTS
// mFirstPTS was set by SkipFragments and represents the raw PTS of the first segment
if (ISCONFIGSET(eAAMPConfig_EnablePTSReStamp) && mFirstPTS > 0)
{
double adjustedOffset;
// Pre-tune seek: pipeline in READY, no flush seek possible, segments must start at PTS 0
// Post-tune seek: pipeline in PAUSED/PLAYING, flush seek to seekPosition, segments match flush position
if (aamp->IsTuneTypeNew && seekPosition > 0)
{
adjustedOffset = 0 - mFirstPTS; // Shift media to start at 0
mNextPts = 0.0; // Reset mNextPts to 0 for pre-tune seeks
AAMPLOG_INFO("Pre-tune seek: Adjusting mPTSOffset from %f to %f, mNextPts to %f (seekPosition=%f, mFirstPTS=%f)",
mPTSOffset.inSeconds(), adjustedOffset, mNextPts.inSeconds(), seekPosition, mFirstPTS);
}
else if (!aamp->IsTuneTypeNew && seekPosition > 0)
{
adjustedOffset = seekPosition - mFirstPTS; // Match pipeline flush position
// Set mNextPts to the period end time on the manifest timeline
// This ensures UpdatePtsOffset calculates correctly for the next period transition
AampTime timelineStart, duration;
GetStartAndDurationForPtsRestamping(timelineStart, duration);
mNextPts = mPeriodStartTime + duration.inSeconds();
AAMPLOG_INFO("Post-tune seek: Adjusting mPTSOffset from %f to %f, mNextPts to %f (seekPosition=%f, mFirstPTS=%f, periodEnd=%f)",
mPTSOffset.inSeconds(), adjustedOffset, mNextPts.inSeconds(), seekPosition, mFirstPTS, mNextPts.inSeconds());
}
else
{
adjustedOffset = mPTSOffset.inSeconds(); // No adjustment for play from 0
AAMPLOG_INFO("Play from 0: mPTSOffset=%f mNextPts=%f seekPosition=%f mFirstPTS=%f",
mPTSOffset.inSeconds(), mNextPts.inSeconds(), seekPosition, mFirstPTS);
}
mPTSOffset = adjustedOffset;
}
else
{
AAMPLOG_INFO("After UpdatePtsOffset: mPTSOffset=%f mNextPts=%f seekPosition=%f mFirstPTS=%f",
mPTSOffset.inSeconds(), mNextPts.inSeconds(), seekPosition, mFirstPTS);
}
FetchAndInjectInitFragments();
}

Expand Down Expand Up @@ -9678,10 +9719,19 @@ void StreamAbstractionAAMP_MPD::UpdatePtsOffset(bool isNewPeriod)
mNextPts += timelineStart - newStart;
AAMPLOG_INFO("newStart %f timelineStart %f", newStart.inSeconds(), timelineStart.inSeconds());
}
mPTSOffset += mNextPts - timelineStart;
// For PTS restamping, the offset should map raw media PTS (starting at timelineStart, usually 0)
// to the period's start time on the manifest timeline
if (ISCONFIGSET(eAAMPConfig_EnablePTSReStamp))
{
mPTSOffset = mPeriodStartTime + timelineStart.inSeconds();
}
else
{
mPTSOffset += mNextPts - timelineStart;
}

AAMPLOG_INFO("Idx %d Id %s mPTSOffsetSec %f mNextPts %f timelineStartSec %f",
mCurrentPeriodIdx, period->GetId().c_str(), mPTSOffset.inSeconds(), mNextPts.inSeconds(), timelineStart.inSeconds());
AAMPLOG_INFO("Idx %d Id %s mPTSOffsetSec %f mNextPts %f timelineStartSec %f mPeriodStartTime %f",
mCurrentPeriodIdx, period->GetId().c_str(), mPTSOffset.inSeconds(), mNextPts.inSeconds(), timelineStart.inSeconds(), mPeriodStartTime);
}

mNextPts = duration + timelineStart;
Expand Down
10 changes: 9 additions & 1 deletion middleware/InterfacePlayerRDK.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2448,7 +2448,10 @@ void InterfacePlayerPriv::SendGstEvents(int mediaType, GstClockTime pts, int ena

if(stream->pendingSeek)
{
if(gstPrivateContext->seekPosition > 0)
// Skip appsrc seek when using mp4demux with PTS restamp - segments already have correct PTS
// Post-tune seeks use pipeline-level seek in Flush() which works correctly
if(gstPrivateContext->seekPosition > 0 &&
!(gstPrivateContext->isMp4DemuxPlayback && enablePTSReStamp))
Comment on lines +2453 to +2454
{
Comment on lines +2451 to 2455
MW_LOG_MIL("gst_element_seek_simple! mediaType:%d pts:%" GST_TIME_FORMAT " seekPosition:%" GST_TIME_FORMAT,
mediaType, GST_TIME_ARGS(pts), GST_TIME_ARGS(gstPrivateContext->seekPosition * GST_SECOND));
Expand All @@ -2458,6 +2461,11 @@ void InterfacePlayerPriv::SendGstEvents(int mediaType, GstClockTime pts, int ena
}

}
else if(gstPrivateContext->isMp4DemuxPlayback && enablePTSReStamp && gstPrivateContext->seekPosition > 0)
{
MW_LOG_INFO("Skipping appsrc seek for mp4demux+PTS restamp - segments have correct PTS. mediaType:%d seekPosition:%" GST_TIME_FORMAT,
mediaType, GST_TIME_ARGS(gstPrivateContext->seekPosition * GST_SECOND));
}
stream->pendingSeek = false;
}
// For mp4 demux playback, there is no qtdemux element in the pipeline, so no need to send override event
Expand Down
25 changes: 19 additions & 6 deletions priv_aamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5624,12 +5624,11 @@ void PrivateInstanceAAMP::TeardownStream(bool newTune, bool disableDownloads)
const bool forceStop = false;
if (!forceStop && !newTune)
{
if ((eMEDIAFORMAT_PROGRESSIVE == mMediaFormat) && (true == mSeekOperationInProgress))
if (((eMEDIAFORMAT_PROGRESSIVE == mMediaFormat) || ISCONFIGSET_PRIV(eAAMPConfig_EnablePTSReStamp)) && (true == mSeekOperationInProgress))
{
AAMPLOG_TRACE("Skip mid-seek flushing of progressive pipeline to position 0");
// If format is progressive and we're doing a teardown to facilitate a seek operation, avoid a flushing seek to position 0.
// With progressive content, playbin will immediately start playback from position 0 and that may not be the desired position.
// TuneHelper() will perform a flushing seek to the correct position afterwards.
AAMPLOG_TRACE("Skip mid-seek flushing of pipeline to position 0 (progressive or PTS restamp)");
// If format is progressive or PTS restamping is enabled, and we're doing a teardown to facilitate a seek operation,
// avoid a flushing seek to position 0. TuneHelper() will perform a flushing seek to the correct position afterwards.
}
else
{
Expand Down Expand Up @@ -5949,6 +5948,17 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
AAMPLOG_INFO ("Resetting mClearPipeline & mEncryptedPeriodFound");
}

// For post-tune seeks with PTS restamping enabled, treat as new tune to avoid flushing seek issues
// This mimics the pre-tune seek flow which works correctly for multi-period content
bool treatSeekAsNewTune = false;
if (!newTune && tuneType == eTUNETYPE_SEEK && ISCONFIGSET_PRIV(eAAMPConfig_EnablePTSReStamp))
{
treatSeekAsNewTune = true;
newTune = true;
mTuneType = eTUNETYPE_NEW_SEEK; // Update mTuneType so IsNewTune() returns true
AAMPLOG_INFO("Post-tune seek with PTS restamping: treating as new tune (mTuneType=%d)", mTuneType);
}

TeardownStream(newTune|| (eTUNETYPE_RETUNE == tuneType));

if(SocUtils::ResetNewSegmentEvent())
Expand Down Expand Up @@ -6386,7 +6396,10 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(this);
if (sink)
{
double flushPosition = (mMediaFormat == eMEDIAFORMAT_PROGRESSIVE) ? updatedSeekPosition : mpStreamAbstractionAAMP->GetFirstPTS();
// Use timeline position for progressive or when PTS restamping is enabled
// GetFirstPTS() returns restamped PTS which can be negative for multi-period seeks
double flushPosition = (mMediaFormat == eMEDIAFORMAT_PROGRESSIVE || ISCONFIGSET_PRIV(eAAMPConfig_EnablePTSReStamp))
? updatedSeekPosition : mpStreamAbstractionAAMP->GetFirstPTS();
// shouldTearDown is set to false, because in case of a new tune pipeline
// might not be in a playing/paused state which causes Flush() to destroy
// pipeline. This has to be avoided.
Expand Down
Loading