Skip to content

Commit

Permalink
Merge pull request #14256 from wordpress-mobile/try/using-lib-in-vide…
Browse files Browse the repository at this point in the history
…o-compression-scenario

Using stories lib in video compression scenario
  • Loading branch information
mzorz authored May 24, 2021
2 parents fc5d54c + b56413c commit 4e1c718
Show file tree
Hide file tree
Showing 13 changed files with 449 additions and 26 deletions.
3 changes: 3 additions & 0 deletions WordPress/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ android {
buildConfigField "boolean", "IS_JETPACK_APP", "false"
buildConfigField "String", "TRACKS_EVENT_PREFIX", '"wpandroid_"'
buildConfigField "String", "PUSH_NOTIFICATIONS_APP_KEY", '"org.wordpress.android"'
buildConfigField "boolean", "MP4_COMPOSER_VIDEO_OPTIMIZATION", "false"

manifestPlaceholders = [magicLinkScheme:"wordpress"]
}
Expand Down Expand Up @@ -139,6 +140,7 @@ android {
wasabi { // "hot" version, can be installed along release, alpha or beta versions
applicationIdSuffix ".beta"
dimension "buildType"
buildConfigField "boolean", "MP4_COMPOSER_VIDEO_OPTIMIZATION", "true"
}

jalapeno { // Pre-Alpha version, used for PR builds, can be installed along release, alpha, beta, dev versions
Expand Down Expand Up @@ -209,6 +211,7 @@ androidExtensions {
}

dependencies {
implementation project(path: ':mp4compose')
implementation project(path:':libs:stories-android:stories')
testImplementation project(path:':photoeditor')
implementation project(path:':libs:image-editor::ImageEditor')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@
import org.wordpress.android.ui.suggestion.SuggestionActivity;
import org.wordpress.android.ui.suggestion.SuggestionType;
import org.wordpress.android.ui.uploads.PostEvents;
import org.wordpress.android.ui.uploads.ProgressEvent;
import org.wordpress.android.ui.uploads.UploadService;
import org.wordpress.android.ui.uploads.UploadUtils;
import org.wordpress.android.ui.uploads.UploadUtilsWrapper;
import org.wordpress.android.ui.uploads.VideoOptimizer;
import org.wordpress.android.ui.utils.AuthenticationUtils;
import org.wordpress.android.ui.utils.UiHelpers;
import org.wordpress.android.util.ActivityUtils;
Expand Down Expand Up @@ -3485,7 +3485,7 @@ public void onPostUploaded(OnPostUploaded event) {

@SuppressWarnings("unused")
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(VideoOptimizer.ProgressEvent event) {
public void onEventMainThread(ProgressEvent event) {
if (!isFinishing()) {
// use upload progress rather than optimizer progress since the former includes upload+optimization
float progress = UploadService.getUploadProgressForMedia(event.media);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import org.wordpress.android.ui.posts.PostUploadAction.MediaUploadedSnackbar
import org.wordpress.android.ui.posts.PostUploadAction.PostRemotePreviewSnackbarError
import org.wordpress.android.ui.posts.PostUploadAction.PostUploadedSnackbar
import org.wordpress.android.ui.uploads.PostEvents
import org.wordpress.android.ui.uploads.ProgressEvent
import org.wordpress.android.ui.uploads.UploadService
import org.wordpress.android.ui.uploads.VideoOptimizer
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.AppLog.T
import javax.inject.Inject
Expand Down Expand Up @@ -275,7 +275,7 @@ class PostListEventListener(

@Suppress("unused")
@Subscribe(threadMode = BACKGROUND)
fun onEventBackgroundThread(event: VideoOptimizer.ProgressEvent) {
fun onEventBackgroundThread(event: ProgressEvent) {
uploadStatusChanged(event.media.localPostId)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.wordpress.android.ui.uploads;

import androidx.annotation.NonNull;

import org.m4m.MediaComposer;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.fluxc.model.MediaModel;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.WPVideoUtils;
import org.wordpress.android.util.analytics.AnalyticsUtils;

import java.util.Map;

import static org.wordpress.android.analytics.AnalyticsTracker.Stat.MEDIA_VIDEO_CANT_OPTIMIZE;

public class M4mVideoOptimizer extends VideoOptimizerBase implements org.m4m.IProgressListener {
public M4mVideoOptimizer(
@NonNull MediaModel media,
@NonNull VideoOptimizationListener listener) {
super(media, listener);
}

/*
* IProgressListener handlers
*/
@Override
public void onMediaStart() {
mStartTimeMS = System.currentTimeMillis();
}

@Override
public void onMediaProgress(float progress) {
sendProgressIfNeeded(progress);
}

@Override
public void onMediaDone() {
trackVideoProcessingEvents(false, null);
selectMediaAndSendCompletionToListener();
}

@Override
public void onMediaPause() {
AppLog.d(AppLog.T.MEDIA, "VideoOptimizer > paused");
}

@Override
public void onMediaStop() {
// This seems to be called called in 2 cases. Do not use to check if we've manually stopped the composer.
// 1. When the encoding is done without errors, before onMediaDone
// 2. When we call 'stop' on the media composer
AppLog.d(AppLog.T.MEDIA, "VideoOptimizer > stopped");
}

@Override
public void onError(Exception e) {
AppLog.e(AppLog.T.MEDIA, "VideoOptimizer > Can't optimize the video", e);
trackVideoProcessingEvents(true, e);
mListener.onVideoOptimizationCompleted(mMedia);
}

@Override
public void start() {
if (!arePathsValidated()) return;

MediaComposer mediaComposer = null;
boolean wasNpeDetected = false;

try {
mediaComposer = WPVideoUtils.getVideoOptimizationComposer(
getContext(),
mInputPath,
mOutputPath,
this,
AppPrefs.getVideoOptimizeWidth(),
AppPrefs.getVideoOptimizeQuality());
} catch (NullPointerException npe) {
AppLog.w(
AppLog.T.MEDIA,
"VideoOptimizer > NullPointerException while getting composer " + npe.getMessage()
);
wasNpeDetected = true;
}

if (mediaComposer == null) {
AppLog.w(AppLog.T.MEDIA, "VideoOptimizer > null composer");
Map<String, Object> properties = AnalyticsUtils.getMediaProperties(getContext(), true,
null, mInputPath);
properties.put("was_npe_detected", wasNpeDetected);
properties.put("optimizer-lib", "m4m");
AnalyticsTracker.track(MEDIA_VIDEO_CANT_OPTIMIZE, properties);
mListener.onVideoOptimizationCompleted(mMedia);
return;
}

// setup done. We're ready to optimize!
try {
mediaComposer.start();
AppLog.d(AppLog.T.MEDIA, "VideoOptimizer > composer started");
} catch (IllegalStateException e) {
AppLog.e(AppLog.T.MEDIA, "VideoOptimizer > failed to start composer", e);
mListener.onVideoOptimizationCompleted(mMedia);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.wordpress.android.util.StringUtils;
import org.wordpress.android.util.WPMediaUtils;
import org.wordpress.android.util.analytics.AnalyticsUtils;
import org.wordpress.android.util.config.Mp4ComposerVideoOptimizationFeatureConfig;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -32,13 +33,14 @@

import javax.inject.Inject;

public class MediaUploadHandler implements UploadHandler<MediaModel>, VideoOptimizer.VideoOptimizationListener {
public class MediaUploadHandler implements UploadHandler<MediaModel>, VideoOptimizationListener {
private static List<MediaModel> sPendingUploads = new ArrayList<>();
private static List<MediaModel> sInProgressUploads = new ArrayList<>();
private static ConcurrentHashMap<Integer, Float> sOptimizationProgressByMediaId = new ConcurrentHashMap<>();

@Inject Dispatcher mDispatcher;
@Inject SiteStore mSiteStore;
@Inject Mp4ComposerVideoOptimizationFeatureConfig mMp4ComposerVideoOptimizationFeatureConfig;

MediaUploadHandler() {
((WordPress) WordPress.getContext().getApplicationContext()).component().inject(this);
Expand Down Expand Up @@ -282,7 +284,12 @@ private void cancelUpload(MediaModel oneUpload, boolean delete) {
private void prepareForUpload(@NonNull MediaModel media) {
if (media.isVideo() && WPMediaUtils.isVideoOptimizationEnabled()) {
addUniqueMediaToInProgressUploads(media);
new VideoOptimizer(media, this).start();

if (mMp4ComposerVideoOptimizationFeatureConfig.isEnabled()) {
new Mp4ComposerVideoOptimizer(media, this).start();
} else {
new VideoOptimizer(media, this).start();
}
} else {
dispatchUploadAction(media);
}
Expand Down Expand Up @@ -443,7 +450,7 @@ enqueued. However, MediaModel references only a single post (`localPostId`). Whe
public void onVideoOptimizationProgress(@NonNull MediaModel media, float progress) {
sOptimizationProgressByMediaId.put(media.getId(), progress);
// fire an event so EditPostActivity and PostsListFragment can show progress
VideoOptimizer.ProgressEvent event = new VideoOptimizer.ProgressEvent(media, progress);
ProgressEvent event = new ProgressEvent(media, progress);
EventBus.getDefault().post(event);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package org.wordpress.android.ui.uploads;

import androidx.annotation.NonNull;

import com.daasuu.mp4compose.composer.ComposerInterface;
import com.daasuu.mp4compose.composer.Listener;

import org.jetbrains.annotations.NotNull;
import org.wordpress.android.analytics.AnalyticsTracker;
import org.wordpress.android.fluxc.model.MediaModel;
import org.wordpress.android.ui.prefs.AppPrefs;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.WPVideoUtils;
import org.wordpress.android.util.analytics.AnalyticsUtils;

import java.util.Map;

import static org.wordpress.android.analytics.AnalyticsTracker.Stat.MEDIA_VIDEO_CANT_OPTIMIZE;

public class Mp4ComposerVideoOptimizer extends VideoOptimizerBase implements Listener {
public Mp4ComposerVideoOptimizer(
@NonNull MediaModel media,
@NonNull VideoOptimizationListener listener) {
super(media, listener);
}

@Override
public void onStart() {
mStartTimeMS = System.currentTimeMillis();
}

@Override
public void onProgress(double progress) {
// this event fires quite often so we only call the listener when progress increases by 1% or more
// NOTE: progress can be -1 with Mp4Composer library
if (progress < 0) return;

sendProgressIfNeeded((float) progress);
}

@Override
public void onCompleted() {
trackVideoProcessingEvents(false, null);
selectMediaAndSendCompletionToListener();
}

@Override
public void onCanceled() {
AppLog.d(AppLog.T.MEDIA, "VideoOptimizer > stopped");
}

@Override
public void onFailed(@NotNull Exception exception) {
AppLog.e(AppLog.T.MEDIA, "VideoOptimizer > Can't optimize the video", exception);
trackVideoProcessingEvents(true, exception);
mListener.onVideoOptimizationCompleted(mMedia);
}

@Override public void start() {
if (!arePathsValidated()) return;

ComposerInterface composer = null;

try {
composer = WPVideoUtils.getVideoOptimizationComposer(
mInputPath,
mOutputPath,
this,
AppPrefs.getVideoOptimizeWidth(),
AppPrefs.getVideoOptimizeQuality());
} catch (Exception e) {
AppLog.w(
AppLog.T.MEDIA,
"VideoOptimizer > Exception while getting composer " + e.getMessage()
);
composer = null;
}

if (composer == null) {
AppLog.w(AppLog.T.MEDIA, "VideoOptimizer > null composer");
Map<String, Object> properties = AnalyticsUtils.getMediaProperties(getContext(), true,
null, mInputPath);
properties.put("optimizer-lib", "mp4composer");
AnalyticsTracker.track(MEDIA_VIDEO_CANT_OPTIMIZE, properties);
mListener.onVideoOptimizationCompleted(mMedia);
return;
}

// setup done. We're ready to optimize!
composer.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,6 @@
import static org.wordpress.android.analytics.AnalyticsTracker.Stat.MEDIA_VIDEO_OPTIMIZE_ERROR;

public class VideoOptimizer implements org.m4m.IProgressListener {
public interface VideoOptimizationListener {
void onVideoOptimizationCompleted(@NonNull MediaModel media);

void onVideoOptimizationProgress(@NonNull MediaModel media, float progress);
}

public static class ProgressEvent {
public final MediaModel media;
public final float progress;

public ProgressEvent(@NonNull MediaModel media, float progress) {
this.media = media;
this.progress = progress;
}
}

private final File mCacheDir;
private final MediaModel mMedia;
private final VideoOptimizationListener mListener;
Expand Down Expand Up @@ -109,6 +93,7 @@ public void start() {
Map<String, Object> properties = AnalyticsUtils.getMediaProperties(getContext(), true,
null, mInputPath);
properties.put("was_npe_detected", wasNpeDetected);
properties.put("optimizer-lib", "m4m");
AnalyticsTracker.track(MEDIA_VIDEO_CANT_OPTIMIZE, properties);
mListener.onVideoOptimizationCompleted(mMedia);
return;
Expand Down Expand Up @@ -145,6 +130,7 @@ private void trackVideoProcessingEvents(boolean isError, Exception exception) {
properties.put("exception_message", exception.getMessage());
AppLog.e(T.MEDIA, exception);
}
properties.put("optimizer-lib", "m4m");

AnalyticsTracker.Stat currentStatToTrack = isError ? MEDIA_VIDEO_OPTIMIZE_ERROR : MEDIA_VIDEO_OPTIMIZED;
AnalyticsTracker.track(currentStatToTrack, properties);
Expand Down
Loading

0 comments on commit 4e1c718

Please sign in to comment.