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 provides a uncommon expertise with a mixture of photographs and movies on a two-column grid. In an effort to preserve a performant video expertise on Android gadgets, we targeted on:

In an effort to cut back the startup latency, we set up a video community connection by sending a dummy HTTP HEAD request through the early software startup time. The identical connection can be utilized to play future movies. That is executed 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 a lot of work after parsing the knowledge from the video url. It:

Since most of our movies’ side ratios are pre-determined, we are able to stop the above work by:

The latter prevents the participant from making an attempt to recalculate the side ratio.

ExoPlayer offers us the setBufferDurationsMs() to customise varied buffering durations used to delay playback till we now have enough knowledge. Since a majority of Pinterest’s media content material is in short-form, we are able to use a lot shorter buffering durations which is able to lead to much less time ready for knowledge 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 fee 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 offers a cache interface to maintain downloaded media knowledge on disk. Nonetheless, within the circumstances once we run into deadly errors attributable to backend bugs, the unhealthy contents can even stick within the cache. This could trigger the applying to proceed encountering the identical playback errors regardless that the backend is mounted.

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 brought about vital overhead on each the reminiscence and bandwidth. Listed here are some excessive stage 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 sort. It takes a measurable quantity of labor for gamers to change context between completely different decoders. Subsequently 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 brought about when switching encoding codecs.

Good Sizing

The pool measurement itself ran by a number of iterations to search out the best area wanted to deal with 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. Nonetheless, it takes a major toll on reminiscence and system stability. We needed to construct logic to make use of this methodology 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 purpose is to share this work to different builders seeking to construct a seamless video UX with minimal setup required. Within the meantime, we hope everybody builds a extra performant video expertise.

To study extra about engineering at Pinterest, try the remainder of our Engineering Weblog and go to our Pinterest Labs website. To discover life at Pinterest, go to our Careers web page.