Skip to content

Commit

Permalink
Upload metrics. (#89)
Browse files Browse the repository at this point in the history
* Upload metrics.

* Redirect fix.

* rename input_standardization_enabled to input_standardization_requested

* Renaming fields.

* Fix.

* Bump com.squareup.okhttp3:okhttp from 4.11.0 to 4.12.0 (#91)

Bumps [com.squareup.okhttp3:okhttp](https://github.com/square/okhttp) from 4.11.0 to 4.12.0.
- [Changelog](https://github.com/square/okhttp/blob/master/CHANGELOG.md)
- [Commits](square/okhttp@parent-4.11.0...parent-4.12.0)

---
updated-dependencies:
- dependency-name: com.squareup.okhttp3:okhttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* rename input_standardization_enabled to input_standardization_requested

* metric keys fixed.

* video_duration now in seconds.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: AJ Lauer Barinov <abarinov@mux.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 30, 2023
1 parent c994f59 commit c45f947
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.annotation.RequiresApi
import com.mux.video.upload.MuxUploadSdk
import io.github.crow_misia.libyuv.FilterMode
import io.github.crow_misia.libyuv.Nv12Buffer
import org.json.JSONArray
import java.io.File
import java.io.OutputStream
import java.nio.BufferOverflowException
Expand All @@ -22,7 +23,8 @@ import kotlin.experimental.and
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
internal class TranscoderContext private constructor(
private var uploadInfo: UploadInfo,
private val appContext: Context
private val appContext: Context,
private val sessionId: String
) {
private val logger get() = MuxUploadSdk.logger

Expand Down Expand Up @@ -94,14 +96,17 @@ internal class TranscoderContext private constructor(
private var resampledAudioOutputStream:OutputStream? = null;
var fileTranscoded = false
private var configured = false
private var nonStandardInputReasons:JSONArray = JSONArray()
private var inputFileDurationMs:Long = 0 // Ms
private var errorDescription = ""

companion object {
const val LOG_TAG = "TranscoderContext"
const val LOG_TAG = "TranscoderContext"

@JvmSynthetic
internal fun create(uploadInfo: UploadInfo, appContext: Context): TranscoderContext {
return TranscoderContext(uploadInfo, appContext)
}
@JvmSynthetic
internal fun create(uploadInfo: UploadInfo, appContext: Context, sessionId: String): TranscoderContext {
return TranscoderContext(uploadInfo, appContext, sessionId)
}
}

private fun getEncoders(mimeType: String, hwCapableOnly:Boolean): ArrayList<MediaCodecInfo> {
Expand All @@ -117,7 +122,7 @@ internal class TranscoderContext private constructor(
}
}
}
return result;
return result
}

private fun configure() {
Expand Down Expand Up @@ -177,6 +182,7 @@ internal class TranscoderContext private constructor(
targetedHeight = MAX_ALLOWED_WIDTH
targetedWidth = targetedHeight * (inputWidth / inputHeighth)
}
nonStandardInputReasons.put("video_resolution")
} else {
targetedWidth = inputWidth
targetedHeight = inputHeighth
Expand All @@ -187,6 +193,7 @@ internal class TranscoderContext private constructor(
if (!mime.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) {
logger.v(LOG_TAG, "Should standardize because the input is not h.264")
shouldStandardize = true
nonStandardInputReasons.put("video_codec")
}
inputBitrate = format.getIntegerCompat(MediaFormat.KEY_BIT_RATE, -1)
inputDuration = format.getLongCompat(MediaFormat.KEY_DURATION, -1)
Expand All @@ -201,8 +208,7 @@ internal class TranscoderContext private constructor(
)
shouldStandardize = true
targetedBitrate = MAX_ALLOWED_BITRATE
} else {
targetedBitrate = inputBitrate
nonStandardInputReasons.put("video_bitrate")
}
inputFramerate = format.getIntegerCompat(MediaFormat.KEY_FRAME_RATE, -1)
targetedFramerate = OPTIMAL_FRAMERATE
Expand All @@ -213,6 +219,7 @@ internal class TranscoderContext private constructor(
)
shouldStandardize = true
targetedFramerate = OPTIMAL_FRAMERATE
nonStandardInputReasons.put("video_framerate")
} else {
targetedFramerate = inputFramerate
}
Expand Down Expand Up @@ -375,7 +382,7 @@ internal class TranscoderContext private constructor(
}

@JvmSynthetic
internal fun process(): UploadInfo {
internal suspend fun process(): UploadInfo {
logger.v(LOG_TAG, "process() starting")
if (!checkIfTranscodingIsNeeded()) {
logger.i(LOG_TAG, "Standardization was not required. Skipping")
Expand All @@ -393,6 +400,8 @@ internal class TranscoderContext private constructor(
}

val started = System.currentTimeMillis()
val metrics = UploadMetrics.create()
var maxStandardInputRes = ""
try {
while (!eofReached) {
if (extractor.sampleTrackIndex == audioTrackIndex) {
Expand All @@ -408,14 +417,24 @@ internal class TranscoderContext private constructor(
muxer!!.stop()
fileTranscoded = true
} catch (err:Exception) {
errorDescription += err.localizedMessage
logger.e(LOG_TAG, "Failed to standardize input file ${uploadInfo.inputFile}", err)
} finally {
releaseCodecs()
}
val duration = System.currentTimeMillis() - started
val ended = System.currentTimeMillis();
val duration = ended - started
logger.i(LOG_TAG, "Transcoding duration time: $duration")
logger.i(LOG_TAG, "Original file size: ${uploadInfo.inputFile.length()}")
logger.i(LOG_TAG, "Transcoded file size: ${uploadInfo.standardizedFile?.length()}")
maxStandardInputRes = (MAX_ALLOWED_WIDTH / MAX_ALLOWED_HEIGTH).toString()
if (fileTranscoded && uploadInfo.optOut) {
metrics.reportStandardizationSuccess(started, ended, inputFileDurationMs,
nonStandardInputReasons, maxStandardInputRes, sessionId, uploadInfo)
} else if(uploadInfo.optOut) {
metrics.reportStandardizationFailed(started, ended, inputFileDurationMs,
errorDescription, nonStandardInputReasons, maxStandardInputRes, sessionId, uploadInfo)
}
return uploadInfo
}

Expand All @@ -431,6 +450,7 @@ internal class TranscoderContext private constructor(
+ ", pts: " + frame.info.presentationTimeUs
)
}
inputFileDurationMs = frame.info.presentationTimeUs * 1000;
muxer!!.writeSampleData(outputVideoTrackIndex, frame.buff, frame.info)
}
}
Expand Down Expand Up @@ -467,6 +487,7 @@ internal class TranscoderContext private constructor(
}

private fun muxAudioFrame(frame:AVFrame) {
inputFileDurationMs = frame.info.presentationTimeUs * 1000;
muxer!!.writeSampleData(
outputAudioTrackIndex,
frame.buff,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ internal class UploadJobFactory private constructor(
val uploadJob = outerScope.async {
// Inside the async { }, we have officially started
statusFlow.value = UploadStatus.Started

val sessionId = UUID.randomUUID().toString()
// This UploadInfo never gets sent outside this coroutine. It contains info related to
// standardizing the the client doesn't need to know/can't know synchronously
var innerUploadInfo = uploadInfo
Expand All @@ -82,7 +82,7 @@ internal class UploadJobFactory private constructor(
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
) {
statusFlow.value = UploadStatus.Preparing
val tcx = TranscoderContext.create(innerUploadInfo, MuxUploadManager.appContext!!)
val tcx = TranscoderContext.create(innerUploadInfo, MuxUploadManager.appContext!!, sessionId)
innerUploadInfo = tcx.process()
if (tcx.fileTranscoded) {
fileStream = withContext(Dispatchers.IO) {
Expand Down Expand Up @@ -174,28 +174,31 @@ internal class UploadJobFactory private constructor(

// We made it!
val finalProgress = createFinalState(fileSize, startTime)
// report this upload asynchronously (unless a debug build of the SDK)
@Suppress("KotlinConstantConditions")
if (BuildConfig.BUILD_TYPE != "debug" && !innerUploadInfo.optOut) {
launch {
metrics.reportUpload(
startTimeMillis = finalProgress.startTime,
endTimeMillis = finalProgress.updatedTime,
uploadInfo = innerUploadInfo,
)
}
}

// finish up
MainScope().launch { MuxUploadManager.jobFinished(innerUploadInfo) }
val success = UploadStatus.UploadSuccess(finalProgress)
if (!innerUploadInfo.optOut) {
metrics.reportUploadSucceeded(
startTime, finalProgress.updatedTime, 0,
sessionId,
uploadInfo
)
}
statusFlow.value = success
Result.success(success)
} catch (e: Exception) {
MuxUploadSdk.logger.e("MuxUpload", "Upload of ${innerUploadInfo.inputFile} failed", e)
val finalState = createFinalState(fileSize, startTime)
val failStatus = UploadStatus.UploadFailed(e, finalState)
statusFlow.value = failStatus
if (!innerUploadInfo.optOut) {
metrics.reportUploadFailed(
startTime, System.currentTimeMillis(), 0,
e.localizedMessage,
sessionId,
uploadInfo
)
}
MainScope().launch { MuxUploadManager.jobFinished(innerUploadInfo, false) }
Result.failure(e)
} finally {
Expand Down
Loading

0 comments on commit c45f947

Please sign in to comment.