实现短视频的录制功能

serial
BlueMatthew 1 year ago
parent 1b954e4edd
commit 8892216a5c

@ -25,6 +25,7 @@ add_definitions(-DTERMINAL_CLIENT)
add_definitions(-DKEEP_FRAME_TYPE_ON_REVERSE) add_definitions(-DKEEP_FRAME_TYPE_ON_REVERSE)
add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(-DBOOST_ALL_NO_LIB)
add_definitions(-DASIO_STANDALONE) add_definitions(-DASIO_STANDALONE)
add_definitions(-DUSING_XY_EXTENSION)
# add_definitions(-DUSING_BREAK_PAD) # add_definitions(-DUSING_BREAK_PAD)

@ -215,7 +215,7 @@ Java_com_xypower_mpapp_MicroPhotoService_init(
extern "C" JNIEXPORT jboolean JNICALL extern "C" JNIEXPORT jboolean JNICALL
Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto( Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto(
JNIEnv* env, JNIEnv* env,
jobject pThis, jlong handler, jint channel, jint preset, jlong scheduleTime, jboolean sendToCma) { jobject pThis, jlong handler, jint channel, jint preset, jlong scheduleTime, jboolean photoOrVideo) {
if (channel < 1 || channel > 0xFF) if (channel < 1 || channel > 0xFF)
{ {
@ -227,7 +227,8 @@ Java_com_xypower_mpapp_MicroPhotoService_notifyToTakePhoto(
return JNI_FALSE; return JNI_FALSE;
} }
std::thread th(&Runner::RequestCapture, pTerminal, (unsigned int)channel, (unsigned int)preset, 0, (unsigned long)scheduleTime); unsigned char type = photoOrVideo ? 0 : 1;
std::thread th(&Runner::RequestCapture, pTerminal, (unsigned int)channel, (unsigned int)preset, type, (unsigned long)scheduleTime);
th.detach(); th.detach();
// pTerminal->RequestCapture((unsigned int)channel, (unsigned int)preset, 0, (unsigned long)scheduleTime); // pTerminal->RequestCapture((unsigned int)channel, (unsigned int)preset, 0, (unsigned long)scheduleTime);
@ -452,3 +453,28 @@ Java_com_xypower_mpapp_MicroPhotoService_getNextScheduleItem(
return data; return data;
} }
*/ */
extern "C" JNIEXPORT void JNICALL
Java_com_xypower_mpapp_MicroPhotoService_recordingFinished(
JNIEnv* env,
jobject pThis, jlong handler, jboolean result, jstring path, jlong videoId) {
CTerminal* pTerminal = reinterpret_cast<CTerminal *>(handler);
if (pTerminal == NULL)
{
return;
}
IDevice* dev = pTerminal->GetDevice();
if (dev != NULL)
{
const char *pathStr = env->GetStringUTFChars(path, 0);
// camera->Open(pathStr, fileNameStr);
unsigned long photoId = videoId;
((CPhoneDevice *)dev)->OnVideoReady(result != JNI_FALSE, pathStr, photoId);
env->ReleaseStringUTFChars(path, pathStr);
}
}

@ -177,6 +177,7 @@ CPhoneDevice::CPhoneDevice(JavaVM* vm, jobject service, const std::string& appPa
mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(I)V"); mRegisterHeartbeatMid = env->GetMethodID(classService, "registerHeartbeatTimer", "(I)V");
mUnregisterTimerMid = env->GetMethodID(classService, "unregisterTimer", "(J)Z"); mUnregisterTimerMid = env->GetMethodID(classService, "unregisterTimer", "(J)Z");
mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z"); mUpdateTimeMid = env->GetMethodID(classService, "updateTime", "(J)Z");
mStartRecordingMid = env->GetMethodID(classService, "startRecording", "(IJIIII)V");
mRequestWakelockMid = env->GetMethodID(classService, "requestWakelock", "(Ljava/lang/String;J)V"); mRequestWakelockMid = env->GetMethodID(classService, "requestWakelock", "(Ljava/lang/String;J)V");
mReleaseWakelockMid = env->GetMethodID(classService, "releaseWakelock", "(Ljava/lang/String;)V"); mReleaseWakelockMid = env->GetMethodID(classService, "releaseWakelock", "(Ljava/lang/String;)V");
@ -643,7 +644,7 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
mCamera = NULL; mCamera = NULL;
} }
ALOGI("TAKE_PHOTO: CH=%u PR=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset); ALOGI("TAKE_PHOTO: CH=%u PR=%u PHOTOID=%u\n", (unsigned int)photoInfo.channel, (unsigned int)photoInfo.preset, photoInfo.photoId);
mPhotoInfo = photoInfo; mPhotoInfo = photoInfo;
mPath = path; mPath = path;
mOsds = osds; mOsds = osds;
@ -673,11 +674,10 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
} }
TurnOnCameraPower(env); TurnOnCameraPower(env);
if (didAttachThread)
{
m_vm->DetachCurrentThread();
}
res = true;
if (mPhotoInfo.mediaType == 0)
{
mCamera = new CPhoneCamera(this, photoInfo.width, photoInfo.height, params); mCamera = new CPhoneCamera(this, photoInfo.width, photoInfo.height, params);
if (mCamera->open(to_string(mPhotoInfo.cameraId)) == 0) if (mCamera->open(to_string(mPhotoInfo.cameraId)) == 0)
{ {
@ -686,10 +686,20 @@ bool CPhoneDevice::TakePhoto(const IDevice::PHOTO_INFO& photoInfo, const vector<
{ {
delete mCamera; delete mCamera;
mCamera = NULL; mCamera = NULL;
return false; res = false;
}
}
else
{
env->CallVoidMethod(m_javaService, mStartRecordingMid, mPhotoInfo.cameraId, (unsigned long)mPhotoInfo.photoId, mPhotoInfo.duration, mPhotoInfo.width, mPhotoInfo.height, mPhotoInfo.duration);
} }
return true; if (didAttachThread)
{
m_vm->DetachCurrentThread();
}
return res;
} }
bool CPhoneDevice::CloseCamera() bool CPhoneDevice::CloseCamera()
@ -707,10 +717,12 @@ bool CPhoneDevice::CloseCamera()
void CPhoneDevice::CloseCamera2(CPhoneDevice::CPhoneCamera* camera, bool turnOffOtg) void CPhoneDevice::CloseCamera2(CPhoneDevice::CPhoneCamera* camera, bool turnOffOtg)
{ {
// std::this_thread::sleep_for(std::chrono::milliseconds(16)); // std::this_thread::sleep_for(std::chrono::milliseconds(16));
if (camera != NULL)
{
camera->close(); camera->close();
delete camera; delete camera;
}
// GpioControl::EnableGpio(CMD_SET_CAM_3V3_EN_STATE, true); // GpioControl::EnableGpio(CMD_SET_CAM_3V3_EN_STATE, true);
JNIEnv* env = NULL; JNIEnv* env = NULL;
@ -791,6 +803,9 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
int aa = 0; int aa = 0;
return false; return false;
} }
mat = cv::imread("/sdcard/com.xypower.mpapp/ai1.jpg");
mPhotoInfo.photoTime = time(NULL); mPhotoInfo.photoTime = time(NULL);
int baseline = 0; int baseline = 0;
cv::Size textSize, textSize2; cv::Size textSize, textSize2;
@ -941,6 +956,26 @@ bool CPhoneDevice::OnImageReady(cv::Mat& mat)
return res; return res;
} }
bool CPhoneDevice::OnVideoReady(bool result, const char* path, unsigned int photoId)
{
mPhotoInfo.photoTime = time(NULL);
CPhoneCamera* pCamera = NULL;
std::vector<IDevice::RECOG_OBJECT> objs;
std::string fullPath = mPath + CTerminal::BuildPhotoFileName(mPhotoInfo);
if (result)
{
std::rename(path, fullPath.c_str());
}
TakePhotoCb(result, mPhotoInfo, fullPath, time(NULL), objs);
bool turnOffOtg = (mPhotoInfo.usbCamera != 0);
std::thread closeThread(&CPhoneDevice::CloseCamera2, this, pCamera, turnOffOtg);
closeThread.detach();
return result;
}
void CPhoneDevice::onError(const std::string& msg) void CPhoneDevice::onError(const std::string& msg)
{ {
// XFLOG(XFLOG_SEVERITY_ERROR, "Failed to Take Photo: %s", msg.c_str()); // XFLOG(XFLOG_SEVERITY_ERROR, "Failed to Take Photo: %s", msg.c_str());

@ -187,6 +187,8 @@ public:
bool GetNextScheduleItem(uint32_t tsBasedZero, uint32_t scheduleTime, vector<uint32_t>& items); bool GetNextScheduleItem(uint32_t tsBasedZero, uint32_t scheduleTime, vector<uint32_t>& items);
void UpdatePosition(double lon, double lat, time_t ts); void UpdatePosition(double lon, double lat, time_t ts);
bool OnVideoReady(bool result, const char* path, unsigned int photoId);
protected: protected:
std::string GetFileName() const; std::string GetFileName() const;
@ -218,6 +220,7 @@ protected:
void QueryPowerInfo(std::map<std::string, std::string>& powerInfo); void QueryPowerInfo(std::map<std::string, std::string>& powerInfo);
std::string QueryCpuTemperature(); std::string QueryCpuTemperature();
bool OnImageReady(cv::Mat& mat); bool OnImageReady(cv::Mat& mat);
void onError(const std::string& msg); void onError(const std::string& msg);
@ -240,6 +243,7 @@ protected:
jmethodID mRegisterHeartbeatMid; jmethodID mRegisterHeartbeatMid;
jmethodID mUnregisterTimerMid; jmethodID mUnregisterTimerMid;
jmethodID mUpdateTimeMid; jmethodID mUpdateTimeMid;
jmethodID mStartRecordingMid;
jmethodID mRequestWakelockMid; jmethodID mRequestWakelockMid;
jmethodID mReleaseWakelockMid; jmethodID mReleaseWakelockMid;

@ -269,25 +269,50 @@ public class MainActivity extends AppCompatActivity {
this.binding.takePhotoBtn.setOnClickListener(new View.OnClickListener() { this.binding.takePhotoBtn.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
MicroPhotoService.takePhoto(MainActivity.this.getApplicationContext(), 1, 255, true); MicroPhotoService.takePhoto(view.getContext(), 1, 255, true);
} }
}); });
this.binding.takePhotoBtn2.setOnClickListener(new View.OnClickListener() { this.binding.takePhotoBtn2.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
MicroPhotoService.takePhoto(MainActivity.this, 2, 255, true); MicroPhotoService.takePhoto(view.getContext(), 2, 255, true);
} }
}); });
this.binding.takePhotoBtn3.setOnClickListener(new View.OnClickListener() { this.binding.takePhotoBtn3.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
MicroPhotoService.takePhoto(MainActivity.this, 3, 255, true); MicroPhotoService.takePhoto(view.getContext(), 3, 255, true);
} }
}); });
this.binding.takePhotoBtn4.setOnClickListener(new View.OnClickListener() { this.binding.takePhotoBtn4.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
MicroPhotoService.takePhoto(MainActivity.this, 4, 255, true); MicroPhotoService.takePhoto(view.getContext(), 4, 255, true);
}
});
this.binding.takeVideoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MicroPhotoService.takePhoto(view.getContext(), 1, 255, false);
}
});
this.binding.takeVideoBtn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MicroPhotoService.takePhoto(view.getContext(), 2, 255, false);
}
});
this.binding.takeVideoBtn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MicroPhotoService.takePhoto(view.getContext(), 3, 255, false);
}
});
this.binding.takeVideoBtn4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MicroPhotoService.takePhoto(view.getContext(), 4, 255, false);
} }
}); });

