Skip to content

Commit

Permalink
Add support to write data to a File using a Uri (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ma7moudHatem authored Apr 20, 2021
1 parent 648b57b commit 16328dc
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@
*/
package com.linkedin.android.litr.exception;

import android.net.Uri;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;

public class MediaTargetException extends MediaTransformationException {

private static final String INVALID_PARAMS_TEXT = "Invalid parameters";
private static final String IO_FAILURE_TEXT = "Failed to open the media target for write.";
private static final String UNSUPPORTED_URI_TYPE_TEXT = "URI type not supported at API level below 26";

private final Error error;
private final String outputFilePath;
private final int outputFormat;

public MediaTargetException(@NonNull Error error, @NonNull String outputFilePath, @IntRange(from=0, to=2) int outputFormat) {
this(error, outputFilePath, outputFormat, new Throwable());
public MediaTargetException(@NonNull Error error, @NonNull Uri outputFileUri, @IntRange(from=0, to=2) int outputFormat, @NonNull Throwable cause) {
this(error, outputFileUri.toString(), outputFormat, cause);
}

public MediaTargetException(@NonNull Error error, @NonNull String outputFilePath, @IntRange(from=0, to=2) int outputFormat, @NonNull Throwable cause) {
Expand All @@ -32,7 +34,8 @@ public MediaTargetException(@NonNull Error error, @NonNull String outputFilePath

public enum Error {
INVALID_PARAMS(INVALID_PARAMS_TEXT),
IO_FAILUE(IO_FAILURE_TEXT);
IO_FAILUE(IO_FAILURE_TEXT),
UNSUPPORTED_URI_TYPE(UNSUPPORTED_URI_TYPE_TEXT);

private final String text;
Error(String text) {
Expand All @@ -50,7 +53,7 @@ public Error getError() {
public String toString() {
return super.toString() + '\n'
+ error.text + '\n'
+ "Output file path: " + outputFilePath + '\n'
+ "Output file path or Uri encoded string: " + outputFilePath + '\n'
+ "MediaMuxer output format: " + outputFormat;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,25 @@
*/
package com.linkedin.android.litr.io;

import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.linkedin.android.litr.exception.MediaTargetException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedList;

import static com.linkedin.android.litr.exception.MediaTargetException.Error.INVALID_PARAMS;
import static com.linkedin.android.litr.exception.MediaTargetException.Error.IO_FAILUE;
import static com.linkedin.android.litr.exception.MediaTargetException.Error.UNSUPPORTED_URI_TYPE;

/**
* An implementation of MediaTarget, which wraps Android's {@link MediaMuxer}
Expand All @@ -40,29 +44,66 @@ public class MediaMuxerMediaTarget implements MediaTarget {

private MediaFormat[] mediaFormatsToAdd;

private ParcelFileDescriptor parcelFileDescriptor;
private String outputFilePath;
private int numberOfTracksToAdd;
private int trackCount;

public MediaMuxerMediaTarget(@NonNull String outputFilePath, @IntRange(from = 1) int trackCount, int orientationHint, int outputFormat) throws MediaTargetException {
this.outputFilePath = outputFilePath;
this.trackCount = trackCount;

/**
* Create an instance using input URI. On Android Oreo (API level 26) and above it can be any URI writeable by the
* provided context, otherwise it must be a "file://" URI. This constructor is especially useful when working with
* FileProvider created URI to comply with scoped storage enforcement on Android 10+
*/
public MediaMuxerMediaTarget(@NonNull Context context, @NonNull Uri outputFileUri,
@IntRange(from = 1) int trackCount, int orientationHint, int outputFormat) throws MediaTargetException {
try {
mediaMuxer = new MediaMuxer(outputFilePath, outputFormat);
mediaMuxer.setOrientationHint(orientationHint);
MediaMuxer mediaMuxer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
parcelFileDescriptor = context.getContentResolver().openFileDescriptor(outputFileUri, "rwt");
if (parcelFileDescriptor != null) {
mediaMuxer = new MediaMuxer(parcelFileDescriptor.getFileDescriptor(), outputFormat);
} else {
throw new IOException("Inaccessible URI " + outputFileUri);
}
} else if ("file".equalsIgnoreCase(outputFileUri.getScheme()) && outputFileUri.getPath() != null) {
mediaMuxer = new MediaMuxer(outputFileUri.getPath(), outputFormat);
} else {
throw new MediaTargetException(UNSUPPORTED_URI_TYPE, outputFileUri, outputFormat, new Throwable());
}
init(mediaMuxer, trackCount, orientationHint);
} catch (IllegalArgumentException illegalArgumentException) {
throw new MediaTargetException(INVALID_PARAMS, outputFileUri, outputFormat, illegalArgumentException);
} catch (IOException ioException) {
releaseFileDescriptor();
throw new MediaTargetException(IO_FAILUE, outputFileUri, outputFormat, ioException);
}
}

numberOfTracksToAdd = 0;
isStarted = false;
queue = new LinkedList<>();
mediaFormatsToAdd = new MediaFormat[trackCount];
public MediaMuxerMediaTarget(@NonNull String outputFilePath, @IntRange(from = 1) int trackCount,
int orientationHint, int outputFormat) throws MediaTargetException {
this.outputFilePath = outputFilePath;
try {
MediaMuxer mediaMuxer = new MediaMuxer(outputFilePath, outputFormat);
init(mediaMuxer, trackCount, orientationHint);
} catch (IllegalArgumentException illegalArgumentException) {
throw new MediaTargetException(INVALID_PARAMS, outputFilePath, outputFormat, illegalArgumentException);
} catch (IOException ioException) {
throw new MediaTargetException(IO_FAILUE, outputFilePath, outputFormat, ioException);
}
}

private void init(@NonNull MediaMuxer mediaMuxer, @IntRange(from = 1) int trackCount, int orientationHint) throws IllegalArgumentException {
this.trackCount = trackCount;

this.mediaMuxer = mediaMuxer;
this.mediaMuxer.setOrientationHint(orientationHint);

numberOfTracksToAdd = 0;
isStarted = false;
queue = new LinkedList<>();
mediaFormatsToAdd = new MediaFormat[trackCount];
}

@Override
public int addTrack(@NonNull MediaFormat mediaFormat, @IntRange(from = 0) int targetTrack) {
mediaFormatsToAdd[targetTrack] = mediaFormat;
Expand Down Expand Up @@ -106,12 +147,23 @@ public void writeSampleData(int targetTrack, @NonNull ByteBuffer buffer, @NonNul
@Override
public void release() {
mediaMuxer.release();
releaseFileDescriptor();
}

@Override
@NonNull
public String getOutputFilePath() {
return outputFilePath;
return outputFilePath != null ? outputFilePath : "";
}

private void releaseFileDescriptor() {
try {
if (parcelFileDescriptor != null) {
parcelFileDescriptor.close();
parcelFileDescriptor = null;
}
} catch (IOException ignored) {
}
}

private class MediaSample {
Expand Down

0 comments on commit 16328dc

Please sign in to comment.