March 28, 2023

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 pictures and movies on a two-column grid. With a view to keep a performant video expertise on Android units, we centered on:

With a view to cut back the startup latency, we set up a video community connection by sending a dummy HTTP HEAD request throughout the early software startup time. The identical connection can be utilized to play future movies. That is carried out 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 knowledge from the video url. It:

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

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

ExoPlayer gives us the setBufferDurationsMs() to customise varied buffering durations used to delay playback till we’ve ample knowledge. Since a majority of Pinterest’s media content material is in short-form, we will 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 big discount in video startup latency. Though the rebuffer fee will increase a bit, the general video UX remains to be improved.

Utilizing the next two parameters, we might 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 might 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 knowledge on disk. Nevertheless, within the instances once we run into deadly errors attributable to backend bugs, the dangerous contents can even stick within the cache. This will 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 cases on the fly, which precipitated vital overhead on each the reminiscence and bandwidth. Listed below are some excessive stage learnings:

Separate By Encoding

Participant cases 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. Due to this fact we pooled our gamers primarily based on the preliminary decoding format. By guaranteeing the recycled gamers with decoders matching the media’s encoding, we eliminated any latency overhead precipitated when switching encoding codecs.

Sensible Sizing

The pool measurement itself ran via a number of iterations to search out the perfect 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:


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.


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 big toll on reminiscence and gadget 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 gadget.

Bettering 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 probably the most difficult is constructing an structure that works for the uniquely Pinterest expertise of the house feed. Our long-term objective 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, 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.