11package io .agora .api .example .examples .advanced ;
22
3- import android .app .Activity ;
3+ import android .content .ContentResolver ;
4+ import android .content .ContentValues ;
45import 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 ;
109import android .os .Bundle ;
1110import android .os .Environment ;
11+ import android .provider .MediaStore ;
1212import android .text .TextUtils ;
1313import android .util .Log ;
1414import android .view .LayoutInflater ;
1818import android .widget .Button ;
1919import android .widget .EditText ;
2020import android .widget .FrameLayout ;
21-
2221import androidx .annotation .NonNull ;
2322import androidx .annotation .Nullable ;
24-
2523import com .yanzhenjie .permission .AndPermission ;
2624import 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-
3325import io .agora .api .example .MainApplication ;
3426import io .agora .api .example .R ;
3527import io .agora .api .example .annotation .Example ;
3628import io .agora .api .example .common .BaseFragment ;
3729import io .agora .api .example .utils .CommonUtil ;
3830import 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
5139import static io .agora .api .example .common .model .Examples .ADVANCED ;
52- import static io .agora .rtc2 .Constants .RAW_AUDIO_FRAME_OP_MODE_READ_ONLY ;
5340import static io .agora .rtc2 .video .VideoCanvas .RENDER_MODE_HIDDEN ;
5441import 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