@ -85,14 +85,15 @@ public class MicroPhotoService extends Service {
// public static final int NOTIFICATION_ID_FOREGROUND_SERVICE = 0; // public static final int NOTIFICATION_ID_FOREGROUND_SERVICE = 0;
public static final String ACTION_MSG_BROADCAST = "ACT_MSG_BROADCAST"; public static final String ACTION_MSG_BROADCAST = "ACT_MSG_BROADCAST";
public static final String ACTION_START = "ACT_START"; public static final String ACTION_START = "com.xypower.mpapp.ACT_START";
public static final String ACTION_STOP = "ACT_STOP"; public static final String ACTION_STOP = "com.xypower.mpapp.ACT_STOP";
public static final String ACTION_MAIN = "ACT_MAIN"; public static final String ACTION_MAIN = "com.xypower.mpapp.ACT_MAIN";
private static final String ACTION_HEARTBEAT = "ACT_HB"; private static final String ACTION_HEARTBEAT = "com.xypower.mpapp.ACT_HB";
private static final String ACTION_TAKE_PHOTO = "ACT_TP"; private static final String ACTION_TAKE_PHOTO = "com.xypower.mpapp.ACT_TP";
private static final String ACTION_TAKE_PHOTO_MANUALLY = "ACT_TP_M"; private static final String ACTION_TAKE_PHOTO_MANUALLY = "com.xypower.mpapp.ACT_TP_M";
private static final String ACTION_HEARTBEAT_MANUALLY = "ACT_HB_M"; private static final String ACTION_HEARTBEAT_MANUALLY = "com.xypower.mpapp.ACT_HB_M";
private static final String ACTION_TIMEOUT = "ACT_TIMEOUT"; private static final String ACTION_TIMEOUT = "com.xypower.mpapp.ACT_TIMEOUT";
public static final String ACTION_VIDEO_FINISHED = "com.xypower.mpapp.ACT_V_FINISHED";
private static final String EXTRA_PARAM_CHANNEL = "Channel"; private static final String EXTRA_PARAM_CHANNEL = "Channel";
private static final String EXTRA_PARAM_PRESET = "Preset"; private static final String EXTRA_PARAM_PRESET = "Preset";
private static final String EXTRA_PARAM_PHOTO_OR_VIDEO = "PhotoOrVideo"; private static final String EXTRA_PARAM_PHOTO_OR_VIDEO = "PhotoOrVideo";
@ -161,6 +162,7 @@ public class MicroPhotoService extends Service {
intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY); intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY);
intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY); intentFilter.addAction(ACTION_HEARTBEAT_MANUALLY);
intentFilter.addAction(ACTION_MSG_BROADCAST); intentFilter.addAction(ACTION_MSG_BROADCAST);
intentFilter.addAction(ACTION_VIDEO_FINISHED);
registerReceiver(mAlarmReceiver, intentFilter); registerReceiver(mAlarmReceiver, intentFilter);
// IntentFilter intentFilter2 = new IntentFilter(ACTION_MSG_BROADCAST); // IntentFilter intentFilter2 = new IntentFilter(ACTION_MSG_BROADCAST);
@ -281,9 +283,10 @@ public class MicroPhotoService extends Service {
int channel = (int) ((val & 0xFF0000L) >> 16); int channel = (int) ((val & 0xFF0000L) >> 16);
int preset = (int) ((val & 0xFF00L) >> 8); int preset = (int) ((val & 0xFF00L) >> 8);
boolean photoOrVideo = ((val & 0xFFL) == 0);
Log.i(TAG, "PhotoTimer Fired: CH=" + channel + " PR=" + preset); Log.i(TAG, "PhotoTimer Fired: CH=" + channel + " PR=" + preset);
mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, true); mService.notifyToTakePhoto(mService.mNativeHandle, channel, preset, ts, photoOrVideo);
} }
} }
@ -340,6 +343,13 @@ public class MicroPhotoService extends Service {
if (what == MSG_WHAT_SENDING_HB) { if (what == MSG_WHAT_SENDING_HB) {
mService.sendHeartbeat(mService.mNativeHandle); mService.sendHeartbeat(mService.mNativeHandle);
} }
} else if (TextUtils.equals(ACTION_VIDEO_FINISHED, action)) {
boolean result = intent.getBooleanExtra("result", false);
String path = intent.getStringExtra("path");
long videoId = intent.getLongExtra("videoId", 0);
Log.i(TAG, "Recording received(" + Long.toString(videoId) + "):" + path);
mService.recordingFinished(mService.mNativeHandle, result, path, videoId);
} }
} }
} }
@ -397,6 +407,20 @@ public class MicroPhotoService extends Service {
registerPhotoTimer(this.getApplicationContext(), channel, preset, ts, timeout, schedules); registerPhotoTimer(this.getApplicationContext(), channel, preset, ts, timeout, schedules);
} }
public void startRecording(int cameraId, long videoId, int duration, int width, int height, int quality) {
Context context = getApplicationContext();
Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.xypower.mvapp");
intent.putExtra("cameraId", cameraId);
intent.putExtra("videoId", videoId);
intent.putExtra("duration", duration);
intent.putExtra("width", width);
intent.putExtra("height", height);
intent.putExtra("quality", quality);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}
// private HashMap<Long, Integer> mTimers = new HashMap<Long, Integer>(); // private HashMap<Long, Integer> mTimers = new HashMap<Long, Integer>();
public boolean registerTimer(long uid, int timeout, long times) { public boolean registerTimer(long uid, int timeout, long times) {
@ -536,6 +560,8 @@ public class MicroPhotoService extends Service {
long val = 0; long val = 0;
val |= ((long)channel << 16); val |= ((long)channel << 16);
val |= ((long)preset << 8); val |= ((long)preset << 8);
val |= photoOrVideo ? 0L : 1L;
schedules.add(Long.valueOf(val)); schedules.add(Long.valueOf(val));
registerPhotoTimer(context, channel, preset, 0, 0, schedules); registerPhotoTimer(context, channel, preset, 0, 0, schedules);
@ -997,12 +1023,12 @@ cellSignalStrengthGsm.getDbm();
protected native long getHeartbeatDuration(long handler); protected native long getHeartbeatDuration(long handler);
protected native long[] getPhotoTimeData(long handler); protected native long[] getPhotoTimeData(long handler);
// protected native long[] getNextScheduleItem(long handler); // protected native long[] getNextScheduleItem(long handler);
protected native boolean notifyToTakePhoto(long handler, int channel, int preset, long scheduleTime, boolean sendToCma); protected native boolean notifyToTakePhoto(long handler, int channel, int preset, long scheduleTime, boolean photoOrVideo);
protected native boolean sendHeartbeat(long handler); protected native boolean sendHeartbeat(long handler);
protected native boolean fireTimeout(long handler, long uid, long times); protected native boolean fireTimeout(long handler, long uid, long times);
protected native void updatePosition(long handler, double lon, double lat, long ts); protected native void updatePosition(long handler, double lon, double lat, long ts);
protected native boolean uninit(long handler); protected native boolean uninit(long handler);
protected native void recordingFinished(long handler, boolean result, String path, long videoId);
////////////////////////GPS//////////////////// ////////////////////////GPS////////////////////
private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER; private static final String GPS_LOCATION_NAME = android.location.LocationManager.GPS_PROVIDER;

@ -238,6 +238,47 @@
app:layout_constraintStart_toEndOf="@+id/takePhotoBtn3" app:layout_constraintStart_toEndOf="@+id/takePhotoBtn3"
app:layout_constraintTop_toTopOf="@+id/takePhotoBtn" /> app:layout_constraintTop_toTopOf="@+id/takePhotoBtn" />
<Button
android:id="@+id/takeVideoBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/takePhotoBtn" />
<Button
android:id="@+id/takeVideoBtn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch2"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button
android:id="@+id/takeVideoBtn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch3"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn2"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button
android:id="@+id/takeVideoBtn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch4"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn3"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button <Button
android:id="@+id/btnSendHb" android:id="@+id/btnSendHb"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -247,7 +288,7 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:minWidth="@dimen/activity_min_width" android:minWidth="@dimen/activity_min_width"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/takePhotoBtn" /> app:layout_constraintTop_toBottomOf="@+id/takeVideoBtn" />
<Button <Button
android:id="@+id/btnRestartApp" android:id="@+id/btnRestartApp"
@ -356,7 +397,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:barrierDirection="right" app:barrierDirection="right"
app:constraint_referenced_ids="textViewCmdId,cmdid,protocol,networkProtocol,saveCfg,takePhotoBtn4,btnChannels,network" app:constraint_referenced_ids="textViewCmdId,cmdid,protocol,networkProtocol,saveCfg,takePhotoBtn4,btnChannels,network,takeVideoBtn4"
tools:layout_editor_absoluteX="46dp" /> tools:layout_editor_absoluteX="46dp" />

@ -243,6 +243,47 @@
app:layout_constraintStart_toEndOf="@+id/takePhotoBtn3" app:layout_constraintStart_toEndOf="@+id/takePhotoBtn3"
app:layout_constraintTop_toBottomOf="@+id/simchange" /> app:layout_constraintTop_toBottomOf="@+id/simchange" />
<Button
android:id="@+id/takeVideoBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch1"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/takePhotoBtn" />
<Button
android:id="@+id/takeVideoBtn2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch2"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button
android:id="@+id/takeVideoBtn3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch3"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn2"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button
android:id="@+id/takeVideoBtn4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:minWidth="@dimen/activity_min_width"
android:text="@string/btn_tv_ch4"
app:layout_constraintStart_toEndOf="@+id/takeVideoBtn3"
app:layout_constraintTop_toTopOf="@+id/takeVideoBtn" />
<Button <Button
android:id="@+id/btnSendHb" android:id="@+id/btnSendHb"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -250,7 +291,7 @@
android:text="@string/main_send_hb" android:text="@string/main_send_hb"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/takePhotoBtn" /> app:layout_constraintTop_toBottomOf="@+id/takeVideoBtn" />
<Button <Button
android:id="@+id/btnRestartApp" android:id="@+id/btnRestartApp"

@ -26,6 +26,10 @@
<string name="btn_tp_ch2">通道2</string> <string name="btn_tp_ch2">通道2</string>
<string name="btn_tp_ch3">通道3</string> <string name="btn_tp_ch3">通道3</string>
<string name="btn_tp_ch4">通道4</string> <string name="btn_tp_ch4">通道4</string>
<string name="btn_tv_ch1">视频1</string>
<string name="btn_tv_ch2">视频2</string>
<string name="btn_tv_ch3">视频3</string>
<string name="btn_tv_ch4">视频4</string>
<string name="channel_cfg_auto_exposure">自动曝光</string> <string name="channel_cfg_auto_exposure">自动曝光</string>
<string name="channel_cfg_auto_focus">自动对焦</string> <string name="channel_cfg_auto_focus">自动对焦</string>
<string name="channel_cfg_width">照片宽</string> <string name="channel_cfg_width">照片宽</string>

Loading…
Cancel
Save