Skip to content

Commit 5b7635b

Browse files
committed
refactored
1 parent 85a2405 commit 5b7635b

File tree

2 files changed

+71
-56
lines changed

2 files changed

+71
-56
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.mobilenext.devicekit
2+
3+
import android.graphics.Bitmap
4+
import android.media.Image
5+
import java.io.ByteArrayOutputStream
6+
7+
object ImageUtils {
8+
9+
@JvmStatic
10+
fun convertToJpeg(image: Image, quality: Int, scale: Float): ByteArray {
11+
val planes = image.planes
12+
val buffer = planes[0].buffer
13+
val pixelStride = planes[0].pixelStride
14+
val rowStride = planes[0].rowStride
15+
val rowPadding = rowStride - pixelStride * image.width
16+
17+
// Create bitmap from image data
18+
val bitmap = Bitmap.createBitmap(
19+
image.width + rowPadding / pixelStride,
20+
image.height,
21+
Bitmap.Config.ARGB_8888
22+
)
23+
bitmap.copyPixelsFromBuffer(buffer)
24+
25+
// Remove row padding if present
26+
val paddingRemovedBitmap = if (rowPadding == 0) {
27+
bitmap
28+
} else {
29+
Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height)
30+
}
31+
32+
// Scale bitmap if needed
33+
val finalBitmap = if (scale != 1.0f) {
34+
val scaledWidth = (image.width * scale).toInt()
35+
val scaledHeight = (image.height * scale).toInt()
36+
Bitmap.createScaledBitmap(paddingRemovedBitmap, scaledWidth, scaledHeight, true)
37+
} else {
38+
paddingRemovedBitmap
39+
}
40+
41+
// Convert to JPEG
42+
val outputStream = ByteArrayOutputStream()
43+
finalBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
44+
val jpegData = outputStream.toByteArray()
45+
46+
// Cleanup
47+
if (finalBitmap != bitmap) {
48+
bitmap.recycle()
49+
}
50+
if (paddingRemovedBitmap != bitmap && paddingRemovedBitmap != finalBitmap) {
51+
paddingRemovedBitmap.recycle()
52+
}
53+
if (finalBitmap != paddingRemovedBitmap) {
54+
finalBitmap.recycle()
55+
}
56+
outputStream.close()
57+
58+
return jpegData
59+
}
60+
}

app/src/main/java/com/mobilenext/devicekit/MjpegServer.kt

Lines changed: 11 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ import java.util.concurrent.CountDownLatch
2121
import java.util.concurrent.TimeUnit
2222
import 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

Comments
 (0)