Skip to content

Commit 7e23281

Browse files
author
Shahen Hovhannisyan
authored
Merge pull request #47 from shahen94/standalone-api
feat(Processing): Provided standalone APIs
2 parents 18d015c + a1c9be7 commit 7e23281

12 files changed

Lines changed: 329 additions & 24 deletions

File tree

.flowconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[ignore]
2+
./node_modules
3+
[include]
4+
./lib
5+
[libs]
6+
7+
[options]

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ class App extends Component {
111111
onTrackerMove={(e) => console.log(e.currentTime)} // iOS only
112112
currentTime={this.video.currentTime} // use this prop to set tracker position iOS only
113113
themeColor={'white'} // iOS only
114+
thumbWidth={30} // iOS only
114115
trackerColor={'green'} // iOS only
115116
onChange={(e) => console.log(e.startTime, e.endTime)}
116117
/>
@@ -119,6 +120,32 @@ class App extends Component {
119120
}
120121
}
121122
```
123+
or you can use ProcessingManager without mounting VideoPlayer component
124+
```
125+
import React, { Component } from 'react';
126+
import { View } from 'react-native';
127+
import { ProcessingManager } from 'react-native-video-processing';
128+
export class App extends Component {
129+
componentWillMount() {
130+
const { source } = this.props;
131+
ProcessingManager.getVideoInfo(source)
132+
.then(({ duration, size }) => console.log(duration, size));
133+
134+
ProcessingManager.trim(source, options) // like VideoPlayer trim options
135+
.then((data) => console.log(data));
136+
137+
ProcessingManager.compress(source, options) // like VideoPlayer compress options
138+
.then((data) => console.log(data));
139+
140+
const maximumSize = { width: 100, height: 200 };
141+
ProcessingManager.getPreviewForSecond(source, forSecond, maximumSize)
142+
.then((data) => console.log(data))
143+
}
144+
render() {
145+
return <View />;
146+
}
147+
}
148+
```
122149

123150
### How to setup Library
124151
[![Setup](https://img.youtube.com/vi/HRjgeT6NQJM/0.jpg)](https://youtu.be/HRjgeT6NQJM)
@@ -134,3 +161,4 @@ class App extends Component {
134161
3. [ ] Android should be able to compress video
135162
4. [ ] More processing options
136163
5. [ ] Create native trimmer component for Android
164+
6. [x] Provide Standalone API

android/react-native-video-processing.iml

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<module external.linked.project.id=":react-native-video-processing" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../../../android" external.system.id="GRADLE" external.system.module.group="vp" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
2+
<module external.linked.project.id=":react-native-video-processing" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/../../android" external.system.id="GRADLE" external.system.module.group="vp" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
33
<component name="FacetManager">
44
<facet type="android-gradle" name="Android-Gradle">
55
<configuration>
@@ -32,12 +32,14 @@
3232
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
3333
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
3434
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
35+
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
3536
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
3637
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
3738
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
3839
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
3940
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
4041
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
42+
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
4143
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
4244
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
4345
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
@@ -64,14 +66,6 @@
6466
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
6567
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
6668
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
67-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
68-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
69-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
70-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
71-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
72-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
73-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
74-
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
7569
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
7670
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
7771
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
@@ -80,12 +74,16 @@
8074
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
8175
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
8276
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
83-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" />
84-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
77+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
78+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
79+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
80+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
81+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
82+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
83+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
84+
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
8585
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
8686
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
87-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
88-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
8987
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
9088
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.0.1/jars" />
9189
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
@@ -95,17 +93,17 @@
9593
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline-okhttp/0.8.1/jars" />
9694
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.fresco/imagepipeline/0.8.1/jars" />
9795
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.facebook.react/react-native/0.20.1/jars" />
96+
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.github.wseemann/FFmpegMediaMetadataRetriever/1.0.14/jars" />
97+
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.yqritc/android-scalablevideoview/1.0.4/jars" />
98+
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/org.webkit/android-jsc/r174650/jars" />
9899
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
99-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
100-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
101100
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
101+
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
102102
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
103103
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
104104
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
105105
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
106-
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
107106
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
108-
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
109107
</content>
110108
<orderEntry type="jdk" jdkName="Android API 23 Platform (1)" jdkType="Android SDK" />
111109
<orderEntry type="sourceFolder" forTests="false" />
@@ -116,8 +114,8 @@
116114
<orderEntry type="library" exported="" name="okio-1.6.0" level="project" />
117115
<orderEntry type="library" exported="" name="stetho-okhttp-1.2.0" level="project" />
118116
<orderEntry type="library" exported="" name="okhttp-2.5.0" level="project" />
119-
<orderEntry type="library" exported="" name="stetho-1.2.0" level="project" />
120117
<orderEntry type="library" exported="" name="jsr305-3.0.0" level="project" />
118+
<orderEntry type="library" exported="" name="stetho-1.2.0" level="project" />
121119
<orderEntry type="library" exported="" name="jackson-core-2.2.3" level="project" />
122120
<orderEntry type="library" exported="" name="fbcore-0.8.1" level="project" />
123121
<orderEntry type="library" exported="" name="commons-cli-1.2" level="project" />
@@ -127,6 +125,7 @@
127125
<orderEntry type="library" exported="" name="fresco-0.8.1" level="project" />
128126
<orderEntry type="library" exported="" name="imagepipeline-okhttp-0.8.1" level="project" />
129127
<orderEntry type="library" exported="" name="bolts-android-1.1.4" level="project" />
128+
<orderEntry type="library" exported="" name="FFmpegMediaMetadataRetriever-1.0.14" level="project" />
130129
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
131130
<orderEntry type="library" exported="" name="drawee-0.8.1" level="project" />
132131
<orderEntry type="library" exported="" name="react-native-0.20.1" level="project" />

android/src/main/java/com/shahenlibrary/Events/Events.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ public class Events {
1111
public static final String GET_PREVIEW_IMAGE = "getPreviewForSecond";
1212
public static final String ERROR_TRIM = "error";
1313
public static final String ORIENTATION = "orientation";
14+
public static final String SIZE = "size";
1415
}

android/src/main/java/com/shahenlibrary/Trimmer/Trimmer.java

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,25 @@
3636
import com.facebook.react.bridge.Arguments;
3737
import com.facebook.react.bridge.Promise;
3838
import com.facebook.react.bridge.ReactApplicationContext;
39+
import com.facebook.react.bridge.ReadableMap;
3940
import com.facebook.react.bridge.WritableArray;
4041
import com.facebook.react.bridge.WritableMap;
4142
import com.facebook.react.uimanager.events.Event;
4243
import com.shahenlibrary.Events.Events;
44+
import com.shahenlibrary.Events.EventsEnum;
45+
import com.shahenlibrary.interfaces.OnTrimVideoListener;
4346
import com.shahenlibrary.utils.VideoEdit;
4447

4548
import java.io.ByteArrayOutputStream;
49+
import java.io.File;
50+
import java.io.IOException;
4651

4752
import wseemann.media.FFmpegMediaMetadataRetriever;
4853

4954
public class Trimmer {
5055

56+
private static final String LOG_TAG = "RNTrimmerManager";
57+
5158
public static void getPreviewImages(String path, Promise promise, ReactApplicationContext ctx) {
5259
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
5360
if (VideoEdit.shouldUseURI(path)) {
@@ -120,13 +127,91 @@ public static void getVideoInfo(String path, Promise promise, ReactApplicationCo
120127
int orientation = Integer.parseInt(mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION));
121128

122129
WritableMap event = Arguments.createMap();
130+
WritableMap size = Arguments.createMap();
131+
132+
size.putInt(Events.WIDTH, width);
133+
size.putInt(Events.HEIGHT, height);
134+
135+
event.putMap(Events.SIZE, size);
123136
event.putInt(Events.DURATION, duration);
124-
event.putInt(Events.WIDTH, width);
125-
event.putInt(Events.HEIGHT, height);
126137
event.putInt(Events.ORIENTATION, orientation);
127138

128139
promise.resolve(event);
129140

130141
mmr.release();
131142
}
143+
144+
static void trim(ReadableMap options, final Promise promise) {
145+
double startMs = options.getDouble("startTime");
146+
double endMs = options.getDouble("endTime");
147+
String mediaSource = options.getString("source");
148+
149+
OnTrimVideoListener trimVideoListener = new OnTrimVideoListener() {
150+
@Override
151+
public void onError(String message) {
152+
Log.d(LOG_TAG, "Trimmed onError: " + message);
153+
WritableMap event = Arguments.createMap();
154+
event.putString(Events.ERROR_TRIM, message);
155+
156+
promise.reject("trim error", message);
157+
}
158+
159+
@Override
160+
public void onTrimStarted() {
161+
Log.d(LOG_TAG, "Trimmed onTrimStarted");
162+
}
163+
164+
@Override
165+
public void getResult(Uri uri) {
166+
Log.d(LOG_TAG, "getResult: " + uri.toString());
167+
WritableMap event = Arguments.createMap();
168+
event.putString("source", uri.toString());
169+
promise.resolve(event);
170+
}
171+
172+
@Override
173+
public void cancelAction() {
174+
Log.d(LOG_TAG, "Trimmed cancelAction");
175+
}
176+
};
177+
Log.d(LOG_TAG, "trimMedia at : startAt -> " + startMs + " : endAt -> " + endMs);
178+
File mediaFile = new File(mediaSource.replace("file:///", "/"));
179+
long startTrimFromPos = (long) startMs * 1000;
180+
long endTrimFromPos = (long) endMs * 1000;
181+
String[] dPath = mediaSource.split("/");
182+
StringBuilder builder = new StringBuilder();
183+
for (int i = 0; i < dPath.length; ++i) {
184+
if (i == dPath.length - 1) {
185+
continue;
186+
}
187+
builder.append(dPath[i]);
188+
builder.append(File.separator);
189+
}
190+
String path = builder.toString().replace("file:///", "/");
191+
192+
Log.d(LOG_TAG, "trimMedia: " + mediaFile.toString() + " isExists: " + mediaFile.exists());
193+
try {
194+
VideoEdit.startTrim(mediaFile, path, startTrimFromPos, endTrimFromPos, trimVideoListener);
195+
} catch (IOException e) {
196+
trimVideoListener.onError(e.toString());
197+
e.printStackTrace();
198+
Log.d(LOG_TAG, "trimMedia: error -> " + e.toString());
199+
}
200+
}
201+
202+
static void getPreviewAtPosition(String source, double sec, final Promise promise) {
203+
FFmpegMediaMetadataRetriever metadataRetriever = new FFmpegMediaMetadataRetriever();
204+
metadataRetriever.setDataSource(source);
205+
206+
Bitmap bmp = metadataRetriever.getFrameAtTime((long) (sec * 1000000));
207+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
208+
bmp.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
209+
byte[] byteArray = byteArrayOutputStream .toByteArray();
210+
String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
211+
212+
WritableMap event = Arguments.createMap();
213+
event.putString("image", encoded);
214+
215+
promise.resolve(event);
216+
}
132217
}

android/src/main/java/com/shahenlibrary/Trimmer/TrimmerManager.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030
import com.facebook.react.bridge.ReactApplicationContext;
3131
import com.facebook.react.bridge.ReactContextBaseJavaModule;
3232
import com.facebook.react.bridge.ReactMethod;
33+
import com.facebook.react.bridge.ReadableMap;
3334

3435
public class TrimmerManager extends ReactContextBaseJavaModule {
35-
public static final String REACT_PACKAGE = "RNTrimmerManager";
36+
static final String REACT_PACKAGE = "RNTrimmerManager";
3637

3738
private final ReactApplicationContext reactContext;
3839

@@ -57,4 +58,22 @@ public void getVideoInfo(String path, Promise promise) {
5758
Log.d(REACT_PACKAGE, "getVideoInfo: " + path);
5859
Trimmer.getVideoInfo(path, promise, reactContext);
5960
}
61+
62+
@ReactMethod
63+
public void trim(ReadableMap options, Promise promise) {
64+
Log.d(REACT_PACKAGE, options.toString());
65+
Trimmer.trim(options, promise);
66+
}
67+
@ReactMethod
68+
public void compress(ReadableMap options, Promise promise) {
69+
Log.d(REACT_PACKAGE, "compress: not supported");
70+
promise.reject("not supported on android", "");
71+
}
72+
73+
@ReactMethod
74+
public void getPreviewImageAtPosition(ReadableMap options, Promise promise) {
75+
String source = options.getString("source");
76+
double sec = options.getDouble("second");
77+
Trimmer.getPreviewAtPosition(source, sec, promise);
78+
}
6079
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// @flow
2+
3+
import { NativeModules } from 'react-native';
4+
import type {
5+
sourceType,
6+
trimOptions
7+
} from './types';
8+
9+
import { getActualSource } from '../utils';
10+
11+
const { RNTrimmerManager: TrimmerManager } = NativeModules;
12+
class ProcessingManager {
13+
static trim(source: sourceType, options: trimOptions): Promise<string> {
14+
const actualSource: string = getActualSource(source);
15+
const mData = { source: actualSource, ...options };
16+
return TrimmerManager.trim(mData)
17+
.then((res) => res.source);
18+
}
19+
static compress(source: sourceType, options: any): Promise<*> {
20+
const actualSource: string = getActualSource(source);
21+
const mData = { source: actualSource, ...options };
22+
return TrimmerManager.compress(mData);
23+
}
24+
static getVideoInfo(source: sourceType): Promise<*> {
25+
const actualSource: string = getActualSource(source);
26+
return TrimmerManager.getVideoInfo(actualSource)
27+
.then(({ duration, size }) => ({
28+
duration: duration / 1000,
29+
size
30+
}));
31+
}
32+
static getPreviewForSecond(source: sourceType, second: number): Promise<*> {
33+
const actualSource: string = getActualSource(source);
34+
const mData = { source: actualSource, second };
35+
return TrimmerManager.getPreviewImageAtPosition(mData)
36+
.then((res) => res.image);
37+
}
38+
}
39+
40+
export default ProcessingManager;

0 commit comments

Comments
 (0)