facebookpixel

Hack Week X Recap

CMMA Blog

During our yearly Hack Week event, Brightcove engineering teams from around the world join forces to build new potential product features—and creative solutions that may involve an entirely new line of products. From June 3 through 7, we held our 10th annual Hack Week, which was one of our biggest and most successful yet!

Check out this video for a behind-the-scenes look at the event:

Hack Week by the numbers

This year, 89 employees (84 engineers joined by five members of our user experience team and several product managers) worked on 39 projects across offices in:

  • Sydney, Australia
  • London, England
  • Boston, MA
  • Scottsdale, AZ
  • Seattle, WA
  • Guadalajara, Mexico

Six teams were completely remote and used video conferencing and online tools to coordinate their efforts across several time zones. And nine projects were directly inspired by suggestions from customers and partners at our PLAY 2019 conference.

And the winner is…

At the end of the event, we celebrated our team’s hard work and gave out several awards in each office.

69529208 f73d 493a 9ba5 223494becd59

The following four awards were given out in our Boston office:

  • People’s Choice was awarded to the lone entry from our UX team for their prototype of a video analytics application for mobile devices—hinting at what the future of analytics might look like on the go. This project was one of several challenges taken on after direct feedback from customers and partners at PLAY 2019.
  • Best Technical Accomplishment was awarded to a project that created a prototype for a new live service utilizing existing open-source technologies that could enable the next generation of live features.
  • Craziest Idea was awarded to a team that explored using Amazon’s Rekognition API to extract metadata from videos to better categorize and identify the subject matter within the video—opening up the possibility of more advanced tagging and targeting of content.
  • The Most Business Impact award was given to a team that experimented with a validation tool for analytics that may one day help proactively identify discrepancies and outliers in our analytics data.

Ideas from PLAY discussions

Several other projects were inspired by conversations our engineers had with our customers and partners at PLAY. One such project was a prototype for technology that automatically detects natural breaks in content and inserts ad cue points—thereby avoiding untimely interruptions in content. Another project explored the possibility of a player testing service that would enable customers to perform A/B testing of their latest players and view the results. I know I speak for the entire team when I say that we love having the opportunity to speak directly with customers and how we can continually innovate to help them succeed.

622790a2 3f4f 4019 8204 271efe30fcb8

Overall, the team and I learned some really valuable lessons during this recent Hack Week, many of which we will carry forward into our work over the coming months. Keep an eye on this space to see how the ideas introduced during this event impact future projects!

 

To view our Partner blog, click here

Player delivery improvements for A/B testing

CMMA Blog

The Problem

New versions of the Brightcove Player are released all the time with the most up-to-date technologies in order to provide best playback experience. In order to get real-time analytics for new changes to the player, Brightcove runs A/B comparison tests to preview the impact of these changes. This blog post will provide an overview of how our A/B testing process works and how we’ve been making improvements to ensure the player is always delivered as efficiently as possible.

Historically, A/B comparison testing has been achieved by bundling together the A and B versions for each player with automatic updates enabled prior to a full release. From a technical perspective, this was done by concatenating the A and B player source code and adding a small “shim” to decide which player to execute at runtime through a project we call the “player-shim-builder”:

owgpd9

After careful analysis of metrics reported during the A/B test, the new Brightcove Player version was either made globally available or rolled back for future consideration. While this system achieved its goal, it had a major problem – bundling together two players doubled the size of the payload for end users. Anyone with a slow internet connection or an old mobile phone could notice a small increase in player load times from our A/B testing. In order to facilitate long-term A/B testing of our player, something had to change.

A New Hope

Before I reveal the secret sauce for how we addressed this issue, it’s important to get an understanding of the Lempel-Ziv coding (LZ77 ) compression algorithm and its role in delivering the Brightcove Player. Virtually all major browsers support it through the gzip Content-Encoding HTTP Header. While a deep dive into the technical details of the algorithm is outside the scope of this blog post, the algorithm compresses data by finding series of repeated characters and using special tokens to refer to these shared bits. Optimal compression ratios are achieved when data with very similar characters are in close proximity.

From a Brightcove Player perspective, this is key—usually only a very small percentage of the overall player code changes between versions. In the case of an A/B test, almost all of the code between the A and B versions is identical. Rather than concatenating the two player codes together, the player-shim-builder can divide each player codebase into small sections, or “stripes,” of the source code, and interweave them into the bundled package. Each stripe from Player A is likely to be very similar to the corresponding stripe from Player B’s source: 

ml96rmm4k4fbngwikydivzskkfuu0hjoykzealib4yxkvqhbwq8nd a1xqhgm ms23zcpcw5chwlh5lmwgsotzbpivle1iil94 1xt gphfavljjpwv6a8rfctlakzhjzuheniuu

