1

This is the code that I'm using to capture video for 7 seconds, then automatically upload the video to Google Drive using Google Drive Android API. The problem is: when the upload is finished, I can't play the video. The saved video in the smartphone can be played, but not the uploaded video.

public class Video extends 
AppCompatActivity implements 
SurfaceHolder.Callback, GoogleApiClient.ConnectionCallbacks, 
GoogleApiClient.OnConnectionFailedListener 
{

    public static File file;
    public static GoogleApiClient mGoogleApiClient;
    MediaRecorder recorder;
    SurfaceHolder holder;
    boolean recording = false;
    FileOutputStream fileOut;
    public static final String TAG = "SaveMe";
    private Camera camera;

    private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;

    Calendar calendar = Calendar.getInstance();
    final int hours = calendar.get(Calendar.HOUR_OF_DAY);
    final int minutes = calendar.get(Calendar.MINUTE);
    int seconds = calendar.get(Calendar.SECOND);


    Date dateNow = new Date();
    SimpleDateFormat dateformatJava = new SimpleDateFormat("dd-MM-yyyy");
    final String date = dateformatJava.format(dateNow);
    private static final String STATE_RESOLVING_ERROR = "resolving_error";
    private static final int REQUEST_RESOLVE_ERROR = 1001;
    private static final String DIALOG_ERROR = "dialog_error";
    private boolean mResolvingError = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        mResolvingError = savedInstanceState != null && savedInstanceState.getBoolean(STATE_RESOLVING_ERROR, false);

        mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addApi(Drive.API)
            .addScope(Drive.SCOPE_FILE)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        recorder = new MediaRecorder();

        initRecorder();
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);



        SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView);
        holder = cameraView.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_video, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void initRecorder() {

        File folder = new File(Environment.getExternalStorageDirectory() + "/SaveMe");
        boolean success = true;
        if (!folder.exists()) {
            success = folder.mkdir();
        }

        File folder2 = new File(Environment.getExternalStorageDirectory() + "/SaveMe/" + date);
        boolean success2 = true;
        if (!folder2.exists()) {
            success2 = folder2.mkdir();
        }

        int cameraId = -1;
        int numberOfCameras = Camera.getNumberOfCameras();
        for (int i = 0; i < numberOfCameras; i++) {
            Camera.CameraInfo info = new Camera.CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                Log.d("saveme", "Camera found");
                cameraId = i;
                break;
            }
        }


        recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);

        CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
        recorder.setProfile(cpHigh);

        file = new java.io.File(Environment.getExternalStorageDirectory() + "/SaveMe/" + date + "/Video " + hours + " " + minutes + ".mp4");
        recorder.setOutputFile(Environment.getExternalStorageDirectory() + "/SaveMe/" + date + "/Video " + hours + " " + minutes + ".mp4");
        Log.i(TAG, "saved");
        recorder.setMaxDuration(9000); // 5 seconds
        recorder.setMaxFileSize(5000000); // Approximately 5 megabytes
        Log.i(TAG, "Start counting");

        new Timer().schedule(new TimerTask() {@Override
            public void run() {
                runOnUiThread(new Runnable() {@Override
                    public void run() {
                        Log.i(TAG, "Thread 7 sec");
                        saveFiletoDrive(file);
                    }
                });
            }
        }, 9000);

    }

    private void saveFiletoDrive(final File file) {
        Log.i(TAG, "Saving....");
        Drive.DriveApi.newDriveContents(getGoogleApiClient()).setResultCallback(
        new ResultCallback < DriveApi.DriveContentsResult > () {@Override
            public void onResult(DriveApi.DriveContentsResult result) {
                String mime = "video/mp4";
                if (!result.getStatus().isSuccess()) {
                    Log.i(TAG, "Failed to create new contents.");
                    return;
                }
                Log.i(TAG, "Connection successful, creating new contents...");
                OutputStream outputStream = result.getDriveContents().getOutputStream();

                FileInputStream fis;
                try {
                    fis = new FileInputStream(file.getPath());
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();

                    byte[] buf = new byte[1024];
                    int n;

                    while ((n = fis.read(buf)) != -1)
                    baos.write(buf, 0, n);

                    outputStream.write(baos.toByteArray());
                    baos.flush();

                    outputStream.close();
                    outputStream = null;
                    fis.close();
                    fis = null;

                } catch (FileNotFoundException e) {
                    Log.w(TAG, "FileNotFoundException: " + e.getMessage());
                } catch (IOException e1) {
                    Log.w(TAG, "Unable to write file contents." + e1.getMessage());
                }

                String title = file.getName();
                MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
                    .setMimeType(mime).setTitle(title).build();

                Drive.DriveApi.getRootFolder(getGoogleApiClient())
                    .createFile(getGoogleApiClient(), metadataChangeSet, result.getDriveContents())
                    .setResultCallback(fileCallback);

                Log.i(TAG, "Creating new video on Drive (" + title + ")");

            }

        });
    }

    final public ResultCallback < DriveFolder.DriveFileResult > fileCallback = new
    ResultCallback < DriveFolder.DriveFileResult > () {@Override
        public void onResult(DriveFolder.DriveFileResult result) {
            if (!result.getStatus().isSuccess()) {
                Log.i(TAG, "Error while trying to create the file");
                return;
            }
            Log.i(TAG, "Successfull !");

        }
    };

    private void prepareRecorder() {
        recorder.setPreviewDisplay(holder.getSurface());

        try {
            recorder.prepare();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {

        File folder = new File(Environment.getExternalStorageDirectory() + "/SaveMe");
        boolean success = true;
        if (!folder.exists()) {
            success = folder.mkdir();
        }

        File folder2 = new File(Environment.getExternalStorageDirectory() + "/SaveMe/" + date);
        boolean success2 = true;
        if (!folder2.exists()) {
            success2 = folder2.mkdir();
        }

        prepareRecorder();
        recorder.start();
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        if (recording) {
            recorder.stop();
            recording = false;
        }
        recorder.release();
    }

    public static GoogleApiClient getGoogleApiClient() {
        return mGoogleApiClient;
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.w(TAG, "Connected to google ");
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!mResolvingError) { // more about this later
            mGoogleApiClient.connect();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGoogleApiClient.connect();
    }

    @Override
    protected void onPause() {
        super.onPause();
        recorder.release();
        if (mGoogleApiClient.isConnected()) {
            mGoogleApiClient.disconnect();
        }
    }

    @Override
    protected void onStop() {
        recorder.release();
        mGoogleApiClient.disconnect();
        super.onStop();
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.w(TAG, "failed to connected to google ");
        if (connectionResult.hasResolution()) {
            try {
                connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
        }
    }

    private class MyAsyncTask extends AsyncTask < Void, Void, Void > {@Override
        protected Void doInBackground(Void...params) {
            Log.i(TAG, "exec");
            saveFiletoDrive(file);
            return null;
        }@Override
        protected void onPostExecute(Void result) {
        }
    }
}
live-love
  • 48,840
  • 22
  • 240
  • 204
Nazmi Asri
  • 11
  • 1
  • Have you checked if the file generated with the inputStream is in fact the same file as the one saved in the fileSystem, before uploading to Drive? – Rivero Aug 12 '15 at 23:08
  • Also, what do you mean by corrupted? What is the size of the uploaded file? If you download it from the web, what content does it contain? – Ofir Aug 14 '15 at 21:33
  • What the code is doing is it will take a video and save it to a folder. The video is successfully uploaded to google Drive, and the size is same. But when I downloaded the video from Google Drive, the video can not be played. I compare the hex from the video in phone and hex from video on Google Drive, some of the hex inside the video is changed and the file is not MP4 when I check the file signature. – Nazmi Asri Aug 15 '15 at 01:50
  • Rivero, how to check the generated file is the same file? And one more things is the video will crash if I put finish() inside the timer. I want it to close the activity after 9 seconds. new Timer().schedule(new TimerTask() {@Override public void run() { runOnUiThread(new Runnable() {@Override public void run() { finish(); } }); } }, 9000); – Nazmi Asri Aug 15 '15 at 02:02
  • When you said you "compare the hex from the video in phone and hex from video on Google Drive", where did you get the file in phone from? Is it (a) from the physical file created by MediaRecorder, or (b) from reading back the file using DriveFile#open()? – Prima Aug 17 '15 at 01:28
  • Another thing is, could it be that you're trying to copy the files to Drive before MediaRecorded finishes writing to it? The saveFileToDrive was called from a thread after 9 seconds, but at that time the MediaRecorder#stop might not be called yet? – Prima Aug 17 '15 at 01:31
  • Yup, it is from file that created by MediaRecorder.. I want to make the app record a video for 9 seconds and then it saved to the phone, and then upload to the Drive. But now when I put finish() and MediaRecorder stop inside the thread, after 9 seconds it is not closing the activity, but it crashing. – Nazmi Asri Aug 17 '15 at 07:58
  • Do you know how to check the upload progress for Drive API, I have a problem with that. I want it to upload on background.. – Nazmi Asri Aug 17 '15 at 07:59
  • This is just a guess, but the crash might be because you're trying to use the MediaRecorder from some other place, when it's already closed by the thread (e.g. from surfaceDestroyed maybe?) Hard to say without stack trace and updated code. – Prima Aug 18 '15 at 00:51
  • Re upload progress, there is currently no way to get detailed progress, but you can request for Completion Events (https://developers.google.com/drive/android/completion) to get notified when the upload is completed. You need to use the variant of createFile that takes in ExecutionOptions. – Prima Aug 18 '15 at 00:54
  • Thank you, I already check the mediarecorder code and finally manage to finish the app without crash, need to stop and release, then finish the activity. Now Im trying to upload the file using service. – Nazmi Asri Aug 19 '15 at 03:41

0 Answers0