簡體   English   中英

獲取音頻文件的持續時間

[英]get duration of audio file

我制作了一個錄音機應用程序,我想在列表視圖中顯示錄音的持續時間。 我保存這樣的錄音:

MediaRecorder recorder = new MediaRecorder();
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
folder = new File(Environment.getExternalStorageDirectory()
            + File.separator + "Audio recordings");
String[] files = folder.list();
    int number = files.length + 1;
    String filename = "AudioSample" + number + ".mp3";
    File output = new File(Environment.getExternalStorageDirectory()
            + File.separator + "Audio recordings" + File.separator
            + filename);
    FileOutputStream writer = new FileOutputStream(output);
    FileDescriptor fd = writer.getFD();
    recorder.setOutputFile(fd);
    try {
        recorder.prepare();
        recorder.start();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        Log.e(LOG_TAG, "prepare() failed");
        e.printStackTrace();
    }

如何獲取此文件的持續時間(以秒為單位)?

提前致謝

---編輯我讓它工作了,我在 MediaPlayer.setOnPreparedListener() 方法中調用了 MediaPlayer.getduration() 所以它返回 0。

MediaMetadataRetriever是一種輕量級且高效的方法。 MediaPlayer太重,在滾動、分頁、列表等高性能環境中可能會出現性能問題。

此外, Error (100,0)可能發生在MediaPlayer因為它很重,有時需要一次又一次地重新啟動。

Uri uri = Uri.parse(pathStr);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(AppContext.getAppContext(),uri);
String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
int millSecond = Integer.parseInt(durationStr);

最快的方法是通過MediaMetadataRetriever 然而,有一個陷阱

如果您使用 URI 和上下文來設置數據源,您可能會遇到錯誤https://code.google.com/p/android/issues/detail?id=35794

解決方案是使用文件的絕對路徑來檢索媒體文件的元數據。

下面是執行此操作的代碼片段

 private static String getDuration(File file) {
                MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
                mediaMetadataRetriever.setDataSource(file.getAbsolutePath());
                String durationStr = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                return Utils.formateMilliSeccond(Long.parseLong(durationStr));
            }

現在您可以使用以下任一格式將毫秒轉換為人類可讀的格式

     /**
         * Function to convert milliseconds time to
         * Timer Format
         * Hours:Minutes:Seconds
         */
        public static String formateMilliSeccond(long milliseconds) {
            String finalTimerString = "";
            String secondsString = "";

            // Convert total duration into time
            int hours = (int) (milliseconds / (1000 * 60 * 60));
            int minutes = (int) (milliseconds % (1000 * 60 * 60)) / (1000 * 60);
            int seconds = (int) ((milliseconds % (1000 * 60 * 60)) % (1000 * 60) / 1000);

            // Add hours if there
            if (hours > 0) {
                finalTimerString = hours + ":";
            }

            // Prepending 0 to seconds if it is one digit
            if (seconds < 10) {
                secondsString = "0" + seconds;
            } else {
                secondsString = "" + seconds;
            }

            finalTimerString = finalTimerString + minutes + ":" + secondsString;

    //      return  String.format("%02d Min, %02d Sec",
    //                TimeUnit.MILLISECONDS.toMinutes(milliseconds),
    //                TimeUnit.MILLISECONDS.toSeconds(milliseconds) -
    //                        TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));

            // return timer string
            return finalTimerString;
        }

要么嘗試以毫秒為單位獲得持續時間:

MediaPlayer mp = MediaPlayer.create(yourActivity, Uri.parse(pathofyourrecording));
int duration = mp.getDuration();

或者測量從recorder.start()recorder.stop()經過的時間,以納秒為單位:

long startTime = System.nanoTime();    
// ... do recording ...    
long estimatedTime = System.nanoTime() - startTime;

嘗試使用

long totalDuration = mediaPlayer.getDuration(); // to get total duration in milliseconds

long currentDuration = mediaPlayer.getCurrentPosition(); // to Gets the current playback position in milliseconds

除以 1000 轉換為秒。

希望這對你有幫助。

根據 Vijay 的回答,該函數為我們提供了音頻/視頻文件的持續時間,但不幸的是,存在運行時異常的問題,因此我整理出以下功能正常工作並返回音頻或視頻文件的確切持續時間。

public String getAudioFileLength(String path, boolean stringFormat) {
    StringBuilder stringBuilder = new StringBuilder();
    try {
        Uri uri = Uri.parse(path);
        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        mmr.setDataSource(HomeActivity.this, uri);
        String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        int millSecond = Integer.parseInt(duration);
        if (millSecond < 0) return String.valueOf(0); // if some error then we say duration is zero
        if (!stringFormat) return String.valueOf(millSecond);
        int hours, minutes, seconds = millSecond / 1000;
        hours = (seconds / 3600);
        minutes = (seconds / 60) % 60;
        seconds = seconds % 60;
        if (hours > 0 && hours < 10) stringBuilder.append("0").append(hours).append(":");
        else if (hours > 0) stringBuilder.append(hours).append(":");
        if (minutes < 10) stringBuilder.append("0").append(minutes).append(":");
        else stringBuilder.append(minutes).append(":");
        if (seconds < 10) stringBuilder.append("0").append(seconds);
        else stringBuilder.append(seconds);
    }catch (Exception e){
        e.printStackTrace();
    }
    return stringBuilder.toString();
}