“Striping” the player for A/B testing has a drastic effect on the size of the player delivered. Using the concatenation method to create a test player results in an index.min.js size of 372 kB, while striping it reduces that size to 212 kB – a 43% reduction in bytes delivered.

However, the striped player code we are delivering is not immediately usable. In order to play video, the player must be de-striped when the page loads and evaluated into executable JavaScript. The following table presents a breakdown of de-striping times for a few major devices and browsers during an initial testing period:

Browser

Device

Player Loads

De-Striping Time
(90th Percentile)

Time to Download 160 kB
(90th Percentile)

Safari

iOS

82629698

6 ms

311 ms

Chrome Mobile

Android

72502892

16 ms

189 ms

Chrome

Windows 10

20244826

4 ms

65 ms

Samsung Browser

Android

9447000

16 ms

256 ms

Edge

Windows 10

6689872

5 ms

63 ms

Safari

OSX

6762600

3 ms

106 ms

Even after accounting for de-stripe times, we found player load times to be significantly faster than concatenation across all major browsers and devices. Certain end users of the Brightcove player no longer have noticeable delays during A/B testing. By optimizing our player delivery strategy, we reduced the initialization time for our player in almost all scenarios.

Striping the player for A/B comparison tests allows us to not only run longer tests without the fear of slowing down player delivery, but also to expand our tests outside of our previous testing windows tailored to developers on Eastern Standard Time. Striping the player to enhance A/B testing is one of the many improvements Brightcove has made to push the limits of global player delivery.

FAQ

 

  1. Why stripe the player at all? Why not select the player at run-time?

    • The Brightcove player code has a long-standing guarantee for synchronous player instantiation. Given an embed code, any script tags invoked after the player is instantiated are guaranteed to refer to a player object, and selecting the player code from a remote asset does not provide similar invariants.

  2. How did you determine the size of the stripes?

    • The sliding window of gzip compression by most browsers is 32 kB. In order to maximize the number of repeated characters between stripes without impacting player publishing time, we use a sliding window of 16 kB for code from each A or B player. We tested on a variety of different stripe sizes to ensure the correct length was selected.

  3. How did you compare de-striping time to download speed?

    • Player delivery download speeds were unavailable for a variety of reasons—instead, we used playback bitrates to estimate the rate at which the player code is downloaded by end users.

To view our Partner blog, click here

Announcing support for Amazon Creator for Fire TV

CMMA Blog

As video consumption on connected TVs increases YOY , we continue to strengthen our partnerships with the leading connected TV platforms in order to bring Brightcove customers the latest, most innovative solutions for reaching and growing their audience on the big screen. We’re excited to announce our most recent development:

Amazon Creator is now available to Brightcove Video Cloud customers. Amazon released an integration with Brightcove for Amazon Creator, a simple-to-use web tool that enables content owners to create web apps for Fire TV without any coding.

In just a few steps , Brightcove customers can make their content that’s hosted and managed in Video Cloud available to millions of Amazon customers. Analytics about video consumption on Fire TV are conveniently captured in Video Cloud. Monetization, via advertising or subscription, is not supported at this time, but the Amazon team looks forward to enhancing the solution over time based on customer need.

“We know that building an app can sometimes be overwhelming for content creators, so we wanted to create an easy, intuitive way for them to showcase their videos on Fire TV,” explains Sashi Bommakanty, software development manager at Amazon. “We’re excited to have enhanced the Amazon Creator product by integrating with longtime partner, Brightcove, giving Video Cloud customers the ability to efficiently and affordably create apps for Fire TV.”

To learn more about Amazon Creator and the Brightcove integration, check out Amazon’s documentation: Use Brightcove as Your Video Source .

To view our Partner blog, click here

This video crashed the player after 19 seconds

CMMA Blog

In any complex software, bugs exist, and when working on a large project you encounter them on a regular basis. The more memorable and interesting ones are the ones that have a simple cause, presenting in unusual and sometimes bizzare ways. This bug started with a single video causing a player to crash. This is by itself not that rare a report, however, the following details definitely stood out:

  • It only happened with a single specific video
  • It only happened on Android (but only on certain versions of Android)
  • It always crashed the player exactly 19 seconds into playback

The video itself was being served to Android devices using HTTP Live Streaming , Apple’s standard for fragmented video delivery based on the m3u playlist format. For content protection, AES-128 with PKCS#7 padding was used. This is generally referred to as HLS Encryption (or “HLSe” for short). Other formats available for the content, such as MPEG-DASH, didn’t present the issue, neither did HLS with FairPlay DRM (or even no drm). The issue was even more specific than “this video”, it was “this video, with HLSe”

