Skip to content

Commit

Permalink
(feature) video recording (#917)
Browse files Browse the repository at this point in the history
* Android: Add video recording support

- Caveats:
  - Wont work if cropping is enabled
- Video recording will be used if mediaType is set to 'video'
  - Mediatype any is not supported since there is no standard intent for capture image or video

* IOS: Add video recording support

- Caveats:
  - Cropping does not work

Video recording will be enabled if mediaType is set to `video` or `any`. Note: With any the native ui
allows the user to choose whether to take a photo or record a video. This differs from android where
mediaType any will just allow taking photos.

* IOS: Set camera video quality to high

* Update README.md (#851)

* Update PickerModule.java (#862)

Fix for default values being kept when calling cropPicker from multiple locations.

Now default values if not passed will be reverted to default.

* version bump

* Add front camera support for android (#876)

* Add front camera support for android

* Update readme

* Update readme

* Update README.md

* Added missing flags to support front camera on some android phones (#891)

* Remove problematic step from manual post-install steps (#821)

* (ios) fix images are not resized after cropping. Fixes #843

* (ios) add example project xcshareddata

* (ios) fixes for camera recording. updated example project with camera recording. updated readme with camera recording

* unify ios and android camera response. Fixes #872
  • Loading branch information
ivpusic authored Jan 18, 2019
1 parent 2eeaf0c commit e562271
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 189 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,25 @@ ImagePicker.openPicker({
**Android: The prop 'cropping' has been known to cause videos not to be display in the gallery on Android. Please do not set cropping to true when selecting videos.**


### Select from camera
### Select from camera

#### Image

```javascript
ImagePicker.openCamera({
width: 300,
height: 400,
cropping: true
cropping: true,
}).then(image => {
console.log(image);
});
```

#### Video

```javascript
ImagePicker.openCamera({
mediaType: 'video',
}).then(image => {
console.log(image);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class PickerModule extends ReactContextBaseJavaModule implements ActivityEventLi
private int height = 0;

private Uri mCameraCaptureURI;
private String mCurrentPhotoPath;
private String mCurrentMediaPath;
private ResultCollector resultCollector = new ResultCollector();
private Compression compression = new Compression();
private ReactApplicationContext reactContext;
Expand Down Expand Up @@ -280,7 +280,7 @@ public void openCamera(final ReadableMap options, final Promise promise) {
}

setConfiguration(options);
resultCollector.setup(promise, multiple);
resultCollector.setup(promise, false);

permissionsCheck(activity, promise, Arrays.asList(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE), new Callable<Void>() {
@Override
Expand All @@ -294,15 +294,25 @@ public Void call() {
private void initiateCamera(Activity activity) {

try {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File imageFile = createImageFile();
String intent;
File dataFile;

if (mediaType.equals("video")) {
intent = MediaStore.ACTION_VIDEO_CAPTURE;
dataFile = createVideoFile();
} else {
intent = MediaStore.ACTION_IMAGE_CAPTURE;
dataFile = createImageFile();
}

Intent cameraIntent = new Intent(intent);

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
mCameraCaptureURI = Uri.fromFile(imageFile);
mCameraCaptureURI = Uri.fromFile(dataFile);
} else {
mCameraCaptureURI = FileProvider.getUriForFile(activity,
activity.getApplicationContext().getPackageName() + ".provider",
imageFile);
dataFile);
}

cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCameraCaptureURI);
Expand Down Expand Up @@ -436,6 +446,12 @@ private WritableMap getSelection(Activity activity, Uri uri, boolean isCamera) t
throw new Exception("Cannot resolve asset path.");
}

String mime = getMimeType(path);
if (mime != null && mime.startsWith("video/")) {
getVideo(activity, path, mime);
return null;
}

return getImage(activity, path);
}

Expand Down Expand Up @@ -514,8 +530,8 @@ private String resolveRealPath(Activity activity, Uri uri, boolean isCamera) thr
path = RealPathUtil.getRealPathFromURI(activity, uri);
} else {
if (isCamera) {
Uri imageUri = Uri.parse(mCurrentPhotoPath);
path = imageUri.getPath();
Uri mediaUri = Uri.parse(mCurrentMediaPath);
path = mediaUri.getPath();
} else {
path = RealPathUtil.getRealPathFromURI(activity, uri);
}
Expand Down Expand Up @@ -690,7 +706,12 @@ private void cameraPickerResult(Activity activity, final int requestCode, final
} else {
try {
resultCollector.setWaitCount(1);
resultCollector.notifySuccess(getSelection(activity, uri, true));
WritableMap result = getSelection(activity, uri, true);

// If recording a video getSelection handles resultCollector part itself and returns null
if (result != null) {
resultCollector.notifySuccess(result);
}
} catch (Exception ex) {
resultCollector.notifyProblem(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
}
Expand All @@ -704,10 +725,15 @@ private void croppingResult(Activity activity, final int requestCode, final int
if (resultUri != null) {
try {
WritableMap result = getSelection(activity, resultUri, false);
result.putMap("cropRect", PickerModule.getCroppedRectMap(data));

resultCollector.setWaitCount(1);
resultCollector.notifySuccess(result);
if (result != null) {
result.putMap("cropRect", PickerModule.getCroppedRectMap(data));

resultCollector.setWaitCount(1);
resultCollector.notifySuccess(result);
} else {
throw new Exception("Cannot crop video files");
}
} catch (Exception ex) {
resultCollector.notifyProblem(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
}
Expand Down Expand Up @@ -752,12 +778,31 @@ private File createImageFile() throws IOException {
File image = File.createTempFile(imageFileName, ".jpg", path);

// Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" + image.getAbsolutePath();
mCurrentMediaPath = "file:" + image.getAbsolutePath();

return image;

}

private File createVideoFile() throws IOException {

String videoFileName = "video-" + UUID.randomUUID().toString();
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);

if (!path.exists() && !path.isDirectory()) {
path.mkdirs();
}

File video = File.createTempFile(videoFileName, ".mp4", path);

// Save a file: path for use with ACTION_VIEW intents
mCurrentMediaPath = "file:" + video.getAbsolutePath();

return video;

}

private static WritableMap getCroppedRectMap(Intent data) {
final int DEFAULT_VALUE = -1;
final WritableMap map = new WritableNativeMap();
Expand Down
13 changes: 9 additions & 4 deletions example/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,17 @@ export default class App extends Component {
};
}

pickSingleWithCamera(cropping) {
pickSingleWithCamera(cropping, mediaType='photo') {
ImagePicker.openCamera({
cropping: cropping,
width: 500,
height: 500,
includeExif: true,
mediaType,
}).then(image => {
console.log('received image', image);
this.setState({
image: {uri: image.path, width: image.width, height: image.height},
image: {uri: image.path, width: image.width, height: image.height, mime: image.mime},
images: null
});
}).catch(e => alert(e));
Expand Down Expand Up @@ -106,7 +107,7 @@ export default class App extends Component {
});
}

pickSingle(cropit, circular=false) {
pickSingle(cropit, circular=false, mediaType) {
ImagePicker.openPicker({
width: 300,
height: 300,
Expand Down Expand Up @@ -151,6 +152,7 @@ export default class App extends Component {
}

renderVideo(video) {
console.log('rendering video');
return (<View style={{height: 300, width: 300}}>
<Video source={{uri: video.uri, type: video.mime}}
style={{position: 'absolute',
Expand Down Expand Up @@ -190,7 +192,10 @@ export default class App extends Component {
</ScrollView>

<TouchableOpacity onPress={() => this.pickSingleWithCamera(false)} style={styles.button}>
<Text style={styles.text}>Select Single With Camera</Text>
<Text style={styles.text}>Select Single Image With Camera</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.pickSingleWithCamera(false, mediaType='video')} style={styles.button}>
<Text style={styles.text}>Select Single Video With Camera</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.pickSingleWithCamera(true)} style={styles.button}>
<Text style={styles.text}>Select Single With Camera With Cropping</Text>
Expand Down
Loading

0 comments on commit e562271

Please sign in to comment.