- There's definitely potential for more code sharing in these
classes, but deferring for now.
- Also made no-scheme default to file://, and allowed smoothstreaming
URLs to be specified with or without the /Manifest suffix.
Before preparation, and when seeking, Mp3Extractor did not handle retrying:
- synchronizedHeader was set before the header was known to be valid, which
means that after seeing one valid frame header and then failing to read, the
synchronization would be treated as complete.
- The input buffer would keep data loaded during synchronization but on the next
call to synchronize when retrying it was not returned to the mark position to
re-parse the data.
This change fixes these issues.
- Make HlsPlaylistParser treat non-positive dimensions as unknown.
- Make HlsPlaylistParser parse floating point resolutions, because
technically that's how they're spec'd.
- Make VideoFormatSelectorUtil treat non-position dimensions as unknown.
Issue: #461
When I moved the id3Reader instantiation out of the while
loop (below where it is now) it was no longer guarded by
the streamTypes.get(streamType) deduping check. This brings
back an equivalent check.
When a XING header is present but not usable (due to missing fields), CBR
seeking can be used instead. It relies on the bitrate. The bitrate from the
unusable XING header is not correct, which leads to incorrect seeking.
Also fix VBRI seeking by setting the correct offset on the frame to parse. Few
people seem to use that format, but I have found two very short truncated
samples which were falling back to the CBR case before but are using VBRI with
this change.
When a passthrough AudioTrack is replaced (due to seeking) the new one behaves
as if it is still emptying data from the old one, with its playback position
advancing until it runs out of data.
Data written while the 'old' AudioTrack was emptying would be discarded, so
avoid writing to the new AudioTrack while the old one is still emptying.
Also avoid using AudioTrack.getTimestamp with passthrough tracks, as this causes
the playback position to jump to a position that breaks audio/video
synchronization.
This also fixes a technical mistake where HlsChunkSource is fed
seekPositionUs=-1 when obtaining the first chunk. This is wrong,
but the usage of this variable within HlsChunkSource enforces that
the seek must stay within bounds, so we get away with it.
Issue: #385
1. prepare() needs to load a TsChunk to actually prepare the source.
2. Source is prepared, but no tracks are enabled (this is why it's
an edge case - no-one is likely to be doing this!).
3. The TsChunk load completes.
We should not load additional chunks in this case.
For Live SmoothStreaming, referential equality checking
isn't enough (it breaks once the manifest is updated).
Updated other instances too just for consistency.
Play movies has an Allocator that attempts to allocate a single
huge byte[] up front to minimize the risk of GC pauses. This abstraction
will be required to keep that when updating them to the new Exo.
VP8 can be decoded by MediaCodec (since very early versions of android). Now that we want WebmExtractor to be general purpose, adding VP8 makes sense as it is a common use case.
This CL adds support for WebM files which have Cues present at the end of the file (i.e.) after Clusters. The file referenced in the bug can now be played back using the demo app. It adds a new flag to WebmExtractor which should be set to true only when being used through ExtractorSampleSource. All others (e.g. DASH) should not set it.
Reference file: http://demos.webmproject.org/exoplayer/glass_vp9_vorbis_cues_at_end.webm
I've found myself doing this a couple of times during local
debugging. It's harmless to have it public, and seems pretty
useful for debugging inside of the mp4 package.
Using a file:// URL for loading an HLS stream (for testing) would fail due to
casting the connection to an HttpURLConnection in DefaultHttpDataSource.
This change makes UriDataSource an interface for objects that are DataSources
with URIs. That allows for reading manifests for HLS using just a UriDataSource
rather than an HttpDataSource (URLs in the playlist are relative to the data
source's URL so the getUri method is needed).
On retrying loading a chunk, the state of the extractor was reset due to a call
to seek(). Prevent this call by only calling init() if no bytes were loaded.
Also make the DefaultExtractorInput use the loading position not the original
stream position so that its getPosition() method returns offsets relative to
the start of the stream, which fixes a bug where the chunk index offsets would
be relative to the wrong position if there was a retry while loading the chunk.
Vorbis decoder in android MediaCodec [1] expects the last 4 bytes of the sample to be the number of samples in the current page. This definition holds good only for Ogg and is irrelevant for WebM. So we always set this to -1 (the decoder will ignore this value if we set it to -1). The android platform media extractor [2] does the same.
This works around an issue the audio track continues to play audio data written
after calling AudioTrack.pause(), which breaks rebuffering behavior (as video
can never catch up if audio continues to be consumed, in some circumstances).
Also don't increment the timestamp wrap count if the track is paused, to work
around an issue where the playback head position jumps back to zero after the
AudioTrack position jumps back to zero.
The OMX component needs to be configured with a format that has a
MIME type of audio/raw. Remove Ac3PassthroughAudioTrackRenderer,
which is no longer used.
The limit on the ts packet buffer can be reduced during processing
if it's discovered to have padding. Hence we need to reset it back
to the ts packet size before processing each packet.
- Keys should not expire during normal playbacks of correctly configured content.
- Attempting to refresh on expiration causes a race condition, that may result
in either failure or brief re-buffer, for the 30s license test video.
- This change provides deterministic behavior, which is to always fail.
Some servers, probably edge cache machines that exclusively serve
chunked media, don't support partial requests. Which is kind of
vaguely reasonable for that particular case. This change modifies
DefaultHttpDataSource to correctly handle this case, by manually
skipping data up to the requested position (and making sure not to
read more data than the requested length).
- Have extractors read from an ExtractorInput. Benefits of this are
(a) The ability to do a "full" read or skip of a specified number
of bytes, (b) The ability to do multiple reads in your extractor's
read method. The ExtractorInput will throw an InterruptedException
if the read has been canceled.
- Provides the extractor with the ability to query the absolute
position of the data being read in the stream. This is needed for
things like parsing a segment index in fragmented mp4, where the
position of the end of the box in the stream is required because
the index offsets are all specified relative to that position.
- Move to builder naming.
- Propagate formats to the TrackOutput instances, rather than having
them be read through the Extractor. There was actually some weird
indexing going on here before (which happened to work, but wasn't
well defined).
As per http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#section-5.2,
the initializaton vector (IV) of the AES decryption algorithm should be set to:
- the IV attribute value if present,
- the sequence number otherwise.
Currently, the IV is set once and use over all next media sequences
where the IV attribute is not set. The fix is to use the provided IV if
given or use the current media sequence number.
- It's probably easiest to think of this as a standalone HLS change, which is splitting out the "loading" and "consuming" sides of HlsExtractor and a good structural change in its own right. To do this, HlsExtractorWrapper becomes a final class implementing the consuming side. HlsExtractor becomes an interface defining the loading side.
- The bigger picture is that, hopefully, HlsExtractor will become a lightweight extractor interface that can be used throughout the library. Because it doesn't need to implement the consuming side, we'll save on having to re-implement the consuming side for every extractor (we'll probably need one consuming side implementation for HLS/DASH/SmoothStreaming, and a second one for everything else, both of which will use SampleQueue). It's expected that the HlsExtractor interface will need to change to accommodate all use cases.
- The next step in unification will be to try and have FragmentedMp4Extractor implement HlsExtractor (which will need renaming). Once this is done, I'll try and move the chunk package over to use the HlsExtractor interface.
- This is a step toward hopefully converging HLS and CHUNK packages.
- Add support for encrypted samples.
- Add support for appending from a DataSource.
- The fmp4 extractor was reading from sampleEncryptionData even
for not-encrypted samples, which I'm pretty sure isn't right.
Fixed this. For all encrypted content I've seen, this change
will be a no-op because isEncrypted is always true if there's
an encryptionBox present.
- Made webm extractor only set cryptoInfo if isEncrypted is true.
- Align variable naming in the two extractors, for clarity.
- Rather than returning a map, return a DrmInitData object,
with mapped and non-mapped implementations.
- Include a suitable mimeType to pass to the MediaDrm. Previously
we were incorrectly passing the mimeType of the samples,
where-as MediaDrm expects the container mimeType. Note that
it doesn't matter whether the mimeType starts with "video" or
"audio", hence using video mimeTypes everywhere.
It was possible for a codec input buffer to be filled with two frames' worth of
data, if seekTo was called after populating a buffer, if waitingForKeys was true
and seeking did not trigger a flush. This caused the CryptoInfo to be configured
as if the input buffer contained a large amount of reconfiguration data as
cleartext.
Move resetting waitingForKeys to flushCodec, so that we don't try to read the
next sample from the source until the first one has been consumed or discarded.
Also remove uriIsFullStream. It's not doing anything particularly
useful, so I think it makes sense to remove it from the public API;
it's unlikely anyone is using it.
Issue: #329
For fields encoded using UTF-16 or UTF-16BE charsets when looking for
termination character we have to look for two zero consecutive bytes.
Otherwise, as many characters encoded with UTF-16 or UTF-16BE has one
of their 2 bytes set with the value zero, we will be truncating text
fields.
- Added support for ID3 frames of types GEOB and PRIV.
- GEOB type is commonly used by dynamic ads provider to include in the
stream information about the ads to be played.
- PRIV type is commonly used for time synchronization (example:
synchronizing playback of a live stream and its webvtt captions) and
also by analytics companies to include tracking information in the
stream.
- Added a sample stream from Apple that contains ID3 metadata.
Note: I'm fairly confident that NetworkLoadable.Parser implementations
can live without the inputEncoding being specified. But not completely
100%...
Issue: #311
Issue: #56
The return value here assumed that the time being searched for
was beyond the start time of the last segment. This fix also
handles the case where the time is prior to the start of the
first segment.
Clear stale blacklist in getChunkOperation before getting next variant.
This ensures:
1.- Player resilience to failures, always trying to look for a working
playlist that allows player to non stop playback.
2.- High quality blacklisted playlists can be reused in case they go up
after a failure. Player always trying to provide the best user
experience.
Added an expiration time field to playlists blacklisted to allow
Exoplayer to continue playback when playlists that failed were
recovered from a bad state.
In live environments, some times occur that primary encoder stop
working for a while. In that cases, HLS failover mechanism in the
player should detect the situation and “switch” to playlists served by
the backup encoder (in case a backup encoder exists). This was well
managed before these changes.
However, and to ensure a playback experience that can recover itself
from temporary issues, we cannot blacklist a playlist forever. When
streaming live events using HLS, it is quite typical that the player
needs to switch from primary to backup playlists, and from backup to
primary ones, from time to time to have playback working when temporary
issues in the network/encoder are happening. Most of the issues are
recoverable, so what I have implemented is a mechanism that makes
blacklisted playlist to be available again after a while (60 seconds).
Evaluation of this algorithm should happen just when something fails.
If player is working with a backup playlist, it shouldn’t switch to the
primary one at least something fail.
Support is provided for the following schemes:
urn:mpeg:dash:utc:direct:2012
urn:mpeg:dash:utc:http-iso:2014
urn:mpeg:dash:utc:http-xsdate:2012
urn:mpeg:dash:utc:http-xsdate:2014
- Data needs to be unescaped before it's passed to SeiReader.
- SeiReader should loop over potentially multiple child messages.
- I also changed the sample passed to the EIA-608 renderer so that
it's the entire sei message payload. The first 8 bytes are
unnecessary, but it seems nicer conceptually to do it this way.
Issue: #295
Previous regular expression for extracting codec information was wrong,
given a line that defines a variant it added information from “CODEC=“
text to the end of the line (including also information about
RESOLUTION or alternate rendition groups as part of the CODEC field).
This is not causing a functional problem (at least known by me)
although is making codecs field storing information that is not related
with the codec.
Some extractor implementations underneath MediaExtractor require a seekTo
call after tracks are selected to ensure samples are read from the correct
position. De-duplicating logic was preventing this from happening in some
cases, causing issues like:
https://github.com/google/ExoPlayer/issues/301
Note that seeking all tracks a side effect of track selection sucks if
you already have one or more tracks selected, because it introduces
discontinuities to the already selected tracks. However, in general, it
*is* necessary to specify the position for the track being selected,
because the underlying extractor doesn't have enough information to know
where to start reading from. It can't determine this based on the read
positions of the already selected tracks, because the samples in these
tracks might be very sparse with respect to time.
I think a more optimal fix would be to change the SampleExtractor
interface to receive the current position as an argument to selectTrack.
For our own extractors, we'd seek the newly selected track to that
position, whilst the already enabled tracks would be left in their
current positions (if possible). For FrameworkSampleExtractor we'd
still have no choice but to call seekTo on the extractor to seek all
of the tracks. This solution ends up being more complex though, because:
- The SampleExtractor then needs a way of telling DefaultSampleSource
which tracks were actually seeked, so that the pendingDiscontinuities
flags can be set correctly.
- It's a weird API that requires the "current playback position to seek
only the track being enabled"
So it may not be worth it! I think this fix is definitely good for now,
in any case.
Issue: #301
- This change:
1. Extracts HlsExtractor interface from TsExtractor.
2. Adds AdtsExtractor for AAC/ADTS streams, which turned out to be
really easy.
Selection of the ADTS extractor relies on seeing the .aac extension.
This is at least guaranteed not to break anything that works already
(since no-one is going to be using .aac as the extension for something
that's not elementary AAC/ADTS).
Issue: #209
I think this is the limit of how far we should be pushing complexity
v.s. efficiency. It's a little complicated to understand, but probably
worth it since the H264 bitstream is the majority of the data.
Issue: #278
Use of Sample objects was inefficient for several reasons:
- Lots of objects (1 per sample, obviously).
- When switching up bitrates, there was a tendency for all Sample
instances to need to expand, which effectively led to our whole
media buffer being GC'd as each Sample discarded its byte[] to
obtain a larger one.
- When a keyframe was encountered, the Sample would typically need
to expand to accommodate it. Over time, this would lead to a
gradual increase in the population of Samples that were sized to
accommodate keyframes. These Sample instances were then typically
underutilized whenever recycled to hold a non-keyframe, leading
to inefficient memory usage.
This CL introduces RollingBuffer, which tightly packs pending sample
data into a byte[]s obtained from an underlying BufferPool. Which
fixes all of the above. There is still an issue where the total
memory allocation may grow when switching up bitrate, but we can
easily fix that from this point, if we choose to restrict the buffer
based on allocation size rather than time.
Issue: #278
- Remove TsExtractor's knowledge of Sample.
- Push handling of Sample objects into SampleQueue as much
as possible. This is a precursor to replacing Sample objects
with a different type of backing memory. Ideally, the
individual readers shouldn't know how the sample data is
stored. This is true after this CL, with the except of the
TODO in H264Reader.
- Avoid double-scanning every H264 sample for NAL units, by
moving the scan for SEI units from SeiReader into H264Reader.
Issue: #278
The complexity around not enabling the video renderer before it
has a valid surface is because MediaCodecTrackRenderer supports
a "discard" mode where it pulls through and discards samples
without a decoder. This mode means that if the demo app were to
enable the renderer before supplying the surface, the renderer
could discard the first few frames prior to getting the surface,
meaning video rendering wouldn't happen until the following sync
frame.
To get a handle on complexity, I think we're better off just removing
support for this mode, which nicely decouples how the demo app
handles surfaces v.s. how it handles enabling/disabling renderers.
Reordering in the extractor isn't going to work well with the
optimizations I'm making there. This change moves sorting back
to the renderer, although keeps all of the renderer
simplifications. It's basically just moving where the sort
happens from one place to another.
I'm not really a fan of micro-optimizations, but given this method
scans through every H264 frame in the HLS case, it seems worthwhile.
The trick here is to examine the first 7 bits of the third byte
first. If they're not all 0s, then we know that we haven't found a
NAL unit, and also that we wont find one at the next two positions.
This allows the loop to increment 3 bytes at a time.
Speedup is around 60% on Art according to some ad-hoc benchmarking.
1. AdtsReader would previously copy all data through an intermediate
adtsBuffer. This change eliminates the additional copy step, and
instead copies directly into Sample objects.
2. PesReader would previously accumulate a whole packet by copying
multiple TS packets into an intermediate buffer. This change
eliminates this copy step. After the change, TS packet buffers
are propagated directly to PesPayloadReaders, which are required
to handle partial payload data correctly. The copy steps in the
extractor are simplified from:
DataSource->Ts_BitArray->Pes_BitArray->Sample->SampleHolder
To:
DataSource->Ts_BitArray->Sample->SampleHolder
Issue: #278
- TsExtractor is now based on ParsableByteArray rather than BitArray.
This makes is much clearer that, for the most part, data is byte
aligned. It will allow us to optimize TsExtractor without worrying
about arbitrary bit offsets.
- BitArray is renamed ParsableBitArray for consistency, and is now
exclusively for bit-stream level reading.
- There are some temporary methods in ParsableByteArray that should be
cleared up once the optimizations are in place.
Issue: #278
This is the start of a sequence of changes to fix the ref'd
github issue. Currently TsExtractor involves multiple memory
copy steps:
DataSource->Ts_BitArray->Pes_BitArray->Sample->SampleHolder
This is inefficient, but more importantly, the copy into
Sample is problematic, because Samples are of dynamically
varying size. The way we end up expanding Sample objects to
be large enough to hold the data being written means that we
end up gradually expanding all Sample objects in the pool
(which wastes memory), and that we generate a lot of GC churn,
particularly when switching to a higher quality which can
trigger all Sample objects to expand.
The fix will be to reduce the copy steps to:
DataSource->TsPacket->SampleHolder
We will track Pes and Sample data with lists of pointers into
TsPackets, rather than actually copying the data. We will
recycle these pointers.
The following steps are approximately how the refactor will
progress:
1. Start reducing use of BitArray. It's going to be way too
complicated to track bit-granularity offsets into multiple packets,
and allow reading across packet boundaries. In practice reads
from Ts packets are all byte aligned except for small sections,
so we'll move over to using ParsableByteArray instead, so we
only need to track byte offsets.
2. Move TsExtractor to use ParsableByteArray except for small
sections where we really need bit-granularity offsets.
3. Do the actual optimization.
Issue: #278
If the timesource track renderer ends, but other track renderers
haven't finished, the player would get stuck in a pending state.
This change enables automatic switching to the media clock in the
case that the timesource renderer has ended, which allows other
renderers to continue to play.
These may occur in VOD streams where a representation's data
is small enough not to require segmentation or an index. For
example subtitle files.
Issue: #268
SampleExtractor will initially only be implemented by FrameworkSampleExtractor
which delegates to a MediaExtractor, but eventually it will also be implemented
by additional extractors.
The sample extractor can be used as a source of samples via DefaultSampleSource.
Also added clamping to getSegmentNum in one case where
it was not already implemented, and defined this behavior
property in the getSegmentNum javadoc.
Issue: #262
Without this, the byte is cast as follows (in bits) if the top
byte is set:
10000010 -> 1000000000000000000000000000010
This works because we then always shift at least one bit left,
and only look at the bottom 8 bits of the result. It's confusing
though. It's clearer if the cast to int gives just adds zeros to
the front, like:
10000010 -> 0000000000000000000000010000010
- Workaround issue where video may freeze whilst audio continues
on some devices that have entered bad states.
- Fix wrap-around for playbacks lasting more than 27 hours.
- Target 4x the minimum specified by the framework.
- Impose a minimum duration (250ms).
- Impose a maximum duration (750ms, or the minimum
specified by the framework if that's larger).
I've removed the ability to specify the multiplication
factor, since the underlying implementation is getting more
complicated, and we should really be able to figure this out
internally.
* this fixes a bug when switching from HE-AAC 22050Hz to AAC 44100Hz (the AudioTrack was not reset and we were trying to send a bad number of bytes, triggering a "AudioTrack.write() called with invalid size" error)
* this also improves quality switches, making it almost seamless
Previously samples belonging to disabled tracks would just
accumulate in an arbitrarily long queue in TsExtractor. We
need to actively throw samples away from disabled tracks up
to the current playback position, so as to prevent this.
Issue: #174
I'm not sure exactly what the implications of this change are,
but I'd really hope that only one program in each stream is carrying
audio/video. For GoPro cameras, they expose the video stream in
the second program, for some reason.
Issue: #116
We've seen a few streams where this assertion fails. If you
just skip the packet, things appear to recover correctly in
all cases I've seen, so replacing failure with a warning.
- Handle read returning NOTHING_READ for AC-3 streams.
- Remove extra checks for the audio track being initialized.
- Call isInitialized() instead of checking audioTrack != null.
ac3Bitrate is set only after the first buffer is handled, which meant that
getting the playback position would cause a divide by zero before then.
When playing back AC-3 content, the ac3Bitrate will always be set after the
first buffer is handled, so return a 0 position if it is not set.
- Adds support for dash manifests that define SegmentTemplate
but no SegmentTimeline.
- Assumes that the device clock is correct when calculating which
segments to load. The final step here is to use the Utc timing
element in the DASH manifest to obtain an accurate client clock.
- Doesn't yet enforce that the client shouldn't load segments that
are in the future or behind the live window.
This fixes the referenced issue, except that the MPD parser
needs to actually parse out UUID and binary data for schemes
that we wish to support. Alternatively, it's easy to applications
to do this themselves by extending the parser and overriding
the parseContentProtection and buildContentProtection methods.
Github Issue: #119
It's cleaner to not inject data into the extractor only
so that it can be read out as though it were parsed from
the stream. This is also an incremental step towards
fixing Github issue #119.
Note: This adds support for the majority of DASH live streams,
however we do not yet correctly support live streams that rely
on UtcTimingElements in their manifests.
Issue: #52
Plus start to properly document the SmoothStreaming package.
Note that where the documentation is a little vague, this is
because the original SmoothStreaming documentation is equally
vague!
- Split sample pools for video/audio/misc, since the typical
required sample sizes are very different (and so it becomes
inefficient to use a sample sized for video to hold audio).
- Add TODO for further improvements.
Issue: #174
The timestamp scaling in SegmentBase.getSegmentTimeUs was
overflowing for some streams. Apply a similar trick to that
applied in the SmoothStreaming case to fix it.
- Move all three buffering constants to a single class (the
chunk source).
- Increase the target buffer to 40s for increased robustness
against temporary network blips.
- Make values configurable via the chunk source constructor.
- Treat captions as a text track for HLS. This allows them to
be enabled/disabled through the demo app UI.
Issue: #165
- Add options to switch abruptly at segment boundaries. Third
parties who guarantee keyframes at the start of segments will
want this, because it makes switching more efficient and hence
rebuffering less likely.
- Switch quality faster when performing a splicing switch (when
we detect that we need to switch variant, we now immediately
request the same segment as we did last time for the new variant,
rather than requesting one more segment for the old variant
before doing this.
1. Correctly replace the AES data source if IV changes.
2. Check the largest timestamp for being equal to MIN_VALUE, and
handle this case properly.
3. Clean up AES data source a little.
Issue: #162
The actual fix here is to not call discardExtractors in HlsSampleSource
whilst the loading thread that's pushing data into it is still running.
It's required to wait for that thread to have exited before doing this.
Issue: #159
Looking up a long in a HashSet<Long> auto boxes the long and leaves
it for the GC. As decodeOnly is relatively infrequent it's much
better to do a simple linear search in a List<Long>. That way
we can avoid boxing every incoming time stamp value. In the general
case this will be linear searching in an empty list, a very fast
operation.
Signed-off-by: Jonas Larsson <jonas@hallerud.se>
AudioTrack contains the portions of MediaCodecAudioTrackRenderer that handle the
platform AudioTrack instance, including synchronization (playback position
smoothing), non-blocking writes and releasing.
This refactoring should not affect the behavior of audio playback, and is in
preparation for adding an Ac3PassthroughAudioTrackRenderer that will use the
AudioTrack.
Passing uncropped dimensions to certain decoders will make them
output frames without proper cropping set.
Signed-off-by: Jonas Larsson <jonas@hallerud.se>
- Add a readBit method to BitsArray for reading a boolean flag.
- Make things accessed from inner classes package visibility to avoid
the compiler generating thunk methods.
- The HlsSampleSource now owns the extractor. TsChunk is more or less dumb.
The previous model was weird, because you'd end up "reading" samples from
TsChunk objects that were actually parsed from the previous chunk (due to
the way the extractor was shared and maintained internal queues).
- Split out consuming and reading in the extractor.
- Make it so we consume 5s ahead. This is a window we allow for uneven
interleaving, whilst preventing huge read-ahead (e.g. in the case of sparse
ID3 samples).
- Avoid flushing the extractor for a discontinuity until it has been fully
drained of previously parsed samples. This avoids skipping media shortly
before discontinuities.
- Also made start-up faster by avoiding double-loading the first segment.
Issue: #3
The key change here is that nextLoadPositionUs is set to -1
if we're not loading but don't have a next chunk ready to
load. This ensures that "missing chunks" in one stream don't
prevent chunks in another stream from loading. This occurs
in SmoothStreaming with TTML subtitles, where the chunks are
sparse.
Propagate elapsedRealtimeUs to the video renderer. This allows
the renderer to calculate and adjust for the elapsed time since
the start of the current rendering loop. Typically this is <2ms,
but there situations where it can go higher (normally when the
video renderer ends up processing more than 1 output buffer in
a single loop).
Also made variable naming more consistent throughout the package.
- Move parsing onto a background thread. This is analogous
to how frame decoding is pushed to MediaCodec, and should
prevent possible jank when new subtitle samples are parsed.
This is more important for out-of-band subtitles, which can
take a second or two to parse fully.
- Add Useful DataSpec method.
- Use native frame release timing in video renderer for
smoother video playback.
- Avoid unnecessary memory copy steps in audio renderer.
- Use non-blocking AudioTrack API.
Previously we'd end up blocking forever in this case, which
is the worst thing we could do :). We could either throw an
exception or just print a warning. Printing a warning is more
in line with what other methods do (Handler prints a "sending
message to dead thread" warning).
This allows ManifestFetcher to both execute the initial
manifest load and be plugged into an ExoPlayer ChunkSource,
where it can be used for repeated manfiest refreshes during
live playback.
This API wasn't particularly nice. Best to remove it whilst
hopefully no-one is using it. Leaving the ReadHead abstraction
in place, since it might well prove useful in the future.
2. Common interface for manifest parsers.
- This effectively moves the common interface from the Fetcher level
(i.e. ManifestFetcher) to the Parser level (i.e. ManifestParser).
- The motivation here is to allow the implementation of components that
can work with a generic ManifestParser implementation.
- Skips unrecognized elements rather than crashing.
- FourCC treated as required for video and optional elsewhere,
as per the SmoothStreaming spec.
- Only parse initData text when we're actually in the ProtectionHeader element
This means that after a decoder flush, the renderer will avoid
feeding non-keyframes into the decoder until it has received and
fed the first keyframe. The decoder has no way of correctly
decoding non-keyframes that arrive before a keyframe.
It looks like for the case of self-contained media segments,
it's possible to get stuck without failure in the case that
the load fails having loaded less than the length of the init
data.
Since we have a Format class as well, it's very confusing that
FormatHolder actually holds a MediaFormat. I think it's quite
likely that Format will need promoting into the root package as
part of the HLS work, which will make this even more confusing
(although it is possible that for HLS we'll define yet another
Format class, if it turns out we need significantly different
fields).
Note - I deliberately avoided renaming the formatHolder
args/params, because they're not particularly ambiguous and
because it introduces some ugly line breaks.
- Bring back requirement for the first video frame to be rendered
before isReady returns true, *unless* we've deduced that the
upstream source is serving multiple renderers.
- Ditto for requiring that the audio track has some buffered data.
- cache ref didn't work because it referred to a private variable
(which isn't documented) from a public interface definition
(which is). Meaning the Javadoc generator was trying to link
to documentation that didn't exist.
The equals check we perform needs to ignore the max dimensions.
This tended to work in practice because formats would be the
same object, but in the case where different format objects
are used, things can break.
- Add constants class. Currently housing a single lonely variable,
which is used generally throughout the library, and so no longer
nicely fits into a specific class.
- Rename a few other constants to add clear units.
- Made minor tweak to ExoPlayer documentation.
1. Use ints rather than longs.
2. Remove some counters that dont seem hugely useful.
3. Replace use of volatile with explicit method calls that
cause a memory barrier. This is a lot more efficient than
using volatile because it can be invoked only once per
doSomeWork.
- Make MediaCodecTrackRenderer.isReady more permissive.
This largely fixes#21
- Bring WebmExtractor closer to FragmentedMp4Extractor.
The two will probably be placed under a common interface
fairly soon, which will allow significant code
deduplication.
* Remove concept of being prepared by simply reporting if format
and/or cues are known.
* Allow replacement of format and/or cues later in the stream.
* Initialization and index segments can be parsed independently
of one another but must be in order due to internal WebM dependencies.
* Let seekTo() work even when cues are unknown.
This paves the way for SegmentTemplate and SegmentList based
mpds, which will implement DashSegmentIndex directly rather than
parsing an index from the media stream.
- Define DashSegmentIndex.
- Make use of DashSegmentIndex in chunk sources.
- Define an implementation of DashSegmentIndex that wraps a SegmentIndex.
- Add method that will allow Representations to return a DashSegmentIndex
directly in the future.
- Add support for non-contiguous index and initialization data in media streams.
For the Webm case this isn't enabled yet due to extractor limitations.
- Removed ability to fetch multiple chunks. This functionality does not extend
properly to SegmentList and SegmentTemplate variants of DASH.
Why: This was a bad initial choice. Manifests typically define bandwidth in
bits/sec. If you divide by 8 then you're throwing away information due to
rounding. Unfortunately it turns out that SegmentTemplate based manifests
require you to be able to recall the bitrate exactly (because it's substituted
in during segment URL construction).
Medium term: We should consider converting all our bandwidth estimation
over to bits/sec as well.
Note1: Also changed Period id to be a string, to match the mpd spec.
Note2: Made small optimization in FormatEvaluator to not consider discarding
the first chunk (durationBeforeThisSegmentUs will always be negative, and even
in the error case where it's not, removing the first thunk should be an error).
- Allow the content type of an adaptation set to be inferred
from the mimeTypes of the contained representations.
- Ensure the contained mimeTypes are consistent with one
another, and with the adaptation set.
Ref: Issue #2
- Add support for parsing avc3 boxes.
- Make workaround for signed sample offsets in trun files always enabled.
- Generalize remaining workaround into a flag, to make it easy to add additional workarounds going forward without changing the API.
- Fix DataSourceStream bug where read wouldn't return -1 having fully read segment whose spec length was unbounded.
This can help custom ChunkSource implementations to act on
this information. For example an adaptive implementation may
choose to blacklist a problematic format if loads of that
format keep failing.
AudioTrack time will go out of sync if the decodeOnly flag
is set of arbitrary samples (as opposed to just those following
a seek). It's a pretty obscure case and it would be weird for
anyone to do it, but we should be robust against it anyway.
1. Fix SimpleCache startReadWrite asymmetry. Allow more concurrency.
- startReadWrite does not have the concept of a read lock. Once
a cached span is returned, the caller can do whatever it likes
for as long as it wants to. This allows a read to be performed
in parallel with a write that starts after it.
- If there's an ongoing write, startReadWrite will block even if
the return operation will be a read. So there's a weird asymmetry
where reads can happen in parallel with writes, but only if the
reads were started first.
- This CL removes the asymmetry, by allowing a read to start even
if the write lock is held.
- Note that the reader needs to be prepared for the thing it's
reading to disappear, but this was already the case, and will
always be the case since the reader will need to handle disk
read failures anyway.
2. Add isCached method.