diff --git a/library/src/main/java/com/mux/video/upload/MuxUploadSdk.kt b/library/src/main/java/com/mux/video/upload/MuxUploadSdk.kt index 8e0c1408..c98d433e 100644 --- a/library/src/main/java/com/mux/video/upload/MuxUploadSdk.kt +++ b/library/src/main/java/com/mux/video/upload/MuxUploadSdk.kt @@ -66,9 +66,10 @@ object MuxUploadSdk { @Suppress("unused") @JvmOverloads fun initialize(appContext: Context, resumeStoppedUploads: Boolean = true) { - MuxUploadManager.appContext = appContext; - initializeUploadPersistence(appContext) - UploadMetrics.initialize(appContext) + val realAppContext = appContext.applicationContext // Just in case they give us something else + MuxUploadManager.appContext = realAppContext + initializeUploadPersistence(realAppContext) + UploadMetrics.initialize(realAppContext) if (resumeStoppedUploads) { MuxUploadManager.resumeAllCachedJobs() } diff --git a/library/src/main/java/com/mux/video/upload/api/MuxUpload.kt b/library/src/main/java/com/mux/video/upload/api/MuxUpload.kt index 5e6ef6e6..371a8a82 100644 --- a/library/src/main/java/com/mux/video/upload/api/MuxUpload.kt +++ b/library/src/main/java/com/mux/video/upload/api/MuxUpload.kt @@ -349,8 +349,9 @@ class MuxUpload private constructor( * for use with Mux Video */ @Suppress("unused") - fun standardizationRequested(enabled: Boolean) { + fun standardizationRequested(enabled: Boolean): Builder { uploadInfo.update(standardizationRequested = enabled) + return this } /** @@ -373,8 +374,9 @@ class MuxUpload private constructor( * here. */ @Suppress("unused") - fun optOutOfEventTracking(optOut: Boolean) { + fun optOutOfEventTracking(optOut: Boolean): Builder { uploadInfo.update(optOut = optOut) + return this } /** diff --git a/library/src/main/java/com/mux/video/upload/api/MuxUploadManager.kt b/library/src/main/java/com/mux/video/upload/api/MuxUploadManager.kt index fc1c42c0..ed833c87 100644 --- a/library/src/main/java/com/mux/video/upload/api/MuxUploadManager.kt +++ b/library/src/main/java/com/mux/video/upload/api/MuxUploadManager.kt @@ -25,13 +25,15 @@ import java.io.File */ object MuxUploadManager { - public var appContext: Context? = null; private val mainScope = MainScope() - private val uploadsByFilename: MutableMap = mutableMapOf() private val observerJobsByFilename: MutableMap = mutableMapOf() private val listeners: MutableSet>> = mutableSetOf() - private val logger get() = MuxUploadSdk.logger + @Suppress("unused") + private val logger by MuxUploadSdk::logger + + @JvmSynthetic + internal var appContext: Context? = null /** * Finds an in-progress, paused, or failed upload and returns a [MuxUpload] to track it, if it was @@ -182,5 +184,4 @@ object MuxUploadManager { } } } - } diff --git a/library/src/main/java/com/mux/video/upload/api/UploadResult.kt b/library/src/main/java/com/mux/video/upload/api/UploadResult.kt new file mode 100644 index 00000000..31e96440 --- /dev/null +++ b/library/src/main/java/com/mux/video/upload/api/UploadResult.kt @@ -0,0 +1,56 @@ +package com.mux.video.upload.api + +/** + * Helper class for parsing [Result] objects from [MuxUpload] in Java. + * + * Kotlin callers can use the [Result] API as normal + */ +class UploadResult { + + companion object { + /** + * Returns true of the upload was successful, + * Returns false if the upload wasn't successful, or if the passed object wasn't a [Result] + */ + @Suppress("unused") + @JvmStatic + fun isSuccessful(result: Result): Boolean { + @Suppress("USELESS_IS_CHECK") // java interprets inline classes like Result as Object + return if (result is Result) { + result.isSuccess + } else { + false + } + + } + + /** + * Returns the final Progress update from [MuxUpload]'s [Result] if if was successful + * Returns `null` if the upload was not successful, or if the passed object wasn't a result + */ + @Suppress("unused") + @JvmStatic + fun getFinalProgress(result: Result): MuxUpload.Progress? { + @Suppress("USELESS_IS_CHECK") // java interprets inline classes like Result as Object + return if (result is Result) { + result.getOrNull() + } else { + null + } + } + + /** + * If the Result was not successful, returns the Exception that caused the failure + */ + @Suppress("unused") + @JvmStatic + fun getError(result: Result): Throwable? { + @Suppress("USELESS_IS_CHECK") // java interprets inline classes like Result as Object + return if (result is Result) { + result.exceptionOrNull() + } else { + null + } + } + } +} diff --git a/library/src/main/java/com/mux/video/upload/api/UploadStatus.kt b/library/src/main/java/com/mux/video/upload/api/UploadStatus.kt index 365350ae..556150ad 100644 --- a/library/src/main/java/com/mux/video/upload/api/UploadStatus.kt +++ b/library/src/main/java/com/mux/video/upload/api/UploadStatus.kt @@ -24,6 +24,12 @@ sealed class UploadStatus { */ open fun getError(): Exception? = null + /** + * Returns whether or not the uplod was successful + */ + @Suppress("unused") + fun isSuccessful(): Boolean = this is UploadSuccess + // Subclasses /** diff --git a/library/src/main/java/com/mux/video/upload/internal/TranscoderContext.kt b/library/src/main/java/com/mux/video/upload/internal/TranscoderContext.kt index fcd9093b..a94defb9 100644 --- a/library/src/main/java/com/mux/video/upload/internal/TranscoderContext.kt +++ b/library/src/main/java/com/mux/video/upload/internal/TranscoderContext.kt @@ -107,7 +107,6 @@ internal class TranscoderContext private constructor( uploadInfo = uploadInfo.update(standardizedFile = destFile) try { - extractor.setDataSource(uploadInfo.inputFile.absolutePath) configureDecoders() configured = true } catch (e:Exception) { @@ -117,66 +116,78 @@ internal class TranscoderContext private constructor( private fun checkIfTranscodingIsNeeded(): Boolean { var shouldStandardize = false - for (i in 0 until extractor.trackCount) { - val format = extractor.getTrackFormat(i) - val mime = format.getString(MediaFormat.KEY_MIME) - var inputDuration:Long = -1; - if (mime?.lowercase()?.contains("video") == true) { - inputWidth = format.getInteger(MediaFormat.KEY_WIDTH) - inputHeighth = format.getInteger(MediaFormat.KEY_HEIGHT) - // Check if resolution is greater then 720p - if ((inputWidth > MAX_ALLOWED_WIDTH && inputHeighth > MAX_ALLOWED_HEIGTH) - || (inputHeighth > MAX_ALLOWED_WIDTH && inputWidth > MAX_ALLOWED_HEIGTH)) { - logger.v(LOG_TAG, "Should standardize because the size is incorrect") - shouldStandardize = true - if(inputWidth > inputHeighth) { - targetedWidth = MAX_ALLOWED_WIDTH - targetedHeight = targetedWidth * (inputHeighth / inputWidth) + try { + extractor.setDataSource(uploadInfo.inputFile.absolutePath) + for (i in 0 until extractor.trackCount) { + val format = extractor.getTrackFormat(i) + val mime = format.getString(MediaFormat.KEY_MIME) + var inputDuration: Long = -1; + if (mime?.lowercase()?.contains("video") == true) { + inputWidth = format.getInteger(MediaFormat.KEY_WIDTH) + inputHeighth = format.getInteger(MediaFormat.KEY_HEIGHT) + // Check if resolution is greater then 720p + if ((inputWidth > MAX_ALLOWED_WIDTH && inputHeighth > MAX_ALLOWED_HEIGTH) + || (inputHeighth > MAX_ALLOWED_WIDTH && inputWidth > MAX_ALLOWED_HEIGTH) + ) { + logger.v(LOG_TAG, "Should standardize because the size is incorrect") + shouldStandardize = true + if (inputWidth > inputHeighth) { + targetedWidth = MAX_ALLOWED_WIDTH + targetedHeight = targetedWidth * (inputHeighth / inputWidth) + } else { + targetedHeight = MAX_ALLOWED_WIDTH + targetedWidth = targetedHeight * (inputWidth / inputHeighth) + } } else { - targetedHeight = MAX_ALLOWED_WIDTH - targetedWidth = targetedHeight * (inputWidth / inputHeighth) + targetedWidth = inputWidth + targetedHeight = inputHeighth } - } else { - targetedWidth = inputWidth - targetedHeight = inputHeighth - } - scaledSizeYuv = Nv12Buffer.allocate(targetedWidth, targetedHeight) + scaledSizeYuv = Nv12Buffer.allocate(targetedWidth, targetedHeight) - // Check if compersion is h264 - if (!mime.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) { - logger.v(LOG_TAG, "Should standardize because the input is not h.264") - shouldStandardize = true - } - inputBitrate = format.getIntegerCompat(MediaFormat.KEY_BIT_RATE, -1) - inputDuration = format.getLongCompat(MediaFormat.KEY_DURATION, -1) - if (inputBitrate == -1 && inputDuration != -1L) { - inputBitrate = ((uploadInfo.inputFile.length() * 8) / (inputDuration / 1000000)).toInt() - } - if (inputBitrate > MAX_ALLOWED_BITRATE) { - logger.v(LOG_TAG, "Should standardize because the input bitrate is too high") - shouldStandardize = true - targetedBitrate = MAX_ALLOWED_BITRATE + // Check if compersion is h264 + if (!mime.equals(MediaFormat.MIMETYPE_VIDEO_AVC)) { + logger.v(LOG_TAG, "Should standardize because the input is not h.264") + shouldStandardize = true + } + inputBitrate = format.getIntegerCompat(MediaFormat.KEY_BIT_RATE, -1) + inputDuration = format.getLongCompat(MediaFormat.KEY_DURATION, -1) + if (inputBitrate == -1 && inputDuration != -1L) { + inputBitrate = + ((uploadInfo.inputFile.length() * 8) / (inputDuration / 1000000)).toInt() + } + if (inputBitrate > MAX_ALLOWED_BITRATE) { + logger.v( + LOG_TAG, + "Should standardize because the input bitrate is too high" + ) + shouldStandardize = true + targetedBitrate = MAX_ALLOWED_BITRATE + } + inputFramerate = format.getIntegerCompat(MediaFormat.KEY_FRAME_RATE, -1) + if (inputFramerate > MAX_ALLOWED_FRAMERATE) { + logger.v( + LOG_TAG, + "Should standardize because the input frame rate is too high" + ) + shouldStandardize = true + targetedFramerate = OPTIMAL_FRAMERATE + } else { + targetedFramerate = inputFramerate + } + videoTrackIndex = i; + inputVideoFormat = format; + extractor.selectTrack(i) } - inputFramerate = format.getIntegerCompat(MediaFormat.KEY_FRAME_RATE, -1) - if (inputFramerate > MAX_ALLOWED_FRAMERATE) { - logger.v(LOG_TAG, "Should standardize because the input frame rate is too high") - shouldStandardize = true - targetedFramerate = OPTIMAL_FRAMERATE - } else { - targetedFramerate = inputFramerate + if (mime?.lowercase()?.contains("audio") == true) { + // TODO check if audio need to be standardized + audioTrackIndex = i; + inputAudioFormat = format; + extractor.selectTrack(i) } - videoTrackIndex = i; - inputVideoFormat = format; - extractor.selectTrack(i) - } - if (mime?.lowercase()?.contains("audio") == true) { - // TODO check if audio need to be standardized - audioTrackIndex = i; - inputAudioFormat = format; - extractor.selectTrack(i) } + } catch (ex:Exception) { + ex.printStackTrace() } - return shouldStandardize } @@ -314,11 +325,12 @@ internal class TranscoderContext private constructor( videoDecoder!!.flush() videoEncoder!!.flush() muxVideoFrame() + muxer!!.stop() + fileTranscoded = true } catch (err:Exception) { logger.e(LOG_TAG, "Failed to standardize input file ${uploadInfo.inputFile}", err) } finally { releaseCodecs() - fileTranscoded = true } val duration = System.currentTimeMillis() - started logger.i(LOG_TAG, "Transcoding duration time: $duration")