From 7d326a6c848a2cffb3564de3907b8905bb7c856a Mon Sep 17 00:00:00 2001 From: Mallikarjun Kamble Date: Tue, 6 Aug 2024 11:54:39 +0530 Subject: [PATCH] Cherry-picked battery code --- app/build.gradle | 3 + app/src/main/AndroidManifest.xml | 1 + .../com/facebook/encapp/BufferTranscoder.java | 35 ++- .../com/facebook/encapp/MainActivity.java | 251 +++++++++++++++++- .../com/facebook/encapp/utils/ParsedData.java | 123 +++++++++ app/src/main/res/layout/activity_main.xml | 73 ++++- .../main/res/layout/activity_visualize.xml | 72 ++++- .../x264_enc/jni/src/JNIx264.cpp | 1 - 8 files changed, 528 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/com/facebook/encapp/utils/ParsedData.java diff --git a/app/build.gradle b/app/build.gradle index bdfafe9c..85382123 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -49,6 +49,9 @@ dependencies { implementation group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.12.0' implementation 'com.google.code.gson:gson:2.8.0' implementation 'com.google.protobuf:protobuf-java:3.19.4' + implementation 'androidx.activity:activity:1.5.1' + implementation 'androidx.activity:activity-ktx:1.5.1' + implementation 'androidx.fragment:fragment:1.3.4' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1a752a27..911c88b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + diff --git a/app/src/main/java/com/facebook/encapp/BufferTranscoder.java b/app/src/main/java/com/facebook/encapp/BufferTranscoder.java index da4684ad..d5ba372c 100644 --- a/app/src/main/java/com/facebook/encapp/BufferTranscoder.java +++ b/app/src/main/java/com/facebook/encapp/BufferTranscoder.java @@ -447,7 +447,19 @@ public String start() { mStats.start(); try { // start bufferTranscoding - bufferTranscoding(trackNum); + long startTime = System.currentTimeMillis(); + long durationMs = 2 * 60 * 1000; // 30 minutes + + while (System.currentTimeMillis() - startTime < durationMs) { + //mExtractor.setDataSource(mTest.getInput().getFilepath()); + //trackNum = mExtractor.getTrackCount(); + mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC); + mExtractor.selectTrack(trackNum); + + bufferTranscoding(trackNum); + + + } } catch (Exception e) { e.printStackTrace(); } @@ -556,6 +568,7 @@ void bufferTranscoding(int trackIndex) throws IOException { fo = new FileOutputStream(file); } + int orgTrackIndex = trackIndex; int estimatedSize = 1024; byte[] headerArray = new byte[estimatedSize]; MediaMuxer muxer = null; @@ -692,6 +705,8 @@ void bufferTranscoding(int trackIndex) throws IOException { if(encOutputExtractDone){ Log.d(TAG, "encOutputExtractDone is true and getEncodedFrame() execution is over"); } + //if(trackIndex == (orgTrackIndex - 1)) + // trackIndex = 0; } if(isx264Encoder) { if (muxer != null) { @@ -1119,19 +1134,19 @@ void submitFrameForEncoding(MediaMuxer muxer, int videoTrackIndex, FileOutputStr wait(WAIT_TIME_SHORT_MS); } catch (InterruptedException e) { e.printStackTrace(); + } } - } - encInpSubmitDone = true; - Log.d(TAG, "Submitted EOF for encoder "); + encInpSubmitDone = true; + Log.d(TAG, "Submitted EOF for encoder "); Log.d(TAG, "Flag: " + decodedBufferInfo.flags + " Size: " + decodedBufferInfo.size + " presentationTimeUs: "+decodedBufferInfo.presentationTimeUs + - " submitted frame for enc: " + mInFramesCount); - } + " submitted frame for enc: " + mInFramesCount); + } }else { - Log.d(TAG, "encInpBuffer is null"); - } + Log.d(TAG, "encInpBuffer is null"); + } - } else { - Log.d(TAG, "index value: " + index); + } else { + Log.d(TAG, "index value: " + index); } } } diff --git a/app/src/main/java/com/facebook/encapp/MainActivity.java b/app/src/main/java/com/facebook/encapp/MainActivity.java index d57a68e5..d5f1d58b 100644 --- a/app/src/main/java/com/facebook/encapp/MainActivity.java +++ b/app/src/main/java/com/facebook/encapp/MainActivity.java @@ -1,7 +1,9 @@ package com.facebook.encapp; +import android.Manifest; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Matrix; @@ -10,10 +12,14 @@ import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.net.Uri; +import android.os.BatteryManager; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.Handler; +import android.os.Looper; import android.os.Process; +import android.provider.DocumentsContract; import android.provider.Settings; import android.util.Log; import android.util.Size; @@ -21,11 +27,15 @@ import android.view.TextureView; import android.view.View; import android.view.ViewTreeObserver; +import android.widget.Button; +import android.widget.ScrollView; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; - +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import static androidx.activity.result.ActivityResultCallerKt.registerForActivityResult; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; @@ -36,15 +46,17 @@ import com.facebook.encapp.utils.CliSettings; import com.facebook.encapp.utils.MediaCodecInfoHelper; import com.facebook.encapp.utils.MemoryLoad; +import com.facebook.encapp.utils.ParsedData; import com.facebook.encapp.utils.OutputMultiplier; import com.facebook.encapp.utils.SizeUtils; import com.facebook.encapp.utils.Statistics; import com.facebook.encapp.utils.VsyncHandler; import com.facebook.encapp.utils.grafika.Texture2dProgram; import com.google.protobuf.TextFormat; - +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; @@ -53,6 +65,8 @@ import java.util.Locale; import java.util.Stack; import java.util.Vector; +import java.util.concurrent.atomic.AtomicReference; +import android.media.MediaCodec; public class MainActivity extends AppCompatActivity { private final static String TAG = "encapp.main"; @@ -81,6 +95,8 @@ public static boolean isStable() { return mStable; } + private List mp4Files = new ArrayList<>(); + public static String getFilenameExtension(String filename) { int last_dot_location = filename.lastIndexOf('.'); String extension = (last_dot_location == -1) ? "" : filename.substring(last_dot_location+1); @@ -126,6 +142,21 @@ private String getCurrentAppVersion() { return currentVersion; } + private Test createTestFromParsedData(ParsedData parsedData) { + Test.Builder testBuilder = Test.newBuilder(); + // Populate Test fields based on ParsedData + testBuilder.getCommonBuilder().setId(parsedData.getId()); + testBuilder.getCommonBuilder().setDescription(parsedData.getDescription()); + testBuilder.getInputBuilder().setFilepath(parsedData.getFilepath()); + testBuilder.getInputBuilder().setRealtime(parsedData.isRealtime()); + testBuilder.getInputBuilder().setShow(parsedData.isShow()); + testBuilder.getConfigureBuilder().setCodec(parsedData.getCodec()); + testBuilder.getConfigureBuilder().setEncode(parsedData.isEncode()); + testBuilder.getConfigureBuilder().setBitrate(parsedData.getBitrate()); + return testBuilder.build(); + } + + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -133,6 +164,22 @@ protected void onCreate(Bundle savedInstanceState) { mVsyncHandler.start(); //setContentView(R.layout.activity_main); setContentView(R.layout.activity_visualize); + final AtomicReference parsedDataRef = new AtomicReference<>(null); + + // Initialize battery-related UI elements + TextView startBatteryTextView = findViewById(R.id.startBatteryTextView); + TextView endBatteryTextView = findViewById(R.id.endBatteryTextView); + TextView batteryStatsTextView = findViewById(R.id.batteryStatsTextView); + Button startButton = findViewById(R.id.startButton); + Button selectFileButton = findViewById(R.id.selectFileButton); + Button stopButton = findViewById(R.id.stopButton); + Button resetButton = findViewById(R.id.resetButton); + TextView selectedFileTextView = findViewById(R.id.selectedFileTextView); + TextView testStatusTextView = findViewById(R.id.testStatusTextView); + + // Initialize battery monitoring variables + final int[] startbatteryInMicroAmps = {-1}; + final int[] endbatteryInMicroAmps = {-1}; // get list of non-granted permissions String[] permissions = retrieveNotGrantedPermissions(this); @@ -175,19 +222,199 @@ protected void onCreate(Bundle savedInstanceState) { mTable = findViewById(R.id.viewTable); Log.d(TAG, "Passed all permission checks"); - if (getTestSettings()) { - (new Thread(new Runnable() { - @Override - public void run() { - performAllTests(); - Log.d(TAG, "***** All tests are done, over and out *****"); - exit(); + + // Battery monitoring logic + ActivityResultLauncher selectFileLauncher = registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> { + if (result.getResultCode() == RESULT_OK && result.getData() != null) { + Uri uri = result.getData().getData(); + String path = getFilePathFromUri(uri); + selectedFileTextView.setText(path); + ParsedData parsedData = parsePbtxtFile(path); + parsedDataRef.set(parsedData); + } } - })).start(); - } else { - listCodecs(); + ); + + selectFileButton.setOnClickListener(v -> { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + selectFileLauncher.launch(intent); + }); + + startButton.setOnClickListener(v -> { + ParsedData parsedData = parsedDataRef.get(); + if (parsedData == null) { + Toast.makeText(this, "No file selected or parsed.", Toast.LENGTH_SHORT).show(); + return; + } + startbatteryInMicroAmps[0] = getChargeCounter(); + startBatteryTextView.setText("Before batteryInMicroAmps: " + startbatteryInMicroAmps[0]); + testStatusTextView.setText("Test is running..."); + + Test test = createTestFromParsedData(parsedData); + PerformTest(test); + + //if (!mp4Files.isEmpty()) { + // for (String mp4FilePath : mp4Files) { + // Test.Builder testBuilder = Test.newBuilder(); + // testBuilder.getInputBuilder().setFilepath(mp4FilePath); + //test = createTestFromParsedData(parsedData); + //PerformTest(test); + // } + //} else { + if (getTestSettings()) { + (new Thread(new Runnable() { + @Override + public void run() { + performAllTests(); + Log.d(TAG, "***** All tests are done, over and out *****"); + + runOnUiThread(new Runnable() { + @Override + public void run() { + endBatteryTextView.setText("After batteryInMicroAmps: " + endbatteryInMicroAmps[0]); + batteryStatsTextView.setText("Battery difference: " + (startbatteryInMicroAmps[0] - endbatteryInMicroAmps[0])); + testStatusTextView.setText("Test completed."); + } + }); + + saveResultsToFile(startbatteryInMicroAmps[0], endbatteryInMicroAmps[0]); + exit(); + } + })).start(); + } else { + listCodecs(); + } + //} + new Handler().postDelayed(() -> { + runOnUiThread(() -> { + endbatteryInMicroAmps[0] = getChargeCounter(); + endBatteryTextView.setText("After batteryInMicroAmps: " + endbatteryInMicroAmps[0]); + batteryStatsTextView.setText("Battery difference: " + (startbatteryInMicroAmps[0] - endbatteryInMicroAmps[0])); + testStatusTextView.setText("Test completed."); + }); + + saveResultsToFile(startbatteryInMicroAmps[0], endbatteryInMicroAmps[0]); + + }, /*30 * 60 */ 2 * 60 * 1000); // 30 minutes in milliseconds + + }); + stopButton.setOnClickListener(v -> { + // Implement logic to stop the test + // This may involve interrupting the thread performing the tests + testStatusTextView.setText("Test stopped."); + }); + + resetButton.setOnClickListener(v -> { + // Implement logic to reset the test + // This may involve resetting UI elements and variables + selectedFileTextView.setText("No file selected"); + startBatteryTextView.setText("Before batteryInMicroAmps: "); + endBatteryTextView.setText("After batteryInMicroAmps: "); + batteryStatsTextView.setText("Battery Stats: "); + testStatusTextView.setText(""); + parsedDataRef.set(null); + }); + } + + private int getChargeCounter() { + BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE); + if (batteryManager != null) { + return batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER); + } + return -1; + } + + private void saveResultsToFile(int startbatteryInMicroAmps, int endbatteryInMicroAmps) { + if (Build.VERSION.SDK_INT >= 23) { + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + return; + } } + File file = new File(Environment.getExternalStorageDirectory(), "BatteryStats.txt"); + try (FileWriter writer = new FileWriter(file, true)) { + if (mp4Files.isEmpty()) { + Log.d(TAG, "No MP4 files to log."); + } else { + for (String mp4File : mp4Files) { + writer.append("FILE : MediaInfo: ").append(mp4File).append("\n"); + writer.append("Before batteryInMicroAmps: ").append(String.valueOf(startbatteryInMicroAmps)).append("\n"); + writer.append("After batteryInMicroAmps: ").append(String.valueOf(endbatteryInMicroAmps)).append("\n"); + } + Log.d(TAG, "Battery stats written to BatteryStats.txt"); + } + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "Error writing to BatteryStats.txt", e); + } + } + + private ParsedData parsePbtxtFile(String path) { + StringBuilder content = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new FileReader(path))) { + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } + } catch (IOException e) { + e.printStackTrace(); + } + return parsePbtxt(content.toString()); + } + + private ParsedData parsePbtxt(String content) { + ParsedData parsedData = new ParsedData(); + String[] lines = content.split("\n"); + for (String line : lines) { + if (line.contains("id:")) { + parsedData.setId(line.split(":")[1].trim().replace("\"", "")); + } else if (line.contains("description:")) { + parsedData.setDescription(line.split(":")[1].trim().replace("\"", "")); + } else if (line.contains("filepath:")) { + parsedData.setFilepath(line.split(":")[1].trim().replace("\"", "")); + } else if (line.contains("realtime:")) { + parsedData.setRealtime(Boolean.parseBoolean(line.split(":")[1].trim())); + } else if (line.contains("show:")) { + parsedData.setShow(Boolean.parseBoolean(line.split(":")[1].trim())); + } else if (line.contains("codec:")) { + parsedData.setCodec(line.split(":")[1].trim().replace("\"", "")); + } else if (line.contains("encode:")) { + parsedData.setEncode(Boolean.parseBoolean(line.split(":")[1].trim())); + } else if (line.contains("bitrate:")) { + parsedData.setBitrate(line.split(":")[1].trim().replace("\"", "")); + } else if (line.startsWith("preset:")) { + parsedData.setPreset(line.split(":")[1].trim().replace("\"", "")); + } else if (line.startsWith("colorSpace:")) { + parsedData.setColorSpace(line.split(":")[1].trim().replace("\"", "")); + } else if (line.startsWith("bitdepth:")) { + parsedData.setBitdepth(Integer.parseInt(line.split(":")[1].trim())); + } else if (line.startsWith("outputFile:")) { + parsedData.setOutputFile(line.split(":")[1].trim().replace("\"", "")); + } else if (line.startsWith("threads:")) { + parsedData.setThreads(Integer.parseInt(line.split(":")[1].trim())); + } + } + return parsedData; + } + + private String getFilePathFromUri(Uri uri) { + String filePath = null; + if (DocumentsContract.isDocumentUri(this, uri)) { + String documentId = DocumentsContract.getDocumentId(uri); + String[] split = documentId.split(":"); + String type = split[0]; + String id = split[1]; + + if ("primary".equalsIgnoreCase(type)) { + filePath = Environment.getExternalStorageDirectory() + "/" + id; + } + } + return filePath; } protected void listCodecs() { diff --git a/app/src/main/java/com/facebook/encapp/utils/ParsedData.java b/app/src/main/java/com/facebook/encapp/utils/ParsedData.java new file mode 100644 index 00000000..f301f0be --- /dev/null +++ b/app/src/main/java/com/facebook/encapp/utils/ParsedData.java @@ -0,0 +1,123 @@ +package com.facebook.encapp.utils; + +public class ParsedData { + private String id; + private String description; + private String filepath; + private boolean realtime; + private boolean show; + private String codec; + private boolean encode; + private String bitrate; + private String preset; + private String colorSpace; + private int bitdepth; + private String outputFile; + private int threads; + + // Getters and setters for all fields + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFilepath() { + return filepath; + } + + public void setFilepath(String filepath) { + this.filepath = filepath; + } + + public boolean isRealtime() { + return realtime; + } + + public void setRealtime(boolean realtime) { + this.realtime = realtime; + } + + public boolean isShow() { + return show; + } + + public void setShow(boolean show) { + this.show = show; + } + + public String getCodec() { + return codec; + } + + public void setCodec(String codec) { + this.codec = codec; + } + + public boolean isEncode() { + return encode; + } + + public void setEncode(boolean encode) { + this.encode = encode; + } + + public String getBitrate() { + return bitrate; + } + + public void setBitrate(String bitrate) { + this.bitrate = bitrate; + } + + public String getPreset() { + return preset; + } + + public void setPreset(String preset) { + this.preset = preset; + } + + public String getColorSpace() { + return colorSpace; + } + + public void setColorSpace(String colorSpace) { + this.colorSpace = colorSpace; + } + + public int getBitdepth() { + return bitdepth; + } + + public void setBitdepth(int bitdepth) { + this.bitdepth = bitdepth; + } + + public String getOutputFile() { + return outputFile; + } + + public void setOutputFile(String outputFile) { + this.outputFile = outputFile; + } + + public int getThreads() { + return threads; + } + + public void setThreads(int threads) { + this.threads = threads; + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index c73c6c05..eff866d1 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,18 +5,18 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true" + android:orientation="vertical" tools:context="com.facebook.encapp.MainActivity"> + android:text="@string/test_is_running" /> + android:layout_height="wrap_content" /> + + +