:)

Kotlin 擴展解決方案

您可以添加它以可靠且安全地獲取音頻文件的持續時間。 如果它不存在或有錯誤,您將返回 0。

myAudioFile.getMediaDuration(context)

/**
 * If file is a Video or Audio file, return the duration of the content in ms
 */
fun File.getMediaDuration(context: Context): Long {
    if (!exists()) return 0
    val retriever = MediaMetadataRetriever()
    return try {
        retriever.setDataSource(context, uri)
        val duration = retriever.extractMetadata(METADATA_KEY_DURATION)
        retriever.release()
        duration.toLongOrNull() ?: 0
    } catch (exception: Exception) {
        0
    }
}

如果您經常使用 String 或 Uri 來處理文件,我建議您還添加這些有用的助手

fun Uri.asFile(): File = File(toString())

fun String?.asUri(): Uri? {
    try {
        return Uri.parse(this)
    } catch (e: Exception) {
        Sentry.captureException(e)
    }
    return null
}

fun String.asFile() = File(this)

如果音頻來自 url,只需等待准備好的:

mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
             length = mp.getDuration();
        }
});

您可以使用這個 readyMade 方法,希望這對某人有所幫助。

示例 1: getAudioFileLength(address, true); // if you want in stringFormat getAudioFileLength(address, true); // if you want in stringFormat示例 2 中: getAudioFileLength(address, false); // if you want in milliseconds getAudioFileLength(address, false); // if you want in milliseconds

public String getAudioFileLength(String path, boolean stringFormat) {

            Uri uri = Uri.parse(path);
            MediaMetadataRetriever mmr = new MediaMetadataRetriever();
            mmr.setDataSource(Filter_Journals.this, uri);
            String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
            int millSecond = Integer.parseInt(duration);

            if (millSecond < 0) return String.valueOf(0); // if some error then we say duration is zero

            if (!stringFormat) return String.valueOf(millSecond);

            int hours, minutes, seconds = millSecond / 1000;

            hours = (seconds / 3600);
            minutes = (seconds / 60) % 60;
            seconds = seconds % 60;

            StringBuilder stringBuilder = new StringBuilder();
            if (hours > 0 && hours < 10) stringBuilder.append("0").append(hours).append(":");
            else if (hours > 0) stringBuilder.append(hours).append(":");

            if (minutes < 10) stringBuilder.append("0").append(minutes).append(":");
            else stringBuilder.append(minutes).append(":");

            if (seconds < 10) stringBuilder.append("0").append(seconds);
            else stringBuilder.append(seconds);

            return stringBuilder.toString();
        }

對我來說,AudioGraph 類來拯救:

public static async Task<double> AudioFileDuration(StorageFile file)
        {
            var result = await AudioGraph.CreateAsync(new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Speech));
            if (result.Status == AudioGraphCreationStatus.Success)
            {
                AudioGraph audioGraph = result.Graph;
                var fileInputNodeResult = await audioGraph.CreateFileInputNodeAsync(file);
                return fileInputNodeResult.FileInputNode.Duration.TotalSeconds;
            }
            return -1;
        }

Kotlin 最短的方法(如果是音頻文件):

private fun getDuration(absolutePath: String): String {
    val retriever = MediaMetadataRetriever()
    retriever.setDataSource(absolutePath)
    //For format in string MM:SS
    val rawDuration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
    val duration = rawDuration.milliseconds
    return format("%02d:%02d", duration.inWholeMinutes, duration.inWholeSeconds % 60)
}

private fun getDurationInSeconds(absolutePath: String): Long {
    val retriever = MediaMetadataRetriever()
    retriever.setDataSource(absolutePath)
    //Return only value in seconds
    val rawDuration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
    return rawDuration.milliseconds.inWholeSeconds
}

編寫文件后,在 MediaPlayer 中打開它,並對其調用 getDuration。

你看過Ringdroid嗎? 它的重量很輕,集成也很簡單。 它也適用於 VBR 媒體文件。

對於獲取持續時間的問題,您可能想要使用 Ringdroid 執行以下操作。

public class AudioUtils
{
    public static long getDuration(CheapSoundFile cheapSoundFile)
    {
        if( cheapSoundFile == null)
            return -1;
        int sampleRate = cheapSoundFile.getSampleRate();
        int samplesPerFrame = cheapSoundFile.getSamplesPerFrame();
        int frames = cheapSoundFile.getNumFrames();
        cheapSoundFile = null;
        return 1000 * ( frames * samplesPerFrame) / sampleRate;
    }

    public static long getDuration(String mediaPath)
    {
        if( mediaPath != null && mediaPath.length() > 0)
            try 
            {
                return getDuration(CheapSoundFile.create(mediaPath, null));
            }catch (FileNotFoundException e){} 
            catch (IOException e){}
        return -1;
    }
}

希望有幫助

很簡單。 使用RandomAccessFile下面是執行此操作的代碼片段

 public static int getAudioInfo(File file) {
    try {
        byte header[] = new byte[12];
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
        randomAccessFile.readFully(header, 0, 8);
        randomAccessFile.close();
        return (int) file.length() /1000;
    } catch (Exception e) {
        return 0;
    }
}

當然,你可以根據你的需要更完整

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM