MediaCodec 从 RTSP 解码 AAC 音频块并播放

2023-12-24

我正在接收包含由以下编码的 aac 音频块的 rtp 数据包libvo_aacenc(44100hz 128kbps 2ch) 来自 FFServer 实例。我正在尝试在 Android 中使用 MediaCodec 对它们进行一一解码,并在解码块后立即播放。

客户端.java

Player player = new Player();
//RTSP listener
@Override
public void onRTSPPacketReceived(RTPpacket packet) {
    byte [] aac_chunk = packet.getpayload();
    player.playAAC(aac_chunk);
}

播放器.java

private MediaCodec decoder;
private AudioTrack audioTrack;
private MediaExtractor extractor;

public Player(){
    extractor = new MediaExtractor();
    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            44100, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT,
            44100,
            AudioTrack.MODE_STREAM);

    MediaFormat format = new MediaFormat();
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm");
    format.setInteger(MediaFormat.KEY_BIT_RATE, 128 * 1024);
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectHE);

    try{
        decoder = MediaCodec.createDecoderByType("audio/mp4a-latm");
        decoder.configure(format, null, null, 0);
    } catch (IOException e) {
        e.printStackTrace();
    }

    decoder.start();
    audioTrack.play();
}

//Decode and play one aac_chunk
public void playAAC(byte [] data){

    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    ByteBuffer[] inputBuffers = decoder.getInputBuffers();
    ByteBuffer[] outputBuffers = decoder.getOutputBuffers();

    int inIndex = decoder.dequeueInputBuffer(-1);
    if (inIndex >= 0) {

        ByteBuffer buffer = inputBuffers[inIndex];
        buffer.put(data, 0, data.length);

        int sampleSize = extractor.readSampleData(buffer, 0);

        if (sampleSize < 0) {
            decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
        } else {
            long presentationTimeUs = extractor.getSampleTime();
            decoder.queueInputBuffer(inIndex, 0, sampleSize, presentationTimeUs, 0);
        }
    }

    int outIndex = decoder.dequeueOutputBuffer(info, TIMEOUT);
    while(outIndex >= 0){
        ByteBuffer outBuffer = outputBuffers[outIndex];
        byte[] decoded_chunk = new byte[info.size];
        outBuffer.get(decoded_chunk); // Read the buffer all at once
        outBuffer.clear(); 

        //!! Decoded decoded_chunk.length = 0 !! 
        System.out.println("DECODED CHUNK SIZE: "+decoded_chunk.length);

        //Instant play of the decoded chunk
        audioTrack.write(decoded_chunk, info.offset, info.offset + info.size); 

        decoder.releaseOutputBuffer(outIndex, false);
        break;
    }
    decoder.flush();
}

启动时,MediaCodec 已正确启动。

MediaCodec: (0xa5040280) start
MediaCodec: (0xa5040280) input buffers allocated
MediaCodec: (0xa5040280) numBuffers (4)
MediaCodec: (0xa5040280) output buffers allocated
MediaCodec: (0xa5040280) numBuffers (4)

问题

我实际上听不到任何声音。 MediaCodec 正在工作,但看起来它没有将任何内容解码到他的输出缓冲区中,因为decoded_chunk.length = 0 and outBuffer.limit() = 0 .

问题

我应该异步填充 MediaCodec 输入缓冲区吗?不幸的是,我在发现的示例中没有找到任何有关此问题的内容:即时解码和播放。

