Skip to content

Merge with latest master (as of 07.04.2020) #1

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5599930
Process specified device sps nal data
spiritedRunning Aug 8, 2016
762429e
add handle avc sps nal data
spiritedRunning Aug 18, 2016
8bbf3ba
Merge pull request #29 from spiritedRunning/pull_request
ypresto Aug 18, 2016
d3ab876
Close stream before calling listener events
ryanwilliams83 Jul 20, 2016
0b3c432
Merge pull request #36 from ypresto/close-before-callback
ypresto Sep 9, 2016
de24f3b
Bump to 0.2.0
ypresto Sep 9, 2016
39cbb94
Add audio constants, fix javadoc error
ypresto Sep 9, 2016
bdf9db3
Fix FileUriExposedException on Android 7.0
ypresto Sep 9, 2016
f7d5712
Add reference to qiita post
ypresto Sep 9, 2016
a5ecf0a
Updated gradle and build tools versions
VeneetReddyK Jun 8, 2017
ba45be5
Bump build tools version to latest
VeneetReddyK Sep 15, 2017
cfd083a
Remove swallowed exception in runPipelines
VeneetReddyK Sep 15, 2017
e9c411c
Merge pull request #53 from PinkFloyded/cancel-bug-fix
ypresto Nov 27, 2017
bfe2807
Parse the geographic location coordinates in the video file and pass …
hkurokawa Aug 8, 2018
43a7eed
Merge pull request #63 from hkurokawa/support-geo-metatag
ypresto Aug 11, 2018
c17dd6d
Add Google maven repo
ypresto Aug 11, 2018
012c3ab
Bump to 0.3.0
ypresto Aug 11, 2018
6261e72
Make available high profile
shts Feb 13, 2019
a09de49
Merge pull request #1 from shts/feature/available-high-profile
shts Feb 13, 2019
df7ee27
Remove profile validation
shts May 7, 2019
c0ee729
Merge pull request #73 from shts/master
ypresto Aug 19, 2019
c5ac813
fix audio output validation to validate on the output format, not the…
edwardotis Oct 31, 2018
ac94c6b
Merge pull request #70 from edwardotis/fix_audio_format_validation
ypresto Aug 19, 2019
aa7dc58
Merge remote-tracking branch 'noaudiostreamfix_repo/noaudiostreamfix'…
Apr 7, 2020
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
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## 0.3.0
- Fix cancel() sometimes not working. (Thanks @strayerM and @PinkFloyded)
- Geolocation support on API>=19. (Thanks @hkurokawa)

## 0.2.0
- Experimental audio transcoding support. (Thanks @aaron112)
- Fix transcode does not run on Huawei Ascend P7. (Thanks @spiritedRunning)
- Fix race condition caused by not closing output before callback. (Thanks @ryanwilliams83)

## 0.1.10
- `Future` support. (Thanks @MaiKambayashi)

## 0.1.X
- Stability updates. (Thanks @ozyozyo)

