找茬小王子 2023-12-13 11:35 采纳率: 50%
浏览 3
已结题

MediaSync的用法问题

我的代码运行后,画面会重复而且还是没有声音,我想知道问题出在哪儿,我需要怎么修改


package com.example.mediacodectest;


import android.annotation.SuppressLint;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaSync;
import android.media.PlaybackParams;
import android.os.Build;
import android.util.Log;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import java.io.IOException;
import java.nio.ByteBuffer;

public class MediaThread3 extends Thread {

    private Surface surface;
    private Surface inputSurface;
    private MediaExtractor extractor;
    private MediaCodec mediaCodec;
    private MediaFormat mformat;
    private String mime = null;
    private int width = 0;
    private int heghit = 0;
    private long startMs = -1;
    private MediaSync sync;
    private AudioTrack audio;

    public MediaThread3(Surface surface) {
        this.surface = surface;
    }

    @SuppressLint("NewApi")
    public void run() {

        int bufsize = AudioTrack.getMinBufferSize(44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
        audio = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufsize, AudioTrack.MODE_STREAM);
        sync = new MediaSync();
        sync.setSurface(surface);
        inputSurface = sync.createInputSurface();
        sync.setAudioTrack(audio);
        sync.setCallback(new syncCallback(), null);
        //设置播放速度
        sync.setPlaybackParams(new PlaybackParams().setSpeed(1.f));

        try {
            //根据视频源获取MediaFormat
            extractor = new MediaExtractor();
            extractor.setDataSource("sdcard/qqq/test2.mp4");
            int numTracks = extractor.getTrackCount();
            Log.d("numTracks", String.valueOf(numTracks));
            for (int i = 0; i < numTracks; i++) {
                mformat = extractor.getTrackFormat(i);
                String mime = mformat.getString(MediaFormat.KEY_MIME);
                Log.d("mime", mime);
                if (mime.startsWith("video/")) {
                    extractor.selectTrack(i);
                    try {
                        mediaCodec = MediaCodec.createDecoderByType(mime);
                        mediaCodec.setCallback(new CodecCallback());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //这样配置之后,解码之后的数据就会 直接显示在mSurface 上边  这里是核心点
                    mediaCodec.configure(mformat, inputSurface, null, 0);
                    break;
                }
            }
            mediaCodec.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    public class syncCallback extends MediaSync.Callback {

        @Override
        public void onAudioBufferConsumed(@NonNull MediaSync sync, @NonNull ByteBuffer audioBuffer, int bufferId) {
            mediaCodec.releaseOutputBuffer(bufferId, true);
        }
    }

    //异步处理解码播放
    public class CodecCallback extends MediaCodec.Callback {
        @SuppressLint("NewApi")
        @Override
        public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
            ByteBuffer inputBuffer = codec.getInputBuffer(index);
            int sampleSize = extractor.readSampleData(inputBuffer, 0);
            if (sampleSize > 0) {
                codec.queueInputBuffer(index, 0, sampleSize, extractor.getSampleTime(), 0);
                extractor.advance();  //下一帧数据
            } else {
                codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            }

        }

        @SuppressLint("NewApi")
        @Override
        public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {

            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                codec.stop();
                codec.release();// 释放组件
                extractor.release();
                return;
            }

            if (index > 0) {
                if (startMs == -1) {
                    startMs = System.currentTimeMillis();
                } else {
                    //保持播放的速度与实际帧率相同
                    while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            if (codec == mediaCodec) {
                // surface timestamp must contain media presentation time in nanoseconds.
                codec.releaseOutputBuffer(index, 1000 * info.presentationTimeUs);
            } else {
                ByteBuffer audioByteBuffer = codec.getOutputBuffer(index);
                sync.queueAudio(audioByteBuffer, index, info.presentationTimeUs);
            }

            //
        }

        @Override
        public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {
            codec.stop();
            codec.release();
            extractor.release();
        }

        @Override
        public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
            mformat = format; // option B
        }
    }
}


  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 12月21日
    • 创建了问题 12月13日

    悬赏问题

    • ¥20 6-3 String类定义
    • ¥15 基于OPENCV的人脸识别
    • ¥20 51单片机学习中的问题
    • ¥30 Windows Server 2016利用兩張網卡處理兩個不同網絡
    • ¥15 Python中knn问题
    • ¥15 使用C#,asp.net读取Excel文件并保存到Oracle数据库
    • ¥15 C# datagridview 单元格显示进度及值
    • ¥15 thinkphp6配合social login单点登录问题
    • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
    • ¥15 如何在scanpy上做差异基因和通路富集?