       time += entry.sampleDelta * entry.sampleCount
     return time / mdhdBox.timescale
 
-  getSampleAtSeconds: (sec) ->
+  # Returns a sample which comes exactly at or immediately after
+  # the specified time (in seconds). If isExclusive=true, it excludes
+  # a sample whose timestamp is equal to the specified time.
+  # If there is no matching sample, this method returns null.
+  getSampleAfterSeconds: (sec, isExclusive=false) ->
     timescale = @findParent('mdia').find('mdhd').timescale
-
     remainingTime = sec * timescale
     sampleNumber = 1
     totalTime = 0
     for entry in @entries
-      samples = Math.ceil(remainingTime / entry.sampleDelta)
-      if samples <= entry.sampleCount
-        totalTime += samples * entry.sampleDelta
+      numSamples = Math.ceil(remainingTime / entry.sampleDelta)
+      if numSamples <= entry.sampleCount
+        totalTime += numSamples * entry.sampleDelta
+        totalSeconds = totalTime / timescale
+        if isExclusive and (totalSeconds <= sec)
+          numSamples++
+          totalTime += entry.sampleDelta
+          totalSeconds = totalTime / timescale
         return {
-          sampleNumber: sampleNumber + samples
+          sampleNumber: sampleNumber + numSamples
+          time: totalTime
+          seconds: totalSeconds
+        }
+      sampleNumber += entry.sampleCount
+      entryDuration = entry.sampleDelta * entry.sampleCount
+      totalTime += entryDuration
+      remainingTime -= entryDuration
+
+    # EOF
+    return null
+
+  # Returns a sample which represents the data at the specified time
+  # (in seconds). If there is no sample at the specified time, this
+  # method returns null.
+  getSampleAtSeconds: (sec) ->
+    timescale = @findParent('mdia').find('mdhd').timescale
+    remainingTime = sec * timescale
+    sampleNumber = 1
+    totalTime = 0
+    for entry in @entries
+      sampleIndexInChunk = Math.floor(remainingTime / entry.sampleDelta)
+      if sampleIndexInChunk < entry.sampleCount
+        totalTime += sampleIndexInChunk * entry.sampleDelta
+        return {
+          sampleNumber: sampleNumber + sampleIndexInChunk
           time: totalTime
           seconds: totalTime / timescale
         }
-      sampleNumber += samples
-      totalTime += samples * entry.sampleDelta
-      remainingTime -= entry.sampleDelta * entry.sampleCount
+      sampleNumber += entry.sampleCount
+      entryDuration = entry.sampleDelta * entry.sampleCount
+      totalTime += entryDuration
+      remainingTime -= entryDuration
+
     # EOF
     return null
 
   # Returns a decoding time for the given sample number.
   # The sample number starts at 1.
   getDecodingTime: (sampleNumber) ->
-    mdhdBox = @findParent('mdia').find('mdhd')
+    trakBox = @findParent('trak')
+    elstBox = trakBox.child('edts')?.child('elst')
+    mdhdBox = trakBox.child('mdia').child('mdhd')
 
     sampleNumber--
-    time = 0
+    if elstBox?
+      time = elstBox.getEmptyDuration()
+    else
+      time = 0
     for entry in @entries
       if sampleNumber > entry.sampleCount
         time += entry.sampleDelta * entry.sampleCount

    #       elst <- self
    mvhdBox = @findParent('moov').find('mvhd')

    entryCount = bits.read_uint32()
    @entries = []
    for i in [1..entryCount]

    # Get next sample number
    stblBox = @videoTrakBox.child('mdia').child('minf').child('stbl')
    sttsBox = stblBox.child('stts') # TimeToSampleBox
    videoSample = sttsBox.getSampleAfterSeconds endSeconds
    if videoSample?
      videoSampleNumber = videoSample.sampleNumber
    else
