修复视频流摄像头翻转的bug

nx_mplive
liuguijing 2 months ago
parent 27809fd87b
commit 4a71482346

@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
// 10,00,000 major-minor-build
def AppMajorVersion = 1
def AppMinorVersion = 0
def AppBuildNumber = 5
def AppBuildNumber = 6
def AppVersionName = AppMajorVersion + "." + AppMinorVersion + "." + AppBuildNumber
def AppVersionCode = AppMajorVersion * 100000 + AppMinorVersion * 1000 + AppBuildNumber

@ -11,6 +11,9 @@
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application
@ -30,11 +33,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".CameraForegroundService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="camera" />
</application>
</manifest>

@ -1,81 +0,0 @@
package com.xypower.mplive;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
public class CameraForegroundService extends Service {
private static final int NOTIFICATION_ID = 123;
private static final String CHANNEL_ID = "camera_service";
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 创建必须的通知Android 8.0+要求)
Notification notification = buildCameraNotification();
// 启动为前台服务
startForeground(NOTIFICATION_ID, notification);
// 在这里可以初始化摄像头
initCameraInService();
return START_STICKY;
}
private Notification buildCameraNotification() {
// 创建点击跳转到应用的PendingIntent
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("摄像头服务运行中")
.setContentText("正在使用摄像头功能")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build();
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"摄像头服务通道",
NotificationManager.IMPORTANCE_HIGH);
serviceChannel.setDescription("用于摄像头服务的通知通道");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
void sendDataToActivity() {
Intent intent = new Intent("ACTION_UPDATE_UI");
intent.putExtra("key", "value");
sendBroadcast(intent);
}
private void initCameraInService() {
// 在这里实现摄像头初始化逻辑
// 注意:部分设备可能仍限制服务中直接访问摄像头
sendDataToActivity();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

@ -1,10 +1,7 @@
package com.xypower.mplive;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
@ -74,9 +71,6 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
private Handler mHandler;
private int cameraId = 0;
private List<CameraItemData> cameraData;
private int autoStart;
private EditText efu;
private int rotation;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -86,17 +80,14 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
setContentView(R.layout.activity_main);
// 关键代码声明为前台可见Android 10+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
setTurnScreenOn(true); // 唤醒屏幕(即使无物理屏)
setShowWhenLocked(true); // 允许锁屏显示
}
// response screen rotation event
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
registerReceiver(updateReceiver, new IntentFilter("ACTION_UPDATE_UI"));
// 启动前台服务
Intent serviceIntent = new Intent(this, CameraForegroundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}
requestPermission();
}
private void requestPermission() {
@ -138,27 +129,18 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
}
}
}
private BroadcastReceiver updateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if ("ACTION_UPDATE_UI".equals(action)) {
String data = intent.getStringExtra("key");
extracted(autoStart, efu, rotation);
}
}
};
private void init() {
Intent intent = getIntent();
autoStart = intent.getIntExtra("autoStart", 1);
final int autoStart = intent.getIntExtra("autoStart", 1);
// restore data.
sp = getSharedPreferences("MpLive", MODE_PRIVATE);
// rtmpUrl = sp.getString("rtmpUrl", rtmpUrl);
// initialize url.
efu = (EditText) findViewById(R.id.url);
final EditText efu = (EditText) findViewById(R.id.url);
btnPublish = (Button) findViewById(R.id.publish);
@ -178,7 +160,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
}
efu.setText(rtmpUrl);
mCameraView = (SrsCameraView) findViewById(R.id.glsurfaceview_camera);
rotation = intent.getIntExtra("rotation", -1);
final int rotation = intent.getIntExtra("rotation", -1);
if (rotation != -1) {
//设置图像显示方向
mCameraView.setPreviewOrientation(rotation);
@ -211,7 +193,30 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
if (autoStart != 0) {
// extracted(autoStart, efu, rotation);
startRTMPServer();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// rtmpUrl = "rtmp://61.169.135.146/live/0";
SharedPreferences.Editor editor = sp.edit();
editor.putString("rtmpUrl", rtmpUrl);
editor.apply();
efu.setText(rtmpUrl + "rotation= " + rotation + " cameraid=" + cameraId + " auto=" + autoStart);
// efu.setText(rtmpUrl + " cameraid=" + cameraId + " auto=" + autoStart);
efu.setText(rtmpUrl);
mPublisher.startPublish(rtmpUrl);
if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
// Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();
}
btnPublish.setText("stop");
btnSwitchEncoder.setEnabled(false);
btnPause.setEnabled(true);
mPublisher.switchCameraFace(cameraId, rotation);
}
}, 500);
} else {
mPublisher.switchCameraFace(cameraId, rotation);
}
@ -242,7 +247,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
efu.setText(rtmpUrl);
mPublisher.startPublish(rtmpUrl);
// mPublisher.startCamera();
mPublisher.switchCameraFace(cameraId, rotation);
mPublisher.switchCameraFace(cameraId,rotation);
if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
@ -281,7 +286,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
int size = cameraData.size();
if (size > 0) {
int i = (++cameraId) % size;
mPublisher.switchCameraFace(cameraId, rotation);
mPublisher.switchCameraFace(cameraId,rotation);
}
}
});
@ -317,32 +322,6 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
});
}
private void extracted(final int autoStart, final EditText efu, final int rotation) {
startRTMPServer();
mPublisher.switchCameraFace(cameraId, rotation);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
// rtmpUrl = "rtmp://61.169.135.146/live/0";
SharedPreferences.Editor editor = sp.edit();
editor.putString("rtmpUrl", rtmpUrl);
editor.apply();
efu.setText(rtmpUrl + "rotation= " + rotation + " cameraid=" + cameraId + " auto=" + autoStart);
// efu.setText(rtmpUrl + " cameraid=" + cameraId + " auto=" + autoStart);
efu.setText(rtmpUrl);
mPublisher.startPublish(rtmpUrl);
if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
// Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();
}
btnPublish.setText("stop");
btnSwitchEncoder.setEnabled(false);
btnPause.setEnabled(true);
}
}, 500);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
@ -424,15 +403,11 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
// }
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(updateReceiver);
}
@Override
protected void onResume() {
super.onResume();
Log.d("com.xypower.mplive", "进入resume");
requestPermission();
final Button btn = (Button) findViewById(R.id.publish);
btn.setEnabled(true);
mPublisher.resumeRecord();

@ -61,7 +61,34 @@ public class GPUImageFilter {
private int[] mGLFboId;
private int[] mGLFboTexId;
private IntBuffer mGLFboBuffer;
private float[] TEX_COORD;
final float TEX_COORD0[] = {
0.0f, 0.0f, // Bottom left.
1.0f, 0.0f, // Bottom right.
0.0f, 1.0f, // Top left.
1.0f, 1.0f // Top right.
};
final float TEX_COORD_90[] = {
0.0f, 1.0f, // Bottom left.
0.0f, 0.0f, // Bottom right.
1.0f, 1.0f, // Top left.
1.0f, 0.0f // Top right.
};
final float TEX_COORD_180[] = {
1.0f, 1.0f, // Bottom left.
0.0f, 1.0f, // Bottom right.
1.0f, 0.0f, // Top left.
0.0f, 0.0f // Top right.
};
final float TEX_COORD_270[] = {
1.0f, 0.0f, // Bottom left.
1.0f, 1.0f, // Bottom right.
0.0f, 0.0f, // Top left.
0.0f, 1.0f // Top right.
};
private float[] TEX_COORD = TEX_COORD0;
public GPUImageFilter() {
this(MagicFilterType.NONE);
@ -476,33 +503,6 @@ public class GPUImageFilter {
// 1.0f, 1.0f // Top right.
// };
final float TEX_COORD0[] = {
0.0f, 0.0f, // Bottom left.
1.0f, 0.0f, // Bottom right.
0.0f, 1.0f, // Top left.
1.0f, 1.0f // Top right.
};
final float TEX_COORD_90[] = {
0.0f, 1.0f, // Bottom left.
0.0f, 0.0f, // Bottom right.
1.0f, 1.0f, // Top left.
1.0f, 0.0f // Top right.
};
final float TEX_COORD_180[] = {
1.0f, 1.0f, // Bottom left.
0.0f, 1.0f, // Bottom right.
1.0f, 0.0f, // Top left.
0.0f, 0.0f // Top right.
};
final float TEX_COORD_270[] = {
1.0f, 0.0f, // Bottom left.
1.0f, 1.0f, // Bottom right.
0.0f, 0.0f, // Top left.
0.0f, 1.0f // Top right.
};
//纹理坐标
TEX_COORD = TEX_COORD0;
if (rotation == 0) {
TEX_COORD = TEX_COORD0;
} else if (rotation == 90) {

Loading…
Cancel
Save