Commit bb332447 authored by 李晓兵's avatar 李晓兵

'录视频插件'

parent b7b6406b
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
-->
# Contributing to Apache Cordova
Anyone can contribute to Cordova. And we need your contributions.
There are multiple ways to contribute: report bugs, improve the docs, and
contribute code.
For instructions on this, start with the
[contribution overview](http://cordova.apache.org/contribute/).
The details are explained there, but the important items are:
- Sign and submit an Apache ICLA (Contributor License Agreement).
- Have a Jira issue open that corresponds to your contribution.
- Run the tests so your patch doesn't break existing functionality.
We look forward to your contributions!
This diff is collapsed.
Apache Cordova
Copyright 2012 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
This diff is collapsed.
This diff is collapsed.
{
"name": "cordova-plugin-media-capture",
"version": "3.0.3",
"description": "Cordova Media Capture Plugin",
"types": "./types/index.d.ts",
"cordova": {
"id": "cordova-plugin-media-capture",
"platforms": [
"android",
"ios",
"windows",
"browser"
]
},
"repository": {
"type": "git",
"url": "https://github.com/apache/cordova-plugin-media-capture"
},
"bugs": {
"url": "https://github.com/apache/cordova-plugin-media-capture/issues"
},
"keywords": [
"cordova",
"media",
"capture",
"ecosystem:cordova",
"cordova-android",
"cordova-ios",
"cordova-windows"
],
"scripts": {
"test": "npm run eslint",
"eslint": "eslint www && eslint src && eslint tests"
},
"author": "Apache Software Foundation",
"license": "Apache-2.0",
"engines": {
"cordovaDependencies": {
">=1.4.4": {
"cordova-ios": ">=4.0.0"
},
"2.0.0": {
"cordova-android": ">=6.3.0"
},
"4.0.0": {
"cordova": ">100"
}
}
},
"devDependencies": {
"eslint": "^4.0.0",
"eslint-config-semistandard": "^11.0.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.3.0",
"eslint-plugin-node": "^5.0.0",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-media-capture"
version="3.0.3">
<name>Capture</name>
<description>Cordova Media Capture Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,media,capture</keywords>
<repo>https://github.com/apache/cordova-plugin-media-capture</repo>
<issue>https://github.com/apache/cordova-plugin-media-capture/issues</issue>
<engines>
<engine name="cordova-android" version=">=6.3.0" />
</engines>
<dependency id="cordova-plugin-file" version="^6.0.0" />
<js-module src="www/CaptureAudioOptions.js" name="CaptureAudioOptions">
<clobbers target="CaptureAudioOptions" />
</js-module>
<js-module src="www/CaptureImageOptions.js" name="CaptureImageOptions">
<clobbers target="CaptureImageOptions" />
</js-module>
<js-module src="www/CaptureVideoOptions.js" name="CaptureVideoOptions">
<clobbers target="CaptureVideoOptions" />
</js-module>
<js-module src="www/CaptureError.js" name="CaptureError">
<clobbers target="CaptureError" />
</js-module>
<js-module src="www/MediaFileData.js" name="MediaFileData">
<clobbers target="MediaFileData" />
</js-module>
<js-module src="www/MediaFile.js" name="MediaFile">
<clobbers target="MediaFile" />
</js-module>
<js-module src="www/helpers.js" name="helpers">
<runs />
</js-module>
<js-module src="www/capture.js" name="capture">
<clobbers target="navigator.device.capture" />
</js-module>
<!-- android -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="Capture" >
<param name="android-package" value="org.apache.cordova.mediacapture.Capture"/>
</feature>
</config-file>
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</config-file>
<source-file src="src/android/Capture.java" target-dir="src/org/apache/cordova/mediacapture" />
<source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/mediacapture" />
<source-file src="src/android/PendingRequests.java" target-dir="src/org/apache/cordova/mediacapture" />
<js-module src="www/android/init.js" name="init">
<runs />
</js-module>
</platform>
<!-- ios -->
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="Capture">
<param name="ios-package" value="CDVCapture" />
</feature>
</config-file>
<header-file src="src/ios/CDVCapture.h" />
<source-file src="src/ios/CDVCapture.m" />
<resource-file src="src/ios/CDVCapture.bundle" />
<framework src="CoreGraphics.framework" />
<framework src="MobileCoreServices.framework" />
</platform>
<!-- windows -->
<platform name="windows">
<config-file target="package.appxmanifest" parent="/Package/Capabilities">
<DeviceCapability Name="microphone" />
<DeviceCapability Name="webcam" />
</config-file>
<js-module src="src/windows/MediaFile.js" name="MediaFile2">
<merges target="MediaFile" />
</js-module>
<js-module src="src/windows/CaptureProxy.js" name="CaptureProxy">
<runs />
</js-module>
</platform>
<!-- browser -->
<platform name="browser">
<!-- this overrides navigator.device.capture namespace with browser-specific implementation -->
<js-module src="src/browser/CaptureProxy.js" name="CaptureProxy">
<runs />
</js-module>
</platform>
</plugin>
This diff is collapsed.
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.mediacapture;
import android.net.Uri;
import android.webkit.MimeTypeMap;
import org.apache.cordova.CordovaInterface;
import java.util.Locale;
// TODO: Replace with CordovaResourceApi.getMimeType() post 3.1.
public class FileHelper {
public static String getMimeTypeForExtension(String path) {
String extension = path;
int lastDot = extension.lastIndexOf('.');
if (lastDot != -1) {
extension = extension.substring(lastDot + 1);
}
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
extension = extension.toLowerCase(Locale.getDefault());
if (extension.equals("3ga")) {
return "audio/3gpp";
}
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
/**
* Returns the mime type of the data specified by the given URI string.
*
* @param uriString the URI string of the data
* @return the mime type of the specified data
*/
public static String getMimeType(Uri uri, CordovaInterface cordova) {
String mimeType = null;
if ("content".equals(uri.getScheme())) {
mimeType = cordova.getActivity().getContentResolver().getType(uri);
} else {
mimeType = getMimeTypeForExtension(uri.getPath());
}
return mimeType;
}
}
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova.mediacapture;
import android.os.Bundle;
import android.util.SparseArray;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Holds the pending javascript requests for the plugin
*/
public class PendingRequests {
private static final String LOG_TAG = "PendingCaptureRequests";
private static final String CURRENT_ID_KEY = "currentReqId";
private static final String REQUEST_KEY_PREFIX = "request_";
private int currentReqId = 0;
private SparseArray<Request> requests = new SparseArray<Request>();
private Bundle lastSavedState;
private CallbackContext resumeContext;
/**
* Creates a request and adds it to the array of pending requests. Each created request gets a
* unique result code for use with startActivityForResult() and requestPermission()
* @param action The action this request corresponds to (capture image, capture audio, etc.)
* @param options The options for this request passed from the javascript
* @param callbackContext The CallbackContext to return the result to
* @return The newly created Request object with a unique result code
* @throws JSONException
*/
public synchronized Request createRequest(int action, JSONObject options, CallbackContext callbackContext) throws JSONException {
Request req = new Request(action, options, callbackContext);
requests.put(req.requestCode, req);
return req;
}
/**
* Gets the request corresponding to this request code
* @param requestCode The request code for the desired request
* @return The request corresponding to the given request code or null if such a
* request is not found
*/
public synchronized Request get(int requestCode) {
// Check to see if this request was saved
if (lastSavedState != null && lastSavedState.containsKey(REQUEST_KEY_PREFIX + requestCode)) {
Request r = new Request(lastSavedState.getBundle(REQUEST_KEY_PREFIX + requestCode), this.resumeContext, requestCode);
requests.put(requestCode, r);
// Only one of the saved requests will get restored, because that's all cordova-android
// supports. Having more than one is an extremely unlikely scenario anyway
this.lastSavedState = null;
this.resumeContext = null;
return r;
}
return requests.get(requestCode);
}
/**
* Removes the request from the array of pending requests and sends an error plugin result
* to the CallbackContext that contains the given error object
* @param req The request to be resolved
* @param error The error to be returned to the CallbackContext
*/
public synchronized void resolveWithFailure(Request req, JSONObject error) {
req.callbackContext.error(error);
requests.remove(req.requestCode);
}
/**
* Removes the request from the array of pending requests and sends a successful plugin result
* to the CallbackContext that contains the result of the request
* @param req The request to be resolved
*/
public synchronized void resolveWithSuccess(Request req) {
req.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, req.results));
requests.remove(req.requestCode);
}
/**
* Each request gets a unique ID that represents its request code when calls are made to
* Activities and for permission requests
* @return A unique request code
*/
private synchronized int incrementCurrentReqId() {
return currentReqId ++;
}
/**
* Restore state saved by calling toBundle along with a callbackContext to be used in
* delivering the results of a pending callback
*
* @param lastSavedState The bundle received from toBundle()
* @param resumeContext The callbackContext to return results to
*/
public synchronized void setLastSavedState(Bundle lastSavedState, CallbackContext resumeContext) {
this.lastSavedState = lastSavedState;
this.resumeContext = resumeContext;
this.currentReqId = lastSavedState.getInt(CURRENT_ID_KEY);
}
/**
* Save the current pending requests to a bundle for saving when the Activity gets destroyed.
*
* @return A Bundle that can be used to restore state using setLastSavedState()
*/
public synchronized Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(CURRENT_ID_KEY, currentReqId);
for (int i = 0; i < requests.size(); i++) {
Request r = requests.valueAt(i);
int requestCode = requests.keyAt(i);
bundle.putBundle(REQUEST_KEY_PREFIX + requestCode, r.toBundle());
}
if (requests.size() > 1) {
// This scenario is hopefully very unlikely because there isn't much that can be
// done about it. Should only occur if an external Activity is launched while
// there is a pending permission request and the device is on low memory
LOG.w(LOG_TAG, "More than one media capture request pending on Activity destruction. Some requests will be dropped!");
}
return bundle;
}
/**
* Holds the options and CallbackContext for a capture request made to the plugin.
*/
public class Request {
// Keys for use in saving requests to a bundle
private static final String ACTION_KEY = "action";
private static final String LIMIT_KEY = "limit";
private static final String DURATION_KEY = "duration";
private static final String QUALITY_KEY = "quality";
private static final String RESULTS_KEY = "results";
// Unique int used to identify this request in any Android Permission or Activity callbacks
public int requestCode;
// The action that this request is performing
public int action;
// The number of pics/vids/audio clips to take (CAPTURE_IMAGE, CAPTURE_VIDEO, CAPTURE_AUDIO)
public long limit = 1;
// Optional max duration of recording in seconds (CAPTURE_VIDEO only)
public int duration = 0;
// Quality level for video capture 0 low, 1 high (CAPTURE_VIDEO only)
public int quality = 1;
// The array of results to be returned to the javascript callback on success
public JSONArray results = new JSONArray();
// The callback context for this plugin request
private CallbackContext callbackContext;
private Request(int action, JSONObject options, CallbackContext callbackContext) throws JSONException {
this.callbackContext = callbackContext;
this.action = action;
if (options != null) {
this.limit = options.optLong("limit", 1);
this.duration = options.optInt("duration", 0);
this.quality = options.optInt("quality", 1);
}
this.requestCode = incrementCurrentReqId();
}
private Request(Bundle bundle, CallbackContext callbackContext, int requestCode) {
this.callbackContext = callbackContext;
this.requestCode = requestCode;
this.action = bundle.getInt(ACTION_KEY);
this.limit = bundle.getLong(LIMIT_KEY);
this.duration = bundle.getInt(DURATION_KEY);
this.quality = bundle.getInt(QUALITY_KEY);
try {
this.results = new JSONArray(bundle.getString(RESULTS_KEY));
} catch(JSONException e) {
// This should never be caught
LOG.e(LOG_TAG, "Error parsing results for request from saved bundle", e);
}
}
private Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putInt(ACTION_KEY, this.action);
bundle.putLong(LIMIT_KEY, this.limit);
bundle.putInt(DURATION_KEY, this.duration);
bundle.putInt(QUALITY_KEY, this.quality);
bundle.putString(RESULTS_KEY, this.results.toString());
return bundle;
}
}
}
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
/* global require, module */
var MediaFile = require('cordova-plugin-media-capture.MediaFile');
var MediaFileData = require('cordova-plugin-media-capture.MediaFileData');
var CaptureError = require('cordova-plugin-media-capture.CaptureError');
/**
* Helper function that converts data URI to Blob
* @param {String} dataURI Data URI to convert
* @return {Blob} Blob, covnerted from DataURI String
*/
function dataURItoBlob (dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString = atob(dataURI.split(',')[1]); // eslint-disable-line no-undef
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], { type: mimeString }); // eslint-disable-line no-undef
}
/**
* Creates basic camera UI with preview 'video' element and 'Cancel' button
* Capture starts, when you clicking on preview.
*/
function CameraUI () {
// Root element for preview
var container = document.createElement('div');
container.style.cssText = 'left: 0px; top: 0px; width: 100%; height: 100%; position: fixed; z-index:9999;' +
'padding: 40px; background-color: rgba(0,0,0,0.75);' +
'text-align:center; visibility: hidden';
// Set up root element contetnts
container.innerHTML =
'<div id="captureHint" style="height:100%; position:relative; display:inline-flex; align-content:flex-start;">' +
'<h2 style="position: absolute; width: 100%; background-color: rgba(255,255,255,0.25); margin: 0">' +
'Click on preview to capture image. Click outside of preview to cancel.</h1>' +
'<video id="capturePreview" style="height: 100%"></video>' +
'</div>';
// Add container element to DOM but do not display it since visibility == hidden
document.body.appendChild(container);
// Create fullscreen preview
var preview = document.getElementById('capturePreview');
preview.autoplay = true;
// We'll show preview only when video element content
// is fully loaded to avoid glitches
preview.onplay = function () {
container.style.visibility = 'visible';
};
this.container = container;
this.preview = preview;
}
/**
* Displays capture preview
* @param {Number} count Number of images to take
* @param {Function} successCB Success callback, that accepts data URL of captured image
* @param {Function} errorCB Error callback
*/
CameraUI.prototype.startPreview = function (count, successCB, errorCB) {
var that = this;
this.preview.onclick = function (e) {
// proceed with capture here
// We don't need to propagate click event to parent elements.
// Otherwise click on vieo element will trigger click event handler
// for preview root element and cause preview cancellation
e.stopPropagation();
// Create canvas element, put video frame on it
// and save its contant as Data URL
var canvas = document.createElement('canvas');
canvas.width = this.videoWidth;
canvas.height = this.videoHeight;
canvas.getContext('2d').drawImage(that.preview, 0, 0);
successCB(canvas.toDataURL('image/jpeg'));
};
this.container.onclick = function () {
// Cancel capture here
errorCB(new CaptureError(CaptureError.CAPTURE_NO_MEDIA_FILES));
};
navigator.getUserMedia({video: true}, function (previewStream) {
// Save video stream to be able to stop it later
that._previewStream = previewStream;
that.preview.src = URL.createObjectURL(previewStream); // eslint-disable-line no-undef
// We don't need to set visibility = true for preview element
// since this will be done automatically in onplay event handler
}, function (/* err */) {
errorCB(new CaptureError(CaptureError.CAPTURE_INTERNAL_ERR));
});
};
/**
* Destroys camera preview, removes all elements created
*/
CameraUI.prototype.destroyPreview = function () {
this.preview.pause();
this.preview.src = null;
this._previewStream.stop();
this._previewStream = null;
if (this.container) {
document.body.removeChild(this.container);
}
};
module.exports = {
captureAudio: function (successCallback, errorCallback) {
if (errorCallback) {
errorCallback(new CaptureError(CaptureError.CAPTURE_NOT_SUPPORTED));
}
},
captureVideo: function (successCallback, errorCallback) {
if (errorCallback) {
errorCallback(new CaptureError(CaptureError.CAPTURE_NOT_SUPPORTED));
}
},
captureImage: function (successCallback, errorCallback, args) {
var fail = function (code) {
if (errorCallback) {
errorCallback(new CaptureError(code || CaptureError.CAPTURE_INTERNAL_ERR));
}
};
var options = args[0];
var limit = options.limit || 1;
if (typeof limit !== 'number' || limit < 1) {
fail(CaptureError.CAPTURE_INVALID_ARGUMENT);
return;
}
// Counter for already taken images
var imagesTaken = 0;
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if (!navigator.getUserMedia) {
fail(CaptureError.CAPTURE_NOT_SUPPORTED);
return;
}
var ui = new CameraUI();
ui.startPreview(limit, function (data) {
// Check if we're done with capture. If so, then destroy UI
if (++imagesTaken >= limit) {
ui.destroyPreview();
}
// Array of resultant MediaFiles
var mediaFiles = [];
// save data to file here
window.requestFileSystem(window.TEMPORARY, data.length * limit, function (fileSystem) {
// If we need to capture multiple files, then append counter to filename
var fileName = limit <= 1 ? 'image.jpg' : 'image' + imagesTaken + '.jpg';
fileSystem.root.getFile(fileName, {create: true}, function (file) {
file.createWriter(function (writer) {
writer.onwriteend = function () {
file.getMetadata(function (meta) {
mediaFiles.push(new MediaFile(file.name, file.toURL(), 'image/jpeg', meta.modificationTime, meta.size));
// Check if we're done with capture. If so, then call a successCallback
if (imagesTaken >= limit) {
successCallback(mediaFiles);
}
}, fail);
};
writer.onerror = fail;
// Since success callback for start preview returns
// a base64 encoded string, we need to convert it to blob first
writer.write(dataURItoBlob(data));
});
}, fail);
}, fail);
}, function (err) {
ui.destroyPreview();
fail(err.code);
});
},
getFormatData: function (successCallback, errorCallback, args) {
var img = document.createElement('img');
img.src = args[0];
img.onload = function () {
if (successCallback) {
successCallback(new MediaFileData(null, 0, img.height, img.width, 0));
}
};
}
};
require('cordova/exec/proxy').add('Capture', module.exports);
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// controller title for Videos
"Videos title" = "Videos";
// accessibility label for recording button
"toggle audio recording" = "starten/beenden der Tonaufnahme";
// notification spoken by VoiceOver when timed recording finishes
"timed recording complete" = "programmierte Aufnahme beendet";
// accessibility hint for display of recorded elapsed time
"recorded time in minutes and seconds" = "aufgenommene Zeit in Minuten und Sekunden";
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// controller title for Videos
"Videos title" = "Videos";
// accessibility label for recording button
"toggle audio recording" = "toggle audio recording";
// notification spoken by VoiceOver when timed recording finishes
"timed recording complete" = "timed recording complete";
// accessibility hint for display of recorded elapsed time
"recorded time in minutes and seconds" = "recorded time in minutes and seconds";
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// controller title for Videos
"Videos title" = "Videos";
// accessibility label for recording button
"toggle audio recording" = "grabación de audio cambiar";
// notification spoken by VoiceOver when timed recording finishes
"timed recording complete" = "tiempo de grabación completo";
// accessibility hint for display of recorded elapsed time
"recorded time in minutes and seconds" = "tiempo registrado en minutos y segundos";
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
// controller title for Videos
"Videos title" = "Videor";
// accessibility label for recording button
"toggle audio recording" = "börja/avsluta inspelning";
// notification spoken by VoiceOver when timed recording finishes
"timed recording complete" = "inspelning har avslutad";
// accessibility hint for display of recorded elapsed time
"recorded time in minutes and seconds" = "inspelad tid in minuter och sekund";
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Foundation/Foundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <AVFoundation/AVFoundation.h>
#import <Cordova/CDVPlugin.h>
#import "CDVFile.h"
enum CDVCaptureError {
CAPTURE_INTERNAL_ERR = 0,
CAPTURE_APPLICATION_BUSY = 1,
CAPTURE_INVALID_ARGUMENT = 2,
CAPTURE_NO_MEDIA_FILES = 3,
CAPTURE_PERMISSION_DENIED = 4,
CAPTURE_NOT_SUPPORTED = 20
};
typedef NSUInteger CDVCaptureError;
@interface CDVImagePicker : UIImagePickerController
{
NSString* callbackid;
NSInteger quality;
NSString* mimeType;
}
@property (assign) NSInteger quality;
@property (copy) NSString* callbackId;
@property (copy) NSString* mimeType;
@end
@interface CDVCapture : CDVPlugin <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
CDVImagePicker* pickerController;
BOOL inUse;
}
@property BOOL inUse;
- (void)captureAudio:(CDVInvokedUrlCommand*)command;
- (void)captureImage:(CDVInvokedUrlCommand*)command;
- (CDVPluginResult*)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId;
- (void)captureVideo:(CDVInvokedUrlCommand*)command;
- (CDVPluginResult*)processVideo:(NSString*)moviePath forCallbackId:(NSString*)callbackId;
- (void)getMediaModes:(CDVInvokedUrlCommand*)command;
- (void)getFormatData:(CDVInvokedUrlCommand*)command;
- (NSDictionary*)getMediaDictionaryFromPath:(NSString*)fullPath ofType:(NSString*)type;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
@end
@interface CDVAudioNavigationController : UINavigationController
@end
/* AudioRecorderViewController is used to create a simple view for audio recording.
* It is created from [Capture captureAudio]. It creates a very simple interface for
* recording by presenting just a record/stop button and a Done button to close the view.
* The recording time is displayed and recording for a specified duration is supported. When duration
* is specified there is no UI to the user - recording just stops when the specified
* duration is reached. The UI has been minimized to avoid localization.
*/
@interface CDVAudioRecorderViewController : UIViewController <AVAudioRecorderDelegate>
{
CDVCaptureError errorCode;
NSString* callbackId;
NSNumber* duration;
CDVCapture* captureCommand;
UIBarButtonItem* doneButton;
UIView* recordingView;
UIButton* recordButton;
UIImage* recordImage;
UIImage* stopRecordImage;
UILabel* timerLabel;
AVAudioRecorder* avRecorder;
AVAudioSession* avSession;
CDVPluginResult* pluginResult;
NSTimer* timer;
BOOL isTimed;
}
@property (nonatomic) CDVCaptureError errorCode;
@property (nonatomic, copy) NSString* callbackId;
@property (nonatomic, copy) NSNumber* duration;
@property (nonatomic, strong) CDVCapture* captureCommand;
@property (nonatomic, strong) UIBarButtonItem* doneButton;
@property (nonatomic, strong) UIView* recordingView;
@property (nonatomic, strong) UIButton* recordButton;
@property (nonatomic, strong) UIImage* recordImage;
@property (nonatomic, strong) UIImage* stopRecordImage;
@property (nonatomic, strong) UILabel* timerLabel;
@property (nonatomic, strong) AVAudioRecorder* avRecorder;
@property (nonatomic, strong) AVAudioSession* avSession;
@property (nonatomic, strong) CDVPluginResult* pluginResult;
@property (nonatomic, strong) NSTimer* timer;
@property (nonatomic) BOOL isTimed;
- (id)initWithCommand:(CDVPlugin*)theCommand duration:(NSNumber*)theDuration callbackId:(NSString*)theCallbackId;
- (void)processButton:(id)sender;
- (void)stopRecordingCleanup;
- (void)dismissAudioView:(id)sender;
- (NSString*)formatTime:(int)interval;
- (void)updateTime;
@end
This diff is collapsed.
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
/* global Windows:true */
var MediaFileData = require('cordova-plugin-media-capture.MediaFileData');
var CaptureError = require('cordova-plugin-media-capture.CaptureError');
module.exports = {
getFormatData: function (successCallback, errorCallback, args) {
Windows.Storage.StorageFile.getFileFromPathAsync(this.fullPath).then(
function (storageFile) {
var mediaTypeFlag = String(storageFile.contentType).split('/')[0].toLowerCase();
if (mediaTypeFlag === 'audio') {
storageFile.properties.getMusicPropertiesAsync().then(
function (audioProperties) {
successCallback(new MediaFileData(null, audioProperties.bitrate, 0, 0, audioProperties.duration / 1000));
}, function () {
errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
}
);
} else if (mediaTypeFlag === 'video') {
storageFile.properties.getVideoPropertiesAsync().then(
function (videoProperties) {
successCallback(new MediaFileData(null, videoProperties.bitrate, videoProperties.height, videoProperties.width, videoProperties.duration / 1000));
}, function () {
errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
}
);
} else if (mediaTypeFlag === 'image') {
storageFile.properties.getImagePropertiesAsync().then(
function (imageProperties) {
successCallback(new MediaFileData(null, 0, imageProperties.height, imageProperties.width, 0));
}, function () {
errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
}
);
} else {
errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
}
}, function () {
errorCallback(new CaptureError(CaptureError.CAPTURE_INVALID_ARGUMENT));
}
);
}
};
{
"name": "cordova-plugin-media-capture-tests",
"version": "3.0.3",
"description": "",
"cordova": {
"id": "cordova-plugin-media-capture-tests",
"platforms": []
},
"keywords": [
"ecosystem:cordova"
],
"author": "",
"license": "Apache 2.0"
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="cordova-plugin-media-capture-tests"
version="3.0.3">
<name>Cordova Media Capture Plugin Tests</name>
<license>Apache 2.0</license>
<dependency id="cordova-plugin-media" />
<js-module src="tests.js" name="tests">
</js-module>
</plugin>
This diff is collapsed.
// Type definitions for Apache Cordova MediaCapture plugin
// Project: https://github.com/apache/cordova-plugin-media-capture
// Definitions by: Microsoft Open Technologies Inc <http://msopentech.com>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
//
// Copyright (c) Microsoft Open Technologies Inc
// Licensed under the MIT license
interface Navigator {
device: Device;
}
interface Device {
capture: Capture;
}
/** This plugin provides access to the device's audio, image, and video capture capabilities. */
interface Capture {
/**
* Start the audio recorder application and return information about captured audio clip files.
* @param onSuccess Executes when the capture operation finishes with an array
* of MediaFile objects describing each captured audio clip file.
* @param onError Executes, if the user terminates the operation before an audio clip is captured,
* with a CaptureError object, featuring the CaptureError.CAPTURE_NO_MEDIA_FILES error code.
* @param options Encapsulates audio capture configuration options.
*/
captureAudio(
onSuccess: (mediaFiles: MediaFile[]) => void,
onError: (error: CaptureError) => void,
options?: AudioOptions): void ;
/**
* Start the camera application and return information about captured image files.
* @param onSuccess Executes when the capture operation finishes with an array
* of MediaFile objects describing each captured image clip file.
* @param onError Executes, if the user terminates the operation before an audio clip is captured,
* with a CaptureError object, featuring the CaptureError.CAPTURE_NO_MEDIA_FILES error code.
* @param options Encapsulates audio capture configuration options.
*/
captureImage(
onSuccess: (mediaFiles: MediaFile[]) => void,
onError: (error: CaptureError) => void,
options?: ImageOptions): void ;
/**
* Start the video recorder application and return information about captured video clip files.
* @param onSuccess Executes when the capture operation finishes with an array
* of MediaFile objects describing each captured video clip file.
* @param onError Executes, if the user terminates the operation before an audio clip is captured,
* with a CaptureError object, featuring the CaptureError.CAPTURE_NO_MEDIA_FILES error code.
* @param options Encapsulates audio capture configuration options.
*/
captureVideo(
onSuccess: (mediaFiles: MediaFile[]) => void,
onError: (error: CaptureError) => void,
options?: VideoOptions): void ;
/** The audio recording formats supported by the device. */
supportedAudioModes: ConfigurationData[];
/** The recording image sizes and formats supported by the device. */
supportedImageModes: ConfigurationData[];
/** The recording video resolutions and formats supported by the device. */
supportedVideoModes: ConfigurationData[];
}
/** Encapsulates properties of a media capture file. */
interface MediaFile {
/** The name of the file, without path information. */
name: string;
/** The full path of the file, including the name. */
fullPath: string;
/** The file's mime type */
type: string;
/** The date and time when the file was last modified. */
lastModifiedDate: Date;
/** The size of the file, in bytes. */
size: number;
/**
* Retrieves format information about the media capture file.
* @param successCallback Invoked with a MediaFileData object when successful.
* @param errorCallback Invoked if the attempt fails, this function.
*/
getFormatData(
successCallback: (data: MediaFileData) => void,
errorCallback?: () => void): void;
}
/** Encapsulates format information about a media file. */
interface MediaFileData {
/** The actual format of the audio and video content. */
codecs: string;
/** The average bitrate of the content. The value is zero for images. */
bitrate: number;
/** The height of the image or video in pixels. The value is zero for audio clips. */
height: number;
/** The width of the image or video in pixels. The value is zero for audio clips. */
width: number;
/** The length of the video or sound clip in seconds. The value is zero for images. */
duration: number;
}
/** Encapsulates the error code resulting from a failed media capture operation. */
interface CaptureError {
/**
* One of the pre-defined error codes listed below.
* CaptureError.CAPTURE_INTERNAL_ERR
* The camera or microphone failed to capture image or sound.
* CaptureError.CAPTURE_APPLICATION_BUSY
* The camera or audio capture application is currently serving another capture request.
* CaptureError.CAPTURE_INVALID_ARGUMENT
* Invalid use of the API (e.g., the value of limit is less than one).
* CaptureError.CAPTURE_NO_MEDIA_FILES
* The user exits the camera or audio capture application before capturing anything.
* CaptureError.CAPTURE_NOT_SUPPORTED
* The requested capture operation is not supported.
*/
code: number;
message: string;
}
declare var CaptureError: {
/** Constructor for CaptureError */
new (code: number, message: string): CaptureError;
CAPTURE_INTERNAL_ERR: number;
CAPTURE_APPLICATION_BUSY: number;
CAPTURE_INVALID_ARGUMENT: number;
CAPTURE_NO_MEDIA_FILES: number;
CAPTURE_NOT_SUPPORTED: number;
CAPTURE_PERMISSION_DENIED: number;
}
/** Encapsulates audio capture configuration options. */
interface AudioOptions {
/**
* The maximum number of audio clips the device's user can capture in a single
* capture operation. The value must be greater than or equal to 1.
*/
limit?: number;
/** The maximum duration of a audio clip, in seconds. */
duration?: number;
}
/** Encapsulates image capture configuration options. */
interface ImageOptions {
/**
* The maximum number of images the user can capture in a single capture operation.
* The value must be greater than or equal to 1 (defaults to 1).
*/
limit?: number;
}
/** Encapsulates video capture configuration options. */
interface VideoOptions {
/**
* The maximum number of video clips the device's user can capture in a single
* capture operation. The value must be greater than or equal to 1.
*/
limit?: number;
/** The maximum duration of a video clip, in seconds. */
duration?: number;
}
/** Encapsulates a set of media capture parameters that a device supports. */
interface ConfigurationData {
/** The ASCII-encoded lowercase string representing the media type. */
type: string;
/** The height of the image or video in pixels. The value is zero for sound clips. */
height: number;
/** The width of the image or video in pixels. The value is zero for sound clips. */
width: number;
}
\ No newline at end of file
...@@ -193,5 +193,13 @@ ...@@ -193,5 +193,13 @@
}, },
"is_top_level": true, "is_top_level": true,
"variables": {} "variables": {}
},
"cordova-plugin-media-capture": {
"source": {
"type": "registry",
"id": "cordova-plugin-media-capture@3.0.3"
},
"is_top_level": true,
"variables": {}
} }
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
<div class="number"> <div class="number">
<span v-for="(item,index) in codeList" :key="index">{{ item }}</span> <span v-for="(item,index) in codeList" :key="index">{{ item }}</span>
</div> </div>
<h-button :disabled="lastTime!=0" class="button" @click="recordVdeo">记住了,开始录制<span v-if="lastTime!=0">({{ lastTime }}s)</span></h-button> <h-button :disabled="lastTime!=0" class="button" @click.native="recordVdeo">记住了,开始录制<span v-if="lastTime!=0">({{ lastTime }}s)</span></h-button>
</div> </div>
<div class="close" @click="downNum=false">X</div> <div class="close" @click="downNum=false">X</div>
</div> </div>
...@@ -76,7 +76,17 @@ export default { ...@@ -76,7 +76,17 @@ export default {
}, },
methods: { methods: {
recordVdeo () { // 开始录制 recordVdeo () { // 开始录制
let vm = this
let onSuccess = function (mediaFiles) {
// 遍历获取录制的文件(iOS 只支持一次录制一个视频)
for (let i = 0; i < mediaFiles.length; i++) {
alert('录制成功!\n\n' + '文件名:' + mediaFiles[i].name + '\n' + '大小:' + mediaFiles[i].size + '\n\n' + 'localURL地址:' + mediaFiles[i].localURL + '\n\n' + 'fullPath地址:' + mediaFiles[i].fullPath)
}
}
let onError = function (error) {
hlsPopup.showLongcenter('录制失败,请重新录制')
}
hlsUtil.captureVideo(onSuccess, onError)
}, },
succesCall () { // 录制成功后进行检测 succesCall () { // 录制成功后进行检测
let vm = this let vm = this
...@@ -173,7 +183,7 @@ export default { ...@@ -173,7 +183,7 @@ export default {
width:90%; width:90%;
height: 50px; height: 50px;
background-color: #0073eb; background-color: #0073eb;
color: #fff; color: #fff !important;
border-radius: 4px; border-radius: 4px;
} }
.down-content { .down-content {
......
...@@ -307,6 +307,17 @@ export default { ...@@ -307,6 +307,17 @@ export default {
} }
}, },
/**
* 录制视频
*/
captureVideo: function(onSuccess, onError){
if (typeof onSuccess === 'function' && typeof onError === 'function') {
navigator.device.capture.captureVideo(onSuccess, onError, {duration: 15});
} else{
window.hlsPopup.showLongBottom('参数有误!')
}
},
/** /**
* 拨打电话仅仅限制于手机 * 拨打电话仅仅限制于手机
* @param number * @param number
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment