Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using stories lib in video compression scenario #14256

Merged
merged 16 commits into from
May 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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