Skip to content

Commit

Permalink
update from file examples
Browse files Browse the repository at this point in the history
  • Loading branch information
pedroSG94 committed Oct 20, 2023
1 parent 107970a commit 3c10827
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.RequiresApi;
Expand Down Expand Up @@ -59,7 +60,7 @@ public class RtmpFromFileActivity extends AppCompatActivity
private SeekBar seekBar;
private EditText etUrl;
private TextView tvFile;
private String filePath = "";
private Uri filePath;
private boolean touching = false;

private String currentDateAndTime = "";
Expand Down Expand Up @@ -143,9 +144,11 @@ public void onAuthSuccessRtmp() {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 5 && data != null) {
filePath = PathUtils.getPath(this, data.getData());
Toast.makeText(this, filePath, Toast.LENGTH_SHORT).show();
tvFile.setText(filePath);
filePath = data.getData();
if (filePath != null) {
Toast.makeText(this, filePath.getPath(), Toast.LENGTH_SHORT).show();
tvFile.setText(filePath.getPath());
}
}
}

Expand All @@ -157,6 +160,7 @@ public void onClick(View view) {
try {
if (!rtmpFromFile.isRecording()) {
if (prepare()) {
rtmpFromFile.setLoopMode(true);
button.setText(R.string.stop_button);
rtmpFromFile.startStream(etUrl.getText().toString());
seekBar.setMax(Math.max((int) rtmpFromFile.getVideoDuration(),
Expand Down Expand Up @@ -236,8 +240,8 @@ public void onClick(View view) {
}

private boolean prepare() throws IOException {
boolean result = rtmpFromFile.prepareVideo(filePath);
result |= rtmpFromFile.prepareAudio(filePath);
boolean result = rtmpFromFile.prepareVideo(getApplicationContext(), filePath);
result |= rtmpFromFile.prepareAudio(getApplicationContext(), filePath);
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.RequiresApi;
Expand Down Expand Up @@ -62,7 +63,7 @@ public class RtspFromFileActivity extends AppCompatActivity
private SeekBar seekBar;
private EditText etUrl;
private TextView tvFile;
private String filePath = "";
private Uri filePath;
private boolean touching = false;

private String currentDateAndTime = "";
Expand Down Expand Up @@ -146,9 +147,11 @@ public void onAuthSuccessRtsp() {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 5 && data != null) {
filePath = PathUtils.getPath(this, data.getData());
Toast.makeText(this, filePath, Toast.LENGTH_SHORT).show();
tvFile.setText(filePath);
filePath = data.getData();
if (filePath != null) {
Toast.makeText(this, filePath.getPath(), Toast.LENGTH_SHORT).show();
tvFile.setText(filePath.getPath());
}
}
}

Expand Down Expand Up @@ -239,8 +242,8 @@ public void onClick(View view) {
}

private boolean prepare() throws IOException {
boolean result = rtspFromFile.prepareVideo(filePath);
result |= rtspFromFile.prepareAudio(filePath);
boolean result = rtspFromFile.prepareVideo(getApplicationContext(), filePath);
result |= rtspFromFile.prepareAudio(getApplicationContext(), filePath);
return result;
}

Expand Down
109 changes: 0 additions & 109 deletions app/src/main/java/com/pedro/streamer/utils/PathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@

package com.pedro.streamer.utils;

import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

import java.io.File;

Expand All @@ -45,110 +40,6 @@ public static File getRecordPath(Context context) {
return context.getExternalFilesDir(null);
}

public static String getPath(final Context context, final Uri uri) {

// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(
context, uri)) {

if (isExternalStorageDocument(uri)) {// ExternalStorageProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
String storageDefinition;

if ("primary".equalsIgnoreCase(type)) {

return Environment.getExternalStorageDirectory() + "/" + split[1];
} else {

if (Environment.isExternalStorageRemovable()) {
storageDefinition = "EXTERNAL_STORAGE";
} else {
storageDefinition = "SECONDARY_STORAGE";
}

return System.getenv(storageDefinition) + "/" + split[1];
}
} else if (isDownloadsDocument(uri)) {// DownloadsProvider

final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri =
ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));

return getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) {// MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];

Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}

final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};

return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {// MediaStore (and general)

// Return the remote address
if (isGooglePhotosUri(uri)) return uri.getLastPathSegment();

return getDataColumn(context, uri, null, null);
} else if ("file".equalsIgnoreCase(uri.getScheme())) {// File
return uri.getPath();
}

return null;
}

private static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {

Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};

try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null) cursor.close();
}
return null;
}

private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}

private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

