Skip to content

[wpe-2.38] MP4 edit lists support breaks smooth playback #1542

@volodymyr-ogorodnik-red

Description

One more scenario found where MP4 edit-list support (#1185) breaks smooth playback ( real customer impacted).
Scenario is originated from Ads insertion into streaming playback, but in general such circumstances could appear on any segmented streams that uses adaptive bitrate playback and mixes content without buffers flush.

Let assume stream A (main video) has edit list with start=0:00:00.083416750.
And stream B (short Ad) has edit list with start=0:00:00.041711111

Now we play Stream A for 15 mins, next Stream B for 30 secs and continue Stream A starting from 15th minute

Also player uses timestampOffset to align pieces in timeline.
for stream B: m_timestampOffset={"value":1066.856901}
in for second part stream A: m_timestampOffset={"value":195.9440000990993}

So last frame from Stream B goes with these numbers:
original values from qtdemux in AppSinkFlushCapsWorkaroundProbe::probe(): buffer: 0x233f540, pts 0:00:29.988355555, dts 0:00:29.946644444, dur 0:00:00.041711111, size 999, offset none, offset_end none, flags 0x6000

original sample on entry in SourceBufferPrivate::didReceiveSample() (adjusted by segment start=0:00:00.041711111):
{"size":999,"pts":{"value":29.946644444,"numerator":29946644444,"denominator":1000000000,"flags":1},"dts":{"value":29.904933333,"numerator":29904933333,"denominator":1000000000,"flags":1},

and updated sample adjusted by m_timestampOffset={"value":1066.856901} :
{"size":999,"pts":{"value":1096.803545444,"numerator":1096803545444,"denominator":1000000000,"flags":1},"dts":{"value":1096.761834333,"numerator":1096761834333,"denominator":1000000000,"flags":1},

The first sample from stream A at 15min looks like:
original values from qtdemux in AppSinkFlushCapsWorkaroundProbe::probe(): buffer: 0x1fe7540, pts 0:15:00.984317650, dts 0:15:00.900900900, dur 0:00:00.041708375, size 1282, offset none, offset_end none, flags 0x4040)

original sample on entry in SourceBufferPrivate::didReceiveSample() (adjusted by segment start=0:00:00.083416750):
{"size":1282,"pts":{"value":900.9009009,"numerator":900900900900,"denominator":1000000000,"flags":1},"dts":{"value":900.81748415,"numerator":900817484150,"denominator":1000000000,"flags":1},

and updated sample adjusted by m_timestampOffset={"value":195.9440000990993}
{"size":1282,"pts":{"value":1096.844900999,"numerator":1096844900999,"denominator":1000000000,"flags":1},"dts":{"value":1096.761484249,"numerator":1096761484249,"denominator":1000000000,"flags":1}

Next two bad things happen in didReceiveSample():

  • removing last frame from stream B (in fact it is already passed downstream and will be decoded/displayed):
    SourceBufferPrivateGStreamer::didReceiveSample(5D620002) Discovered out-of-order frames, from: {"size":999,"pts":{"value":1096.803545444,"numerator":1096803545444,"denominator":1000000000,"flags":1},"dts":{"value":1096.761834333,"numerator":1096761834333,"denominator":1000000000,"flags":1},
    Jul 15 13:42:54.969223 E0B7B1-APPSTB-301000193203 WPEWebProcess[28120]: 250715-12:42:54.969114 [mod=Media, lvl=DEBUG] [tid=18] TrackBuffer::didReceiveSample(5D621B75) removing sample {"size":999,"pts":{"value":1096.803545444,"numerator":1096803545444,"denominator":1000000000,"flags":1},"dts":{"value":1096.761834333,"numerator":1096761834333,"denominator":1000000000,"flags":1},

  • not inserting first frame from stream A (really, really bad if this is an I-Frame), extra debug shows this:
    SourceBufferPrivateGStreamer::didReceiveSample(5D620002) skip unordered sample, lastEnqueuedDecodeKey: dts:{"value":1096.761834333,"numerator":1096761834333,"denominator":1000000000,"flags":1} pts:{"value":1096.803545444,"numerator":1096803545444,"denominator":1000000000,"flags":1}

When I have removed edit list support, all PTSes/DTSes are aligned and no frame is lost:
Stream B has last inserted frame: pts: 1096,845256555, dts: 1096,80354544
Stream A has first inserted frame: pts: 1096,928317749 dts: 1096,844900999

It is also not a perfect state, since last frame from stream B will have extended presentation duration, but this is rather pure player issue.

Some ideas went trough my mind while analyzing this situation (all have drawbacks, unfortunately):

  • adjust timestampOffset with offsets from edit-list
  • adjust/keep in sync lastEnqueuedDecodeKey when we have removed samples from buffer
  • keep/remove all frames staring from "random-access points" to avoid macroblocks/artefacts when decoding

I can provide more logs/details related to my case if needed.
Any proposal to try besides reverting edit-list support is much appreciated.

Thank you.
Vova.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions