@@ -21,10 +21,15 @@ import java.util.concurrent.CountDownLatch
2121import java.util.concurrent.TimeUnit
2222import kotlin.system.exitProcess
2323
24- class MjpegServer (private val quality : Int = 90 , private val scale : Float = 1.0f ) {
24+ class MjpegServer (quality : Int , scale : Float ) {
25+ private val quality: Int = quality
26+ private val scale: Float = scale
27+
2528 companion object {
2629 private const val TAG = " MjpegServer"
2730 private const val BOUNDARY = " BoundaryString"
31+ private const val DEFAULT_QUALITY = 80
32+ private const val DEFAULT_SCALE = 1.0f
2833
2934 @JvmStatic
3035 fun main (args : Array <String >) {
@@ -40,21 +45,21 @@ class MjpegServer(private val quality: Int = 90, private val scale: Float = 1.0f
4045 }
4146
4247 private fun parseArguments (args : Array <String >): Pair <Int , Float > {
43- var quality = 90
44- var scale = 1.0f
48+ var quality = DEFAULT_QUALITY
49+ var scale = DEFAULT_SCALE
4550
4651 var i = 0
4752 while (i < args.size) {
4853 when (args[i]) {
4954 " --quality" -> {
5055 if (i + 1 < args.size) {
51- quality = args[i + 1 ].toIntOrNull()?.coerceIn(1 , 100 ) ? : 90
56+ quality = args[i + 1 ].toIntOrNull()?.coerceIn(1 , 100 ) ? : DEFAULT_QUALITY
5257 i++
5358 }
5459 }
5560 " --scale" -> {
5661 if (i + 1 < args.size) {
57- scale = args[i + 1 ].toFloatOrNull()?.coerceIn(0.1f , 2.0f ) ? : 1.0f
62+ scale = args[i + 1 ].toFloatOrNull()?.coerceIn(0.1f , 2.0f ) ? : DEFAULT_SCALE
5863 i++
5964 }
6065 }
@@ -124,7 +129,7 @@ Connection: close
124129 try {
125130 image = reader.acquireLatestImage()
126131 if (image != null ) {
127- val jpegData = convertImageToJpeg (image, quality, scale)
132+ val jpegData = ImageUtils .convertToJpeg (image, quality, scale)
128133 outputMjpegFrame(jpegData)
129134 Log .d(TAG , " Frame output: ${jpegData.size} bytes" )
130135 }
@@ -173,56 +178,6 @@ Connection: close
173178 System .out .flush()
174179 }
175180
176- private fun convertImageToJpeg (image : Image , quality : Int , scale : Float ): ByteArray {
177- val planes = image.planes
178- val buffer = planes[0 ].buffer
179- val pixelStride = planes[0 ].pixelStride
180- val rowStride = planes[0 ].rowStride
181- val rowPadding = rowStride - pixelStride * image.width
182-
183- // Create bitmap from image data
184- val bitmap = Bitmap .createBitmap(
185- image.width + rowPadding / pixelStride,
186- image.height,
187- Bitmap .Config .ARGB_8888
188- )
189- bitmap.copyPixelsFromBuffer(buffer)
190-
191- // Remove row padding if present
192- val paddingRemovedBitmap = if (rowPadding == 0 ) {
193- bitmap
194- } else {
195- Bitmap .createBitmap(bitmap, 0 , 0 , image.width, image.height)
196- }
197-
198- // Scale bitmap if needed
199- val finalBitmap = if (scale != 1.0f ) {
200- val scaledWidth = (image.width * scale).toInt()
201- val scaledHeight = (image.height * scale).toInt()
202- Bitmap .createScaledBitmap(paddingRemovedBitmap, scaledWidth, scaledHeight, true )
203- } else {
204- paddingRemovedBitmap
205- }
206-
207- // Convert to JPEG
208- val outputStream = ByteArrayOutputStream ()
209- finalBitmap.compress(Bitmap .CompressFormat .JPEG , quality, outputStream)
210- val jpegData = outputStream.toByteArray()
211-
212- // Cleanup
213- if (finalBitmap != bitmap) {
214- bitmap.recycle()
215- }
216- if (paddingRemovedBitmap != bitmap && paddingRemovedBitmap != finalBitmap) {
217- paddingRemovedBitmap.recycle()
218- }
219- if (finalBitmap != paddingRemovedBitmap) {
220- finalBitmap.recycle()
221- }
222- outputStream.close()
223-
224- return jpegData
225- }
226181
227182 private fun createVirtualDisplay (
228183 width : Int ,
0 commit comments