Support for FLAC in ISO BMFF with MSE in StreamingServer application

Chrome platform supports FLAC encoding in ISO BMFF (fragmented MP4) media since version 62 (October 2017), however the support for FLAC (and Opus) overall did not become standard and comprehensive since then.

I hooked up Microsoft FLAC Audio Encoder MFT into media streaming application to produce media and check browser compatibility.

  • /audio.mp4?flac – produces FLAC in ISO BMFF media on the fly, resulting in streamable media used here in Google’s demo
  • /audio.mp4?flac&duration=50 – allows to override duration and generate longer content; there is no chunked HTTP transfer [yet] so the content needs to be fully generated before it is sent, beware if doing real long files
  • /audio.mp4 – without “flac” specifier with or without duration results in single AAC track media
  • /audio.mp4.html?flac – produces a wrapper HTML page offering playback of the media (see below)

HTML is repeating Google’s demo and is feeding the FLAC MP4 audio into HTML5 media element:

std::string Text;
Text.append("<html><body>");
Text.append(Format("<p>Audio MIME type: audio/mp4; codecs=\"%hs\"</p>", Codecs.c_str()));
Text.append("<audio controls />");
Text.append("<script>");
Text.append(Format("const uri = 'audio.mp4%ls';", Request.GetQueryString().c_str()));
Text.append(Format("const mimeType = 'audio/mp4; codecs=\"%hs\"';", Codecs.c_str()));
auto constexpr g_Script = R"script(
    const audio = document.querySelector('audio');
    if (MediaSource.isTypeSupported(mimeType)) {
        const mediaSource = new MediaSource();
        audio.src = URL.createObjectURL(mediaSource);
        mediaSource.addEventListener('sourceopen', function () {
            URL.revokeObjectURL(audio.src);
            const sourceBuffer = mediaSource.addSourceBuffer(mimeType);
            console.log('Fetching audio file...');
            fetch(uri)
                .then(response => response.arrayBuffer())
                .then(data => {
                    sourceBuffer.appendBuffer(data);
                    sourceBuffer.addEventListener('updateend', function () {
                        if (!sourceBuffer.updating && mediaSource.readyState === 'open') {
                            mediaSource.endOfStream();
                            console.log('Audio is ready to play!');
                        }
                    });
                });
        });
    } else {
        console.log('MIME type ' + mimeType + ' is not supported on this platform with MSE.');
    }
)script";
Text.append(g_Script);
Text.append("</script>");
Text.append("</body></html>");
Response->Initialize(HTTP_STATUS_OK, "OK");
Response->AddHeader(HttpHeaderContentType, "text/html; charset=utf-8");
AddAccessControlResponseHeaders(*Response);
Response->AddMemoryEntityChunk(Text);
Response->Send();

The generated FLAC MP4 asset is playable not just on Chrome, it can be played on:

  • new Edge (obviously, it’s Chromium based)
  • VLC player on Windows
  • MPC-HC player on Windows (libav backed)
  • Safari on macOS (but not on iOS, neither from HTML wrapper because of MSE absence nor directly)
  • Some Android phone (“Samsung Internet” browser? WTF; both directly and via MSE interface from HTML wrapper)
  • UWP MediaPlayerElement control

The ISO BMFF content is styled for low latency progressive streaming, it’s just concatenated into complete file. For this reason the FLAC content can also be put into adaptive bitrate streaming media asset like HLS, and the application does it as well, but it deserves a separate blog post and support for FLAC in HLS is not as good.

Download links

Binaries:

  • 64-bit: StreamingServer.exe (in .ZIP archive)
  • License: This software is free to use; builds have time based expiration

Leave a Reply