{"id":430,"date":"2026-06-30T11:49:27","date_gmt":"2026-06-30T11:49:27","guid":{"rendered":"https:\/\/www.stormstreaming.com\/blog\/?p=430"},"modified":"2026-06-30T11:49:28","modified_gmt":"2026-06-30T11:49:28","slug":"webcodecs-low-level-media-encoding-and-decoding-in-the-browser","status":"publish","type":"post","link":"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/","title":{"rendered":"WebCodecs \u2013 Low-Level Media Encoding and Decoding in the Browser"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">For everyone building \u2013 or planning to build \u2013 video streaming services that run inside a web browser, there comes a moment when the standard tools simply aren&#8217;t enough. The <strong>&lt;video&gt;<\/strong> tag, Media Source Extensions, WebRTC \u2013 each does its job, but each also hides the codec behind a thick layer of abstraction that you can neither see into nor control. In this article, I will allow myself to describe the WebCodecs API: what it is, where it came from, what it gives us, what it demands in return, and how it fits into a modern low-latency streaming pipeline.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">History and origins<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Here is the thing worth understanding first: the low-level machinery that WebCodecs exposes has been sitting inside our browsers for years. We have been using it the whole time \u2013 only indirectly, and without any control over it. Every time WebRTC negotiated a video call, the browser was busy encoding and decoding frames on our behalf, deep inside its own pipeline. We could start the process and stop it, but we could not reach in and touch the codec itself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And let me make one point absolutely clear right at the outset, because it is the source of most early confusion<strong>: WebCodecs is not a protocol. It is a browser API.<\/strong> It says nothing whatsoever about how the encoded bytes arrive at the page. That is entirely up to you \u2013 the data can come over plain WebSockets, over WebTransport, over a fetch stream, or even from a file on disk. WebCodecs does not care. Its only job is to turn encoded data into frames, and frames back into encoded data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So why did it need to exist at all? For most of the web&#8217;s history, the browsers&#8217; codecs were locked away. You could hand a file to a &lt;video&gt; element, push a container into Media Source Extensions, or decode a clip through the Web Audio API \u2013 but there was no general-purpose way to take a raw stream of encoded frames and simply say: &#8220;decode this.&#8221; Developers who needed real control responded by shipping entire codecs compiled to JavaScript or WebAssembly. This meant re-downloading a decoder the browser already had built in, burning CPU and battery on software decoding, and giving up hardware acceleration entirely.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">WebCodecs was the W3C&#8217;s answer. The Media Working Group designed it as a thin, low-level interface that exposes the browser&#8217;s existing audio and video encoders and decoders directly to JavaScript. Chrome shipped it as stable in version 94 (2021), and the other engines followed over the following years. The design philosophy is deliberately minimal: the API hands you raw frames and encoded chunks, and otherwise stays out of your way.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">What it is and main characteristics<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">At its core, WebCodecs is a codec API and nothing more. It gives your code direct access to the browser&#8217;s built-in encoders and decoders, operating on two kinds of data:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Encoded data<\/strong> \u2013 EncodedVideoChunk and EncodedAudioChunk, which carry codec-specific compressed bytes (an H.264 access unit, an AAC frame, and so on).<\/li>\n\n\n\n<li><strong>Raw data<\/strong> \u2013 VideoFrame for decoded pictures and AudioData for decoded audio samples, ready to be rendered.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The best way to grasp what you are signing up for is this: with WebCodecs, you are effectively writing your own video player inside the browser, from the decoder outward. The browser gives you the engine; the rest of the car is yours to build.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is also why it is worth repeating what WebCodecs is not. It is not a networking layer, and it is not a container parser. It will not fetch your stream, it will not demux your fMP4 or MPEG-TS, and it will not synchronise audio with video for you. Those responsibilities stay firmly on your side of the fence. This is both its greatest strength and its steepest learning curve.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Core building blocks<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The entire API is built around a small set of classes, which makes it pleasantly easy to learn even if it is demanding to use well:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>VideoDecoder <\/strong>\u2013 takes EncodedVideoChunk objects and produces VideoFrame objects.<\/li>\n\n\n\n<li><strong>VideoEncoder <\/strong>\u2013 takes VideoFrame objects and produces EncodedVideoChunk objects.<\/li>\n\n\n\n<li><strong>AudioDecoder \u2013<\/strong> takes EncodedAudioChunk objects and produces AudioData objects.<\/li>\n\n\n\n<li><strong>AudioEncoder <\/strong>\u2013 takes AudioData objects and produces EncodedAudioChunk objects.<\/li>\n\n\n\n<li><strong>ImageDecoder \u2013<\/strong> a convenience decoder for still images and animated image formats.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Two data carriers round things out: VideoFrame, which holds a decoded picture (and can be drawn straight to a canvas or uploaded as a WebGL\/WebGPU texture), and AudioData, which holds decoded PCM samples destined for an AudioWorklet. The symmetry between the encode and decode paths is intentional, and it makes the mental model refreshingly clean.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Advantages<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The appeal of WebCodecs comes down to one word: control. Once you accept the responsibility that comes with it, you gain capabilities no higher-level API can match:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Ultra-low latency.<\/strong> Because you own the decode queue and the buffer directly, there is no opaque internal buffering deciding when a frame finally reaches the screen. Glass-to-glass latency can be pushed down to the level of WebRTC \u2013 and, with the right transport and tuning, even below it.<\/li>\n\n\n\n<li><strong>Full control<\/strong> \u2013 and full responsibility. This is the trade at the heart of the API. Nothing is hidden from you, which means nothing is handled for you either. (More on the second half of that bargain in the next section.)<\/li>\n\n\n\n<li><strong>Hardware acceleration.<\/strong> When the system codec is GPU-backed, the browser uses it automatically and falls back to software only when it must \u2013 without you re-implementing anything.<\/li>\n\n\n\n<li><strong>Frame-accurate access.<\/strong> Every decoded frame is yours, with its presentation timestamp, ready to be inspected, processed, composited, or dropped.<\/li>\n\n\n\n<li><strong>Off-main-thread operation.<\/strong> Decoders and encoders run happily inside Web Workers, and frames can be rendered to an OffscreenCanvas, keeping the UI thread smooth even under heavy load.<\/li>\n\n\n\n<li><strong>Custom rendering.<\/strong> Draw frames to a 2D canvas, feed them to WebGL or WebGPU, or pipe them through your own compositor.<\/li>\n\n\n\n<li><strong>A natural partner for modern transports.<\/strong> Paired with WebTransport or the emerging Media over QUIC stack, WebCodecs forms the backbone of the next generation of low-latency, high-scale streaming.<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Disadvantages and challenges<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Everything WebCodecs hands you in control, it takes back in complexity. This is not an API you reach for casually \u2013 and the honest summary of its downside is simple: there is an enormous amount of difficult machinery to get right, and you have to get it right all at once.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>You build the whole pipeline.<\/strong> Demuxing the container, managing the buffer, absorbing network jitter, synchronising audio and video, smoothing the playback clock \u2013 all of it is your code. The API gives you a decoder, not a player.<\/li>\n\n\n\n<li><strong>Audio rendering is on you.<\/strong> Decoded AudioData has to reach the speakers through an AudioWorklet, which in practice means writing a ring buffer and feeding it sample-accurately. Get the timing wrong and you hear clicks, gaps, or drift.<\/li>\n\n\n\n<li><strong>A\/V synchronisation is genuinely hard.<\/strong> Keeping a separate audio clock and video clock locked together \u2013 including catch-up logic when one falls behind \u2013 is one of the trickiest parts of any custom player, and WebCodecs does none of it for you.<\/li>\n\n\n\n<li><strong>No networking, no containers.<\/strong> You supply the transport and the demuxer. The browser will not parse your fMP4 for you here.<\/li>\n\n\n\n<li><strong>Backpressure must be respected.<\/strong> Decoders expose a queue; flood it and you fall behind, starve it and you stall. Managing that pressure is part of the job.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">None of these are insurmountable, but together they explain why a production-grade WebCodecs player is a serious engineering effort rather than a weekend project.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Supported codecs<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">WebCodecs itself does not mandate a codec list. The available codecs depend on the underlying platform, which leads to the single most important practical fact in this section: different browsers on different operating systems can expose <strong>different combinations of codecs<\/strong>, and your viewers will be spread across all of them. You therefore cannot assume support \u2013 you probe for it at runtime with VideoDecoder.isConfigSupported() (and the equivalents for the other classes) before configuring anything.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In broad terms, the commonly available video codecs are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AVC \/ H.264 (effectively universal)<\/li>\n\n\n\n<li>HEVC \/ H.265 (where the platform licenses and exposes it)<\/li>\n\n\n\n<li>VP8 and VP9<\/li>\n\n\n\n<li>AV1<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">And on the audio side:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>AAC<\/li>\n\n\n\n<li>Opus<\/li>\n\n\n\n<li>MP3<\/li>\n\n\n\n<li>FLAC<\/li>\n\n\n\n<li>Vorbis<\/li>\n\n\n\n<li>PCM (raw, uncompressed \u2013 useful as an AudioData format)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A word of caution on the encode path: support for encoding is patchier than for decoding. AAC encoding, for example, is absent in Firefox on every platform and unavailable on desktop Linux across browsers, while MP3 encoding is essentially unsupported anywhere. Always probe, never assume.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Browser support<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This is the section to read carefully, because WebCodecs reached broad, dependable support only relatively recently:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Chrome \/ Edge<\/strong> \u2013 full support since version 94 (2021) on desktop; Chrome for Android caught up with the complete API more recently.<\/li>\n\n\n\n<li><strong>Firefox<\/strong> \u2013 full support on desktop from roughly version 130 onward. Firefox for Android, however, does not support it.<\/li>\n\n\n\n<li><strong>Safari<\/strong> \u2013 this is the one that matters most. Safari 26.0 (late 2025) finally brought full WebCodecs support across macOS, iOS, and iPadOS. That last point is the turning one: it is only since Safari 26 that the API works on iPhones and iPads at all in its complete form \u2013 and it is precisely that milestone that makes WebCodecs viable for widespread, production use rather than a desktop-only curiosity. Earlier Safari versions, from 16.4 through 18.7, shipped only the video interfaces, with no audio path \u2013 the very limitation that made building a fully cross-platform player on iOS such an ordeal for so long.<\/li>\n\n\n\n<li><strong>Opera (80+)<\/strong> and <strong>Samsung Internet (17+)<\/strong> follow the Chromium support model.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The practical takeaway: on modern devices you can now rely on WebCodecs almost everywhere, but if your audience still includes older iOS versions, you must plan a fallback path \u2013 exactly as you would for any other cutting-edge media feature.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">How it fits into a streaming pipeline \u2013 the mechanics<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">WebCodecs sits in the middle of a chain you assemble yourself. A typical live-playback pipeline looks like this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Transport<\/strong>. Encoded media arrives over the network \u2013 commonly a WebSocket, increasingly WebTransport or a Media over QUIC layer for the lowest latency. (Remember: WebCodecs is indifferent to which.)<\/li>\n\n\n\n<li><strong>Demuxing<\/strong>. Your code \u2013 or a small WebAssembly demuxer \u2013 parses the container, whether fMP4, MPEG-TS, or a custom framing, and pulls out the raw encoded units, tagging each with its timestamp.<\/li>\n\n\n\n<li><strong>Decoding<\/strong>. Each unit becomes an EncodedVideoChunk or EncodedAudioChunk and is pushed into the appropriate decoder. Timestamps are expressed in microseconds, and the decoder needs a key frame to begin, so key-frame tracking matters.<\/li>\n\n\n\n<li><strong>Frame handling<\/strong>. The decoder emits VideoFrame and AudioData objects through callbacks. You hold these in your own buffers, managing decoder backpressure so you neither stall nor overrun.<\/li>\n\n\n\n<li><strong>Rendering<\/strong>. Video frames are drawn to a canvas \u2013 2D, WebGL, or WebGPU \u2013 on a clock you control; audio samples are written into an AudioWorklet ring buffer and played back sample-accurately.<\/li>\n\n\n\n<li><strong>Synchronisation<\/strong>. A master clock \u2013 usually the audio clock \u2013 drives the timing, and the video side catches up or drops frames to stay aligned. Techniques such as WSOLA can gently stretch or compress audio to absorb drift without audible artefacts.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">It is, in essence, the architecture of a media player turned inside out: every stage that a &lt;video&gt; element normally hides becomes explicit, inspectable, and tunable.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">WebCodecs vs MSE vs WebRTC<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Choosing WebCodecs is a design decision, not a default. It helps to know where it sits relative to the alternatives:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Media Source Extensions (MSE)<\/strong> works at the container level. You append fragmented MP4 and the browser handles demuxing, buffering, decoding, and synchronisation. It is far less work and excellent for HLS\/DASH-style playback \u2013 but its internal buffering is a black box, which puts a floor on how low your latency can go.<\/li>\n\n\n\n<li><strong>WebRTC<\/strong> is purpose-built for real-time, peer-to-peer communication. It is superb for sub-second conversational latency at low volume, but its signalling complexity and one-to-few design make it awkward for large-scale broadcast.<\/li>\n\n\n\n<li><strong>WebCodecs<\/strong> gives you the codec and nothing else, leaving transport, buffering, and sync in your hands. That is more work, but it is the only path to a player tuned exactly to your latency, scale, and feature requirements.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In short: MSE for convenience, WebRTC for conversation, WebCodecs for control.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Summary<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">WebCodecs closes a gap that sat open in the web platform for over a decade. By exposing the browser&#8217;s own, hardware-accelerated codecs directly to JavaScript, it finally lets developers build serious, low-latency media applications without smuggling entire decoders into WebAssembly. The price is responsibility: WebCodecs hands you a powerful engine but no chassis, and the surrounding pipeline \u2013 demuxing, buffering, synchronisation, audio rendering \u2013 is yours to engineer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Safari 26 bringing full support to the Apple ecosystem, the API has crossed an important threshold. Capabilities that previously had to be polyfilled or skipped now deserve a first-class implementation, and WebCodecs \u2013 particularly alongside WebTransport and Media over QUIC \u2013 is poised to underpin the next generation of streaming on the web.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Storm Streaming Server &amp; WebCodecs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This is exactly the territory where a purpose-built player earns its keep. The Storm player leverages WebCodecs to deliver ultra-low-latency playback directly in the browser, with full control over the decode queue, buffering, and audio-video synchronisation rather than relying on a higher-level API&#8217;s opaque buffering. Combined with Storm Streaming Server&#8217;s own low-latency delivery, this allows glass-to-glass latency well below what conventional HLS or DASH playback can offer \u2013 while gracefully falling back on platforms where WebCodecs is unavailable, so that no viewer is ever left without a stream.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For everyone building \u2013 or planning to build \u2013 video streaming services that run inside a web browser, there comes a moment when the standard tools simply aren&#8217;t enough. The &lt;video&gt; tag, Media Source Extensions, WebRTC \u2013 each does its job, but each also hides the codec behind a thick layer of abstraction that you [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":431,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5],"tags":[213,64,212,198,202,217,233,234],"class_list":["post-430","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news","tag-aac","tag-api","tag-av1","tag-h-264","tag-h-265","tag-opus","tag-webcodecs","tag-webrtc-alternative"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v15.9.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>WebCodecs \u2013 Low-Level Media Encoding and Decoding in the Browser - Storm Streaming Blog<\/title>\n<link rel=\"canonical\" href=\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WebCodecs \u2013 Low-Level Media Encoding and Decoding in the Browser - Storm Streaming Blog\" \/>\n<meta property=\"og:description\" content=\"For everyone building \u2013 or planning to build \u2013 video streaming services that run inside a web browser, there comes a moment when the standard tools simply aren&#8217;t enough. The &lt;video&gt; tag, Media Source Extensions, WebRTC \u2013 each does its job, but each also hides the codec behind a thick layer of abstraction that you [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\" \/>\n<meta property=\"og:site_name\" content=\"Storm Streaming Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/stormstreaming\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-30T11:49:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-30T11:49:28+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.stormstreaming.com\/blog\/wp-content\/uploads\/2026\/06\/405386ff-5b4d-4695-bd3c-ff6672453406.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1448\" \/>\n\t<meta property=\"og:image:height\" content=\"1086\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\">\n\t<meta name=\"twitter:data1\" content=\"11 minutes\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/#website\",\"url\":\"https:\/\/www.stormstreaming.com\/blog\/\",\"name\":\"Storm Streaming Blog\",\"description\":\"Streaming case studies, tutorials and product quick-start guides\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/www.stormstreaming.com\/blog\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/www.stormstreaming.com\/blog\/wp-content\/uploads\/2026\/06\/405386ff-5b4d-4695-bd3c-ff6672453406.png\",\"width\":1448,\"height\":1086},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/#webpage\",\"url\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\",\"name\":\"WebCodecs \\u2013 Low-Level Media Encoding and Decoding in the Browser - Storm Streaming Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/#primaryimage\"},\"datePublished\":\"2026-06-30T11:49:27+00:00\",\"dateModified\":\"2026-06-30T11:49:28+00:00\",\"author\":{\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/#\/schema\/person\/080da2bb15e37ea36834821bc1a47af1\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/\",\"url\":\"https:\/\/www.stormstreaming.com\/blog\/\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\",\"url\":\"https:\/\/www.stormstreaming.com\/blog\/webcodecs-low-level-media-encoding-and-decoding-in-the-browser\/\",\"name\":\"WebCodecs \\u2013 Low-Level Media Encoding and Decoding in the Browser\"}}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/#\/schema\/person\/080da2bb15e37ea36834821bc1a47af1\",\"name\":\"Szymon Polok\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/www.stormstreaming.com\/blog\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a7045b5126d6ff6fe28e8e0175f084e957fa52dc5026af9131e9e1f82d22e3e3?s=96&d=mm&r=g\",\"caption\":\"Szymon Polok\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/posts\/430","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/comments?post=430"}],"version-history":[{"count":1,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/posts\/430\/revisions"}],"predecessor-version":[{"id":432,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/posts\/430\/revisions\/432"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/media\/431"}],"wp:attachment":[{"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/media?parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/categories?post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.stormstreaming.com\/blog\/wp-json\/wp\/v2\/tags?post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}