Two things were suboptimal from a performance point of view:
a) consider a large media object such as a video keyframe, which
may be split up into multiple fragments. We would assemble
the media object as follows:
buf = join (join (join (frag1, frag2), frag3), frag4)
which causes many unnecessary memcpy()s, and malloc/free,
which could easily add up to a multiple of the actual object
size. To avoid this, we allocate a buffer of the size needed
from the start and copy fragments into that directly.
b) for every fragment to join, we would create a sub-buffer
before joining it (which would discard the sub-buffer again),
leading to unnecessary miniobject create/free churn.
Conflicts:
gst/asfdemux/asfpacket.c
gst/asfdemux/asfpacket.h
We have already retrieved the stream for that stream number and
made sure it's not NULL, so no need to do it again here; neither
the number nor the streams changed since the last time.
Quite a few (broken?) files have a packet duration of 1ms, which is
most definitely wrong for either audio or video packets.
We therefore avoid using that value and instead use other metrics to
determine the buffer duration (like using the extended stream properties
average frame duration if present and valid).
Some files have payload with timestamps smaller than the preroll duration.
Instead of blindly substracting the preroll value (and ending up with
insanely high timestamps on the outgoing buffers), we make sure we
never go below 0.
Fixes#610432
When receiving bogus data, we have to avoid subtracting a value
larger than 'size' from 'size' variable, resulting in a wrap
that would make 'size' a really large bogus value.
Fixes#599333
This also makes timestamps (more) consistent before and after a possible
seek, and moreover makes for reasonable position reporting in live stream
(whose payload timestamps should not be taken for granted).
The problem that happens is the following:
* A packet with multiple payloads comes in
* Those payloads get handled one by one
* The first payload contains the first audio payload with timestamp A
* The second payload contains the first video (key)frame with timestamp V (where V < A)
With the previous code, the following would happen:
* the first payload gets processed, then passed to queue_for_stream
* queue_for_stream detects it's the first valid timestamp received and stores
first_ts = A
* the second payload gets processed, then pass to queue_for_stream
* queue_for_stream detects the timestamp is lower than first_ts... and
discards it... resulting in losing the first keyframe of the video stream
We've been having this issue for *ages*... it's just that nobody noticed it
that much with playbin. But with playbin2's aggresive multiqueue handling, this
will result in multiqueue not being able to preroll (because the video decoder will
be dropping a ton of buffers before (maybe) receiving the next keyframe).
Tested with over 200 asf files, and they all play the first frame correctly now,
even the most braindead ones.
Drop packets with an invalid replicated data length
instead of continuing with an invalid timestamp
and uninitialized payload metadata.
All other code assumes that the timestamps are valid.
Original commit message from CVS:
* gst/asfdemux/asfpacket.c: (gst_asf_payload_queue_for_stream):
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_reset),
(gst_asf_demux_init), (gst_asf_demux_push_complete_payloads),
(gst_asf_demux_process_file):
* gst/asfdemux/gstasfdemux.h:
Make all timestamps start from zero in pull-mode too; some small
clean-ups and FIXMEs here and there.
Original commit message from CVS:
* gst/asfdemux/asfpacket.c: (gst_asf_demux_parse_payload),
(gst_asf_demux_parse_packet):
If packet size is specified within the packet and smaller than
the actual packet size, don't parse beyond the size specified in
the packet (this makes us parse some cases of packets with single
compressed payloads cleanly, see e.g stream from #431318). Also
add a sanity check when parsing compressed single payloads.
Original commit message from CVS:
* gst/asfdemux/asfpacket.c: (gst_asf_payload_queue_for_stream):
* gst/asfdemux/gstasfdemux.c: (gst_asf_demux_seek_index_lookup),
(gst_asf_demux_handle_seek_event),
(gst_asf_demux_push_complete_payloads):
Seeking improvements: honour the KEY_UNIT seek flag; after a seek, only
send data from the keyframe right before the new segment start to
make sure the decoder doesn't have to decode more than absolutely
necessary.
Original commit message from CVS:
* gst/asfdemux/Makefile.am:
* gst/asfdemux/asfpacket.c: (asf_packet_read_varlen_int),
(asf_packet_create_payload_buffer),
(asf_payload_find_previous_fragment),
(gst_asf_payload_queue_for_stream), (gst_asf_demux_parse_payload),
(gst_asf_demux_parse_packet):
* gst/asfdemux/asfpacket.h:
* gst/asfdemux/gstasfdemux.c:
(gst_asf_demux_reset_stream_state_after_discont),
(gst_asf_demux_push_complete_payloads), (gst_asf_demux_loop),
(gst_asf_demux_setup_pad), (gst_asf_demux_descramble_buffer),
(gst_asf_demux_process_chunk):
* gst/asfdemux/gstasfdemux.h:
New packet parsing code: should put halfway decent timestamps on
buffers, and might even set the appropriate keyframe/discont buffer
flags from time to time (and even if it doesn't, I'm at least able
to debug this code); only used in pull-mode so far. Still needs
some more work, like payload extensions parsing and proper flow
aggregation, and stream activation based on preroll. Stay tuned.