Enhancing the Participant on Android. Gray Skold | (former Android Video… | by Pinterest Engineering | Pinterest Engineering Weblog | Dec, 2022

Gray Skold | (former Android Video Engineer) ; Lin Wang | Android Efficiency Engineer; Sheng Liu | Android Efficiency Engineer

Close up of black analog speedometer — Photo by CHUTTERSNAP on Unsplash

Pinterest Android App gives a uncommon expertise with a mixture of pictures and movies on a two-column grid. So as to preserve a performant video expertise on Android units, we targeted on:

So as to scale back the startup latency, we set up a video community connection by sending a dummy HTTP HEAD request in the course of the early software startup time. The identical connection can be utilized to play future movies. That is performed even earlier than any video urls are returned from our server.

okhttpNetworkClient.newCall( Request.Builder().url(videoUrl).cacheControl(FORCE_NETWORK).head().build() ).enqueue(callback)

The identical technique additionally applies to UI rendering. We discovered Exoplayer tends to do numerous work after parsing the data from the video url. It:

Since most of our movies’ facet ratios are pre-determined, we will stop the above work by:

The latter prevents the participant from attempting to recalculate the facet ratio.

ExoPlayer gives us the setBufferDurationsMs() to customise varied buffering durations used to delay playback till we’ve ample information. Since a majority of Pinterest’s media content material is in short-form, we will use a lot shorter buffering durations which can end in much less time ready for information to load.

setBufferDurationsMs( minBufferMs = 1_000, maxBufferMs = 50_000, bufferForPlaybackMs = 500, bufferForPlaybackAfterRebufferMs = 1_000 )

By doing this, we noticed a major discount in video startup latency. Though the rebuffer charge will increase a bit, the general video UX continues to be improved.

Utilizing the next two parameters, we may successfully guarantee movies loaded in-feed are restricted by their viewport measurement (i.e. to keep away from loading a big 1080p video in a small 360 pixel viewport).

buildUponParameters() .setMaxVideoSize(maxVideoWidth, maxVideoHeight) .setExceedVideoConstraintsIfNecessary(false)

The Pinterest app performs a number of muted movies within the grid on the identical time. Utilizing the next parameters, we may disable the audio rendering to save lots of community bandwidth to obtain the audio and reminiscence consumption to course of them.

buildUponParameters() .setMaxAudioBitrate(0) .setMaxAudioChannelCount(0) .setExceedAudioConstraintsIfNecessary(false)

Exoplayer gives a cache interface to maintain downloaded media information on disk. Nevertheless, within the instances once we run into deadly errors attributable to backend bugs, the unhealthy contents also can stick within the cache. This may trigger the appliance to proceed encountering the identical playback errors though the backend is fastened.

We use SimpleCache.removeResource() to purge the soiled cache when the next deadly IO errors are returned from the Player.Listener.onPlayerError():

Lastly, we constructed our personal cache to pool gamers as they’re wanted. Traditionally, we instantiated new participant situations on the fly, which precipitated important overhead on each the reminiscence and bandwidth. Listed here are some excessive degree learnings:

Separate By Encoding

Participant situations are successfully holding onto a reference to an underlying decoder primarily based on the final rendered media’s encoding kind. It takes a measurable quantity of labor for gamers to modify context between completely different decoders. Due to this fact we pooled our gamers primarily based on the preliminary decoding format. By making certain the recycled gamers with decoders matching the media’s encoding, we eliminated any latency overhead precipitated when switching encoding codecs.

Good Sizing

The pool measurement itself ran by a number of iterations to search out the perfect house wanted to accommodate a number of video performs whereas avoiding OutOfMemory (OOM) and ANR. The next two APIs are utilized to not over-burdening the system:

OnTrimMemory(int)

This was our key callback used to tell us that we should always clear our participant cache pool as we begin to get dangerously near sending OOMs.

setForegroundMode(true)

Setting this flag will let the Exoplayer to retain a direct reference to the video decoder and preserve it in reminiscence even within the idle state. Nevertheless, it takes a major toll on reminiscence and system stability. We needed to construct logic to make use of this technique conservatively, primarily based on each the present software lifecycle and present accessible reminiscence on the system.

Enhancing the efficiency of video playback is a unending investigation into the inner-workings of the ExoPlayer library in addition to our personal product’s distinct use-cases, however what’s essentially the most difficult is constructing an structure that works for the uniquely Pinterest expertise of the house feed. Our long-term aim is to share this work to different builders trying to construct a seamless video UX with minimal setup required. Within the meantime, we hope everybody builds a extra performant video expertise.

To be taught extra about engineering at Pinterest, take a look at the remainder of our Engineering Weblog and go to our Pinterest Labs web site. To discover life at Pinterest, go to our Careers web page.