Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4K standardization #139

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions library/src/main/java/com/mux/video/upload/api/MuxUpload.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.net.Uri
import androidx.annotation.MainThread
import com.mux.video.upload.MuxUploadSdk
import com.mux.video.upload.api.MuxUpload.Builder
import com.mux.video.upload.internal.InputStandardization
import com.mux.video.upload.internal.MaximumResolution
import com.mux.video.upload.internal.UploadInfo
import com.mux.video.upload.internal.update
import kotlinx.coroutines.*
Expand Down Expand Up @@ -330,7 +332,6 @@ class MuxUpload private constructor(
inputFile = videoFile,
chunkSize = 8 * 1024 * 1024, // GCP recommends at least 8M chunk size
retriesPerChunk = 3,
standardizationRequested = true,
optOut = false,
uploadJob = null,
statusFlow = null,
Expand All @@ -344,13 +345,23 @@ class MuxUpload private constructor(
return this
}

/**
* If requested, the Upload SDK will try to standardize the input file in order to optimize it
* for use with Mux Video
*/
@Suppress("unused")
fun standardizationRequested(enabled: Boolean, maxResolution: MaximumResolution): Builder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the parameter name be updated to requested here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add in a separate PR, so we can get this merged.

uploadInfo.update(InputStandardization(enabled, maxResolution))
return this
}