Luckily for testing purposes this bug was easy to reproduce in Google’s ExoPlayer demo app, and with a respectable selection of test devices on-hand, it didn’t take long to get error codes and stack traces out of logcat for various major Android versions. The specific errors varied depending on the version of Android on the device, but they all shared a common theme; notably that there was some issue decrypting the media in one of the video segments. The primary exception, and the most interesting “Caused by” exception further down the stack trace, were all variants of these two (differing in wording among the Android versions tested):

java.io.IOException: Error while finalizing cipher
        at javax.crypto.CipherInputStream.fillBuffer(CipherInputStream.java:104)
        at javax.crypto.CipherInputStream.read(CipherInputStream.java:155)
        at com.google.android.exoplayer2.source.hls.Aes128DataSource.read(Aes128DataSource.java:96)
Caused by: javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT
        at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
        at com.android.org.conscrypt.OpenSSLCipher$EVP_CIPHER.doFinalInternal(OpenSSLCipher.java:568)
        at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:385)
        at javax.crypto.Cipher.doFinal(Cipher.java:1476)

Diving deeper here, code-wise, is a bit of a rabbit hole. The core cryptographic code is written in C and is pretty intimidating if you’re not used to it. Luckily, that “caused by” has a nice readable type, notably javax.crypto.BadPaddingException, so that helps us narrow down the issue further; the problem is with the padding. As per the specification from Apple, the padding algorithm being used in HLSe is PKCS#7, which is described in RFC-5652 Section 6.3 :

6.3.  Content-encryption Process

   The content-encryption key for the desired content-encryption
   algorithm is randomly generated.  The data to be protected is padded
   as described below, then the padded data is encrypted using the
   content-encryption key.  The encryption operation maps an arbitrary
   string of octets (the data) to another string of octets (the
   ciphertext) under control of a content-encryption key.  The encrypted
   data is included in the EnvelopedData encryptedContentInfo
   encryptedContent OCTET STRING.

   Some content-encryption algorithms assume the input length is a
   multiple of k octets, where k is greater than one.  For such
   algorithms, the input shall be padded at the trailing end with
   k-(lth mod k) octets all having value k-(lth mod k), where lth is
   the length of the input.  In other words, the input is padded at
   the trailing end with one of the following strings:

                     01 -- if lth mod k = k-1
                  02 02 -- if lth mod k = k-2
                      .
                      .
                      .
            k k ... k k -- if lth mod k = 0

   The padding can be removed unambiguously since all input is padded,
   including input values that are already a multiple of the block size,
   and no padding string is a suffix of another.  This padding method is
   well defined if and only if k is less than 256.

If you’re anything like me, that description is a little hard to picture in your head. So here’s a few examples (all padding to a 16 byte block size):

  • 88 7c 46 66 9a 2f a2 59 4d 1e would be padded with 06 06 06 06 06 06
  • 63 would be padded with 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f 0f
  • f5 5c 6b 13 cf 54 f8 45 c1 ca 67 ec 50 20 12 would be padded with 01

Simple enough then; in plain English, the value of the padded bytes is the number of bytes being padded, up to the block size being used.

Armed with an understanding of how the padding should work, and an error indicating incorrect padding, the next step was to check the code handling the padding for the video. The service in question is written in Go , which doesn’t have an implementation of PKCS#7 in its standard library, so the service has it’s own implementation. Here it is:

PKCS7Pad(in []byte) []byte {
    padding := 16 - (len(in) % 16)
    for i := 0; i < padding; i++ {
        in = append(in, byte(padding))
    }
    return in
}

Short and simple… and no obvious mistakes. There are even unit tests which seem to assert exactly the behaviour we’re expecting. So perhaps we need some more clues. It was at this point a detour was taken to compare what our code was producing to other implementations. Luckily the AES-128 encryption applied to HLSe segments is applied to the entire segment file, rather than just to parts of the file contents, as can happen with other content protection schemes. Producing alternative encrypted segments was easily done with OpenSSL , and we could use our dynamic media packager to get a non-protected copy of segments to encrypt. With a segment downloaded in both clear, and AES-128 encrypted, an alternative encrypted segment was generated using the following command:

openssl aes-128-cbc -K $KEY -iv $IV -in clear.ts -out alt_protected.ts

Doing this revealed a new and interesting piece of information, the output of the encryption from OpenSSL was exactly 16 bytes larger than the output from our Go app (ie. one block). Perhaps the issue wasn’t in the padding, but some strange edge case where a final block wasn’t being added. Reviewing the Go code again with this new piece of information in mind, the following conditional started to look suspicious:

