Skip to content

Commit 3a532f5

Browse files
committed
[BFX] 安卓存储权限适配,音视频原始数据截屏位置调整到/sdcard/Pictures/Agora/
1 parent bb983fb commit 3a532f5

3 files changed

Lines changed: 81 additions & 46 deletions

File tree

Android/APIExample/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
android:allowBackup="true"
1616
android:icon="@mipmap/ic_launcher"
1717
android:label="@string/app_name"
18+
android:requestLegacyExternalStorage="true"
1819
android:roundIcon="@mipmap/ic_launcher_round"
1920
android:supportsRtl="true"
2021
android:theme="@style/AppTheme">

Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessAudioRawData.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,9 @@ public boolean onMixedAudioFrame(int i, int i1, int i2, int i3, int i4, ByteBuff
334334
}
335335

336336
@Override
337-
public boolean onPlaybackAudioFrameBeforeMixing(int i, int i1, int i2, int i3, int i4, int i5, ByteBuffer byteBuffer, long l, int i6) {
337+
public boolean onPlaybackAudioFrameBeforeMixing(String s, int i, int i1, int i2, int i3, int i4, ByteBuffer byteBuffer, long l, int i5) {
338338
return false;
339339
}
340-
341340
};
342341

343342
/**

Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessRawData.java

Lines changed: 79 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package io.agora.api.example.examples.advanced;
22

3-
import android.app.Activity;
3+
import android.content.ContentResolver;
4+
import android.content.ContentValues;
45
import android.content.Context;
5-
import android.graphics.Bitmap;
6-
import android.graphics.BitmapFactory;
7-
import android.graphics.ImageFormat;
8-
import android.graphics.Rect;
9-
import android.graphics.YuvImage;
6+
import android.graphics.*;
7+
import android.net.Uri;
8+
import android.os.Build;
109
import android.os.Bundle;
1110
import android.os.Environment;
11+
import android.provider.MediaStore;
1212
import android.text.TextUtils;
1313
import android.util.Log;
1414
import android.view.LayoutInflater;
@@ -18,38 +18,25 @@
1818
import android.widget.Button;
1919
import android.widget.EditText;
2020
import android.widget.FrameLayout;
21-
2221
import androidx.annotation.NonNull;
2322
import androidx.annotation.Nullable;
24-
2523
import com.yanzhenjie.permission.AndPermission;
2624
import com.yanzhenjie.permission.runtime.Permission;
27-
28-
import java.io.ByteArrayOutputStream;
29-
import java.io.File;
30-
import java.io.FileOutputStream;
31-
import java.nio.ByteBuffer;
32-
3325
import io.agora.api.example.MainApplication;
3426
import io.agora.api.example.R;
3527
import io.agora.api.example.annotation.Example;
3628
import io.agora.api.example.common.BaseFragment;
3729
import io.agora.api.example.utils.CommonUtil;
3830
import io.agora.base.VideoFrame;
39-
import io.agora.rtc2.ChannelMediaOptions;
40-
import io.agora.rtc2.Constants;
41-
import io.agora.rtc2.IRtcEngineEventHandler;
42-
import io.agora.rtc2.RtcConnection;
43-
import io.agora.rtc2.RtcEngine;
44-
import io.agora.rtc2.RtcEngineConfig;
45-
import io.agora.rtc2.video.EncodedVideoFrameInfo;
46-
import io.agora.rtc2.video.IVideoEncodedImageReceiver;
47-
import io.agora.rtc2.video.IVideoFrameObserver;
48-
import io.agora.rtc2.video.VideoCanvas;
49-
import io.agora.rtc2.video.VideoEncoderConfiguration;
31+
import io.agora.rtc2.*;
32+
import io.agora.rtc2.video.*;
33+
34+
import java.io.ByteArrayOutputStream;
35+
import java.io.File;
36+
import java.io.OutputStream;
37+
import java.nio.ByteBuffer;
5038

5139
import static io.agora.api.example.common.model.Examples.ADVANCED;
52-
import static io.agora.rtc2.Constants.RAW_AUDIO_FRAME_OP_MODE_READ_ONLY;
5340
import static io.agora.rtc2.video.VideoCanvas.RENDER_MODE_HIDDEN;
5441
import static io.agora.rtc2.video.VideoEncoderConfiguration.STANDARD_BITRATE;
5542

@@ -68,7 +55,7 @@ public class ProcessRawData extends BaseFragment implements View.OnClickListener
6855
private EditText et_channel;
6956
private RtcEngine engine;
7057
private int myUid;
71-
private boolean joined = false, isSnapshot = true;
58+
private boolean joined = false, isSnapshot = false;
7259

7360
@Override
7461
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -269,16 +256,11 @@ public boolean OnEncodedVideoImageReceived(ByteBuffer byteBuffer, EncodedVideoFr
269256
private final IVideoFrameObserver iVideoFrameObserver = new IVideoFrameObserver() {
270257
@Override
271258
public boolean onCaptureVideoFrame(VideoFrame videoFrame) {
272-
Log.i(TAG, "OnEncodedVideoImageReceived");
259+
Log.i(TAG, "OnEncodedVideoImageReceived"+Thread.currentThread().getName());
273260
if(isSnapshot){
274261
isSnapshot = false;
275-
String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "snapshot";
276-
File appDir = new File(storePath);
277-
if (!appDir.exists()) {
278-
appDir.mkdir();
279-
}
280-
String fileName = System.currentTimeMillis() + ".jpg";
281-
File file = new File(appDir, fileName);
262+
263+
// get image bitmap
282264
VideoFrame.I420Buffer buffer = videoFrame.getBuffer().toI420();
283265
ByteBuffer ib = ByteBuffer.allocate(videoFrame.getBuffer().getHeight() * videoFrame.getBuffer().getWidth() * 2);
284266
ib.put(buffer.getDataY());
@@ -291,15 +273,9 @@ public boolean onCaptureVideoFrame(VideoFrame videoFrame) {
291273
videoFrame.getBuffer().getWidth(), videoFrame.getBuffer().getHeight()), 50, out);
292274
byte[] imageBytes = out.toByteArray();
293275
Bitmap bm = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
294-
Bitmap bitmap = bm;
295-
try {
296-
FileOutputStream fos = new FileOutputStream(file);
297-
bitmap.compress(Bitmap.CompressFormat.PNG, 80, fos);
298-
fos.flush();
299-
fos.close();
300-
} catch (Exception e) {
301-
e.printStackTrace();
302-
}
276+
277+
// save to file
278+
saveBitmap2Gallery(bm);
303279
}
304280
return false;
305281
}
@@ -442,4 +418,63 @@ public void run() {
442418
}
443419
};
444420

421+
public void saveBitmap2Gallery(Bitmap bm){
422+
long currentTime = System.currentTimeMillis();
423+
424+
// name the file
425+
String imageFileName = "IMG_AGORA_"+ currentTime + ".jpg";
426+
String imageFilePath;
427+
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
428+
imageFilePath = Environment.DIRECTORY_PICTURES + File.separator + "Agora" + File.separator;
429+
else imageFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
430+
+ File.separator + "Agora"+ File.separator;
431+
432+
// write to file
433+
434+
OutputStream outputStream;
435+
ContentResolver resolver = requireContext().getContentResolver();
436+
ContentValues newScreenshot = new ContentValues();
437+
Uri insert;
438+
newScreenshot.put(MediaStore.Images.ImageColumns.DATE_ADDED,currentTime);
439+
newScreenshot.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, imageFileName);
440+
newScreenshot.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpg");
441+
newScreenshot.put(MediaStore.Images.ImageColumns.WIDTH, bm.getWidth());
442+
newScreenshot.put(MediaStore.Images.ImageColumns.HEIGHT, bm.getHeight());
443+
try {
444+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
445+
newScreenshot.put(MediaStore.Images.ImageColumns.RELATIVE_PATH,imageFilePath);
446+
}else{
447+
// make sure the path is existed
448+
File imageFileDir = new File(imageFilePath);
449+
if(!imageFileDir.exists()){
450+
boolean mkdir = imageFileDir.mkdirs();
451+
if(!mkdir) {
452+
showLongToast("save failed, error: cannot create folder. Make sure app has the permission.");
453+
return;
454+
}
455+
}
456+
newScreenshot.put(MediaStore.Images.ImageColumns.DATA, imageFilePath+imageFileName);
457+
newScreenshot.put(MediaStore.Images.ImageColumns.TITLE, imageFileName);
458+
}
459+
460+
// insert a new image
461+
insert = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, newScreenshot);
462+
// write data
463+
outputStream = resolver.openOutputStream(insert);
464+
465+
bm.compress(Bitmap.CompressFormat.PNG, 80, outputStream);
466+
outputStream.flush();
467+
outputStream.close();
468+
469+
newScreenshot.clear();
470+
newScreenshot.put(MediaStore.Images.ImageColumns.SIZE, new File(imageFilePath).length());
471+
resolver.update(insert, newScreenshot, null, null);
472+
473+
showLongToast("save success, you can view it in gallery");
474+
} catch (Exception e) {
475+
showLongToast("save failed, error: "+ e.getMessage());
476+
e.printStackTrace();
477+
}
478+
479+
}
445480
}

0 commit comments

Comments
 (0)