Add: FFmpegMediaRetriever usage

pull/209/head
xufulong 3 years ago
parent bc6eca53e8
commit dd09704876
  1. 20
      app/src/main/cpp/metadata/ffmpeg_media_retriever.c
  2. 1
      app/src/main/java/com/frank/ffmpeg/activity/MainActivity.kt
  3. 100
      app/src/main/java/com/frank/ffmpeg/activity/ProbeFormatActivity.kt
  4. 24
      app/src/main/res/layout/activity_probe.xml
  5. 3
      app/src/main/res/values-en/strings.xml
  6. 3
      app/src/main/res/values/strings.xml

@ -49,8 +49,8 @@ int get_scaled_context(State *s, AVCodecContext *pCodecCtx, int width, int heigh
s->scaled_codecCtx->pix_fmt = TARGET_IMAGE_FORMAT; s->scaled_codecCtx->pix_fmt = TARGET_IMAGE_FORMAT;
s->scaled_codecCtx->codec_type = AVMEDIA_TYPE_VIDEO; s->scaled_codecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
s->scaled_codecCtx->bit_rate = codecP->bit_rate; s->scaled_codecCtx->bit_rate = codecP->bit_rate;
s->scaled_codecCtx->time_base.num = s->video_st->codec->time_base.num; s->scaled_codecCtx->time_base.num = pCodecCtx->time_base.num;
s->scaled_codecCtx->time_base.den = s->video_st->codec->time_base.den; s->scaled_codecCtx->time_base.den = pCodecCtx->time_base.den;
if (!targetCodec || avcodec_open2(s->scaled_codecCtx, targetCodec, NULL) < 0) { if (!targetCodec || avcodec_open2(s->scaled_codecCtx, targetCodec, NULL) < 0) {
LOGE("avcodec_open2() failed\n"); LOGE("avcodec_open2() failed\n");
@ -490,7 +490,6 @@ int get_embedded_picture(State **state_ptr, AVPacket *pkt) {
int i = 0; int i = 0;
int got_packet = 0; int got_packet = 0;
AVFrame *frame = NULL; AVFrame *frame = NULL;
State *state = *state_ptr; State *state = *state_ptr;
if (!state || !state->pFormatCtx) { if (!state || !state->pFormatCtx) {
@ -520,8 +519,9 @@ int get_embedded_picture(State **state_ptr, AVPacket *pkt) {
break; break;
} }
avcodec_send_packet(state->video_st->codec, pkt); AVCodecContext *pCodecContext = state->video_st->codec;
int ret = avcodec_receive_frame(state->video_st->codec, frame); avcodec_send_packet(pCodecContext, pkt);
int ret = avcodec_receive_frame(pCodecContext, frame);
if (ret == 0) { if (ret == 0) {
got_frame = 1; got_frame = 1;
} else { } else {
@ -534,7 +534,7 @@ int get_embedded_picture(State **state_ptr, AVPacket *pkt) {
convertedPkt.size = 0; convertedPkt.size = 0;
convertedPkt.data = NULL; convertedPkt.data = NULL;
convert_image(state, state->video_st->codec, frame, &convertedPkt, &got_packet, -1, -1); convert_image(state, pCodecContext, frame, &convertedPkt, &got_packet, -1, -1);
av_packet_unref(pkt); av_packet_unref(pkt);
av_init_packet(pkt); av_init_packet(pkt);
@ -556,7 +556,6 @@ int get_embedded_picture(State **state_ptr, AVPacket *pkt) {
} }
av_frame_free(&frame); av_frame_free(&frame);
if (got_packet) { if (got_packet) {
return SUCCESS; return SUCCESS;
} else { } else {
@ -579,8 +578,9 @@ void decode_frame(State *state, AVPacket *pkt, int *got_frame, int64_t desired_f
if (!is_supported_format(codec_id, pix_fmt)) { if (!is_supported_format(codec_id, pix_fmt)) {
*got_frame = 0; *got_frame = 0;
avcodec_send_packet(state->video_st->codec, pkt); AVCodecContext *pCodecContext = state->video_st->codec;
int ret = avcodec_receive_frame(state->video_st->codec, frame); avcodec_send_packet(pCodecContext, pkt);
int ret = avcodec_receive_frame(pCodecContext, frame);
if (ret == 0) { if (ret == 0) {
*got_frame = 1; *got_frame = 1;
} else { } else {
@ -593,7 +593,7 @@ void decode_frame(State *state, AVPacket *pkt, int *got_frame, int64_t desired_f
av_packet_unref(pkt); av_packet_unref(pkt);
} }
av_init_packet(pkt); av_init_packet(pkt);
convert_image(state, state->video_st->codec, frame, pkt, got_frame, width, height); convert_image(state, pCodecContext, frame, pkt, got_frame, width, height);
break; break;
} }
} else { } else {

@ -71,7 +71,6 @@ class MainActivity : BaseActivity() {
-> intent.setClass(this@MainActivity, ProbeFormatActivity::class.java) -> intent.setClass(this@MainActivity, ProbeFormatActivity::class.java)
8 //audio effect 8 //audio effect
-> intent.setClass(this@MainActivity, AudioEffectActivity::class.java) -> intent.setClass(this@MainActivity, AudioEffectActivity::class.java)
// -> intent.setClass(this@MainActivity, MediaPlayerActivity::class.java)
else -> { else -> {
} }
} }

@ -1,25 +1,29 @@
package com.frank.ffmpeg.activity package com.frank.ffmpeg.activity
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Message import android.os.Message
import android.text.TextUtils import android.util.Log
import android.view.View import android.view.View
import android.widget.ImageView
import android.widget.ProgressBar import android.widget.ProgressBar
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import com.frank.ffmpeg.R import com.frank.ffmpeg.R
import com.frank.ffmpeg.handler.FFmpegHandler import com.frank.ffmpeg.handler.FFmpegHandler
import com.frank.ffmpeg.handler.FFmpegHandler.*
import com.frank.ffmpeg.model.MediaBean import com.frank.ffmpeg.model.MediaBean
import com.frank.ffmpeg.tool.JsonParseTool import com.frank.ffmpeg.tool.JsonParseTool
import com.frank.ffmpeg.util.FFmpegUtil import com.frank.ffmpeg.util.FFmpegUtil
import com.frank.ffmpeg.util.FileUtil import com.frank.ffmpeg.util.FileUtil
import com.frank.ffmpeg.handler.FFmpegHandler.MSG_BEGIN import com.frank.ffmpeg.metadata.FFmpegMediaRetriever
import com.frank.ffmpeg.handler.FFmpegHandler.MSG_FINISH import java.lang.StringBuilder
/** /**
* Using ffprobe to parse media format data * Using ffprobe to parse media format data
@ -33,6 +37,10 @@ class ProbeFormatActivity : BaseActivity() {
private var layoutProbe: RelativeLayout? = null private var layoutProbe: RelativeLayout? = null
private var ffmpegHandler: FFmpegHandler? = null private var ffmpegHandler: FFmpegHandler? = null
private var view: View? = null
private val MSG_FRAME = 9099
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
private val mHandler = object : Handler() { private val mHandler = object : Handler() {
override fun handleMessage(msg: Message) { override fun handleMessage(msg: Message) {
@ -47,11 +55,21 @@ class ProbeFormatActivity : BaseActivity() {
layoutProbe!!.visibility = View.VISIBLE layoutProbe!!.visibility = View.VISIBLE
val result = msg.obj?: msg.obj val result = msg.obj?: msg.obj
if (result != null) { if (result != null) {
val resultFormat = JsonParseTool.stringFormat(result as MediaBean) val mediaInfo = JsonParseTool.stringFormat(result as MediaBean)
if (!TextUtils.isEmpty(resultFormat) && txtProbeFormat != null) { if (!mediaInfo.isNullOrEmpty() && txtProbeFormat != null) {
txtProbeFormat!!.text = resultFormat txtProbeFormat!!.text = mediaInfo
}
} }
} }
MSG_INFO -> {
val mediaInfo = msg.obj as String
if (!mediaInfo.isNullOrEmpty()) {
txtProbeFormat!!.text = mediaInfo
}
}
MSG_FRAME -> {
val bitmap = msg.obj as Bitmap
findViewById<ImageView>(R.id.img_frame).setImageBitmap(bitmap)
} }
else -> { else -> {
} }
@ -73,16 +91,28 @@ class ProbeFormatActivity : BaseActivity() {
progressProbe = getView(R.id.progress_probe) progressProbe = getView(R.id.progress_probe)
layoutProbe = getView(R.id.layout_probe) layoutProbe = getView(R.id.layout_probe)
initViewsWithClick(R.id.btn_probe_format) initViewsWithClick(R.id.btn_probe_format)
initViewsWithClick(R.id.btn_retrieve_format)
txtProbeFormat = getView(R.id.txt_probe_format) txtProbeFormat = getView(R.id.txt_probe_format)
} }
override fun onViewClick(view: View) { override fun onViewClick(view: View) {
this.view = view
selectFile() selectFile()
} }
override fun onSelectedFile(filePath: String) { override fun onSelectedFile(filePath: String) {
when (view?.id) {
R.id.btn_probe_format -> {
doHandleProbe(filePath) doHandleProbe(filePath)
} }
R.id.btn_retrieve_format -> {
Thread {retrieveMediaMetadata(filePath)}.start()
}
else -> {
}
}
}
/** /**
* use ffprobe to parse video/audio format metadata * use ffprobe to parse video/audio format metadata
@ -104,4 +134,62 @@ class ProbeFormatActivity : BaseActivity() {
mHandler.removeCallbacksAndMessages(null) mHandler.removeCallbacksAndMessages(null)
} }
private fun retrieveMediaMetadata(path :String) {
if (path.isEmpty()) {
return
}
try {
val resultBuilder = StringBuilder()
val retriever = FFmpegMediaRetriever()
retriever.setDataSource(path)
val duration = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_DURATION)
if (duration != null)
resultBuilder.append("duration:$duration\n")
val audioCodec = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_AUDIO_CODEC)
if (audioCodec != null)
resultBuilder.append("audioCodec:$audioCodec\n")
val videoCodec = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_VIDEO_CODEC)
if (videoCodec != null)
resultBuilder.append("videoCodec:$videoCodec\n")
val width = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_VIDEO_WIDTH)
val height = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_VIDEO_HEIGHT)
if (width != null && height != null)
resultBuilder.append("resolution:$width x $height\n")
val frameRate = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_FRAME_RATE)
if (frameRate != null)
resultBuilder.append("frameRate:$frameRate\n")
val sampleRate = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_SAMPLE_RATE)
if (sampleRate != null)
resultBuilder.append("sampleRate:$sampleRate\n")
val channelCount = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_CHANNEL_COUNT)
if (channelCount != null)
resultBuilder.append("channelCount:$channelCount\n")
val channelLayout = retriever.extractMetadata(FFmpegMediaRetriever.METADATA_KEY_CHANNEL_LAYOUT)
if (channelLayout != null)
resultBuilder.append("channelLayout:$channelLayout\n")
mHandler.obtainMessage(MSG_INFO, resultBuilder.toString()).sendToTarget()
// Retrieve frame with timeUs
val bitmap = retriever.getFrameAtTime(5 * 1000000)
if (bitmap != null) {
Log.e("FFmpegRetriever", "bitmap width=${bitmap.width}--height=${bitmap.height}")
mHandler.obtainMessage(MSG_FRAME, bitmap).sendToTarget()
}
retriever.release()
} catch (e : Exception) {
Log.e("FFmpegRetriever", "ffmpeg error=$e")
}
}
} }

@ -11,10 +11,21 @@
android:id="@+id/btn_probe_format" android:id="@+id/btn_probe_format"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="60dp" android:layout_marginTop="50dp"
android:text="@string/media_probe" android:text="@string/media_probe"
android:textColor="@color/colorPrimary" android:textColor="@color/colorPrimary"
android:layout_centerHorizontal="true"/> android:layout_alignParentStart="true"
android:layout_marginStart="20dp"/>
<Button
android:id="@+id/btn_retrieve_format"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="@string/media_retrieve"
android:textColor="@color/colorPrimary"
android:layout_alignParentEnd="true"
android:layout_marginEnd="20dp"/>
<TextView <TextView
android:id="@+id/txt_probe_format" android:id="@+id/txt_probe_format"
@ -25,6 +36,15 @@
android:textSize="16sp" android:textSize="16sp"
android:layout_below="@+id/btn_probe_format" android:layout_below="@+id/btn_probe_format"
android:layout_centerHorizontal="true"/> android:layout_centerHorizontal="true"/>
<ImageView
android:id="@+id/img_frame"
android:layout_width="160dp"
android:layout_height="90dp"
android:layout_below="@+id/txt_probe_format"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true"/>
</RelativeLayout> </RelativeLayout>
<ProgressBar <ProgressBar

@ -37,7 +37,8 @@
<string name="media_extra_audio">Audio extract</string> <string name="media_extra_audio">Audio extract</string>
<string name="media_extract_video">Video extract</string> <string name="media_extract_video">Video extract</string>
<string name="media_play">Media play</string> <string name="media_play">Media play</string>
<string name="media_probe">Media probe</string> <string name="media_probe">Probe media info</string>
<string name="media_retrieve">Retrieve media info</string>
<string name="media_dubbing">Media dubbing</string> <string name="media_dubbing">Media dubbing</string>
<string name="video_cut">Video cut</string> <string name="video_cut">Video cut</string>

@ -37,7 +37,8 @@
<string name="media_extra_audio">提取音频</string> <string name="media_extra_audio">提取音频</string>
<string name="media_extract_video">提取视频</string> <string name="media_extract_video">提取视频</string>
<string name="media_play">音视频播放</string> <string name="media_play">音视频播放</string>
<string name="media_probe">解析多媒体格式</string> <string name="media_probe">probe多媒体信息</string>
<string name="media_retrieve">retrieve多媒体信息</string>
<string name="media_dubbing">配音</string> <string name="media_dubbing">配音</string>
<string name="video_cut">视频剪切</string> <string name="video_cut">视频剪切</string>

Loading…
Cancel
Save