public static void updateGallery(Context context, String path) {
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(path))));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public abstract class BaseDecoder {
private volatile long lastExtractorTs = 0;
//Avoid decode while change output surface
protected AtomicBoolean pause = new AtomicBoolean(false);
protected volatile boolean looped = false;

public boolean initExtractor(String filePath) throws IOException {
extractor = new MediaExtractor();
Expand Down Expand Up @@ -93,9 +94,14 @@ public boolean initExtractor(FileDescriptor fileDescriptor, long offset, long le
extractor.setDataSource(fileDescriptor, offset, length);
return extract(extractor);
}

Context context;
Uri uri;
Map<String, String> headers;
public boolean initExtractor(Context context, Uri uri, Map<String, String> headers)
throws IOException {
this.context = context;
this.uri = uri;
this.headers = headers;
extractor = new MediaExtractor();
extractor.setDataSource(context, uri, headers);
return extract(extractor);
Expand Down Expand Up @@ -146,15 +152,20 @@ protected boolean prepare(Surface surface) {

protected void resetCodec(Surface surface) {
boolean wasRunning = running;
stopDecoder();
stopDecoder(!wasRunning);
prepare(surface);
if (wasRunning) {
start();
}
}

protected void stopDecoder() {
stopDecoder(true);
}

protected void stopDecoder(boolean clearTs) {
running = false;
if (clearTs) startTs = 0;
if (handlerThread != null) {
if (handlerThread.getLooper() != null) {
if (handlerThread.getLooper().getThread() != null) {
Expand Down Expand Up @@ -185,7 +196,7 @@ protected void stopDecoder() {

public void moveTo(double time) {
synchronized (sync) {
extractor.seekTo((long) (time * 10E5), MediaExtractor.SEEK_TO_CLOSEST_SYNC);
extractor.seekTo((long) (time * 10E5), MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
lastExtractorTs = extractor.getSampleTime();
}
}
Expand Down Expand Up @@ -217,12 +228,23 @@ public double getTime() {
protected abstract void finished();

private void decode() {
startTs = System.nanoTime() / 1000;
if (startTs == 0) {
startTs = System.nanoTime() / 1000;
}
long sleepTime = 0;
long accumulativeTs = 0;
while (running) {
synchronized (sync) {
if (pause.get()) continue;
if (looped) {
double time = getTime();
if (time > 0) {
moveTo(0);
continue;
} else {
looped = false;
}
}
int inIndex = codec.dequeueInputBuffer(10000);
int sampleSize = 0;
if (inIndex >= 0) {
Expand Down Expand Up @@ -259,14 +281,14 @@ private void decode() {
}
boolean render = decodeOutput(output);
codec.releaseOutputBuffer(outIndex, render && bufferInfo.size != 0);
} else if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 || sampleSize < 0) {
Log.i(TAG, "end of file");
if (loopMode) {
double reamingTime = getDuration() - getTime();
if (reamingTime < 1 && loopMode) {
moveTo(0);
} else {
finished();
break;
looped = true;
}
} else if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 || sampleSize < 0) {
Log.i(TAG, "end of file");
finished();
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions library/src/main/java/com/pedro/library/base/FromFileBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaFormat;
import android.net.Uri;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -153,6 +155,19 @@ public boolean prepareVideo(FileDescriptor fileDescriptor, int bitRate, int rota
return finishPrepareVideo(bitRate, rotation, avcProfile, avcProfileLevel);
}

/**
* @param uri Uri to video MP4 file.
* @param bitRate H264 in bps.
* @return true if success, false if you get a error (Normally because the encoder selected
* doesn't support any configuration seated or your device hasn't a H264 encoder).
* @throws IOException Normally file not found.
*/
public boolean prepareVideo(Context context, Uri uri, int bitRate, int rotation, int avcProfile,
int avcProfileLevel) throws IOException {
if (!videoDecoder.initExtractor(context, uri, null)) return false;
return finishPrepareVideo(bitRate, rotation, avcProfile, avcProfileLevel);
}

public boolean prepareVideo(String filePath, int bitRate, int rotation) throws IOException {
return prepareVideo(filePath, bitRate, rotation, -1, -1);
}
Expand All @@ -165,6 +180,14 @@ public boolean prepareVideo(String filePath) throws IOException {
return prepareVideo(filePath, 1200 * 1024, 0);
}

public boolean prepareVideo(Context context, Uri uri, int bitRate, int rotation) throws IOException {
return prepareVideo(context, uri, bitRate, rotation, -1, -1);
}

public boolean prepareVideo(Context context, Uri uri) throws IOException {
return prepareVideo(context, uri, 1200 * 1024, 0);
}

public boolean prepareVideo(FileDescriptor fileDescriptor) throws IOException {
return prepareVideo(fileDescriptor, 1200 * 1024, 0);
}
Expand Down Expand Up @@ -203,6 +226,18 @@ public boolean prepareAudio(FileDescriptor fileDescriptor, int bitRate) throws I
return finishPrepareAudio(bitRate);
}

/**
* @param uri Uri to audio file.
* @param bitRate AAC in kb.
* @return true if success, false if you get a error (Normally because the encoder selected
* doesn't support any configuration seated or your device hasn't a H264 encoder).
* @throws IOException Normally file not found.
*/
public boolean prepareAudio(Context context, Uri uri, int bitRate) throws IOException {
if (!audioDecoder.initExtractor(context, uri, null)) return false;
return finishPrepareAudio(bitRate);
}

private boolean finishPrepareAudio(int bitRate) {
audioDecoder.prepareAudio();
boolean result = audioEncoder.prepareAudioEncoder(bitRate, audioDecoder.getSampleRate(),
Expand Down Expand Up @@ -253,6 +288,10 @@ public boolean prepareAudio(String filePath) throws IOException {
return prepareAudio(filePath, 64 * 1024);
}

public boolean prepareAudio(Context context, Uri uri) throws IOException {
return prepareAudio(context, uri, 64 * 1024);
}

protected abstract void prepareAudioRtp(boolean isStereo, int sampleRate);

/**
Expand Down

0 comments on commit 3c10827

Please sign in to comment.