diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
-## 0.0.1.0
+## 0.1.1.0
+
+- Improve the 'feedReader' implementation to ensure the initialization frame is fully read.
+- 'feedReader' now returns an error when called with an empty buffer.
+
+## 0.1.0.0
 
 - Initial version
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -1,12 +1,13 @@
 module Main (main) where
 
-import Codec.EBML qualified as EBML
 import Data.ByteString qualified as BS
 import Data.Text qualified as Text
 import Data.Text.IO qualified
 import System.Environment (getArgs)
 import System.IO (Handle, IOMode (ReadMode), stdin, withBinaryFile)
 
+import Codec.EBML qualified as EBML
+
 main :: IO ()
 main =
     getArgs >>= \case
@@ -25,8 +26,9 @@
     putStr "Reading 2048 bytes... "
     buf <- BS.hGet handl 2048
     case EBML.feedReader buf ir of
-        Left e -> error (Text.unpack e)
-        Right (Nothing, _) | buf == "" -> putStrLn "Done!"
+        Left e
+            | buf == "" -> putStrLn "Done!"
+            | otherwise -> error (Text.unpack e)
         Right (mFrame, newIR) -> do
             case mFrame of
                 Nothing -> putStrLn "Need more data"
diff --git a/ebml.cabal b/ebml.cabal
--- a/ebml.cabal
+++ b/ebml.cabal
@@ -5,11 +5,15 @@
 -- see: https://github.com/sol/hpack
 
 name:           ebml
-version:        0.1.0.0
+version:        0.1.1.0
 synopsis:       A pure EBML parser
 description:    Pure decoder for the Extensible Binary Meta Language (EBML) format.
                 .
                 Use this library to parse mkv/webm file or split a webm stream segments.
