From e915be92088d1d9b265ea30350bc3a8a2def2ed8 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 11:06:09 +0530 Subject: [PATCH 01/13] First pass at adding transcode support This does a hard-coded audio encode to vorbis-in-ogg. In the long term, this should use encodebin and real encoding profiles. --- jni/Android.mk | 22 ++++++ jni/README.gst-sdk | 8 ++ jni/transcode.c | 91 +++++++++++++++++++++++ src/org/wikimedia/commons/Transcoder.java | 10 +++ 4 files changed, 131 insertions(+) create mode 100644 jni/Android.mk create mode 100644 jni/README.gst-sdk create mode 100644 jni/transcode.c create mode 100644 src/org/wikimedia/commons/Transcoder.java diff --git a/jni/Android.mk b/jni/Android.mk new file mode 100644 index 000000000..fdd2a2851 --- /dev/null +++ b/jni/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libtranscode +LOCAL_SRC_FILES := transcode.c +LOCAL_SHARED_LIBRARIES := gstreamer_android +LOCAL_LDLIBS := -landroid + +include $(BUILD_SHARED_LIBRARY) + +GSTREAMER_SDK_ROOT := $(GSTREAMER_SDK_ROOT_ANDROID) +GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_SDK_ROOT)/share/gst-android/ndk-build/ +include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk +GSTREAMER_PLUGINS := \ + $(GSTREAMER_PLUGINS_CORE) \ + $(GSTREAMER_PLUGINS_PLAYBACK) \ + audioparsers id3demux isomp4 ogg vorbis \ + amrnb amrwbdec faad mad mpegaudioparse \ + amc + +include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk diff --git a/jni/README.gst-sdk b/jni/README.gst-sdk new file mode 100644 index 000000000..c14029f7a --- /dev/null +++ b/jni/README.gst-sdk @@ -0,0 +1,8 @@ +* Get the GStreamer SDK for Android + - http://docs.gstreamer.com/display/GstSDK/Installing+for+Android+development + - user: test, pass: Jo6eem7e (these will go away once the SDK gets out of the + beta stage) +* Get the NDK +* export GSTREAMER_SDK_ROOT_ANDROID=/path/to/unpacked/gstreamer/sdk +* cd jni; /ndk-build +* cd ..; Continue building as usual diff --git a/jni/transcode.c b/jni/transcode.c new file mode 100644 index 000000000..783e496dd --- /dev/null +++ b/jni/transcode.c @@ -0,0 +1,91 @@ +#include + +#include + +static int init(void) +{ + /* XXX: ZERO thread-safety guarantees here */ + static gboolean inited = 0; + + if (inited) + return 0; + + gst_init(NULL, NULL); + return 0; +} + +static int transcode(const char *infile, const char *outfile, + const char *profile) +{ + GstElement *pipeline; + GstBus *bus; + GstMessage *msg; + gchar pipeline_str[1024]; + + init(); + + snprintf(pipeline_str, 1024, + "filesrc location=%s ! decodebin2 ! audioconvert ! " + "vorbisenc ! oggmux ! filesink location=%s", + infile, outfile); + + pipeline = gst_parse_launch(pipeline_str, NULL); + + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + bus = gst_element_get_bus(pipeline); + msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ERROR | GST_MESSAGE_EOS); + + if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { + GError *err = NULL; + gchar *debug_info = NULL; + + gst_message_parse_error(msg, &err, &debug_info); + + GST_ERROR_OBJECT(pipeline, "%s -- %s", err->message, + debug_info ? debug_info : "no debug info"); + + g_error_free(err); + g_free(debug_info); + } + + if (msg != NULL) + gst_message_unref (msg); + + gst_object_unref (bus); + gst_element_set_state (pipeline, GST_STATE_NULL); + gst_object_unref (pipeline); +} + +jint Java_org_wikimedia_commons_Transcoder_transcode(JNIEnv* env, + jclass *klass, jstring infile, jstring outfile, jstring profile) +{ + const char *in; + const char *out; + const char *prof = NULL; + + if (!infile || !outfile) + return -1; + + in = (*env)->GetStringUTFChars(env, infile, 0); + out = (*env)->GetStringUTFChars(env, outfile, 0); + + if (profile) + prof = (*env)->GetStringUTFChars(env, profile, 0); + + return transcode(in, out, prof); +} + + +#ifdef TEST +int main(int argc, char **argv) +{ + if (argc != 3) + return -1; + + transcode(argv[1], argv[2], NULL); + + return 0; +} +#endif diff --git a/src/org/wikimedia/commons/Transcoder.java b/src/org/wikimedia/commons/Transcoder.java new file mode 100644 index 000000000..b25bb0fbd --- /dev/null +++ b/src/org/wikimedia/commons/Transcoder.java @@ -0,0 +1,10 @@ +package org.wikimedia.commons; + +public class Transcoder { + public static native int transcode(String infile, String outfile, + String profile); + + static { + System.loadLibrary("transcode"); + } +} From af9dd0832fcf931e7c3730b6246dd91a25b93f18 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 12:25:40 +0530 Subject: [PATCH 02/13] Add external storage read/write permissions We need this in order to access files stored on MMC and to write out (temporary files) before uploading. The latter will be done away with once we hook up the trancode pipeline to directly provide encoded blocks rather than writing to a file. --- AndroidManifest.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 32b0d31a7..c28e2fe7d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -12,6 +12,8 @@ + + - \ No newline at end of file + From 46bd6853887b1d688e836e7737d3f1c690ca0fbb Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 13:15:55 +0530 Subject: [PATCH 03/13] Quote filenames in transcode pipeline Needed for files with spaces in their names. --- jni/transcode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jni/transcode.c b/jni/transcode.c index 783e496dd..4d022a6d0 100644 --- a/jni/transcode.c +++ b/jni/transcode.c @@ -25,8 +25,8 @@ static int transcode(const char *infile, const char *outfile, init(); snprintf(pipeline_str, 1024, - "filesrc location=%s ! decodebin2 ! audioconvert ! " - "vorbisenc ! oggmux ! filesink location=%s", + "filesrc location=\"%s\" ! decodebin2 ! audioconvert ! " + "vorbisenc ! oggmux ! filesink location=\"%s\"", infile, outfile); pipeline = gst_parse_launch(pipeline_str, NULL); From 81aacd7b1155450c381943f0ab8d3f0b456f29f1 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 15:05:42 +0530 Subject: [PATCH 04/13] Fix return value in transcode function --- jni/transcode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jni/transcode.c b/jni/transcode.c index 4d022a6d0..07d88eace 100644 --- a/jni/transcode.c +++ b/jni/transcode.c @@ -56,6 +56,8 @@ static int transcode(const char *infile, const char *outfile, gst_object_unref (bus); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); + + return 0; } jint Java_org_wikimedia_commons_Transcoder_transcode(JNIEnv* env, From 836d35e7080a9ce49eaa700e7b8ec6d5ff0e488a Mon Sep 17 00:00:00 2001 From: YuviPanda Date: Sun, 11 Nov 2012 15:10:09 +0530 Subject: [PATCH 05/13] Initial support for GStreamer Audio Encoding to Ogg --- AndroidManifest.xml | 1 + res/values/strings.xml | 6 ++ .../wikimedia/commons/CommonsApplication.java | 8 ++ src/org/wikimedia/commons/ShareActivity.java | 41 ++++++----- src/org/wikimedia/commons/UploadService.java | 73 ++++++++++++++++--- 5 files changed, 101 insertions(+), 28 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c28e2fe7d..4997d9697 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -36,6 +36,7 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index c0b25a718..72661de3b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -28,4 +28,10 @@ Finishing uploading %1$s Uploading %1$s failed Tap to retry + + Starting %1$s Transcoding + Transcoding %1$s + Finished Transcoding %1$s + Failed Transcoding %1$s + Tap to try again \ No newline at end of file diff --git a/src/org/wikimedia/commons/CommonsApplication.java b/src/org/wikimedia/commons/CommonsApplication.java index 005e3d6f4..f5ede4677 100644 --- a/src/org/wikimedia/commons/CommonsApplication.java +++ b/src/org/wikimedia/commons/CommonsApplication.java @@ -1,6 +1,7 @@ package org.wikimedia.commons; import java.io.IOException; +import com.gst_sdk.GStreamer; import java.io.StringWriter; import javax.xml.transform.*; @@ -39,6 +40,13 @@ public class CommonsApplication extends Application { public void onCreate() { // TODO Auto-generated method stub super.onCreate(); + System.loadLibrary("gstreamer_android"); + try { + GStreamer.init(this); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } api = createMWApi(); } diff --git a/src/org/wikimedia/commons/ShareActivity.java b/src/org/wikimedia/commons/ShareActivity.java index 61a70942b..9fcf56a94 100644 --- a/src/org/wikimedia/commons/ShareActivity.java +++ b/src/org/wikimedia/commons/ShareActivity.java @@ -33,7 +33,7 @@ public class ShareActivity extends AuthenticatedActivity { private EditText titleEdit; private EditText descEdit; - private Uri imageUri; + private Uri mediaUri; @Override protected void onAuthCookieAcquired(String authCookie) { @@ -44,26 +44,29 @@ public class ShareActivity extends AuthenticatedActivity { final Context that = this; if(intent.getAction().equals(Intent.ACTION_SEND)) { - if(intent.getType().startsWith("image/")) { + mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); + + final String mimeType = intent.getType(); + if(mimeType.startsWith("image/")) { ImageLoaderTask loader = new ImageLoaderTask(backgroundImageView); - imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - loader.execute(imageUri); - - uploadButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent uploadIntent = new Intent(getApplicationContext(), UploadService.class); - uploadIntent.putExtra(UploadService.EXTRA_MEDIA_URI, imageUri); - uploadIntent.putExtra(UploadService.EXTRA_TARGET_FILENAME, titleEdit.getText().toString()); - uploadIntent.putExtra(UploadService.EXTRA_DESCRIPTION, descEdit.getText().toString()); - uploadIntent.putExtra(UploadService.EXTRA_EDIT_SUMMARY, "Mobile upload from Wikimedia Commons Android app"); - startService(uploadIntent); - Toast startingToast = Toast.makeText(that, R.string.uploading_started, Toast.LENGTH_LONG); - startingToast.show(); - finish(); - } - }); + loader.execute(mediaUri); } + + uploadButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent uploadIntent = new Intent(getApplicationContext(), UploadService.class); + uploadIntent.putExtra(UploadService.EXTRA_MEDIA_URI, mediaUri); + uploadIntent.putExtra(UploadService.EXTRA_TARGET_FILENAME, titleEdit.getText().toString()); + uploadIntent.putExtra(UploadService.EXTRA_DESCRIPTION, descEdit.getText().toString()); + uploadIntent.putExtra(UploadService.EXTRA_MIMETYPE, mimeType); + uploadIntent.putExtra(UploadService.EXTRA_EDIT_SUMMARY, "Mobile upload from Wikimedia Commons Android app"); + startService(uploadIntent); + Toast startingToast = Toast.makeText(that, R.string.uploading_started, Toast.LENGTH_LONG); + startingToast.show(); + finish(); + } + }); } } diff --git a/src/org/wikimedia/commons/UploadService.java b/src/org/wikimedia/commons/UploadService.java index ad68bd653..013fc3733 100644 --- a/src/org/wikimedia/commons/UploadService.java +++ b/src/org/wikimedia/commons/UploadService.java @@ -28,6 +28,7 @@ public class UploadService extends IntentService { public static final String EXTRA_TARGET_FILENAME = EXTRA_PREFIX + ".filename"; public static final String EXTRA_DESCRIPTION = EXTRA_PREFIX + ".description"; public static final String EXTRA_EDIT_SUMMARY = EXTRA_PREFIX + ".summary"; + public static final String EXTRA_MIMETYPE = EXTRA_PREFIX + ".mimetype"; private NotificationManager notificationManager; private CommonsApplication app; @@ -46,6 +47,9 @@ public class UploadService extends IntentService { public static final int NOTIFICATION_DOWNLOAD_COMPLETE = 2; public static final int NOTIFICATION_UPLOAD_FAILED = 3; + public static final int NOTIFICATION_TRANSCODING_IN_PROGRESS = 4; + public static final int NOTIFICATION_TRANSCODING_FAILED = 5; + private class NotificationUpdateProgressListener implements ProgressListener { Notification curNotification; @@ -98,12 +102,20 @@ public class UploadService extends IntentService { app = (CommonsApplication)this.getApplicationContext(); } + private String getRealPathFromURI(Uri contentUri) { + String[] proj = { MediaStore.Images.Media.DATA }; + CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null); + Cursor cursor = loader.loadInBackground(); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } @Override protected void onHandleIntent(Intent intent) { MWApi api = app.getApi(); - InputStream file; - long length; + InputStream file = null; + long length = 0; ApiResult result; RemoteViews notificationView; @@ -112,20 +124,63 @@ public class UploadService extends IntentService { String filename = intent.getStringExtra(EXTRA_TARGET_FILENAME); String description = intent.getStringExtra(EXTRA_DESCRIPTION); String editSummary = intent.getStringExtra(EXTRA_EDIT_SUMMARY); + String mimeType = intent.getStringExtra(EXTRA_MIMETYPE); String notificationTag = mediaUri.toString(); Date dateCreated = null; try { - file = this.getContentResolver().openInputStream(mediaUri); - length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength(); - Cursor cursor = this.getContentResolver().query(mediaUri, - new String[] { MediaStore.Images.ImageColumns.DATE_TAKEN }, null, null, null); - if(cursor.getCount() != 0) { - cursor.moveToFirst(); - dateCreated = new Date(cursor.getInt(0)); + Log.d("Commons", "MimeType is " + mimeType); + if(mimeType.startsWith("image/")) { + file = this.getContentResolver().openInputStream(mediaUri); + length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength(); + Cursor cursor = this.getContentResolver().query(mediaUri, + new String[] { MediaStore.Images.ImageColumns.DATE_TAKEN }, null, null, null); + if(cursor.getCount() != 0) { + cursor.moveToFirst(); + dateCreated = new Date(cursor.getInt(0)); + } + } else if (mimeType.startsWith("audio/")) { + String srcPath = this.getRealPathFromURI(mediaUri); + File destFile = File.createTempFile("org.wikimedia.commons", ".ogg"); + Log.d("Commons", "Path is " + srcPath); + Log.d("Commons", "Dest is " + destFile.getAbsolutePath()); + + Notification transcodeNotification = new NotificationCompat.Builder(this).setAutoCancel(true) + .setSmallIcon(R.drawable.ic_launcher) + .setAutoCancel(true) + .setOngoing(true) + .setContentTitle(String.format(getString(R.string.transcoding_progress_title_in_progress), filename)) + .setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0)) + .setTicker(String.format(getString(R.string.transcoding_progress_title_in_progress), filename)) + .getNotification(); + + startForeground(NOTIFICATION_TRANSCODING_IN_PROGRESS, transcodeNotification); + + int transcodeResult = Transcoder.transcode(srcPath, destFile.getAbsolutePath(), null); + stopForeground(true); + + if(transcodeResult != 0) { + Notification failureNotification = new NotificationCompat.Builder(this).setAutoCancel(true) + .setSmallIcon(R.drawable.ic_launcher) + .setAutoCancel(true) + .setContentIntent(PendingIntent.getService(getApplicationContext(), 0, intent, 0)) + .setTicker(String.format(getString(R.string.transcoding_failed_notification_title), filename)) + .setContentTitle(String.format(getString(R.string.transcoding_failed_notification_title), filename)) + .setContentText(getString(R.string.transcoding_failed_notification_subtitle)) + .getNotification(); + notificationManager.notify(NOTIFICATION_TRANSCODING_FAILED, failureNotification); + return; + } + + file = new FileInputStream(destFile); + length = destFile.length(); + dateCreated = new Date(destFile.lastModified()); + Log.d("Commons", "Transcode doen!"); } } catch (FileNotFoundException e) { throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); } notificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress); From 363cd8b3e7f5667fd0bdaa3bfeb216d2f5a180ab Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 16:38:22 +0530 Subject: [PATCH 06/13] Add progress reporting to transcoder --- jni/Android.mk | 1 + jni/transcode.c | 69 ++++++++++++++++++----- src/org/wikimedia/commons/Transcoder.java | 7 ++- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/jni/Android.mk b/jni/Android.mk index fdd2a2851..74c1acb5b 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -15,6 +15,7 @@ include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk GSTREAMER_PLUGINS := \ $(GSTREAMER_PLUGINS_CORE) \ $(GSTREAMER_PLUGINS_PLAYBACK) \ + debug \ audioparsers id3demux isomp4 ogg vorbis \ amrnb amrwbdec faad mad mpegaudioparse \ amc diff --git a/jni/transcode.c b/jni/transcode.c index 07d88eace..516ef39ec 100644 --- a/jni/transcode.c +++ b/jni/transcode.c @@ -15,7 +15,7 @@ static int init(void) } static int transcode(const char *infile, const char *outfile, - const char *profile) + const char *profile, jobject cb_obj, JNIEnv *env) { GstElement *pipeline; GstBus *bus; @@ -25,8 +25,10 @@ static int transcode(const char *infile, const char *outfile, init(); snprintf(pipeline_str, 1024, - "filesrc location=\"%s\" ! decodebin2 ! audioconvert ! " - "vorbisenc ! oggmux ! filesink location=\"%s\"", + "filesrc location=\"%s\" ! " + "progressreport silent=true format=percent update-freq=1 ! " + "decodebin2 ! audioconvert ! vorbisenc ! oggmux ! " + "filesink location=\"%s\"", infile, outfile); pipeline = gst_parse_launch(pipeline_str, NULL); @@ -34,22 +36,58 @@ static int transcode(const char *infile, const char *outfile, gst_element_set_state (pipeline, GST_STATE_PLAYING); bus = gst_element_get_bus(pipeline); - msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, - GST_MESSAGE_ERROR | GST_MESSAGE_EOS); - if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { - GError *err = NULL; - gchar *debug_info = NULL; + for (;;) { + msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_ELEMENT); - gst_message_parse_error(msg, &err, &debug_info); + switch (GST_MESSAGE_TYPE(msg)) { + case GST_MESSAGE_ELEMENT: { + const GstStructure *s = gst_message_get_structure(msg); + int percent; + jclass cb_class; + jmethodID cb_id; - GST_ERROR_OBJECT(pipeline, "%s -- %s", err->message, - debug_info ? debug_info : "no debug info"); + if (!cb_obj) + break; - g_error_free(err); - g_free(debug_info); + if (!g_str_equal(gst_structure_get_name(s), "progress")) + break; + + gst_structure_get_int(s, "percent", &percent); + + break; + + cb_class = (*env)->FindClass(env, "org/wikimedia/commons/TranscoderProgressCallback"); + cb_id = (*env)->GetMethodID(env, cb_class, "transcodeProgressCb", "(I)V"); + (*env)->CallVoidMethod(env, cb_obj, cb_id, percent); + + break; + } + + case GST_MESSAGE_ERROR: { + GError *err = NULL; + gchar *debug_info = NULL; + + gst_message_parse_error(msg, &err, &debug_info); + + GST_ERROR_OBJECT(pipeline, "%s -- %s", err->message, + debug_info ? debug_info : "no debug info"); + + g_error_free(err); + g_free(debug_info); + goto done; + } + + case GST_MESSAGE_EOS: + goto done; + + default: + break; + } } +done: if (msg != NULL) gst_message_unref (msg); @@ -61,7 +99,8 @@ static int transcode(const char *infile, const char *outfile, } jint Java_org_wikimedia_commons_Transcoder_transcode(JNIEnv* env, - jclass *klass, jstring infile, jstring outfile, jstring profile) + jclass *klass, jstring infile, jstring outfile, jstring profile, + jobject cb_obj) { const char *in; const char *out; @@ -76,7 +115,7 @@ jint Java_org_wikimedia_commons_Transcoder_transcode(JNIEnv* env, if (profile) prof = (*env)->GetStringUTFChars(env, profile, 0); - return transcode(in, out, prof); + return transcode(in, out, prof, cb_obj, env); } diff --git a/src/org/wikimedia/commons/Transcoder.java b/src/org/wikimedia/commons/Transcoder.java index b25bb0fbd..196bed6d4 100644 --- a/src/org/wikimedia/commons/Transcoder.java +++ b/src/org/wikimedia/commons/Transcoder.java @@ -1,8 +1,11 @@ package org.wikimedia.commons; public class Transcoder { - public static native int transcode(String infile, String outfile, - String profile); + public interface TranscoderProgressCallback { + public void transcodeProgressCb(int percent); + } + + public static native int transcode(String infile, String outfile, String profile, TranscoderProgressCallback cb); static { System.loadLibrary("transcode"); From 7c828bd939baf2247d7f057f2675a1521017c1d4 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 16:38:36 +0530 Subject: [PATCH 07/13] Fix upload file name Server accepts .ogg only --- src/org/wikimedia/commons/UploadService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/wikimedia/commons/UploadService.java b/src/org/wikimedia/commons/UploadService.java index 013fc3733..b73623020 100644 --- a/src/org/wikimedia/commons/UploadService.java +++ b/src/org/wikimedia/commons/UploadService.java @@ -142,6 +142,7 @@ public class UploadService extends IntentService { } else if (mimeType.startsWith("audio/")) { String srcPath = this.getRealPathFromURI(mediaUri); File destFile = File.createTempFile("org.wikimedia.commons", ".ogg"); + filename = filename + ".ogg"; Log.d("Commons", "Path is " + srcPath); Log.d("Commons", "Dest is " + destFile.getAbsolutePath()); From ec5bcfc48ea024c1f0a274a4e5d96f0690294315 Mon Sep 17 00:00:00 2001 From: YuviPanda Date: Sun, 11 Nov 2012 16:48:54 +0530 Subject: [PATCH 08/13] First shot at getting progress for Transcoding --- src/org/wikimedia/commons/UploadService.java | 25 +++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/org/wikimedia/commons/UploadService.java b/src/org/wikimedia/commons/UploadService.java index b73623020..18b15700c 100644 --- a/src/org/wikimedia/commons/UploadService.java +++ b/src/org/wikimedia/commons/UploadService.java @@ -4,6 +4,7 @@ import java.io.*; import java.util.Date; import org.mediawiki.api.*; +import org.wikimedia.commons.Transcoder.TranscoderProgressCallback; import org.wikimedia.commons.media.Media; import de.mastacode.http.ProgressListener; @@ -49,7 +50,21 @@ public class UploadService extends IntentService { public static final int NOTIFICATION_TRANSCODING_IN_PROGRESS = 4; public static final int NOTIFICATION_TRANSCODING_FAILED = 5; - + + private class TranscodeProgressListener implements TranscoderProgressCallback { + + private Notification curNotification; + public TranscodeProgressListener(Notification curNotification) { + this.curNotification = curNotification; + } + @Override + public void transcodeProgressCb(int percent) { + curNotification.contentView.setProgressBar(R.id.uploadNotificationProgress, 100, percent, false); + startForeground(NOTIFICATION_TRANSCODING_IN_PROGRESS, curNotification); + Log.d("Commons", "Percentage: " + percent); + } + + } private class NotificationUpdateProgressListener implements ProgressListener { Notification curNotification; @@ -146,18 +161,22 @@ public class UploadService extends IntentService { Log.d("Commons", "Path is " + srcPath); Log.d("Commons", "Dest is " + destFile.getAbsolutePath()); + RemoteViews transcodeNotificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress); + transcodeNotificationView.setTextViewText(R.id.uploadNotificationTitle, String.format(getString(R.string.transcoding_progress_title_in_progress), filename)); + transcodeNotificationView.setProgressBar(R.id.uploadNotificationProgress, 100, 0, false); + Notification transcodeNotification = new NotificationCompat.Builder(this).setAutoCancel(true) .setSmallIcon(R.drawable.ic_launcher) .setAutoCancel(true) .setOngoing(true) - .setContentTitle(String.format(getString(R.string.transcoding_progress_title_in_progress), filename)) + .setContent(transcodeNotificationView) .setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0)) .setTicker(String.format(getString(R.string.transcoding_progress_title_in_progress), filename)) .getNotification(); startForeground(NOTIFICATION_TRANSCODING_IN_PROGRESS, transcodeNotification); - int transcodeResult = Transcoder.transcode(srcPath, destFile.getAbsolutePath(), null); + int transcodeResult = Transcoder.transcode(srcPath, destFile.getAbsolutePath(), null, new TranscodeProgressListener(transcodeNotification)); stopForeground(true); if(transcodeResult != 0) { From 8fae40f1e4eeda3e92d9980ed223006e44d4daba Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 17:35:56 +0530 Subject: [PATCH 09/13] Fix upload progress callback in transcoder --- jni/Android.mk | 2 +- jni/transcode.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/jni/Android.mk b/jni/Android.mk index 74c1acb5b..74d87c80a 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := libtranscode LOCAL_SRC_FILES := transcode.c LOCAL_SHARED_LIBRARIES := gstreamer_android -LOCAL_LDLIBS := -landroid +LOCAL_LDLIBS := -landroid -llog include $(BUILD_SHARED_LIBRARY) diff --git a/jni/transcode.c b/jni/transcode.c index 516ef39ec..00090fa03 100644 --- a/jni/transcode.c +++ b/jni/transcode.c @@ -1,6 +1,7 @@ #include #include +#include static int init(void) { @@ -56,11 +57,23 @@ static int transcode(const char *infile, const char *outfile, gst_structure_get_int(s, "percent", &percent); - break; + cb_class = (*env)->FindClass(env, "org/wikimedia/commons/Transcoder$TranscoderProgressCallback"); + if ((*env)->ExceptionCheck(env)) { + __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "Class not found"); + break; + } - cb_class = (*env)->FindClass(env, "org/wikimedia/commons/TranscoderProgressCallback"); cb_id = (*env)->GetMethodID(env, cb_class, "transcodeProgressCb", "(I)V"); + if ((*env)->ExceptionCheck(env)) { + __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "Method not found"); + break; + } + (*env)->CallVoidMethod(env, cb_obj, cb_id, percent); + if ((*env)->ExceptionCheck(env)) { + __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "Method call failed"); + break; + } break; } From 3500c5a5cbd61dc35730a146b69379f19e619e2a Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 17:36:17 +0530 Subject: [PATCH 10/13] Drop GStreamer amc codecs temporarily We don't use these yet, and init causes a crash on the Galaxy S3 running Jelly Bean. --- jni/Android.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jni/Android.mk b/jni/Android.mk index 74d87c80a..265816da7 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -17,7 +17,6 @@ GSTREAMER_PLUGINS := \ $(GSTREAMER_PLUGINS_PLAYBACK) \ debug \ audioparsers id3demux isomp4 ogg vorbis \ - amrnb amrwbdec faad mad mpegaudioparse \ - amc + amrnb amrwbdec faad mad mpegaudioparse include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk From ab23fa3af57064dc1e90d8b7f85c30ffc1ef3b57 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 17:52:08 +0530 Subject: [PATCH 11/13] Add wavparse to transcoder Needed got reading wav files --- jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jni/Android.mk b/jni/Android.mk index 265816da7..cbfeb34b4 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -16,7 +16,7 @@ GSTREAMER_PLUGINS := \ $(GSTREAMER_PLUGINS_CORE) \ $(GSTREAMER_PLUGINS_PLAYBACK) \ debug \ - audioparsers id3demux isomp4 ogg vorbis \ + audioparsers id3demux isomp4 ogg vorbis wavparse \ amrnb amrwbdec faad mad mpegaudioparse include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer.mk From fcf14318de533335d08fc0496d8872a37a340018 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 11 Nov 2012 18:07:48 +0530 Subject: [PATCH 12/13] Return an error if transcode fails --- jni/transcode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jni/transcode.c b/jni/transcode.c index 00090fa03..5eb390a14 100644 --- a/jni/transcode.c +++ b/jni/transcode.c @@ -22,6 +22,7 @@ static int transcode(const char *infile, const char *outfile, GstBus *bus; GstMessage *msg; gchar pipeline_str[1024]; + int ret = 0; init(); @@ -89,6 +90,8 @@ static int transcode(const char *infile, const char *outfile, g_error_free(err); g_free(debug_info); + + ret = -1; goto done; } @@ -108,7 +111,7 @@ done: gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); - return 0; + return ret; } jint Java_org_wikimedia_commons_Transcoder_transcode(JNIEnv* env, From f25fc8870fca4bbef794c4e1bda5f5baa7c4bc6c Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Mon, 12 Nov 2012 14:29:57 +0530 Subject: [PATCH 13/13] Fix build instructions for native bits --- jni/README.gst-sdk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jni/README.gst-sdk b/jni/README.gst-sdk index c14029f7a..b095c9c68 100644 --- a/jni/README.gst-sdk +++ b/jni/README.gst-sdk @@ -4,5 +4,5 @@ beta stage) * Get the NDK * export GSTREAMER_SDK_ROOT_ANDROID=/path/to/unpacked/gstreamer/sdk -* cd jni; /ndk-build -* cd ..; Continue building as usual +* (in top-level source dir) /ndk-build +* Continue building as usual