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"/>