+                .
+                Checkout a motivating use-case presented in this blog post: [Broadcasting a WebM stream using MSE](https://tristancacqueray.github.io/blog/broadcasting-webm).
+                .
+                Read the haskell-ebml demo app for simple usage: [Main.hs](https://github.com/TristanCacqueray/haskell-ebml/blob/main/app/Main.hs).
 category:       Codec
 homepage:       https://github.com/TristanCacqueray/haskell-ebml#readme
 bug-reports:    https://github.com/TristanCacqueray/haskell-ebml/issues
@@ -31,9 +35,9 @@
   exposed-modules:
       Codec.EBML
   other-modules:
+      Codec.EBML.Decoder
       Codec.EBML.Element
-      Codec.EBML.Get
-      Codec.EBML.Header
+      Codec.EBML.Matroska
       Codec.EBML.Pretty
       Codec.EBML.Schema
       Codec.EBML.Stream
diff --git a/src/Codec/EBML.hs b/src/Codec/EBML.hs
--- a/src/Codec/EBML.hs
+++ b/src/Codec/EBML.hs
@@ -65,9 +65,9 @@
 import Data.Text (Text)
 import Data.Text qualified as Text
 
+import Codec.EBML.Decoder
 import Codec.EBML.Element
-import Codec.EBML.Get
-import Codec.EBML.Header
+import Codec.EBML.Matroska
 import Codec.EBML.Pretty
 import Codec.EBML.Schema
 import Codec.EBML.Stream
diff --git a/src/Codec/EBML/Decoder.hs b/src/Codec/EBML/Decoder.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/EBML/Decoder.hs
@@ -0,0 +1,105 @@
+module Codec.EBML.Decoder where
+
+import Data.Binary.Get (Get, bytesRead, getByteString, isEmpty, lookAheadM)
+import Data.Text.Encoding (decodeUtf8)
+import Data.Word (Word64)
+
+import Codec.EBML.Element
+import Codec.EBML.Schema
+import Data.Bits (Bits)
+
+getElement :: EBMLSchemas -> Get EBMLElement
+getElement schemas = do
+    elth <- getElementHeader
+    getElementValue schemas elth
+
+getElementValue :: EBMLSchemas -> EBMLElementHeader -> Get EBMLElement
+getElementValue schemas elth = do
+    -- here is a good place to add traceM debug
+    val <- case lookupSchema elth.eid schemas of
+        Nothing -> getBinary elth
+        Just schema -> schema.decode schemas elth
+    pure $ EBMLElement elth val
+
+getDocument :: EBMLSchemas -> Get EBMLDocument
+getDocument schemas = EBMLDocument <$> go
+  where
+    go = do
+        empty <- isEmpty
+        if empty
+            then pure []
+            else do
+                elt <- getElement schemas
+                elts <- go
+                pure (elt : elts)
+
+getBinary :: EBMLElementHeader -> Get EBMLValue
+getBinary elth = case elth.size of
+    Nothing -> fail "Invalid binary header size"
+    Just sz -> EBMLBinary <$> getByteString (fromIntegral sz)
+
+getText :: EBMLElementHeader -> Get EBMLValue
+getText elth = case elth.size of
+    Nothing -> fail "Invalid text header size"
+    Just sz -> EBMLText . decodeUtf8 <$> getByteString (fromIntegral sz)
+
+getUnsignedInteger :: EBMLElementHeader -> Get EBMLValue
+getUnsignedInteger elth = EBMLUnsignedInteger <$> getInt elth.size
+
+getInteger :: EBMLElementHeader -> Get EBMLValue
+getInteger elth = EBMLUnsignedInteger <$> getInt elth.size
+
+getInt :: (Bits a, Integral a) => Maybe Word64 -> Get a
+getInt size = getVar sz 0
+  where
+    -- TODO: check the value is in the [0..8] range
+    sz = maybe 0 fromIntegral size
+
+getRoot :: EBMLSchemas -> EBMLElementHeader -> Get EBMLValue
+getRoot schemas elth = case elth.size of
+    Nothing -> EBMLRoot <$> getUntil schemas elth.eid
+    Just sz -> getRootFixed schemas sz
+
+getUntil :: EBMLSchemas -> EBMLID -> Get [EBMLElement]
+getUntil schemas eid = go
+  where
+    getChild :: Get (Maybe EBMLElement)
+    getChild = do
+        -- This is not exactly correct. The rfc-8794 spec (chapter 6.2) says we should decode until
+        -- any valid parent or global element. Because the EBMLSchema doesn't yet contain this information,
+        -- and because in practice such unknown-sized element are segment/cluster, we simply decode until
+        -- we find a matching element.
+        elth <- getElementHeader
+        if elth.eid == eid
+            then pure Nothing
+            else Just <$> getElementValue schemas elth
+
+    go = do
+        empty <- isEmpty
+        if empty
+            then pure []
+            else goGet
+
+    goGet =
+        lookAheadM getChild >>= \case
+            Just elt -> do
+                elts <- go
+                pure (elt : elts)
+            Nothing -> pure []
+
+getRootFixed :: EBMLSchemas -> Word64 -> Get EBMLValue
+getRootFixed schemas sz = do
+    startPosition <- bytesRead
+    let maxPosition = startPosition + fromIntegral sz
+        getChilds = do
+            currentPosition <- bytesRead
+            if
+                    | currentPosition > maxPosition ->
+                        fail $ "Element decode position " <> show currentPosition <> " exceed parent size " <> show sz
+                    | currentPosition == maxPosition ->
+                        pure []
+                    | otherwise -> do
+                        elt <- getElement schemas
+                        elts <- getChilds
+                        pure (elt : elts)
+    EBMLRoot <$> getChilds
diff --git a/src/Codec/EBML/Get.hs b/src/Codec/EBML/Get.hs
deleted file mode 100644
--- a/src/Codec/EBML/Get.hs
+++ /dev/null
@@ -1,105 +0,0 @@
-module Codec.EBML.Get where
-
-import Data.Binary.Get (Get, bytesRead, getByteString, isEmpty, lookAheadM)
-import Data.Text.Encoding (decodeUtf8)
-import Data.Word (Word64)
-
-import Codec.EBML.Element
-import Codec.EBML.Schema
-import Data.Bits (Bits)
-
-getElement :: EBMLSchemas -> Get EBMLElement
-getElement schemas = do
-    elth <- getElementHeader
-    getElementValue schemas elth
-
-getElementValue :: EBMLSchemas -> EBMLElementHeader -> Get EBMLElement
-getElementValue schemas elth = do
-    -- here is a good place to add traceM debug
-    val <- case lookupSchema elth.eid schemas of
-        Nothing -> getBinary elth
-        Just schema -> schema.decode schemas elth
-    pure $ EBMLElement elth val
-
-getDocument :: EBMLSchemas -> Get EBMLDocument
-getDocument schemas = EBMLDocument <$> go
-  where
-    go = do
-        empty <- isEmpty
-        if empty
-            then pure []
-            else do
-                elt <- getElement schemas
-                elts <- go
-                pure (elt : elts)
-
-getBinary :: EBMLElementHeader -> Get EBMLValue
-getBinary elth = case elth.size of
-    Nothing -> fail "Invalid binary header size"
-    Just sz -> EBMLBinary <$> getByteString (fromIntegral sz)
-
-getText :: EBMLElementHeader -> Get EBMLValue
-getText elth = case elth.size of
-    Nothing -> fail "Invalid text header size"
-    Just sz -> EBMLText . decodeUtf8 <$> getByteString (fromIntegral sz)
-
-getUnsignedInteger :: EBMLElementHeader -> Get EBMLValue
-getUnsignedInteger elth = EBMLUnsignedInteger <$> getInt elth.size
-
-getInteger :: EBMLElementHeader -> Get EBMLValue
-getInteger elth = EBMLUnsignedInteger <$> getInt elth.size
-
-getInt :: (Bits a, Integral a) => Maybe Word64 -> Get a
-getInt size = getVar sz 0
-  where
-    -- TODO: check the value is in the [0..8] range
-    sz = maybe 0 fromIntegral size
-
-getRoot :: EBMLSchemas -> EBMLElementHeader -> Get EBMLValue
-getRoot schemas elth = case elth.size of
-    Nothing -> EBMLRoot <$> getUntil schemas elth.eid
-    Just sz -> getRootFixed schemas sz
-
-getUntil :: EBMLSchemas -> EBMLID -> Get [EBMLElement]
-getUntil schemas eid = go
-  where
-    getChild :: Get (Maybe EBMLElement)
-    getChild = do
-        -- This is not exactly correct. The rfc-8794 spec (chapter 6.2) says we should decode until
-        -- any valid parent or global element. Because the EBMLSchema doesn't yet contain this information,
-        -- and because in practice such unknown-sized element are segment/cluster, we simply decode until
-        -- we find a matching element.
-        elth <- getElementHeader
-        if elth.eid == eid
-            then pure Nothing
-            else Just <$> getElementValue schemas elth
-
-    go = do
-        empty <- isEmpty
-        if empty
-            then pure []
-            else goGet
-
-    goGet =
-        lookAheadM getChild >>= \case
-            Just elt -> do
-                elts <- go
-                pure (elt : elts)
-            Nothing -> pure []
-
-getRootFixed :: EBMLSchemas -> Word64 -> Get EBMLValue
-getRootFixed schemas sz = do
-    startPosition <- bytesRead
-    let maxPosition = startPosition + fromIntegral sz
-        getChilds = do
-            currentPosition <- bytesRead
-            if
-                    | currentPosition > maxPosition ->
-                        fail $ "Element decode position " <> show currentPosition <> " exceed parent size " <> show sz
-                    | currentPosition == maxPosition ->
-                        pure []
-                    | otherwise -> do
-                        elt <- getElement schemas
-                        elts <- getChilds
-                        pure (elt : elts)
-    EBMLRoot <$> getChilds
diff --git a/src/Codec/EBML/Header.hs b/src/Codec/EBML/Header.hs
deleted file mode 100644
--- a/src/Codec/EBML/Header.hs
+++ /dev/null
@@ -1,33 +0,0 @@
--- | Header schema definition, see: https://github.com/ietf-wg-cellar/ebml-specification/blob/master/specification.markdown#ebml-header-elements
-module Codec.EBML.Header where
-
-import Data.Text (Text)
-
-import Codec.EBML.Element
-import Codec.EBML.Get
-import Codec.EBML.Schema
-
-schemaHeader :: [EBMLSchema]
-schemaHeader =
-    [ EBMLSchema "EBML" 0x1A45DFA3 getRoot
-    , EBMLSchema "DocType" 0x4282 (const getText)
-    , EBMLSchema "Segment" 0x18538067 getRoot
-    , EBMLSchema "Info" 0x1549A966 getRoot
-    , EBMLSchema "Cluster" 0x1F43B675 getRoot
-    ]
-        <> map fromUints uints
-
-fromUints :: (Text, EBMLID) -> EBMLSchema
-fromUints (n, i) = EBMLSchema n i (const getUnsignedInteger)
-
-uints :: [(Text, EBMLID)]
-uints =
-    [ ("EBMLVersion", 0x4286)
-    , ("EBMLReadVersion", 0x42F7)
-    , ("EBMLMaxIDLength", 0x42F2)
-    , ("EBMLMaxSizeLength", 0x42F3)
-    , ("DocTypeVersion", 0x4287)
-    , ("DocTypeReadVersion", 0x4285)
-    , ("TimestampScale", 0x2AD7B1)
-    , ("Timestamp", 0xE7)
-    ]
diff --git a/src/Codec/EBML/Matroska.hs b/src/Codec/EBML/Matroska.hs
new file mode 100644
--- /dev/null
+++ b/src/Codec/EBML/Matroska.hs
@@ -0,0 +1,32 @@
+module Codec.EBML.Matroska where
+
+import Data.Text (Text)
+
+import Codec.EBML.Decoder
+import Codec.EBML.Element
+import Codec.EBML.Schema
+
+schemaHeader :: [EBMLSchema]
+schemaHeader =
+    [ EBMLSchema "EBML" 0x1A45DFA3 getRoot
+    , EBMLSchema "DocType" 0x4282 (const getText)
+    , EBMLSchema "Segment" 0x18538067 getRoot
+    , EBMLSchema "Info" 0x1549A966 getRoot
+    , EBMLSchema "Cluster" 0x1F43B675 getRoot
+    ]
+        <> map fromUints uints
+
+fromUints :: (Text, EBMLID) -> EBMLSchema
+fromUints (n, i) = EBMLSchema n i (const getUnsignedInteger)
+
+uints :: [(Text, EBMLID)]
+uints =
+    [ ("EBMLVersion", 0x4286)
+    , ("EBMLReadVersion", 0x42F7)
+    , ("EBMLMaxIDLength", 0x42F2)
+    , ("EBMLMaxSizeLength", 0x42F3)
+    , ("DocTypeVersion", 0x4287)
+    , ("DocTypeReadVersion", 0x4285)
+    , ("TimestampScale", 0x2AD7B1)
+    , ("Timestamp", 0xE7)
+    ]
diff --git a/src/Codec/EBML/Stream.hs b/src/Codec/EBML/Stream.hs
--- a/src/Codec/EBML/Stream.hs
+++ b/src/Codec/EBML/Stream.hs
@@ -1,14 +1,40 @@
+{- | This module contains the incremental decoder logic to process a continuous stream.
+
+Here is an example stream layout:
+
+> | EBML | SIZE | ELT | ELTA | ELT | ... | SEGMENT | USIZE | ELT | ELTB | ... |
+> | CLUSTER | USIZE | ELT | ELTC   | ... | CLUSTER | USIZE | ELT | ELT  | ... |
+
+There are two difficulties:
+
+- The element are not aligned, a segment id can start at position 15.
+- Unknown sized element, such as segment and cluster, need to use a look-ahead to ensure it is completed.
+
+Here are the main scenarios:
+
+- The initial buffers does not contains the begining of a media segment.
+  In that case we need to accumulate the data to provide the complete initialization segments.
+
+- The buffer contains multiple segments. In that case we need to find the last one, e.g. the most recent.
+
+- The buffer ends on the middle of the cluster id, e.g. "...\x1f\x43".
+  In that case we need to wait for the next buffer to confirm a new media segment exists.
+  We also need to returns the end of the previous buffer, so that the media segment does start with "\x1f\x43...".
+  This is somehow already managed by the 'Data.Binary.Get.runGetIncremental'.
+
+Checkout the 'testIncrementalLookahead' case in the test/Spec.hs module that validates these scenarios.
+-}
 module Codec.EBML.Stream (StreamReader, newStreamReader, StreamFrame (..), feedReader) where
 
-import Control.Monad (void, when)
+import Control.Monad (when)
 import Data.Binary.Get qualified as Get
 import Data.ByteString qualified as BS
 import Data.Text (Text)
 import Data.Text qualified as Text
 
+import Codec.EBML.Decoder
 import Codec.EBML.Element
-import Codec.EBML.Get
-import Codec.EBML.Header
+import Codec.EBML.Matroska
 import Codec.EBML.Schema
 import Codec.EBML.WebM qualified as WebM
 
@@ -22,12 +48,8 @@
 
 -- | Create a stream reader with 'newStreamReader', and decode media segments with 'feedReader'.
 data StreamReader = StreamReader
-    { acc :: [BS.ByteString]
-    -- ^ Accumulate data in case the header is not completed in the first buffer.
-    , consumed :: Int
-    -- ^ Keep track of the decoder position accross multiple buffers.
-    , header :: Maybe BS.ByteString
-    -- ^ The stream initialization segments.
+    { header :: Either (Int, [BS.ByteString]) BS.ByteString
+    -- ^ The stream initialization segments, either an accumulator (read bytes, list of buffer), either the full segments.
     , decoder :: Get.Decoder ()
     -- ^ The current decoder.
     }
@@ -35,6 +57,23 @@
 streamSchema :: EBMLSchemas
 streamSchema = compileSchemas schemaHeader
 
+-- | Read elements until the first cluster eid.
+getUntilNextCluster :: Get.Get [EBMLElement]
+getUntilNextCluster =
+    Get.lookAheadM getNonCluster >>= \case
+        Just elt -> do
+            elts <- getUntilNextCluster
+            pure (elt : elts)
+        Nothing -> pure []
+  where
+    getNonCluster = do
+        eid <- getElementID
+        if eid == 0x1F43B675
+            then pure Nothing
+            else do
+                elth <- EBMLElementHeader eid <$> getMaybeDataSize
+                Just <$> getElementValue streamSchema elth
+
 -- | Read the initialization frame.
 getInitialization :: Get.Get ()
 getInitialization = do
@@ -47,7 +86,7 @@
     segmentHead <- getElementHeader
     when (segmentHead.eid /= 0x18538067) do
         fail $ "Invalid segment: " <> show segmentHead
-    elts <- getUntil streamSchema 0x1F43B675
+    elts <- getUntilNextCluster
     case WebM.decodeSegment elts of
         Right _webmDocument -> pure ()
         Left err -> fail (Text.unpack err)
@@ -58,66 +97,41 @@
     clusterHead <- getElementHeader
     when (clusterHead.eid /= 0x1F43B675) do
         fail $ "Invalid cluster: " <> show clusterHead
-    getClusterBody
-
-getClusterBody :: Get.Get ()
-getClusterBody = do
-    elts <- getUntil streamSchema 0x1F43B675
+    elts <- getUntilNextCluster
     case elts of
         (elt : _) | elt.header.eid == 0xE7 -> pure ()
         _ -> fail "Cluster first element is not a timestamp"
 
-getClusterRemaining :: Get.Get ()
-getClusterRemaining = do
-    elth <- getElementHeader
-    if elth.eid == 0x1F43B675
-        then -- This is in fact a new cluster, get its body
-            getClusterBody
-        else -- This is a cluster left-over, let's keep on reading until a new start
-            void (getUntil streamSchema 0x1F43B675)
-
 -- | Initialize a stream reader.
 newStreamReader :: StreamReader
-newStreamReader = StreamReader [] 0 Nothing (Get.runGetIncremental getInitialization)
+newStreamReader = StreamReader (Left (0, [])) (Get.runGetIncremental getInitialization)
 
 -- | Feed data into a stream reader. Returns either an error, or maybe a new 'StreamFrame' and an updated StreamReader.
 feedReader :: BS.ByteString -> StreamReader -> Either Text (Maybe StreamFrame, StreamReader)
 feedReader = go Nothing
   where
     -- This is the end
-    go Nothing "" sr = case Get.pushEndOfInput sr.decoder of
-        Get.Fail _ _ s -> Left (Text.pack s)
-        Get.Partial _ -> Left "Missing data"
-        Get.Done "" _ _ -> Right (Nothing, sr)
-        Get.Done{} -> Left "Left-over data"
+    go Nothing "" _ = Left "empty buffer"
     -- Feed the decoder
     go mFrame bs sr =
         case Get.pushChunk sr.decoder bs of
             Get.Fail _ _ s -> Left (Text.pack s)
-            newDecoder@(Get.Partial _) ->
-                let newAcc = case sr.header of
-                        Nothing -> bs : sr.acc
-                        -- We don't need to accumulate data once the header is known.
-                        Just _ -> []
-                    newSR = StreamReader newAcc (sr.consumed + BS.length bs) sr.header newDecoder
-                 in Right (mFrame, newSR)
-            Get.Done leftover consumed _
-                | BS.null leftover ->
-                    -- We might have ended on a in-cluster element, use the remainingDecoder next time
-                    Right (mFrame, newIR remainingDecoder)
-                | otherwise ->
-                    -- There might be a new frame after, keep on decoding
-                    go newFrame leftover (newIR segmentDecoder)
+            -- More data is needed.
+            newDecoder@(Get.Partial _) -> Right (mFrame, newSR)
               where
+                -- Accumulate the buffer for the initialization segments if needed.
+                newHeader = case sr.header of
+                    Left (consumed, acc) -> Left (consumed + BS.length bs, bs : acc)
+                    Right _ -> sr.header
+                newSR = StreamReader newHeader newDecoder
+            Get.Done leftover consumed _ -> go newFrame leftover newSR
+              where
                 -- The header is either the one already parsed, or the current complete decoded buffer.
                 newHeader = case sr.header of
-                    Just header -> header
-                    Nothing ->
-                        let currentPos = fromIntegral consumed - sr.consumed
-                         in mconcat $ reverse (BS.take currentPos bs : sr.acc)
+                    Left (prevConsumed, acc) ->
+                        let currentPos = fromIntegral consumed - prevConsumed
+                         in mconcat $ reverse (BS.take currentPos bs : acc)
+                    Right header -> header
                 -- The new frame starts after what was decoded.
                 newFrame = Just (StreamFrame newHeader leftover)
-                newIR = StreamReader [] 0 (Just newHeader)
-
-    remainingDecoder = Get.runGetIncremental getClusterRemaining
-    segmentDecoder = Get.runGetIncremental getCluster
+                newSR = StreamReader (Right newHeader) (Get.runGetIncremental getCluster)
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -39,6 +39,7 @@
               , "0010 0000 0000 0000 0000 0010"
               , "0001 0000 0000 0000 0000 0000 0000 0010"
               ]
+        , testCase "Incremental lookahead" (pure ())
         ]
 
 testVarInts :: String -> BS.ByteString
@@ -60,6 +61,7 @@
         "Integration tests"
         [ testGroup "sample" (decodeFile sampleFile 53054906 4458 49 0 2794)
         , testGroup "stream" (decodeFile streamFile 3499 260 6 6 1006)
+        , testCase "Incremental lookahead" testIncrementalLookahead
         ]
   where
     decodeFile bs size headerSize clusterCount clusterTs1 clusterTs2
@@ -81,10 +83,10 @@
                 let go buf sr acc =
                         let (cur, next) = BS.splitAt 256 buf
                          in case EBML.feedReader cur sr of
-                                Left e -> error (Text.unpack e)
-                                Right (mFrame, nextSR)
-                                    | cur == "" -> reverse newAcc
-                                    | otherwise -> go next nextSR newAcc
+                                Left e
+                                    | cur == "" -> reverse acc
+                                    | otherwise -> error (Text.unpack e)
+                                Right (mFrame, nextSR) -> go next nextSR newAcc
                                   where
                                     newAcc = maybe acc (: acc) mFrame
                     frames = go bs EBML.newStreamReader []
@@ -95,3 +97,65 @@
                 forM_ frames $ \frame -> do
                     BS.take 4 frame.media @?= "\x1f\x43\xb6\x75"
             ]
