| README_H264_CHECK.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/anyun/h264/H264EncodeService.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/anyun/h264/H264EncodeService2.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/anyun/h264/model/ResourceInfo.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/anyun/h264/model/WatermarkInfo.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| app/src/main/java/com/anyun/h264/util/FileUtil.java | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| check_h264.py | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| 多进程方案使用说明.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| 如何检查test.h264文件.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
README_H264_CHECK.md
@@ -118,3 +118,4 @@ ``` åºè¯¥çå°ï¼`00 00 00 01` æ `00 00 01`ï¼Annex-Bèµ·å§ç ï¼ app/src/main/aidl/com/anyun/h264/model/ResourceInfo.aidl
@@ -5,3 +5,4 @@ */ parcelable ResourceInfo; app/src/main/java/com/anyun/h264/H264EncodeService.java
@@ -11,6 +11,7 @@ import com.anyun.h264.model.ResourceInfo; import com.anyun.h264.model.WatermarkInfo; import com.anyun.h264.util.FileUtil; import org.json.JSONException; import org.json.JSONObject; @@ -123,6 +124,7 @@ * ç¼ç é 置类 */ private static class EncodeConfig { boolean useTFCard=true;//å¦æä¸ºtrueï¼åå¨tfcard æ ¹ç®å½å»ºä¸ä¸ªh264æä»¶å¤¹ï¼å¨h264ç®å½ä¸ä»¥å½åæ¥æä¸ºååçæä»¶å¤¹ï¼æ¯å¦20250123ï¼ï¼ç¶åh264æä»¶å°±åå ¥ä»¥å½åæ¥å为ååçç®å½ä¸ boolean enableFileOutput; //æ¯å¦å¼å¯h264æä»¶åå ¥ boolean enableNetworkTransmit; //å¼å¯h264ï¼ç½ç»å®æ¶æ¨æµ String ip; @@ -147,6 +149,7 @@ config.port = 0; config.simPhone = null; config.cameraId = 1; // é»è®¤ä½¿ç¨ç¬¬ä¸ä¸ªæå头 config.useTFCard = false; // é»è®¤ä¸ä½¿ç¨TFå¡ return config; } @@ -159,6 +162,7 @@ config.ip = json.optString("ip", null); config.port = json.optInt("port", 0); config.simPhone = json.optString("simPhone", null); config.useTFCard = json.optBoolean("useTFCard", false); // è§£æcameraIdï¼å¦ææªæå®ï¼é»è®¤ä¸º1ï¼ if (json.has("cameraId")) { @@ -396,6 +400,57 @@ } /** * è·åè¾åºæä»¶ç®å½ï¼æ ¹æ®useTFCardé ç½®ï¼ * @param useTFCard æ¯å¦ä½¿ç¨TFå¡ * @return è¾åºç®å½è·¯å¾ */ private String getOutputFileDirectory(boolean useTFCard) { if (useTFCard) { // 使ç¨TFå¡ï¼/sdcard/h264/å½åæ¥æ/ try { String storagePath = FileUtil.getStoragePath(this, true); if (storagePath == null || storagePath.trim().isEmpty()) { Timber.w("TF card storage path not available, fallback to app directory"); return outputFileDirectory; } File externalStorage = new File(storagePath); if (!externalStorage.exists()) { Timber.w("TF card storage directory does not exist: %s, fallback to app directory", storagePath); return outputFileDirectory; } // è·åå½åæ¥æï¼æ ¼å¼ï¼yyyyMMddï¼å¦20250123ï¼ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.CHINA); String dateDir = dateFormat.format(new Date()); // æå»ºè·¯å¾ï¼/sdcard/h264/20250123/ File h264Dir = new File(externalStorage, "h264"); File dateDirFile = new File(h264Dir, dateDir); // å建ç®å½ï¼å¦æä¸åå¨ï¼ if (!dateDirFile.exists()) { boolean created = dateDirFile.mkdirs(); if (!created && !dateDirFile.exists()) { Timber.e("Failed to create TF card directory: %s, fallback to app directory", dateDirFile.getAbsolutePath()); return outputFileDirectory; } } String tfCardPath = dateDirFile.getAbsolutePath(); Timber.d("Using TF card directory: %s", tfCardPath); return tfCardPath; } catch (Exception e) { Timber.e(e, "Error getting TF card directory, fallback to app directory"); return outputFileDirectory; } } else { // 使ç¨åºç¨å¤é¨åå¨ç®å½ return outputFileDirectory; } } /** * å¯å¨ç¼ç ï¼ç»ä¸æ¹æ³ï¼æ¯ææä»¶åå ¥åç½ç»ä¼ è¾çç»åï¼ * @param config ç¼ç é ç½® * @return 0-æåï¼1-失败 @@ -405,8 +460,8 @@ Timber.e("Encode config cannot be null"); return 1; } Timber.d("Starting encode mode, fileOutput: %b, networkTransmit: %b", config.enableFileOutput, config.enableNetworkTransmit); Timber.d("Starting encode mode, fileOutput: %b, networkTransmit: %b, useTFCard: %b", config.enableFileOutput, config.enableNetworkTransmit, config.useTFCard); // 妿ç¼ç å¨å·²ç»å¨è¿è¡ï¼åªæ´æ°é ç½® if (h264Encoder != null) { @@ -456,9 +511,12 @@ int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE); // è·åè¾åºæä»¶ç®å½ï¼æ ¹æ®useTFCardé ç½®ï¼ String outputDir = getOutputFileDirectory(config.useTFCard); // 设置è¾åºæä»¶ç®å½ï¼H264Encoderä¼èªå¨ç®¡çæä»¶åå»ºï¼æ¯åéä¸ä¸ªæä»¶ï¼ // 使ç¨ä¸ä¸ªä¸´æ¶æä»¶åæ¥è®¾ç½®ç®å½ï¼H264Encoderä¼å¨åå§åæ¶å建第ä¸ä¸ªæä»¶ File tempFile = new File(outputFileDirectory, "temp.h264"); File tempFile = new File(outputDir, "temp.h264"); h264Encoder.setOutputFile(tempFile.getAbsolutePath()); h264Encoder.setEnableFileOutput(config.enableFileOutput); app/src/main/java/com/anyun/h264/H264EncodeService2.java
@@ -8,6 +8,7 @@ import com.anyun.h264.model.ResourceInfo; import com.anyun.h264.model.WatermarkInfo; import com.anyun.h264.util.FileUtil; import org.json.JSONException; import org.json.JSONObject; @@ -102,6 +103,7 @@ int height; int framerate; String simPhone; boolean useTFCard = false; // æ¯å¦ä½¿ç¨TFå¡ // ä»JSONè§£æé ç½® static EncodeConfig fromJson(String jsonConfig) throws JSONException { @@ -114,6 +116,7 @@ config.ip = null; config.port = 0; config.simPhone = null; config.useTFCard = false; // é»è®¤ä¸ä½¿ç¨TFå¡ return config; } @@ -124,6 +127,7 @@ config.ip = json.optString("ip", null); config.port = json.optInt("port", 0); config.simPhone = json.optString("simPhone", null); config.useTFCard = json.optBoolean("useTFCard", false); return config; } @@ -216,10 +220,61 @@ } /** * è·åè¾åºæä»¶ç®å½ï¼æ ¹æ®useTFCardé ç½®ï¼ * @param useTFCard æ¯å¦ä½¿ç¨TFå¡ * @return è¾åºç®å½è·¯å¾ */ private String getOutputFileDirectory(boolean useTFCard) { if (useTFCard) { // 使ç¨TFå¡ï¼/sdcard/h264/å½åæ¥æ/ try { String storagePath = FileUtil.getStoragePath(this, true); if (storagePath == null || storagePath.trim().isEmpty()) { Timber.w("TF card storage path not available, fallback to app directory (camera2)"); return outputFileDirectory; } File externalStorage = new File(storagePath); if (!externalStorage.exists()) { Timber.w("TF card storage directory does not exist: %s, fallback to app directory (camera2)", storagePath); return outputFileDirectory; } // è·åå½åæ¥æï¼æ ¼å¼ï¼yyyyMMddï¼å¦20250123ï¼ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.CHINA); String dateDir = dateFormat.format(new Date()); // æå»ºè·¯å¾ï¼/sdcard/h264/20250123/ File h264Dir = new File(externalStorage, "h264"); File dateDirFile = new File(h264Dir, dateDir); // å建ç®å½ï¼å¦æä¸åå¨ï¼ if (!dateDirFile.exists()) { boolean created = dateDirFile.mkdirs(); if (!created && !dateDirFile.exists()) { Timber.e("Failed to create TF card directory: %s, fallback to app directory (camera2)", dateDirFile.getAbsolutePath()); return outputFileDirectory; } } String tfCardPath = dateDirFile.getAbsolutePath(); Timber.d("Using TF card directory (camera2): %s", tfCardPath); return tfCardPath; } catch (Exception e) { Timber.e(e, "Error getting TF card directory, fallback to app directory (camera2)"); return outputFileDirectory; } } else { // 使ç¨åºç¨å¤é¨åå¨ç®å½ return outputFileDirectory; } } /** * å¯å¨æä»¶ç¼ç 模å¼ï¼åªåå ¥æä»¶ï¼ä¸è¿è¡ç½ç»æ¨éï¼ */ private int startFileEncode(EncodeConfig config) { Timber.d("Starting file encode mode (camera2)"); Timber.d("Starting file encode mode (camera2), useTFCard: %b", config != null ? config.useTFCard : false); // 妿ç¼ç å¨å·²ç»å¨è¿è¡ï¼å 忢 if (h264Encoder != null) { @@ -238,9 +293,13 @@ int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE); // è·åè¾åºæä»¶ç®å½ï¼æ ¹æ®useTFCardé ç½®ï¼ boolean useTFCard = config != null && config.useTFCard; String outputDir = getOutputFileDirectory(useTFCard); // 设置è¾åºæä»¶ç®å½ï¼H264Encoderä¼èªå¨ç®¡çæä»¶åå»ºï¼æ¯åéä¸ä¸ªæä»¶ï¼ // 使ç¨ä¸ä¸ªä¸´æ¶æä»¶åæ¥è®¾ç½®ç®å½ï¼H264Encoderä¼å¨åå§åæ¶å建第ä¸ä¸ªæä»¶ File tempFile = new File(outputFileDirectory, "temp.h264"); File tempFile = new File(outputDir, "temp.h264"); h264Encoder.setOutputFile(tempFile.getAbsolutePath()); h264Encoder.setEnableFileOutput(true); // å¯ç¨æä»¶è¾åº @@ -299,9 +358,13 @@ int framerate = config != null && config.framerate > 0 ? config.framerate : DEFAULT_FRAME_RATE; h264Encoder.setEncoderParams(width, height, framerate, DEFAULT_BITRATE); // è·åè¾åºæä»¶ç®å½ï¼æ ¹æ®useTFCardé ç½®ï¼ boolean useTFCard = config != null && config.useTFCard; String outputDir = getOutputFileDirectory(useTFCard); // 设置è¾åºæä»¶ç®å½ï¼H264Encoderä¼èªå¨ç®¡çæä»¶åå»ºï¼æ¯åéä¸ä¸ªæä»¶ï¼ // 使ç¨ä¸ä¸ªä¸´æ¶æä»¶åæ¥è®¾ç½®ç®å½ï¼H264Encoderä¼å¨åå§åæ¶å建第ä¸ä¸ªæä»¶ File tempFile = new File(outputFileDirectory, "temp.h264"); File tempFile = new File(outputDir, "temp.h264"); h264Encoder.setOutputFile(tempFile.getAbsolutePath()); h264Encoder.setEnableFileOutput(true); // å¯ç¨æä»¶è¾åº app/src/main/java/com/anyun/h264/model/ResourceInfo.java
@@ -156,3 +156,4 @@ } app/src/main/java/com/anyun/h264/model/WatermarkInfo.java
@@ -138,3 +138,4 @@ } } app/src/main/java/com/anyun/h264/util/FileUtil.java
New file @@ -0,0 +1,47 @@ package com.anyun.h264.util; import android.content.Context; import android.os.storage.StorageManager; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class FileUtil { //è·åæå ¥çTFCardç®å½è·¯å¾ public static String getStoragePath(Context mContext, boolean is_removale) { if (mContext != null) { StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); Class<?> storageVolumeClazz = null; try { storageVolumeClazz = Class.forName("android.os.storage.StorageVolume"); Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList"); Method getPath = storageVolumeClazz.getMethod("getPath"); Method isRemovable = storageVolumeClazz.getMethod("isRemovable"); Object result = getVolumeList.invoke(mStorageManager); final int length = Array.getLength(result); for (int i = 0; i < length; i++) { Object storageVolumeElement = Array.get(result, i); String path = (String) getPath.invoke(storageVolumeElement); boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement); if (is_removale == removable) { return path; } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return null; } else { return null; } } } check_h264.py
@@ -208,3 +208,4 @@ sys.exit(0 if success else 1) ¶à½ø³Ì·½°¸Ê¹ÓÃ˵Ã÷.md
@@ -116,3 +116,4 @@ - æææä½é½éè¿AIDLæ¥å£è¿è¡è¿ç¨é´éä¿¡ ÈçºÎ¼ì²étest.h264Îļþ.md
@@ -182,3 +182,4 @@ 3. **ç¨VLCææ¾**éªè¯ 4. **å¦æè¿æé®é¢**ï¼è¿è¡æ£æ¥å·¥å ·è·å详ç»è¯æ