## 0.1.0
- First release.
22 changes: 15 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ repositories {
```

```groovy
compile 'net.ypresto.androidtranscoder:android-transcoder:0.1.10'
compile 'net.ypresto.androidtranscoder:android-transcoder:0.2.0'
```

## Note (PLEASE READ FIRST)
Expand All @@ -78,6 +78,20 @@ Use [qtfaststart-java](https://github.com/ypresto/qtfaststart-java) to place moo
- Android does not gurantees that all devices have bug-free codecs/accelerators for your codec parameters (especially, resolution). Refer [supported media formats](http://developer.android.com/guide/appendix/media-formats.html) for parameters guaranteed by [CTS](https://source.android.com/compatibility/cts-intro.html).
- This library does not support video files recorded by other device like digital cameras, iOS (mov files, including non-baseline profile h.264), etc.


## More information about internals

There is a blog post about this library written in Japanese.
http://qiita.com/yuya_presto/items/d48e29c89109b746d000

While it is Japanese, diagrams would be useful for understanding internals of this library.

## References for Android Low-Level Media APIs

- http://bigflake.com/mediacodec/
- https://github.com/google/grafika
- https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright

## License

```
Expand All @@ -95,9 +109,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

## References for Android Low-Level Media APIs

- http://bigflake.com/mediacodec/
- https://github.com/google/grafika
- https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright
10 changes: 9 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.android.tools.build:gradle:2.3.3'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand All @@ -15,5 +19,9 @@ buildscript {
allprojects {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
}
3 changes: 2 additions & 1 deletion example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apply plugin: 'com.android.application'

android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
buildToolsVersion '25.0.0'

defaultConfig {
applicationId "net.ypresto.androidtranscoder.example"
Expand All @@ -21,4 +21,5 @@ android {

dependencies {
compile project(':lib')
compile 'com.android.support:support-core-utils:24.2.0'
}
20 changes: 17 additions & 3 deletions example/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.ypresto.androidtranscoder.example" >
package="net.ypresto.androidtranscoder.example">

<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="18" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
android:theme="@style/AppTheme">
<activity
android:name=".TranscoderActivity"
android:label="@string/app_name" >
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="net.ypresto.androidtranscoder.example.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.support.v4.content.FileProvider;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
Expand All @@ -26,6 +27,7 @@

public class TranscoderActivity extends Activity {
private static final String TAG = "TranscoderActivity";
private static final String FILE_PROVIDER_AUTHORITY = "net.ypresto.androidtranscoder.example.fileprovider";
private static final int REQUEST_CODE_PICK = 1;
private static final int PROGRESS_BAR_MAX = 1000;
private Future<Void> mFuture;
Expand Down Expand Up @@ -55,7 +57,10 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
final File file;
if (resultCode == RESULT_OK) {
try {
file = File.createTempFile("transcode_test", ".mp4", getExternalFilesDir(null));
File outputDir = new File(getExternalFilesDir(null), "outputs");
//noinspection ResultOfMethodCallIgnored
outputDir.mkdir();
file = File.createTempFile("transcode_test", ".mp4", outputDir);
} catch (IOException e) {
Log.e(TAG, "Failed to create temporary file.", e);
Toast.makeText(this, "Failed to create temporary file.", Toast.LENGTH_LONG).show();
Expand Down Expand Up @@ -89,7 +94,10 @@ public void onTranscodeProgress(double progress) {
public void onTranscodeCompleted() {
Log.d(TAG, "transcoding took " + (SystemClock.uptimeMillis() - startTime) + "ms");
onTranscodeFinished(true, "transcoded file placed on " + file, parcelFileDescriptor);
startActivity(new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.fromFile(file), "video/mp4"));
Uri uri = FileProvider.getUriForFile(TranscoderActivity.this, FILE_PROVIDER_AUTHORITY, file);
startActivity(new Intent(Intent.ACTION_VIEW)
.setDataAndType(uri, "video/mp4")
.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION));
}

@Override
Expand Down
6 changes: 6 additions & 0 deletions example/src/main/res/xml/file_paths.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="output_videos"
path="Android/data/net.ypresto.androidtranscoder.example/files/outputs" />
</paths>
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Mon Mar 09 14:43:12 JST 2015
#Thu Jun 08 12:40:11 IST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
4 changes: 2 additions & 2 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ apply plugin: 'bintray-release'

android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
buildToolsVersion '25.0.2'

defaultConfig {
minSdkVersion 18
Expand All @@ -32,7 +32,7 @@ android {
publish {
groupId = 'net.ypresto.androidtranscoder'
artifactId = 'android-transcoder'
version = '0.1.10-SNAPSHOT'
version = '0.3.0'
licences = ['Apache-2.0']
website = 'https://github.com/ypresto/android-transcoder'
autoPublish = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.ypresto.androidtranscoder.utils;

import junit.framework.TestCase;

public class ISO6709LocationParserTest extends TestCase {
public void testParse() {
ISO6709LocationParser parser = new ISO6709LocationParser();
assertEquals(new float[]{35.658632f, 139.745411f}, parser.parse("+35.658632+139.745411/"));
assertEquals(new float[]{40.75f, -074.00f}, parser.parse("+40.75-074.00/"));
// with Altitude
assertEquals(new float[]{-90f, +0f}, parser.parse("-90+000+2800/"));
assertEquals(new float[]{27.5916f, 086.5640f}, parser.parse("+27.5916+086.5640+8850/"));
// ranged data
assertEquals(new float[]{35.331f, 134.224f}, parser.parse("+35.331+134.224/+35.336+134.228/"));
assertEquals(new float[]{35.331f, 134.224f}, parser.parse("+35.331+134.224/+35.336+134.228/+35.333+134.229/+35.333+134.227/"));
}

public void testParseFailure() {
ISO6709LocationParser parser = new ISO6709LocationParser();
assertNull(parser.parse(null));
assertNull(parser.parse(""));
assertNull(parser.parse("35 deg 65' 86.32\" N, 139 deg 74' 54.11\" E"));
assertNull(parser.parse("+35.658632"));
assertNull(parser.parse("+35.658632-"));
assertNull(parser.parse("40.75-074.00"));
assertNull(parser.parse("+40.75-074.00.00"));
}

private static void assertEquals(float[] expected, float[] actual) {
assertEquals(expected.length, actual.length);
for (int i = 0; i < expected.length; i++) {
assertTrue(Float.compare(expected[i], actual[i]) == 0);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,20 @@ public void onTranscodeProgress(double progress) {

@Override
public void onTranscodeCompleted() {
listener.onTranscodeCompleted();
closeStream();
listener.onTranscodeCompleted();
}

@Override
public void onTranscodeCanceled() {
listener.onTranscodeCanceled();
closeStream();
listener.onTranscodeCanceled();
}

@Override
public void onTranscodeFailed(Exception exception) {
listener.onTranscodeFailed(exception);
closeStream();
listener.onTranscodeFailed(exception);
}

private void closeStream() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void setup() {

@Override
public MediaFormat getDeterminedFormat() {
return mInputFormat;
return mActualOutputFormat;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,8 @@
import android.media.MediaFormat;

import net.ypresto.androidtranscoder.format.MediaFormatExtraConstants;
import net.ypresto.androidtranscoder.utils.AvcCsdUtils;
import net.ypresto.androidtranscoder.utils.AvcSpsUtils;

import java.nio.ByteBuffer;

class MediaFormatValidator {
// Refer: http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Profiles
private static final byte PROFILE_IDC_BASELINE = 66;

public static void validateVideoOutputFormat(MediaFormat format) {
String mime = format.getString(MediaFormat.KEY_MIME);
Expand All @@ -34,11 +28,6 @@ public static void validateVideoOutputFormat(MediaFormat format) {
if (!MediaFormatExtraConstants.MIMETYPE_VIDEO_AVC.equals(mime)) {
throw new InvalidOutputFormatException("Video codecs other than AVC is not supported, actual mime type: " + mime);
}
ByteBuffer spsBuffer = AvcCsdUtils.getSpsBuffer(format);
byte profileIdc = AvcSpsUtils.getProfileIdc(spsBuffer);
if (profileIdc != PROFILE_IDC_BASELINE) {
throw new InvalidOutputFormatException("Non-baseline AVC video profile is not supported by Android OS, actual profile_idc: " + profileIdc);
}
}

public static void validateAudioOutputFormat(MediaFormat format) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
import android.media.MediaFormat;
import android.media.MediaMetadataRetriever;
import android.media.MediaMuxer;
import android.os.Build;
import android.util.Log;

import net.ypresto.androidtranscoder.BuildConfig;
import net.ypresto.androidtranscoder.format.MediaFormatStrategy;
import net.ypresto.androidtranscoder.utils.ISO6709LocationParser;
import net.ypresto.androidtranscoder.utils.MediaExtractorUtils;

import java.io.FileDescriptor;
Expand Down Expand Up @@ -137,9 +140,17 @@ private void setupMetadata() throws IOException {
// skip
}

// TODO: parse ISO 6709
// String locationString = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION);
// mMuxer.setLocation(Integer.getInteger(rotationString, 0));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
String locationString = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION);
if (locationString != null) {
float[] location = new ISO6709LocationParser().parse(locationString);
if (location != null) {
mMuxer.setLocation(location[0], location[1]);
} else {
Log.d(TAG, "Failed to parse the location metadata: " + locationString);
}
}
}

try {
mDurationUs = Long.parseLong(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)) * 1000;
Expand Down Expand Up @@ -189,7 +200,7 @@ public void onDetermineOutputFormat() {
mAudioTrackTranscoder.setup();
}

private void runPipelines() {
private void runPipelines() throws InterruptedException {
long loopCount = 0;
if (mDurationUs <= 0) {
double progress = PROGRESS_UNKNOWN;
Expand All @@ -208,11 +219,7 @@ private void runPipelines() {
if (mProgressCallback != null) mProgressCallback.onProgress(progress);
}
if (!stepped) {
try {
Thread.sleep(SLEEP_TO_WAIT_TRACK_TRANSCODERS);
} catch (InterruptedException e) {
// nothing to do
}
Thread.sleep(SLEEP_TO_WAIT_TRACK_TRANSCODERS);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package net.ypresto.androidtranscoder.format;

public class MediaFormatStrategyPresets {
public static final int AUDIO_BITRATE_AS_IS = -1;
public static final int AUDIO_CHANNELS_AS_IS = -1;

/**
* @deprecated Use {@link #createExportPreset960x540Strategy()}.
*/
Expand Down Expand Up @@ -45,7 +48,7 @@ public static MediaFormatStrategy createAndroid720pStrategy(int bitrate) {
/**
* Preset based on Nexus 4 camera recording with 720p quality.
* This preset is ensured to work on any Android &gt;=4.3 devices by Android CTS (if codec is available).
* <p/>
* <br>
* Note: audio transcoding is experimental feature.
*
* @param bitrate Preferred bitrate for video encoding.
Expand Down
Loading