diff --git a/app/src/main/cpp/metadata/ffmpeg_media_retriever.c b/app/src/main/cpp/metadata/ffmpeg_media_retriever.c
index 7a4327f..84a21f0 100755
--- a/app/src/main/cpp/metadata/ffmpeg_media_retriever.c
+++ b/app/src/main/cpp/metadata/ffmpeg_media_retriever.c
@@ -487,7 +487,7 @@ void convert_image(State *state, AVCodecContext *pCodecCtx, AVFrame *pFrame, AVP
}
}
-int get_embedded_picture(State **state_ptr, AVPacket *pkt) {
+int get_audio_thumbnail(State **state_ptr, AVPacket *pkt) {
int i = 0;
int got_packet = 0;
AVFrame *frame = NULL;
diff --git a/app/src/main/cpp/metadata/ffmpeg_media_retriever.h b/app/src/main/cpp/metadata/ffmpeg_media_retriever.h
index edcb117..f697dde 100755
--- a/app/src/main/cpp/metadata/ffmpeg_media_retriever.h
+++ b/app/src/main/cpp/metadata/ffmpeg_media_retriever.h
@@ -54,6 +54,7 @@ int set_data_source_fd(State **ps, int fd, int64_t offset, int64_t length);
const char* extract_metadata(State **ps, const char* key);
int get_frame_at_time(State **ps, int64_t timeUs, int option, AVPacket *pkt);
int get_scaled_frame_at_time(State **ps, int64_t timeUs, int option, AVPacket *pkt, int width, int height);
+int get_audio_thumbnail(State **state_ptr, AVPacket *pkt);
int set_native_window(State **ps, ANativeWindow* native_window);
void release(State **ps);
diff --git a/app/src/main/cpp/metadata/media_retriever.cpp b/app/src/main/cpp/metadata/media_retriever.cpp
index 92b6d93..f12b706 100755
--- a/app/src/main/cpp/metadata/media_retriever.cpp
+++ b/app/src/main/cpp/metadata/media_retriever.cpp
@@ -47,6 +47,12 @@ int MediaRetriever::getScaledFrameAtTime(int64_t timeUs, int option, AVPacket *p
return ::get_scaled_frame_at_time(&state, timeUs, option, pkt, width, height);
}
+int MediaRetriever::getAudioThumbnail(AVPacket *pkt)
+{
+ Mutex::Autolock lock(mLock);
+ return ::get_audio_thumbnail(&state, pkt);
+}
+
int MediaRetriever::setNativeWindow(ANativeWindow* native_window)
{
Mutex::Autolock lock(mLock);
diff --git a/app/src/main/cpp/metadata/media_retriever.h b/app/src/main/cpp/metadata/media_retriever.h
index d316cf6..cfa14ae 100755
--- a/app/src/main/cpp/metadata/media_retriever.h
+++ b/app/src/main/cpp/metadata/media_retriever.h
@@ -30,6 +30,7 @@ public:
const char* extractMetadata(const char* key);
int getFrameAtTime(int64_t timeUs, int option, AVPacket *pkt);
int getScaledFrameAtTime(int64_t timeUs, int option, AVPacket *pkt, int width, int height);
+ int getAudioThumbnail(AVPacket *pkt);
int setNativeWindow(ANativeWindow* native_window);
private:
diff --git a/app/src/main/cpp/metadata/media_retriever_jni.cpp b/app/src/main/cpp/metadata/media_retriever_jni.cpp
index 8966503..b864340 100755
--- a/app/src/main/cpp/metadata/media_retriever_jni.cpp
+++ b/app/src/main/cpp/metadata/media_retriever_jni.cpp
@@ -260,6 +260,37 @@ RETRIEVER_FUNC(jbyteArray, native_1getScaleFrameAtTime, jlong timeUs, jint optio
return array;
}
+RETRIEVER_FUNC(jbyteArray, native_1getAudioThumbnail)
+{
+ MediaRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == nullptr) {
+ jniThrowException(env, mIllegalStateException, mNoAvailableMsg);
+ return nullptr;
+ }
+
+ AVPacket packet;
+ av_init_packet(&packet);
+ jbyteArray array = nullptr;
+
+ if (retriever->getAudioThumbnail(&packet) == 0) {
+ int size = packet.size;
+ uint8_t* data = packet.data;
+ array = env->NewByteArray(size);
+ if (!array) {
+ LOGE(LOG_TAG, "getAudioThumbnail: OutOfMemoryError is thrown.");
+ } else {
+ jbyte* bytes = env->GetByteArrayElements(array, nullptr);
+ if (bytes != nullptr) {
+ memcpy(bytes, data, size);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+ }
+ }
+ }
+
+ av_packet_unref(&packet);
+ return array;
+}
+
RETRIEVER_FUNC(void, native_1release)
{
MediaRetriever* retriever = getRetriever(env, thiz);
diff --git a/app/src/main/java/com/frank/ffmpeg/activity/ProbeFormatActivity.kt b/app/src/main/java/com/frank/ffmpeg/activity/ProbeFormatActivity.kt
index 7875abf..50da0f3 100644
--- a/app/src/main/java/com/frank/ffmpeg/activity/ProbeFormatActivity.kt
+++ b/app/src/main/java/com/frank/ffmpeg/activity/ProbeFormatActivity.kt
@@ -185,6 +185,8 @@ class ProbeFormatActivity : BaseActivity() {
// Retrieve frame with timeUs
val bitmap = retriever.getFrameAtTime(5 * 1000000)
+ // Retrieve audio thumbnail, if it has embedded
+// val bitmap = retriever.audioThumbnail
if (bitmap != null) {
Log.e("FFmpegRetriever", "bitmap width=${bitmap.width}--height=${bitmap.height}")
mHandler.obtainMessage(MSG_FRAME, bitmap).sendToTarget()
diff --git a/app/src/main/java/com/frank/ffmpeg/metadata/FFmpegMediaRetriever.java b/app/src/main/java/com/frank/ffmpeg/metadata/FFmpegMediaRetriever.java
index b9ac574..bb3ed28 100755
--- a/app/src/main/java/com/frank/ffmpeg/metadata/FFmpegMediaRetriever.java
+++ b/app/src/main/java/com/frank/ffmpeg/metadata/FFmpegMediaRetriever.java
@@ -203,6 +203,15 @@ public class FFmpegMediaRetriever {
return getScaledFrameAtTime(timeUs, OPTION_CLOSEST_SYNC, width, height);
}
+ public Bitmap getAudioThumbnail() {
+ byte[] picture = native_getAudioThumbnail();
+ if (picture != null) {
+ return BitmapFactory.decodeByteArray(picture, 0, picture.length, null);
+ }
+
+ return null;
+ }
+
public void release() {
native_release();
}
@@ -223,6 +232,8 @@ public class FFmpegMediaRetriever {
private native byte[] native_getScaleFrameAtTime(long timeUs, int option, int width, int height);
+ private native byte[] native_getAudioThumbnail();
+
private native void native_release();
/**
diff --git a/app/src/main/res/layout/activity_probe.xml b/app/src/main/res/layout/activity_probe.xml
index fd292e4..6d92928 100644
--- a/app/src/main/res/layout/activity_probe.xml
+++ b/app/src/main/res/layout/activity_probe.xml
@@ -13,9 +13,10 @@
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="@string/media_probe"
+ android:textSize="12sp"
android:textColor="@color/colorPrimary"
android:layout_alignParentStart="true"
- android:layout_marginStart="20dp"/>
+ android:layout_marginStart="10dp"/>
+ android:layout_marginEnd="10dp"/>