Skip to content

Commit

Permalink
WIP BufferedMediaDataSource rework.
Browse files Browse the repository at this point in the history
  • Loading branch information
colinrtwhite committed Oct 20, 2019
1 parent dadaee6 commit b143800
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,14 @@ class VideoFrameDecoderTest {

@Test
fun specificFrameTime() {
val frameMicros = 32600000L
val result = runBlocking {
decoder.decode(
pool = pool,
source = context.assets.open("video.mp4").source().buffer(),
size = OriginalSize,
options = createOptions(
parameters = Parameters {
set(VIDEO_FRAME_MICROS_KEY, frameMicros, frameMicros.toString())
set(VIDEO_FRAME_MICROS_KEY, 32600000L)
}
)
)
Expand Down
34 changes: 32 additions & 2 deletions coil-video/src/main/java/coil/decode/BufferedMediaDataSource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,48 @@ package coil.decode
import android.media.MediaDataSource
import android.os.Build.VERSION_CODES.M
import androidx.annotation.RequiresApi
import okio.BufferedSink
import okio.BufferedSource
import okio.buffer
import okio.sink
import java.io.File

@RequiresApi(M)
internal class BufferedMediaDataSource(private val source: BufferedSource) : MediaDataSource() {

companion object {
private const val MAX_MEMORY_BUFFER_SIZE: Long = 10 * 1024 * 1024 // 10MB
}

private var fileSize = 0L
private var file: File? = null
private var sink: BufferedSink? = null

override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int {
return source.peek()
val bytesRead = source.peek()
.apply { skip(position) }
.run { read(buffer, offset, size) }

// Avoid buffering large videos into memory by writing to a temp file if
// the memory buffer grows too large.
if (source.buffer.size > MAX_MEMORY_BUFFER_SIZE) {
val fileBuffer = sink ?: run {
val tempFile = createTempFile().also { file = it }
tempFile.sink().buffer().also { sink = it }
}
fileSize += bytesRead.toLong()
source.buffer.copyTo(fileBuffer.buffer, source.buffer.size - bytesRead, bytesRead.toLong())
fileBuffer.emitCompleteSegments()
}

return bytesRead
}

override fun getSize() = -1L

override fun close() = source.close()
override fun close() {
source.close()
sink?.close()
file?.delete()
}
}
2 changes: 1 addition & 1 deletion coil-video/src/main/java/coil/decode/VideoFrameDecoder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class VideoFrameDecoder(private val context: Context) : Decoder {
mediaDataSource = BufferedMediaDataSource(source)
retriever.setDataSource(mediaDataSource)
} else {
// Write the source to disk so it can be read on pre-M.
// Write the source to a temp file so it can be read on pre-M.
tempFile = createTempFile()
source.use { tempFile.sink().use(source::readAll) }
retriever.setDataSource(tempFile.path)
Expand Down

0 comments on commit b143800

Please sign in to comment.