+
+    testIncrementalLookahead = do
+        let eltA = 0x10
+            segment = 0x2b
+            eltB = 0x43
+            cluster1 = 0x104
+            eltC = 0x113
+            cluster2 = 0x36b
+        -- validate the addresses
+        BS.take 4 (BS.drop segment streamFile) @?= "\x18\x53\x80\x67"
+        BS.take 4 (BS.drop cluster1 streamFile) @?= "\x1f\x43\xb6\x75"
+        BS.take 4 (BS.drop cluster2 streamFile) @?= "\x1f\x43\xb6\x75"
+        let getIDat pos =
+                let elth = runGet EBML.getElementHeader (BS.fromStrict $ BS.drop pos streamFile)
+                 in elth.eid
+        getIDat eltA @?= EBML.EBMLID 0x42f7
+        getIDat eltB @?= EBML.EBMLID 0x1549a966
+        getIDat eltC @?= EBML.EBMLID 0xa3
+
+        -- validate the first two media cluster
+        let c1 = "\x1f\x43\xb6\x75\x01\xff\xff\xff\xff\xff\xff\xff\xe7\x81\x06\xa3"
+            c2 = "\x1f\x43\xb6\x75\x01\xff\xff\xff\xff\xff\xff\xff\xe7\x82\x03\xee\xa3"
+        BS.drop cluster1 streamFile `checkPrefix` c1
+        BS.drop cluster2 streamFile `checkPrefix` c2
+
+        -- Test stream reader with pathological buffer size
+        let runIncrementalTest size = testIncremental size EBML.newStreamReader streamFile [c1, c2]
+        -- Make sure the first two cluster are covered.
+        forM_ [1, 2, 7] runIncrementalTest
+        forM_ [eltA, segment, eltB, cluster1, eltC] $ \pos -> do
+            runIncrementalTest pos
+            forM_ [15, 8, 7, 4, 2, 1] $ \offset -> do
+                runIncrementalTest (pos - offset)
+                runIncrementalTest (pos + offset)
+
+        -- Until c2 can be parsed, the latest media segment must be c1
+        testIncremental cluster2 EBML.newStreamReader streamFile [c1]
+        forM_ [1, 2, 3] $ \offset -> do
+            testIncremental (cluster2 - offset) EBML.newStreamReader streamFile [c1]
+            testIncremental (cluster2 + offset) EBML.newStreamReader streamFile [c1]
+
+        -- The buffer contains both clusters, the latest media segment must be c2
+        forM_ [4, 5, 8, 16, 24] $ \offset -> do
+            testIncremental (cluster2 + offset) EBML.newStreamReader streamFile [c2]
+
+checkPrefix :: HasCallStack => BS.ByteString -> BS.ByteString -> Assertion
+checkPrefix b1 b2 = BS.take (BS.length b2) b1 @?= BS.take (BS.length b1) b2
+
+testIncremental :: HasCallStack => Int -> EBML.StreamReader -> BS.ByteString -> [BS.ByteString] -> IO ()
+testIncremental _ _ _ [] = pure ()
+testIncremental _ _ "" _ = error "Reached the end of file"
+testIncremental size sr buf clusters@(x : xs) = do
+    let (chunk, nextBuf) = BS.splitAt size buf
+    case EBML.feedReader chunk sr of
+        Left e -> error (Text.unpack e)
+        Right (mFrame, nextSR) -> do
+            nextClusters <- case mFrame of
+                Nothing -> pure clusters
+                Just f -> do
+                    (f.media <> nextBuf) `checkPrefix` x
+                    pure xs
+            testIncremental size nextSR nextBuf nextClusters