我遵循这些例子:

  • 解码并播放 AAC 文件,提取媒体信息。 (link https://github.com/taehwandev/MediaCodecExample/blob/master/src/net/thdev/mediacodecexample/decoder/AudioDecoderThread.java)
  • 实现 MediaCodec 的方式相同但不同,定义的步骤(link https://dpsm.wordpress.com/2012/07/28/android-mediacodec-decoded/)

我已经按照官方文档中所述使用异步模式下的 MediaCodec 和 MediaCodec.Callback 解决了这个问题here https://developer.android.com/reference/android/media/MediaCodec.html这是仅适用于 Android minSdkVersion 21。

基本上,我对收到的每个 RTP 音频块使用了一个队列,然后每次 MediaCodec 缓冲状态更改时我都会收到通知。实际上处理解码器流程更容易。

decoder.setCallback(new MediaCodec.Callback() {
       @Override
       public void onInputBufferAvailable(@NonNull MediaCodec mediaCodec, int i) {
             //One InputBuffer is available to decode 
             while (true) {
                  if(queue.size() > 0) {
                      byte[] data = queue.removeFirst();
                      MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
                      ByteBuffer buffer = mediaCodec.getInputBuffer(i);
                      buffer.put(data, 0, data.length);
                      mediaCodec.queueInputBuffer(i, 0, data.length, 0, 0);
                      break;
                   }
              }
        }

        @Override
        public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec, int i, @NonNull MediaCodec.BufferInfo info) {
              //DECODING PACKET ENDED
              ByteBuffer outBuffer = mediaCodec.getOutputBuffer(i);
              byte[] chunk = new byte[info.size];
              outBuffer.get(chunk); // Read the buffer all at once
              outBuffer.clear(); 
              audioTrack.write(chunk, info.offset, info.offset + info.size); // AudioTrack write data
              mediaCodec.releaseOutputBuffer(i, false);
        }

        @Override
        public void onError(@NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {}

        @Override
        public void onOutputFormatChanged(@NonNull MediaCodec mediaCodec, @NonNull MediaFormat mediaFormat) {}
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MediaCodec 从 RTSP 解码 AAC 音频块并播放 的相关文章

  • 如何检测 Android 设备中的新应用

    我想检测用户何时安装或删除应用程序 但没有找到BroadcastReceiver就是这样做的 在我的应用程序中 我获取了有关该类已安装应用程序的信息PackageManager 但我不想定期扫描应用程序 有没有BroadcastReceiv
  • 是否可以在图片上叠加图标

    我正在创建一个允许用户上传图片的应用程序 当图片上传成功后 我想在右上角添加一个绿色的勾号 可绘制 失败时也一样 但有一个十字 Atm 我正在使用 Glide 在屏幕上显示 URI 我怎样才能做到这一点 您可以通过调用 glide 侦听器来
  • 如何在 TableRow 的一个单元格中添加超过 1 个视图?

    如上所述 如何将 2 个视图放入一个单元格中tablerow 我创建了一个表格布局 并通过代码添加行 下面是我的代码 TableLayout v TableLayout inflater inflate R layout featureit
  • 自动调整文本视图大小不起作用

    您好 我在我的 Android 应用程序中使用自动调整大小文本视图 我的应用程序 minSdkVersion 是 19 所以我正在使用支持库 https developer android com guide topics ui look
  • firebase android 基于类的更新不尊重字段名称的大小写

    我声明了以下类 注意大小写选择 public class User private String DisplayName private Boolean Proxy false SuppressWarnings unused public
  • 如何在 Android 上启用 OpenGL 扩展 GL_EXT_shader_framebuffer_fetch?

    我正在使用 OpenGL ES 2 0 开发一个 Android 应用程序 我想使用GL EXT shader framebuffer fetch https www khronos org registry gles extensions
  • 如何阻止 Android ViewFlipper 循环?

    我将 ViewFlipper 设置为每 5 秒自动翻转一次 省略一些细节 它看起来像这样并且工作正常 ViewFlipper flipper ViewFlipper findViewById R id myflipperid flipper
  • 如何将字节数组转换为图像 [kotlin]

    我想将字节数组转换为图像并在图像视图中显示它 但不知道该怎么做 有人可以指导我吗 我使用这个函数将位图转换为字节数组 private fun BitmapToByteArray ByteArray val stream ByteArrayO
  • MaterialComponents 中 AppCompat.Button.Borderless 的替代品是什么?

    由于我的项目中的一些需求 我必须使用MaterialComponents 所以我以前的UI变得混乱 我需要改变它 上一张带有 AppCompat 的图片 带有 MaterialComponents 的新图像 Code 主要款式
  • 是否可以将 BitmapDescriptor 转换为 Bitmap?

    我需要将 BitmapDescriptor 转换为 Bitmap 我可以使用以下代码将位图转换为 BitmapDescriptor BitmapDescriptor bd BitmapDescriptorFactory fromBitmap
  • 如何获取与 TextView 关联的字符串资源的 id?

    我可以访问 TextView 实例 获取它的资源 ID 并通过以下方式获取它的资源名称getResources getResourceEntryName 但我似乎找不到一种方法来获取与其关联的字符串的 id 如何动态获取与 TextView
  • 如何在运行时添加TextView?

    如何在运行时向布局添加新的 TextView 是否可以 完整的解决方案 View parent parent view where to add ViewGroup layout new LinearLayout context layou
  • android 中的 lang.NumberFormatException

    我有以下代码 除了在后台线程中从数据库读取一些值并使用这些值之外什么也不做 我使用 jar 绘制折线图 对于我用于每个数组值的折线图 问题是第三个我传递给绘制 LineChart 的构造函数的参数是 float float viteza S
  • 将项目导入 Eclipse 后出现“必须重写超类方法”错误

    任何时候我必须将我的项目重新导入到 Eclipse 中 如果我重新安装了 Eclipse 或者更改了项目的位置 几乎全部我的重写方法的格式不正确 导致错误 该方法必须重写超类方法 值得注意的是 无论出于何种原因 Android 项目中方法参
  • 旋转器扩展到屏幕边界之外

    我有一个布局 其中包含一个三行的 TableLayout 每行都有一个 TextView 和一个 Spinner Spinners 的柱子设置为拉伸 我的问题是 当旋转器包含长字符串时 旋转器会超出屏幕边缘 我希望他们截断字符串 这是问题的
  • HTC One M8 - 使用第二个后置摄像头

    我有一台 HTC One M8 设备 它有 2 个后置摄像头和一个额外的前置摄像头 我的问题是尝试访问第二个后置摄像头 我已经成功制作了一个应用程序 它同时运行 2 个摄像头 1 个前置摄像头和 1 个后置摄像头 但问题是我无法访问第二个后
  • 在 Android 模拟器中更改屏幕亮度

    Android模拟器可以测试屏幕亮度变化吗 我尝试过各种示例 它们都使用以下代码片段 WindowManager LayoutParams lp window getAttributes lp screenBrightness some f
  • 如何在Android上读取/写入外部USB存储设备?

    我目前正在制作一个应用程序 需要能够读取和写入通过 USB OTG 适配器连接的 USB 闪存驱动器 有没有一种简单的方法可以通过标准访问此存储Java io File蜜蜂 该应用程序只能在运行 Android 4 2 2 的已 root
  • 如何在 EditText 中用逗号分隔数字

    我有一个 EditText 其 inputType 为number 当用户打字时 我想用逗号分隔数字 这是一个小例子 123 将表示为 123 1234 将表示为 1 234 12345 将表示为 12 345 等等 我尝试使用 TextW
  • 为什么在 this 方法中添加 If 语句会大大降低速度?

    我在中遇到过这个回答另一个问题 https stackoverflow com questions 12233594 faster way to apply alpha to a jpeg in an android app 我试图诊断哪些

随机推荐