For fragmented streams with extra data at the end of the mdat
qtdemux was not dropping those bytes and would try to use
that extra data as the beginning of a new atom, causing the
stream to fail.
https://bugzilla.gnome.org/show_bug.cgi?id=743407
When dealing with fragmented files, we will get more accurate duration
information via the mfra and moof atoms.
In order for playback to not stop at the initial duration (from the
moov atom), we need to check and update the various duration variables
when we find more information.
Fixes playback of fragmented files in pull mode
When seeking or finding the previous keyframe, do
comparisons against targets and segments using composition time
to correctly decide which sample times match.
Currently during header parsing, we scan through the entire file
and skip every moof+mdat chunk for fragmented mp4s, which makes
start-up incredibly slow. Instead, just stop at the first moof
chunk when have a moov, and start exposing the streams, so we
can go and start handling the moofs for real.
Empty segments in an edit list have a media_start time of -1,
as they don't actually play any media. Allow for that when
aligning to the reference stream in reverse play.
Change the way the output framerate is calculated
to ignore the first sample (which is sometimes truncated
in my testing) and use the new gst_video_guess_framerate()
function to recognise common standard framerates better.
Remove the code that was sorting the first 20 sample
durations and then ignoring the result.
This makes sense in DASH reverse playback, where the upstream dashdemux
will download DASH segments in reverse order, but push their buffers
forward to qtdemux and mark each segment start as DISCONT. This needs
to be forwarded downstream to the parser/decoder, otherwise it won't work.
https://bugzilla.gnome.org/show_bug.cgi?id=734443
When writing out a trak with an edit list, make sure the
overall file duration is also updated to reflect the
lengthening of the stream.
Add some more debug to qtdemux to warn about streams that
are longer than the file and get truncated.
Handle the transformation matrix cases where there are only simple rotations
(90, 180 or 270 degrees) and use a tag for those cases. This is a common scenario
when recording with mobile devices
https://bugzilla.gnome.org/show_bug.cgi?id=679522
They are very confusing for people, and more often than not
also just not very accurate. Seeing 'last reviewed: 2005' in
your docs is not very confidence-inspiring. Let's just remove
those comments.
Make sure empty segments are used and pushed with a gap event
to represent its data (or lack of it)
Each QtSegment is mapped into a GstSegment with the corresponding
media range. For empty QtSegments a gap event is pushed instead
of GstBuffers and it advances to the next QtSegment.
To make this work with seeks, need to keep track of the starting
'base' to make sure it remains consistently increasing when
pushing new segment events.
For example: if a seek makes qtdemux start from 5s, the first
segment will have a base=0. When the next segment is activated,
its base time will be QtSegment.time - qtdemux.segment_base so
that it doesn't include the first 5s that weren't played and
shouldn't be accounted on the running time
This purposedly will remove the fix made for
https://bugzilla.gnome.org/show_bug.cgi?id=700264, at this
point it was decided to respect the gaps, even if they cause
a delay on playback, because that's the way the file was crafted.
https://bugzilla.gnome.org/show_bug.cgi?id=345830
Make it clear what should be handled purely by mss mode:
1) Expose the streams on the first moof as there are no moov atoms
2) Properly cleanup streams on flushes
Add a note about the meaning of upstream_newsegment and mss_mode
for future reference.
Make all other special fragment handling shared for both dash
and mss streams.
In a fragmented scenario, qtdemux is operating in push mode
and it gets a fragmented buffer. While processing its data
downstream gets unlinked (or a input-selector changes its
active pad and returns not-linked). Qtdemux stops processing
this fragment and returns not-linked upstream, leaving the
remaining data in its adapter.
When it gets an EOS it should make sure that all the data it
had received is pushed before pushing EOS.
Some buffers can have multiple moov atoms inside and the strategy
of using the gst_adapter_prev_pts timestamp to get the base timestamp
for the media of the fragment would fail as it would reuse the same
base timestamp for all moofs in the buffer instead of accumulating
the durations for all of them.
Heres a better explanation of the issue:
qtdemux receives a buffer where PTS(buf) = X
buf -> moofA | moofB | moofC
The problem was that PTS(buf) was used as the base timestamp for
all 3 moofs, causing all buffers to be X based. In this case we want
only moofA to be X based as it is what the PTS on buf means, and the
other moofB and moofC just use the accumulated timestamp from the
previous moofs durations.
To solve this, this patch uses gst_adapter_prev_pts distance
result, this allows qtdemux to calculate if it should use the
resulting pts or just accumulate the samples as it can identify
if the moofs belong to the same upstream buffer or not.
https://bugzilla.gnome.org/show_bug.cgi?id=719783
In SmoothStreaming fragmented scenario, the timestamps are calculated
starting from the fragment buffer timestamp. When there is a not-linked
return from downstream, qtdemux will return upstream and will keep the
non-pushed data into its adapter.
On a new fragment buffer pushed to qtdemux, the new buffer timestamp
would overwrite the previous one that should be used on the still
to be pushed buffers. Because of this, this patch will also
update the fragment_start timestamp from the adapter last pts
to make sure the moof and timestamps are in sync and will result
in correct timestamps for all fragments.
In the scenario of "mdat | moov (with fragmented artifacts)" qtdemux
could read the moov again after the mdat because it was considering the
media as a fragmented one.
To avoid this loop this patch makes it store
the last processed moov_offset to avoid parsing it again.
And it also checks if there are any samples to play before
resturning to the mdat, so that it knows there is new data to be played.
https://bugzilla.gnome.org/show_bug.cgi?id=691570
When parsing a trak only free streams on failures if those streams
were created locally. They could have been created from a previous
fragment, in this case we they have valid info from the other fragment.
Including pads.
https://bugzilla.gnome.org/show_bug.cgi?id=691570
As for text subtitles and as suggested in #712643, throw
away the 2 byte terminator packets that some encoders insert.
This will make things better when remuxing and causes generation
of gap events.
Clean up the handling of mp4s streams. Use the generic esds
descriptor function to extract the palette, instead of hard coding
a wrong magic offset.
Add some more size safety checks when parsing ES descriptors, and
replace magic numbers with the descriptive constants that are already
defined.
Enhance dump output for stsd atoms.
Streams from both bug 712643 and historic bug 568278 now both work
correctly.
Fixes: #712643
Assume a file with atoms in the following order: moov, mdat, moof,
mdat, moof ...
The first moov usually doesn't contain any sample entries atoms (or
they are all set to 0 length), because the real samples are signaled
at the moofs. In push mode, qtdemux parses the moov and then finds the mdat,
but then it has 0 entries and assumes it is EOS.
This patch makes it continue parsing in case it is a fragmented file so that
it might find the moofs and play the media.
https://bugzilla.gnome.org/show_bug.cgi?id=710623
In push mode, when qtdemux can't use a seek to skip the mdat buffer it has
to buffer it for later use.
The issue is that after parsing the next moov/moof, there might be some
trailing bytes from the next atom in the file. This data was being discarded
along with the already parsed moov/moof and playback would fail to continue
after the contents of this moov/moof are played.
This is particularly bad on fragmented files that have the mdat before the
corresponding moof. So you'd get:
mdat|moof|mdat|moof ...
When a moof was received, it usually came with some extra bytes that would
belong to the next mdat (because upstream doesn't care about atoms alignment).
So those bytes were being discarded and playback would fail.
This patch makes qtdemux store those extra bytes to reuse them later after the
mdat is emptied.
https://bugzilla.gnome.org/show_bug.cgi?id=710623
Use g_date_time seconds manipulation to allow to cover the quicktime
spec for creation_time. It uses seconds since 1904.
Both paths could be done using the generic approach of seconds since
1904 with GDateTime handling, but the first path using seconds from
1970 should be more commonly found and avoids a few objects creation and
ref/unref, so keep it there for performance.
Additionally, the code for handling seconds since 1970 changed from >
to >= because having 0 seconds since 1970 is also a valid case for that
path to handle.
https://bugzilla.gnome.org/show_bug.cgi?id=707975
Check for GST_SEEK_TYPE_NONE for stop poistion and only update
the stop time if it is requested. Otherwise just maintain whatever
was stored at the segment
https://bugzilla.gnome.org/show_bug.cgi?id=707530
When the segment has a defined stop position, qtdemux should check
when streams reach this position and mark those as EOS. When all
streams are EOS it will return GST_FLOW_EOS to upstream to allow
the pipeline to finish instead of continuously consume buffers
from upstream that are not useful for the segment.
https://bugzilla.gnome.org/show_bug.cgi?id=707530
When handling seeks in push mode, qtdemux converts the seek to bytes
and pushes upstream. It needs to keep track of the seek and the
subsequent segment to be able to map them back to the requested
seek time and properly preserve the segment stop of the seek.
This is done by using the start offset in bytes of the seek,
that should be the same of the segment from upstream. And this
is also backwards compatible with what qtdemux already was using.
https://bugzilla.gnome.org/show_bug.cgi?id=707530
Amendment 2 of ISO/IEC 14496-15 (AVC file format) is defining a new
structure for fragmented MP4 called "avc3". The principal difference
between AVC1 and AVC3 is the location of the codec initialisation
data (e.g. SPS, PPS). In AVC1 this data is placed in the initial
MOOV box (moov.trak.mdia.minf.stbl.stsd.avc1) but in AVC3 this data
goes in the first sample of every fragment (i.e. the first sample in
each mdat box). The principal reason for avc3 is to make it easier
for client implementations, because it removes the requirement to
insert the SPS+PPS in to the decoder pipeline every time there is a
representation change.
This commit adds support for the "avc3" atom, which is almost identical
to the "avc1" atom, except it does not contain any SPS or PPS data.
https://bugzilla.gnome.org/show_bug.cgi?id=702004
This should make decoders able to precisely push buffers until the stop
time in case they need the next keyframe to do it.
Also, according to gst_segment_clip, it should only push a buffer that
the starting ts is strictly smaller than the segment stop, so we change
the min < comparison for <=
Use the same seqnum on messages and events for derived events.
Fixed for flushes / stream-start / segment after a seek, and segment
after a segment.
Fixes#676242