/**
* If requested, the Upload SDK will try to standardize the input file in order to optimize it
* for use with Mux Video
*/
@Suppress("unused")
fun standardizationRequested(enabled: Boolean): Builder {
uploadInfo.update(standardizationRequested = enabled)
uploadInfo.update(InputStandardization(enabled))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here as well, should this be updated to requested?

return this
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ internal class TranscoderContext private constructor(
) {
private val logger get() = MuxUploadSdk.logger

val MAX_ALLOWED_BITRATE = 8000000
val MAX_ALLOWED_FRAMERATE = 120;
val MAX_ALLOWED_WIDTH = 1920
val MAX_ALLOWED_HEIGTH = 1080
val MAX_ALLOWED_BITRATE: Int
val MAX_ALLOWED_FRAMERATE = 120
val MIN_ALLOWED_FRAMERATE = 5
val MAX_ALLOWED_WIDTH: Int
val MAX_ALLOWED_HEIGTH: Int
val OPTIMAL_FRAMERATE = 30
val I_FRAME_INTERVAL = 5 // in seconds
val MAX_ALLOWED_I_FRAME_INTERVAL: Int
val OUTPUT_SAMPLERATE = 48000
val OUTPUT_NUMBER_OF_CHANNELS = 2
val OUTPUT_AUDIO_BITRATE = 96000
Expand All @@ -60,6 +62,7 @@ internal class TranscoderContext private constructor(
private var targetedWidth = -1
private var targetedHeight = -1
private var targetedFramerate = -1
private var targetedIFrameInterval = -1
private var targetedBitrate = -1
private var scaledSizeYuv: Nv12Buffer? = null
private var resampleCreated = false
Expand Down Expand Up @@ -100,6 +103,20 @@ internal class TranscoderContext private constructor(
private var inputFileDurationMs:Long = 0 // Ms
private var errorDescription = ""

init {
if (uploadInfo.inputStandardization.maximumResolution == MaximumResolution.Preset3840x2160) {
this.MAX_ALLOWED_BITRATE = 20000000
this.MAX_ALLOWED_I_FRAME_INTERVAL = 10
this.MAX_ALLOWED_WIDTH = 4096
this.MAX_ALLOWED_HEIGTH = 4096
} else {
this.MAX_ALLOWED_BITRATE = 8000000
this.MAX_ALLOWED_I_FRAME_INTERVAL = 5
this.MAX_ALLOWED_WIDTH = uploadInfo.inputStandardization.maximumResolution.width
this.MAX_ALLOWED_HEIGTH = uploadInfo.inputStandardization.maximumResolution.height
}
}

companion object {
const val LOG_TAG = "TranscoderContext"

Expand Down Expand Up @@ -212,7 +229,7 @@ internal class TranscoderContext private constructor(
}
inputFramerate = format.getIntegerCompat(MediaFormat.KEY_FRAME_RATE, -1)
targetedFramerate = OPTIMAL_FRAMERATE
if (inputFramerate > MAX_ALLOWED_FRAMERATE) {
if (inputFramerate > MAX_ALLOWED_FRAMERATE || inputFramerate < MIN_ALLOWED_FRAMERATE) {
logger.v(
LOG_TAG,
"Should standardize because the input frame rate is too high"
Expand All @@ -223,6 +240,13 @@ internal class TranscoderContext private constructor(
} else {
targetedFramerate = inputFramerate
}
val iFrameInterval = format.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL)
if (iFrameInterval > MAX_ALLOWED_I_FRAME_INTERVAL) {
shouldStandardize = true
targetedIFrameInterval = I_FRAME_INTERVAL
} else {
targetedIFrameInterval = iFrameInterval
}
videoTrackIndex = i;
inputVideoFormat = format;
extractor.selectTrack(i)
Expand Down Expand Up @@ -316,7 +340,7 @@ internal class TranscoderContext private constructor(
)
outputVideoFormat!!.setInteger("slice-height", targetedHeight + targetedHeight/2);
outputVideoFormat!!.setInteger("stride", targetedWidth);
outputVideoFormat!!.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL)
outputVideoFormat!!.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, targetedIFrameInterval)
outputVideoFormat!!.setInteger(
MediaFormat.KEY_BITRATE_MODE,
MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR
Expand Down
35 changes: 32 additions & 3 deletions library/src/main/java/com/mux/video/upload/internal/UploadInfo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,34 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.StateFlow
import java.io.File

enum class MaximumResolution(val width: Int, val height: Int) {
/// By default the standardized input will be
/// scaled down to 1920x1080 (1080p) from a larger
/// size. Inputs with smaller dimensions won't be
/// scaled up.
Default(1920, 1080),
/// The standardized input will be scaled down
/// to 1280x720 (720p) from a larger size. Inputs
/// with smaller dimensions won't be scaled up.
Preset1280x720(1280, 1080), // 720p
/// The standardized input will be scaled down
/// to 1920x1080 (1080p) from a larger size. Inputs
/// with smaller dimensions won't be scaled up.
Preset1920x1080(1920, 1080), // 1080p
/// The standardized input will be scaled down
/// to 3840x2160 (2160p/4K) from a larger size.
/// Inputs with smaller dimensions won't be scaled
/// up.
Preset3840x2160(3840, 2160) // 2160p
}

data class InputStandardization(
@JvmSynthetic internal val standardizationRequested: Boolean = true,
@JvmSynthetic internal val maximumResolution: MaximumResolution = MaximumResolution.Default,
) {

}

/**
* This object is the SDK's internal representation of an upload that is in-progress. The public
* object is [MuxUpload], which is backed by an instance of this object.
Expand All @@ -18,7 +46,7 @@ import java.io.File
* Job and Flows populated
*/
internal data class UploadInfo(
@JvmSynthetic internal val standardizationRequested: Boolean = true,
@JvmSynthetic internal val inputStandardization: InputStandardization = InputStandardization(),
@JvmSynthetic internal val remoteUri: Uri,
@JvmSynthetic internal val inputFile: File,
@JvmSynthetic internal val standardizedFile: File? = null,
Expand All @@ -29,6 +57,7 @@ internal data class UploadInfo(
@JvmSynthetic internal val statusFlow: StateFlow<UploadStatus>?,
) {
fun isRunning(): Boolean = uploadJob?.isActive ?: false
fun isStandardizationRequested(): Boolean = inputStandardization.standardizationRequested
}

/**
Expand All @@ -37,7 +66,7 @@ internal data class UploadInfo(
*/
@JvmSynthetic
internal fun UploadInfo.update(
standardizationRequested: Boolean = this.standardizationRequested,
inputStandardization: InputStandardization = InputStandardization(),
remoteUri: Uri = this.remoteUri,
file: File = this.inputFile,
standardizedFile: File? = this.standardizedFile,
Expand All @@ -47,7 +76,7 @@ internal fun UploadInfo.update(
uploadJob: Deferred<Result<UploadStatus>>? = this.uploadJob,
statusFlow: StateFlow<UploadStatus>? = this.statusFlow,
) = UploadInfo(
standardizationRequested,
inputStandardization,
remoteUri,
file,
standardizedFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ internal class UploadJobFactory private constructor(
val startTime = System.currentTimeMillis()
try {
// See if the file need to be converted to a standard input.
if (uploadInfo.standardizationRequested
if (uploadInfo.isStandardizationRequested()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
) {
statusFlow.value = UploadStatus.Preparing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ internal class UploadMetrics private constructor() {
body.put("version", "1")
val data = getEventInfo(startTimeMillis, "upload_start_time", endTimeMillis,
"upload_end_time", inputFileDurationMs, uploadInfo)
data.put("input_standardization_requested", uploadInfo.standardizationRequested
data.put("input_standardization_requested", uploadInfo.isStandardizationRequested()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
body.put("data", data)
sendPost(body)
Expand All @@ -200,7 +200,7 @@ internal class UploadMetrics private constructor() {
body.put("version", "1")
val data = getEventInfo(startTimeMillis, "upload_start_time", endTimeMillis,
"upload_end_time", inputFileDurationMs, uploadInfo)
data.put("input_standardization_requested", uploadInfo.standardizationRequested
data.put("input_standardization_requested", uploadInfo.isStandardizationRequested()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
data.put("error_description", errorDescription)
body.put("data", data)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.mux.video.upload.internal.options

class DirectUploadOptions {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this isn't used, can we delete it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, yes, this is sufficient


}
Loading