大疆的東西,我真的太喜歡了。。。喜歡到想看看是如何做出來的。 逆向菜雞,安卓羸弱,反正就是個看熱鬧的主,大佬們輕點拍~ 這個就是將應(yīng)用退殼的東西 具體是一個梆梆企業(yè)版的殼子,我是在真機(jī)上面把殼砸了的 大概就是在運行前,需要從殼里面把真正的應(yīng)用解壓出來,然后我們從內(nèi)存里面把這個dump出來,因為是一個完整的調(diào)用鏈條,然后再組裝回來~~~~ https://mydown.yesky.com/pcsoft/413552646.html 當(dāng)然了,這個東西是可以解壓的 算了,本來想展示點別的東西,這個電腦不合適,看源碼吧 其實java還好一點,反編譯的源碼還有點難懂,C#完全就是源碼。。。 一個是R文件的解析,在安卓的世界里面各種資源都是要被打包到R文件里面的,所以你看到的是一個這樣的反編譯的資源文件 我推測,對于一些控制類的操作是用json打包發(fā)送的 視頻流+控制“流” Google分析的組件,畢竟作為國際大廠,出海是必然的 二維碼的組件,作為一些登錄時使用 第二個jar文件,我推測是給poctek 2代的直播流寫的模塊 你看這個是虎牙直播的組件 public UUID getUUId() { return this.uuid; }
public boolean isEmpty() { return this.raw.isEmpty(); } 可以點進(jìn)去仔細(xì)的看,這里的包沒有混淆 這里是dji的實現(xiàn),讓我稍微看看是什么東西 package com.dji.socialsdkwx.login.wechat;
import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;
public class SocialWeChatActivity extends AppCompatActivity implements IWXAPIEventHandler { private IWXAPI api;
/* access modifiers changed from: protected */ public void onCreate(Bundle bundle) { }
/* access modifiers changed from: protected */ public void onNewIntent(Intent intent) { }
public void onReq(BaseReq baseReq) { }
public void onResp(BaseResp baseResp) { } } import com.tencent.mm.opensdk.modelbase.BaseReq; import com.tencent.mm.opensdk.modelbase.BaseResp; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler; 你看這個,其實是微信的登錄接口,至于其它的可能要設(shè)置語言才可以打開 package com.dji.livestream.livetype;
import android.app.Dialog; import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity;
import com.dji.device.util.c; import com.dji.livestream.R; import com.dji.livestream.bean.DJILiveLoadingStage; import com.dji.livestream.bean.b; import com.dji.livestream.livetype.-$; import com.dji.livestream.livetype.a; import com.dji.livestream.page.LiveStreamBaseActivity; import dji.base.ui.thirdparty.permission.CommonPermissionHelper;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.l; 這里的安卓庫分為三類,原生的安卓構(gòu)件,dji自己的庫 以及使用的三方庫 EventBus的特性包括: ? 簡化了組件間的通訊 ? 分離了事件的發(fā)送者和接受者; ? 在Activity、Fragment和線程中表現(xiàn)良好; ? 避免了復(fù)雜的和易錯的依賴關(guān)系和聲明周期問題; ? 使得代碼更簡潔; ? 更快; ? 更?。s50k的jar包) ? 實際上超過1億的app證明了它的性能; ? 有高級屬性,例如發(fā)布線程、訂閱屬性等。 可以看到有很多新的軟件庫在里面,比如全新的儲存管理 以及有很多的廣播接收器,F(xiàn)acebook,HW 看,HW的推送庫 以及全新的安卓庫 干哦兄弟! 原生C++ 以及FFmpeg的解碼庫 以及人臉追蹤???是用的這種東西嗎 private final String[] PERMISSIONS = {"android.permission.BLUETOOTH", "android.permission.BLUETOOTH_ADMIN", "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"}; // permissions={blue,blue_admin,access_file_location,access_coarse_location} private final int REQUEST_CODE_LIVE_SETTINGS = 1011; // request_code_live_settings
這里的代碼做了一點識別,可以看到要動態(tài)申請的權(quán)限是藍(lán)牙的 private Dialog confirmDialog; private com.dji.device.common.a connectHelper; private View facebookLive; private View facebookSelectedIcon; private Handler handler = new Handler(Looper.getMainLooper()); private View huyaLive; private View huyaSelectedIcon; private View kuaiShouLive; private View kuaiShouSelectedIcon; private CommonPermissionHelper permissionHelper; private CommonPermissionHelper.a permissionRequestData; private a.b presenter; private View rtmpLive; private View rtmpSelectedIcon; 在看這些函數(shù)就很有趣了,有連接大疆相機(jī)時候的指引,臉書的直播,虎牙的直播,快手的直播,以及支持自定義的RTMP直播 import com.dji.device.connect.bean.c; package com.dji.network.bean; import com.google.gson.annotations.SerializedName; public class BaseBean extends BaseSerializable { @SerializedName("code") protected int code; @SerializedName("msg") protected String msg;
public int getCode() { return this.code; }
public String getMsg() { return this.msg; }
public void setCode(int i) { this.code = i; }
public void setMsg(String str) { this.msg = str; } } 基本可序列化??? 這里是小米的推送包 public String dataPlatform() { return "XiaoMi Push"; }
Retrofit2簡單的說就是一個網(wǎng)絡(luò)請求的適配器,它將一個基本的Java接口通過動態(tài)代理的方式翻譯成一個HTTP請求,并通過OkHttp去發(fā)送請求。 Gson(又稱Google Gson)是Google公司發(fā)布的一個開放源代碼的Java庫,主要用途為序列化Java對象為JSON字符串,或反序列化JSON字符串成Java對象。 https://djigo-hk.djiservice.org 不鳥我 Osmo Shield Domain package com.dji.pano.osmo.mobile;
import com.dji.pano.osmo.mobile.b;
class b$1 implements b.a { final /* synthetic */ b a;
b$1(b bVar) { this.a = bVar; }
public void a() { }
public void a(int i, String str) { this.a.a(i, str); }
public void a(String str) { }
public void b() { }
public void c() { } } implements是一個類實現(xiàn)一個接口用的關(guān)鍵字 ,他是用來實現(xiàn)接口中定義的抽象方法。比如:people是一個接口,他里面有say這個方法。public interface people(){ public say();}但是接口沒有方法體。只能通過一個具體的類去實現(xiàn)其中的方法體。比如chinese這個類,就實現(xiàn)了people這個接口。public class chinese implements people{ public say() {System.out.println("你好!");}} https://github.com/square/wire public RootData(Integer num, EncryptionType encryptionType, PlatformType platformType, String str, Integer num2, Integer num3, ByteString byteString, String str2, Integer num4, String str3, ByteString byteString2) { super(a, byteString2); this.version = num; this.encryption = encryptionType; this.platform = platformType; this.app_key = str; this.app_version = num2; this.plaintext_len = num3; this.content = byteString; this.cmd = str2; this.timestamp = num4; this.signature = str3; } 這個是一個協(xié)議的實現(xiàn)我沒有細(xì)研究,直接貼上來 package com.dji.tracking.jnienum;
public enum CameraFace { LTSOT_FRONT_CAMERA(1), // ltsot_front_camera LTSOT_BEHIND_CAMERA(2); public final int value;
private CameraFace(int i) { this.value = i; } } 這個是關(guān)于臉部追蹤的代碼 package com.dji.tracking.jnienum;
public enum CheckedObjectType { ML_OBJ_OTHER(0, "其他"), ML_OBJ_HEAD_SHOULDER(1, "頭肩"), ML_OBJ_PERSON(2, "人"), ML_OBJ_FACE(5, "臉"), ML_OBJ_PET(6, "寵物"), ML_OBJ_GESTURE_PALM(101, "手掌"), ML_OBJ_GESTURE_VICTORY(102, "V型手勢"), ML_OBJ_GESTURE_OTHER(103, "其他手勢"), ML_OBJ_NONE(-1, "NONE"); public final String tip; public final int value;
private CheckedObjectType(int i, String str) { this.value = i; this.tip = str; }
public static CheckedObjectType a(int i) { CheckedObjectType[] values = values(); for (CheckedObjectType checkedObjectType : values) { if (checkedObjectType.value == i) { return checkedObjectType; } } return ML_OBJ_NONE; } } 物體識別 package com.dji.tracking.jinout;
import androidx.core.util.Pools;
public class TrackingBox { private static Pools.SynchronizedPool<TrackingBox> sPool = new Pools.SynchronizedPool<>(10); public float centerX; public float centerY; public float height; public float width;
public static TrackingBox obtain() { TrackingBox trackingBox = (TrackingBox) sPool.acquire(); return trackingBox != null ? trackingBox : new TrackingBox(); }
public void recycle() { sPool.release(this); } } 繪制一個追蹤的盒子 package com.dji.tracking.jnienum;
public enum RotateAngle { ML_ROTATE_0(0), ML_ROTATE_90_CLOCKWISE(1), ML_ROTATE_180(2), ML_ROTATE_90_COUNTERCLOCKWISE(3); public final int value;
private RotateAngle(int i) { this.value = i; } } 旋轉(zhuǎn)的角度 package com.dji.tracking.jnienum;
import androidx.collection.SparseArrayCompat;
public enum TrackingMode { TK_MODE_UNFUSED(-1), TK_MODE_LOST(0), TK_MODE_TRACKED(1), TK_MODE_NOT_CONFIDENT(2), TK_MODE_REDETECTED(3), TK_MODE_GESTURE_STOP(4), TK_MODE_REAL_LOST(5); private static final SparseArrayCompat<TrackingMode> h = new SparseArrayCompat<>(); public final int value;
private TrackingMode(int i2) { this.value = i2; }
public static TrackingMode a(int i2) { TrackingMode trackingMode = (TrackingMode) h.get(i2); if (trackingMode == null) { TrackingMode[] values = values(); int length = values.length; int i3 = 0; while (true) { if (i3 >= length) { break; } TrackingMode trackingMode2 = values[i3]; if (trackingMode2.value == i2) { trackingMode = trackingMode2; break; } i3++; } if (trackingMode == null) { trackingMode = TK_MODE_UNFUSED; } h.put(i2, trackingMode); } return trackingMode; } } 追蹤模式 package com.dji.tracking;
import android.os.Build; import com.dji.tracking.a.a; import com.dji.tracking.a.b;
/* access modifiers changed from: package-private */ public class g { private static final String[] a = {"HUAWEI ANE", "HONOR STF"};
static f a() { String upperCase = String.format("%s %s", Build.BRAND, Build.MODEL).toUpperCase(); for (String str : a) { if (upperCase.contains(str)) { return new a(); } } return new b(); } } 這個不知道是為什么,單獨的說了華為,大寫? 最后看看這個,video里面有什么 package com.dji.video.codec;
import android.media.MediaCodec; import com.dji.video.stream.AACFrameDelegate; import com.dji.video.stream.AudioConfigs; import com.dji.video.utils.c; import java.nio.ByteBuffer; import java.util.UUID; import java.util.UUID;
public class AudioStreamDecoder { private final int a = 0; private final int b = 1; private final int c = 3; private int d = 0; private MediaCodec e; private ByteBuffer[] f; private ByteBuffer[] g; private boolean h; private boolean i = false; private long j = 0; private final int k = 16384; private c l = new c(64, 16384); private byte[] m = new byte[16384]; private a n; private AudioConfigs o; private UUID p; private AACFrameDelegate q; private boolean r = false;
class a extends Thread { private boolean b = false;
a() { }
public void run() { } } 音頻解碼類 package com.dji.video.codec;
import com.dji.video.codec.MediaCodecDecoder; import com.dji.video.edit.MvModel; import java.util.ArrayList; import java.util.Hashtable; import java.util.List;
public class c { public static List<MediaCodecDecoder.a> a = new ArrayList(); public static Hashtable<String, MediaCodecDecoder.b> b = new Hashtable<>();
public static void a(ArrayList<MvModel> arrayList) { if (arrayList != null) { if (a.size() > 0) { a.clear(); } if (b.size() > 0) { b.clear(); } for (int i = 0; i < arrayList.size(); i++) { MvModel mvModel = arrayList.get(i); if (mvModel.d() == 1) { MediaCodecDecoder.b bVar = new MediaCodecDecoder.b(); String b2 = mvModel.b(); bVar.a = mvModel.e(); bVar.b = mvModel.f(); bVar.d = mvModel.g(); bVar.c = (int) (mvModel.h() + mvModel.c()); if (!b.containsKey(b2)) { b.put(b2, bVar); } else if (b.get(b2).c < bVar.c) { b.put(b2, bVar); } } } } } } 推測這個是視頻編輯功能里面的一個子功能 下面的代碼有這個庫 MediaCodec類可用于訪問Android底層的多媒體編解碼器,例如,編碼器/解碼器組件。它是Android底層多媒體支持基礎(chǔ)架構(gòu)的一部分(通常與MediaExtractor, MediaSync, MediaMuxer, MediaCrypto, MediaDrm, Image, Surface, 以及AudioTrack一起使用)。
import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.MediaExtractor; import android.media.MediaFormat; package com.dji.video.codec;
import android.media.MediaCodec; import android.media.MediaCodecInfo; import android.media.MediaCodecList; import android.media.MediaExtractor; import android.media.MediaFormat; import android.os.Build; import java.io.File; import java.io.IOException; import java.util.List; import junit.framework.Assert;
public class e { public class a { private c b;
public a(c cVar) { this.b = cVar; }
private void a(int i) throws Exception { }
public void a() throws Exception { } }
public class b { private c b;
public b(c cVar) { this.b = cVar; }
private void a(MediaExtractor mediaExtractor, int i, MediaCodec mediaCodec) throws Exception { }
public void a() throws Exception { } }
public class c { int a = 0; boolean b = false; boolean c = false;
public c() { } }
public class d extends Thread { private a b;
public d(a aVar) { this.b = aVar; }
public void run() { try { this.b.a(); } catch (Exception e) { e.printStackTrace(); } } }
/* renamed from: com.dji.video.codec.e$e reason: collision with other inner class name */ public class C0001e extends Thread { private b b;
public C0001e(b bVar) { this.b = bVar; }
public void run() { try { this.b.a(); } catch (Exception e) { e.printStackTrace(); } } }
public e() { this.b = null; this.c = null; this.l = 1280; this.m = 720; this.n = this.l; this.o = this.m; this.p = this.l; this.q = this.m; this.r = 0; this.s = 0; this.t = 0; this.u = 0; this.v = 0; this.w = 0; this.x = 0; this.y = 0; this.z = "video/avc"; this.A = 6000000; this.B = 6000000; this.C = 25; this.D = 25; this.E = -1; this.I = false; this.J = false; this.O = 0; this.P = false; this.X = false; this.b = e(); this.c = f(); }
static /* synthetic */ int J(e eVar) { int i2 = eVar.O; eVar.O = i2 + 1; return i2; }
static /* synthetic */ int L(e eVar) { int i2 = eVar.T; eVar.T = i2 + 1; return i2; }
/* access modifiers changed from: private */ public int a(MediaExtractor mediaExtractor) { return 0; }
/* access modifiers changed from: private */ public void a(byte[] bArr, byte[] bArr2, int i2, int i3, int i4, int i5) { }
private static boolean a(int i2) { if (!(i2 == 39 || i2 == 2130706688)) { switch (i2) { case 19: case 20: case 21: break; default: return false; } } return true; }
/* access modifiers changed from: private */ public static int b(MediaCodecInfo mediaCodecInfo, String str) { MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(str); for (int i2 = 0; i2 < capabilitiesForType.colorFormats.length; i2++) { int i3 = capabilitiesForType.colorFormats[i2]; if (a(i3)) { return i3; } } Assert.fail("找不到適合的顏色格式 " + mediaCodecInfo.getName() + " / " + str); return 0; }
/* access modifiers changed from: private */ public static MediaCodecInfo b(String str) { String[] supportedTypes; int codecCount = MediaCodecList.getCodecCount(); for (int i2 = 0; i2 < codecCount; i2++) { MediaCodecInfo codecInfoAt = MediaCodecList.getCodecInfoAt(i2); if (codecInfoAt.isEncoder()) { for (String str2 : codecInfoAt.getSupportedTypes()) { if (str2.equalsIgnoreCase(str)) { return codecInfoAt; } } continue; } } return null; }
private static boolean b(int i2) { if (!(i2 == 39 || i2 == 2130706688)) { switch (i2) { case 19: case 20: return false; case 21: break; default: throw new RuntimeException("unknown format " + i2); } } return true; }
/* access modifiers changed from: private */ public void c(String str) { }
private void d() throws IOException { }
private String e() { return Build.MODEL; }
private String f() { return Build.VERSION.RELEASE; }
static /* synthetic */ int x(e eVar) { int i2 = eVar.M; eVar.M = i2 + 1; return i2; }
public void a() { }
public void a(long j2, long j3, int i2) { }
public void a(long j2, long j3, String str, String str2, String str3, int i2) { }
public void a(b bVar) { this.Y = bVar; }
public void b() { }
public void c() { } } 這段代碼,emmm,啥也看不出出來了,只能猜了 https://www.android-doc.com/reference/android/media/MediaCodecInfo.CodecCapabilities.html public static int b(MediaCodecInfo mediaCodecInfo, String str) { MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(str); for (int i2 = 0; i2 < capabilitiesForType.colorFormats.length; i2++) { int i3 = capabilitiesForType.colorFormats[i2]; if (a(i3)) { return i3; } } Assert.fail("找不到適合的顏色格式 " + mediaCodecInfo.getName() + " / " + str); return 0; } 看這個函數(shù),傳入一個編碼函數(shù),和一個strings 然后就是一個遍歷在匹配一個什么東西?應(yīng)該是顏色的格式 package com.dji.video.codec;
import android.graphics.BitmapFactory;
public class ImageDecoder { private int a; private int b;
public static int[] get_image_paras(String str) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(str, options); return new int[]{options.outWidth, options.outHeight, 0, 0}; }
public int get_height() { return this.b; }
public int[] get_image_data(String str) { return null; }
public void get_image_para(String str) { }
public int get_width() { return this.a; } } 這個函數(shù)簡單,見名知其義 package com.dji.video.codec;
import java.util.HashMap; import wseemann.media.FFmpegMediaMetadataRetriever;
public class VideoDescription { private static final String a = "VideoDescription"; private String b; private HashMap<String, String> c;
private void a(FFmpegMediaMetadataRetriever.a aVar, String str) { }
private native void nativeGetDescription(String str, HashMap<String, String> hashMap);
public void a(String str) { }
public String b(String str) { return null; } } 這個函數(shù)是讀取一個視頻的info 就先到這里~下期再見 |
|