androidx / androidx/media

ExoPlayer skips several seconds of mp4 randomly

Open
#786 2 comments 3 reactions 1 assignee View on GitHub

@rohitjoins is already working on this.

Since Nov 10, 2023.

bug needs triage
Dominant language
Java
Stars
3k
Forks
955
Avg merge
12d 14h
Merged PRs (30d)
2

Description

Version

Media3 1.1.1

More version details

media3-exoplayer = "1.1.1" (and at least 2 previous)

Please see the minimal reproduction sample project https://github.com/samoylenkodmitry/ExoPlayer-bug-reproduce

Devices that reproduce the issue

Android emulator API 30, x86 or x86_64 ABI, Android 11.0 (Google APIs or Google Play)

Devices that do not reproduce the issue

Samsung Galaxy SM-7970, Android 13

Reproducible in the demo app?

Not tested

Reproduction steps

I wrote a sample minimal implementation project https://github.com/samoylenkodmitry/ExoPlayer-bug-reproduce that includes emulation of a server side hosting of mp4 on a localhost

Steps to reproduce

  1. Create an Android emulator API 30, x86 or x86_64 ABI, Android 11.0 (Google APIs or Google Play)
  2. Run the app on the emulator
  3. Close the app after playback finishes
  4. Run the app again (repeat if necessary)

Expected result

Video starts playing from the beginning and plays to the end.

Actual result

Video starts playing from the beginning and skips some frames at some time in the middle of the video.

Notes

  • The bug is not reproducible on any other emulator (API 28, 29, 31, 32, 33, 34) or hard to reproduce
  • The bug is not reproducible on a physical device (Samsung Galaxy SM-7970, Android 13), or hard to reproduce
  • The bug is not reproducible when playing from a local asset, or when there is no network delay.
  • The bug reproduced while playing a single mp4 and also while playing a dash stream consisting of an mp4 chunks.

Video

To reproduce the bug, use the the script to generate a video python gen_mp4.py (in app/src/main/assets/gen).
The script requires ffmpeg to be installed.
Video consists of several chunks concatenated together. Each chunk is a 3 second video with a random color.

Code to reproduce the bug

Dependencies
[versions]
agp = "8.3.0-alpha11"
kotlin = "1.9.0"
core-ktx = "1.12.0"
media3-common = "1.1.1"
media3-exoplayer = "1.1.1"
media3-ui = "1.1.1"
media3-exoplayer-dash = "1.1.1"
nanohttpd = "2.3.1"

[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
androidx-media3-common = { group = "androidx.media3", name = "media3-common", version.ref = "media3-common" }
androidx-media3-exoplayer = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "media3-exoplayer" }
androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3-ui" }
androidx-media3-dash = { group = "androidx.media3", name = "media3-exoplayer-dash", version.ref = "media3-exoplayer-dash" }
nanohttpd = { group = "org.nanohttpd", name = "nanohttpd", version.ref = "nanohttpd" }

[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

Activity
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.media3.common.MediaItem
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView
import fi.iki.elonen.NanoHTTPD
import java.io.IOException
import java.lang.Thread.sleep
import java.util.concurrent.atomic.AtomicLong

@UnstableApi
class MainActivity : AppCompatActivity() {

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(PlayerView(this).apply {
			controllerShowTimeoutMs = 100_000
			showController()
			player = ExoPlayer.Builder(context).build().apply {
				setMediaItem(MediaItem.fromUri("http://127.0.0.1:8080/gen/video.mp4"))
				prepare()
				playWhenReady = true
				val prev = AtomicLong()
				post(object : Runnable {
					override fun run() {
						val pos = contentPosition
						val delta = pos - prev.getAndSet(pos)
						if (delta > 500L) AlertDialog.Builder(context).setMessage("$delta ms skipped, pos=$pos").show()
						postDelayed(this, 100)
					}
				})
			}
		})
	}

	private val server = object : NanoHTTPD(8080) {

		override fun serve(session: IHTTPSession): Response = try {
			sleep(1337)
			newChunkedResponse(Response.Status.OK, "video/mp4", assets.open(session.uri.drop(1)))
		} catch (e: IOException) {
			newFixedLengthResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "File not found")
		}
	}.apply { start() }
}
Expected result

Does not skip any second of video

Actual result

Skips about 2 to 3 seconds randomly

Media

Media file is a generated one in the sample project: https://github.com/samoylenkodmitry/ExoPlayer-bug-reproduce/raw/main/app/src/main/assets/gen/video.mp4

Please see the minimal reproduction sample project https://github.com/samoylenkodmitry/ExoPlayer-bug-reproduce

Bug Report
  • You will email the zip file produced by adb bugreport to android-media-github@google.com after filing this issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.