// If this block does not match the AES block size we need to pad it out
if bytesRead != aes.BlockSize {

At face value, the algorithm simply reads data from the input buffer in chunks of length equal to the block size. It then checks how many blocks were read and pads to 16 bytes if necessary. Finally it passes the 16 byte buffer into the cipher and streams the output to an output buffer. So realistically, we only expect this conditional to trigger on the final block, because that’s the only one that will need padding. After some back and forth, something started to become obvious; there’s a scenario that isn’t explicitly being handled…. what if the final block is equal in length to the block size? The Go code will simply do nothing, asserting that no padding is required. To be sure, let’s check the spec again:

the input shall be padded at the trailing end with k-(lth mod k) octets all having value k-(lth mod k), where lth is the length of the input.

So if k is the block size, and lth is the length of the intput, then a block of length 16 would need 16-(0 mod 16) bytes of padding. 16-(0 mod 16) equals 16… So actually this is supposed to have an entire block of padding at the end, with the value of each padded byte set to 16! Finally, a lead! Our Go code isn’t spec compliant!

Skipping forward somewhat through testing a patch against the same content presenting the issue, we finally get working playback past the 19 second mark in the video! Ultimately the fix was to rewrite the flawed conditional to instead pad the last block regardless of how many bytes were read. This resolved the issue once and for all!

In summary, all the odd characteristics of this bug report stemmed from the the unlikely reality that out of all the content we’ve tested with our system, this is the first time that a video (stored as a fragmented mp4, muxed into transport stream segments) has resulted in a segment having a length (in bytes) that was perfectly divisible by 16. Why 19 seconds into the video? Well the segments are 10 seconds long and it was the third segment with the incorrect padding. Why did the crash only occur on some versions of android, and seemingly no other devices? Well it seems like the majority of implementations are resilient to this mistake. The older versions of Android were susceptible, but more modern versions could handle it.

With all questions answered, and the bug fixed, there’s nothing left to cover except a few lessons learned:

  • Use existing, battle-tested implementations of standardised algorithms whenever possible.
  • If you do end up implementing one yourself, you need to be pedantic with the spec. Missing an edge case will cost you!
  • Even the really fun and weird bugs can have boring solutions.

To view our Partner blog, click here

Brightcove Engineering's Hack Week X

CMMA Blog

This week Brightcove Engineering teams from across the globe will embark on our annual Hack Week. Now in its 10th year, participants from five offices and various remote locations around the world will be working collaboratively to use their skills and imaginations to build creative solutions, invent potential new product features, or even devise entirely new product lines. Hack Week is a time where no idea is too crazy and no technology is too new for consideration.

This year we are excited to be working alongside our new co-workers who join us from the Ooyala OVP acquisition. As we do every year, we make every effort to promote cross-site team building—flying several engineers from remote offices to our Boston, MA headquarters in addition to sending several Boston-based engineers to those same remote offices, including our new location in Guadalajara, Mexico.

Teams compete for prizes in various categories like Most Business Impact, Most Innovative, Craziest Idea, People’s Choice, and Best Hacker. Not all ideas are winners, but there is still value in projects that don’t prove successful. They provide valuable learning opportunities to validate or reject concepts before long-term engineering projects are considered.

Two of the latest products and features that resulted from previous Hack Weeks include Dynamic Delivery and our newest play back engine for the Brightcove Player , which allows us to use Media Source Extensions to playback HLS content on desktop browsers.

It will be exciting to see which projects rise to the top this year! Half the fun of Hack Week is seeing all of the innovative projects that our talented engineering teams develop and the new paths they forge for the future of digital video and streaming services.

Keep an eye on the Tech Talk blog for Hack Week updates, information on the winning projects, and more over the coming days and weeks!

 

 

To view our Partner blog, click here

Deprecation of Twitter @mentions in Brightcove Social

CMMA Blog

In an effort to control the bad behavior of some Twitter users — particularly those who use social media applications to spam and bully — Twitter has instituted new policies, and deployed automated systems to detect and enforce these policies.

One policy states that an application will be terminated if the monitoring system detects the use of @mentions that are not replied to by the mentioned party within an unspecified time period. In a sample use case we saw, the players mentioned during coverage of a high school football game did not respond to tweets while they were on the field. A network bot that was monitoring the feed misinterpreted this as bullying behavior, and automatically blocked the application’s access to the Twitter platform. Reinstatement required filing an appeal through the support team, and the outage lasted for several hours.

The situation that caused the outage was innocent, accidental, and in compliance with the spirit of Twitter’s policies. But Twitter is dealing with these issues on an enormous scale and is forced to automate their processes. Over 143,000 applications were suspended in Q118 alone.

To address this policy change, Brightcove Social will not allow @mentions when publishing tweets. The Brightcove Social user interface will detect the condition and issue an error with recommendations and an explanation. @mentions will be converted to #mentions for tweets published using Autosync. The impact for the users is that the tweets will not automatically appear in the feed of the mentioned party. This will go into effect on 11/19/18.

While not ideal, this change protects all Brightcove Social users from inadvertent and unplanned shutdowns. If you have any concerns, please contact your account manager.

For more information about the Twitter policies, please read The Twitter Rules .

To view our Partner blog, click here