I'm trying to get the video captured with the camera to get the base64 but without success.
async takeVideo() {
let options: CaptureVideoOptions = {
limit: 1,
duration: 30,
};
this.mediaCapture.captureVideo(options).then(async (video: MediaFile[]) => {
let deviceUrl = video[0].fullPath;
let info :any = await this.file.resolveLocalFilesystemUrl(deviceUrl);
console.log(info);
if (deviceUrl.includes('/private')) {
deviceUrl = deviceUrl.replace('/private', 'file://');
}
const pathToRead = deviceUrl.substr(0, deviceUrl.lastIndexOf('/') + 1);
const nameToRead = deviceUrl.substr(deviceUrl.lastIndexOf('/') + 1);
this.file.readAsDataURL(pathToRead, nameToRead).then(result => {
console.log(result);
}),(error) => {
console.log("ERROR!")
console.log(error);
}
}
In xcode, I print the info
{"isFile":true,"isDirectory":false,"name":"69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV","fullPath":"/69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV","filesystem":"<FileSystem: temporary>","nativeURL":"file:///var/mobile/Containers/Data/Application/DEAF6F3C-AE8C-4017-A383-DE93FEE4B6D9/tmp/69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV"}
The values I send to readAsDataURL are:
[log] - pathToRead file:///var/mobile/Containers/Data/Application/DEAF6F3C-AE8C-4017-A383-DE93FEE4B6D9/tmp/
[log] - nameToRead 69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV
And then I see these logs:
To Native Cordova -> File getFileMetadata File1360924565 ["options": [cdvfile://localhost/temporary/69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV]]
To Native Cordova -> File readAsDataURL File1360924566 ["options": [cdvfile://localhost/temporary/69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV, 0, 94579]]
To Native Cordova -> File readAsDataURL File1360924567 ["options": [cdvfile://localhost/temporary/69560062032__436D1450-8884-43A1-A0C3-214235ABD744.MOV, 0, 94579]]
After that, I do not receive anything, neither error, nor the result, i have to mention that neither readAsDataURL and readAsArrayBuffer nor work for me
Related
As the title says I have some video saved on an s3 bucket. I set my nodejs to stream it on my react app. It works fine on all devices except iOS. I did some searches and I can't find the issue. The server is returning the initial bytes request as 206. I checked the headers but I can't find the issue:
Here is my nodejs:
After it reaches the path:
if (!range) {
res.status(400).send("returning err!");
return;
}
s3.headObject({
Bucket: process.env.AWS_BUCKET_NAME,
Key: req.params.key
}, function (err, data) {
if (err) {
// an error occurred
console.error(err);
return res.status(500).send("returning err");
}
const videoSize = Number(data.ContentLength);
const CHUNK_SIZE = 10 ** 6; // 1MB
const start = Number(range.replace(/\D/g, ""));
const end = Math.min(start + CHUNK_SIZE, videoSize - 1);
var params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: req.params.key,
Range: range,
};
var stream = s3.getObject(params).createReadStream();
res.status(206);
res.set('Content-Type', data.ContentType);
res.set('Content-Disposition','inline');
res.set('Accept-Ranges','bytes');
res.set('Accept-Encoding', 'Identity');
res.set('Content-Range', 'bytes ' + start + '-' + end + '/' + videoSize);
res.set('Content-Length', data.ContentLength);
res.set('X-Playback-Session-Id', req.header('X-Playback-Session-Id')); // Part of the attempt to fix
res.set('Connection', 'keep-alive');
res.set('Last-Modified', data.LastModified);
res.set('ETag', data.ETag);
stream.pipe(res);
Here is my Frontend React player code:
<ReactPlayer
ref={player}
// onProgress={onProgress}
playsinline={true}
url={[{ src: source, type: 'video/mp4;' }]} // video location
controls // gives the front end video controls
width='100%'
className='react-player'
height='100%'
allow='autoplay; encrypted-media'
allowFullScreen
// muted={true}
playing={playing}
onPlay={() => setPlaying(true)}
// onPause={() => setPlaying(false)} //part of the attempt to fix
// onSeek={(seek) => playerSeeker(seek)} //part of the attempt to fix
config={{
file: {
attributes: {
controlsList: 'nodownload'
}
}
}}
onContextMenu={e => e.preventDefault()}
onEnded={(e) => onVideoEnded(e)}
onError={(e) => onVideoError(e)}
/>
Again, the first request on iOS is returning a 206 success but node always ends the stream before it even start playing.
Turns out It was just the
res.set('Content-Length', data.ContentLength);
Instead of sending the full length for the video, I needed to return the length of the calculated range.
I implemented functionality for download image in React Native using RNFetchBlob Its Working fine with android but on IOS device it's not working.
Following is my react native code for download functionality.
downloadImg = (url) => {
var that = this;
async function requestCameraPermission() {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
{
title: 'Test App',
message: 'Test App needs access to your gallery ',
}
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
that.actualDownload(url);
} else {
Alert.alert('Permission Denied!', 'You need to give storage permission to download the file');
}
}
if (Platform.OS === 'android') {
requestCameraPermission();
} else {
this.actualDownload(url);
}
}
actualDownload = (url) => {
var date = new Date();
var image_URL = url;
var ext = this.getExtention(image_URL);
ext = "." + ext[0];
const { config, fs } = RNFetchBlob;
let PictureDir = Platform.OS === 'ios' ? fs.dirs.DocumentDir : fs.dirs.PictureDir;
let options = {
fileCache: true,
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
path: PictureDir + "/Images/image_" + Math.floor(date.getTime()
+ date.getSeconds() / 2) + ext,
description: 'Image'
}
}
config(options).fetch('GET', image_URL).then((res) => {
console.log("Thank you","Image Downloaded Successfully.");
});
}
the addAndroidDownloads only works for android. when you use the addAndroidDownloads the path in config is not useless. but for ios, the path has to be added.
try the following code, and you can add progress for ios.
actualDownload = (url) => {
var date = new Date();
var image_URL = url;
var ext = this.getExtention(image_URL);
ext = "." + ext[0];
const { config, fs } = RNFetchBlob;
let PictureDir = Platform.OS === 'ios' ? fs.dirs.DocumentDir : fs.dirs.PictureDir;
let options = {
fileCache: true,
path: PictureDir + "/Images/image_" + Math.floor(date.getTime() // add it
addAndroidDownloads: {
useDownloadManager: true,
notification: true,
path: PictureDir + "/Images/image_" + Math.floor(date.getTime()
+ date.getSeconds() / 2) + ext,
description: 'Image'
}
}
config(options).fetch('GET', image_URL).then((res) => {
console.log("Thank you","Image Downloaded Successfully.");
});
}
here are the document says:
When using DownloadManager, fileCache and path properties in config will not take effect, because Android DownloadManager can only store files to external storage, also notice that Download Manager can only support GET method, which means the request body will be ignored.
That method works for ios as well. The notification doesn't come. If you want to check that it is downloaded or not, you can check it by logging the path in terminal(Mac) or cmd(Windows) and access it through the terminal itself.
It might not be visible in finder(Mac) or file explorer(Windows).
You can follow the path that you log from the function in this way:
cd ~/Library/Developer/CoreSimulator/Devices...
The solution changes will be included in the upcoming release 5.0. Please check the comment from nativescript-imagepicker team:
https://github.com/NativeScript/nativescript-imagepicker/issues/217
Thanks for your time.
Selected image size is different from the original image, How to get the original file size ?
Which platform(s) does your issue occur on?
emulator IOS 11.4 on
iphone 8 Plus
real device IOS 11.4 on IPad air
Please, provide the following version numbers that your issue occurs with:
"nativescript-imagepicker": "6.0.4"
CLI: Nativescript 4.2.0
"tns-core-modules": "^4.2.1",
"tns-platform-declarations": "^3.3.0"
Plugin(s):
"devDependencies": {
"babel-traverse": "6.26.0",
"babel-types":"6.26.0",
"babylon":
"6.18.0",
"lazy": "1.0.11",
"nativescript-dev-typescript": "0.7.2",
"typescript": "~2.7.2"
}
Is there any code involved?
Here I use #NevinDry's code:
the original image is 2 MB, and it became 20MB after 'imageSource.saveToFile(path1, "jpeg");'
pickFile() {
let context = imagepickerModule.create({
mediaType: 1,//image only
mode: "single"
});
context
.authorize()
.then(function () {
return context.present();
})
.then(selection => {
selection.forEach(selected => {
let file;
fromAsset(selected).then((imageSource) => {
const folder = knownFolders.documents().path;
const fileName = "test.jpg";
const path1 = path.join(folder, fileName);
const saved = imageSource.saveToFile(path1, "jpeg");
console.log("saved:" + saved);
if (saved) {
console.log("Image saved successfully!");
file = File.fromPath(path1);
console.log("path1:" + path1);
this._checkFileSize(path1);
}
})
});
})
.catch(function (e) {
console.log(e);
});
}
private _checkFileSize(fileUri: string): boolean {
if (isIOS) {
var defManager = NSFileManager.defaultManager;
console.debug("the file path:" + fileUri);
var fileAttributes = defManager.attributesOfItemAtPathError(fileUri);
console.debug(defManager);
var fileSizeNumber = fileAttributes.objectForKey(NSFileSize);
console.debug(fileSizeNumber);
var fileSizeNumberB = fileSizeNumber / 1000000.0;
console.debug("file size in Megabytes");
console.debug(fileSizeNumberB);
return true;
}
}
I also tried below solution: the 2MB image turns to 6MB. Better but not correct.
One more thing maybe related, 'imageSource.saveToFile(filePath, fileType);'
the original file type is jpg , so I keep fileType as jpg here. If uses PNG, the size is bigger.
pickfile2(){
let context = imagepickerModule.create({
mediaType: 1,//image only
mode: "single"
});
context
.authorize()
.then(function () {
return context.present();
})
.then(selection => {
selection.forEach(selected => {
const ios = selected.ios;
if (ios && ios.mediaType === PHAssetMediaType.Image) {
const opt = PHImageRequestOptions.new();
opt.version = PHImageRequestOptionsVersion.Current;
PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
ios, opt, (imageData: NSData, dataUTI: string, orientation: UIImageOrientation, info: NSDictionary<any, any>) => {
console.debug(info.objectForKey("PHImageFileURLKey").toString());
let srcfilePath = info.objectForKey("PHImageFileURLKey").toString();
let fileName = this.extractImageName(srcfilePath);
let fileType: "png" | "jpeg" | "jpg" = this.extractImageType(fileName);
console.log("fileName:" + fileName);
console.log("srcfilePath:" + srcfilePath);
//get image instance from data; it doesn't work via 'fromPath'
let imageSource: ImageSource = <ImageSource>fromData(imageData);
let filePath = path.join(this.filePickerPath, fileName);
console.log("filePath:" + filePath);
let saved = imageSource.saveToFile(filePath, fileType);
console.log("saved:" + saved);
if (saved) {
this._checkFileSize(filePath);
}
});
}
});
})
.catch(function (e) {
console.log(e);
});
}
The playground code is here
The page went crash once added npm package 'tns-platform-declarations' from it. So please download it if you want to run. Then
remove the folder version of nativescript-imagepicker#6.0.4
rename package1.json to package.json
In references.d.ts, add additiona '/' before '//' to make it as '///' on the two lines.
npm install. That demo should work on your env.
Anyway, Does anyone have idea on it ? Thanks.
I am using cordova-plugin-media-with-compression for an app which runs on IOS and Android. On Android the code is working perfectly, records, play, stop, erase, no problem. On IOS I can play the files saved using the android app, but as soon as I try to record I get error 1 which is MEDIA_ERR_ABORTED (no idea what that means). So works perfectly on Android, but will not record on IOS. I am also using cordovafile for other things and they work, so I know cordova file is working and I verified that I am getting a legitimate folder for the mediapath.
I used the code right out of the example.
$scope.mediapath = cordova.file.externalApplicationStorageDirectory || cordova.file.tempDirectory || cordova.file.sharedDirectory;
$rootScope.mediaOptions = {
SampleRate: 16000,
NumberOfChannels: 1
};
$scope.mediafile = "record-audio.m4a";
$scope.media = new Media($scope.mediapath + $scope.mediafile, function () {
console.log("recordAudio():Audio Success");
},
function (err) { console.log("recordAudio():Audio Error: " + err.code); },
function (s) {
if (s === 4) {
$timeout(function () {
angular.element(document.getElementById('stopButton')).triggerHandler('click');
}, 0);
}
} );
$scope.media.startRecordWithCompression($rootScope.mediaOptions);
Even though . $scope.mediapath = $scope.mediapath.fullPath; worked for a while, I had further errors and ended up with this solution. Note I keep both mediapath and mediapath1 because when using $cordovaFile.readAsDataURL($rootScope.mediapath, $scope.mediafile)... I need the mediapath for ios and android.
$rootScope.mediaOptions = {
SampleRate: 16000,
NumberOfChannels: 1
};
$rootScope.mediapath = cordova.file.tempDirectory || cordova.file.dataDirectory || cordova.file.externalApplicationStorageDirectory || cordova.file.sharedDirectory || cordova.file.applicationStorageDirectory;
$rootScope.mediapath1 = $rootScope.mediapath;
if (cordova.platformId === 'ios') {
$rootScope.mediapath1 = '';
}
then when I need to initialize the media
$scope.mediafile = "audio.m4a";
$scope.media = new Media($rootScope.mediapath1 + $scope.mediafile,
function () {
console.log("recordAudio():Audio Success");
},
function (err) { console.log("recordAudio():Audio Error: " + err.code + err.message); },
function (s) {
// catch change to audio here for example when s===4 the recording has been stopped.
}
});
$scope.media.startRecordWithCompression($rootScope.mediaOptions)
;
I am trying to use the audio recording as described in the PhoneGap API documentation. But on IOS there seems to be a problem with the file URI for myrecording.wav. I am using the following code to write to a file named myrecodring.wav
function recordAudio() {
var src = "myrecording.wav";
var mediaRec = new Media(src, onSuccess, onError);
// Record audio
mediaRec.startRecord();
// Stop recording after 10 sec
var recTime = 0;
var recInterval = setInterval(function() {
recTime = recTime + 1;
setAudioPosition(recTime + " sec");
if (recTime >= 10) {
clearInterval(recInterval);
mediaRec.stopRecord();
}
}, 1000);
}
i've also tried file://myrecording.wav and file:///myrecording.wav
i've done my test on ios5 iphone 4gs. I get the failure message with code 1 saying "Cannot use audio file from resource...."
Thanks for you help,
Martin
You have to first get file system:
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, gotFS, fail);
Then get the file:
function gotFS(fileSystem) {
alert('got FS');
fileSystem.root.getFile("myrecording4.wav", {create: true, exclusive: false}, gotFileEntry, fail);
}
Now you can get the file URI:
function gotFileEntry(fileEntry) {
alert('File URI: ' + fileEntry.toURI());
}