【问题标题】:Exoplayer play audio from byte array - ByteArrayDataSourceExoplayer 从字节数组播放音频 - ByteArrayDataSource
【发布时间】:2017-03-12 12:32:34
【问题描述】:

使用 Exoplayer,我正在尝试从字节数组播放音频文件。我正在尝试使用 ByteArrayDataSource,但在调用构造函数时出现错误:new ByteArrayDataSource(data); 这是我想出的代码:

private void prepareExoPlayerFromByteArray(byte[] data){
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(null), new DefaultLoadControl());
        exoPlayer.addListener(eventListener);


        final ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(data);

        /*
        DataSpec dataSpec = new DataSpec(byteArrayDataSource.getUri());
        try {
            byteArrayDataSource.open(dataSpec);
        } catch (IOException e) {
            e.printStackTrace();
        }
        */

        DataSource.Factory factory = new DataSource.Factory() {
            @Override
            public DataSource createDataSource() {
                return byteArrayDataSource;
            }
        };

        MediaSource audioSource = new ExtractorMediaSource(byteArrayDataSource.getUri(),
                factory, new DefaultExtractorsFactory(),null,null);
        exoPlayer.prepare(audioSource);
    }

我得到的错误是:

E/ExoPlayerImplInternal: Internal runtime error.
                                                                                java.lang.NullPointerException
                                                                                    at com.google.android.exoplayer2.util.Assertions.checkNotNull(Assertions.java:107)
                                                                                    at com.google.android.exoplayer2.source.ExtractorMediaPeriod$ExtractingLoadable.<init>(ExtractorMediaPeriod.java:591)
                                                                                    at com.google.android.exoplayer2.source.ExtractorMediaPeriod.startLoading(ExtractorMediaPeriod.java:452)
                                                                                    at com.google.android.exoplayer2.source.ExtractorMediaPeriod.prepare(ExtractorMediaPeriod.java:165)
                                                                                    at com.google.android.exoplayer2.ExoPlayerImplInternal.maybeUpdateLoadingPeriod(ExoPlayerImplInternal.java:1260)
                                                                                    at com.google.android.exoplayer2.ExoPlayerImplInternal.updatePeriods(ExoPlayerImplInternal.java:1102)
                                                                                    at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:447)
                                                                                    at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:98)
                                                                                    at android.os.Looper.loop(Looper.java:234)
                                                                                    at android.os.HandlerThread.run(HandlerThread.java:61)
                                                                                    at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)

错误似乎来自 ByteArrayDataSource 的构造函数,并表示传递给它的数据为空,这不是我在调用它之前检查的那样,并且该数组中有 14002427 个字节。

/**
   * @param data The data to be read.
   */
  public ByteArrayDataSource(byte[] data) {
    Assertions.checkNotNull(data);
    Assertions.checkArgument(data.length > 0);
    this.data = data;
  } 

我做错了什么,我该如何解决?有没有人有一个通过将字节数组作为源传递来使用 Exoplayer 播放音频文件的工作示例?

【问题讨论】:

  • @pskink 即使我确实使用了 MediaPlayer,您建议的方法也不采用字节数组。无关紧要,因为我需要使用 Exoplayer 来做到这一点。
  • 有什么解决办法吗?我面临着完全相同的问题
  • 如果可以,请在下面参考我的回答,然后请点赞。谢谢你:)

标签: android arrays audio exoplayer


【解决方案1】:
class UriByteDataHelper {


        public Uri getUri(byte[] data) {

            try {
                URL url = new URL(null, "bytes:///" + "audio", new BytesHandler(data));
                return Uri.parse( url.toURI().toString());
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }

        }

        class BytesHandler extends URLStreamHandler {
            byte[] mData;
            public BytesHandler(byte[] data) {
                mData = data;
            }

            @Override
            protected URLConnection openConnection(URL u) throws IOException {
                return new ByteUrlConnection(u, mData);
            }
        }

        class ByteUrlConnection extends URLConnection {
            byte[] mData;
            public ByteUrlConnection(URL url, byte[] data) {
                super(url);
                mData = data;
            }

            @Override
            public void connect() throws IOException {
            }

            @Override
            public InputStream getInputStream() throws IOException {

                return new ByteArrayInputStream(mData);
            }
        }
    }



  private void prepareExoPlayerFromByteArray(byte[] data){
        exoPlayer = ExoPlayerFactory.newSimpleInstance(this, new DefaultTrackSelector(null), new DefaultLoadControl());
        exoPlayer.addListener(eventListener);

        final MByteArrayDataSource byteArrayDataSource = new MByteArrayDataSource(data);
        Log.i(TAG,"ByteArrayDataSource constructed.");
        Uri audioByteUri = new UriByteDataHelper().getUri(data);
        DataSpec dataSpec = new DataSpec(audioByteUri);
        try {
            byteArrayDataSource.open(dataSpec);
        } catch (IOException e) {
            e.printStackTrace();
        }


        DataSource.Factory factory = new DataSource.Factory() {
            @Override
            public DataSource createDataSource() {
                return byteArrayDataSource;
            }
        };
        Log.i(TAG,"DataSource.Factory constructed.");


        MediaSource audioSource = new ExtractorMediaSource(audioByteUri,
                factory, new DefaultExtractorsFactory(),null,null);
        Log.i(TAG,"Audio source constructed.");
        exoPlayer.prepare(audioSource);
        initMediaControls();
    }

【讨论】:

  • 使用上面的代码创建Uri,用于直接从字节数组播放音频数据......如果有任何问题,请告诉我。
  • 正是我要找的东西,而且效果很好。
  • 您已经创建了一个 MByteArrayDataSource 类型的新对象。这与标准的 com.google.android.exoplayer2.upstream.ByteArrayDataSource 有什么不同吗?
  • 还有“bytes:///”+“audio”,是否需要更新为与项目相关的字符串,或者这是最终正确的字符串?
  • 如果你没有音频文件,只有字节数组,有什么办法可以做到这一点?我没有可以使用的 Uri,因为数据来自 NDN。
【解决方案2】:

byteArrayDataSource.getUri() 将是 null,如果你不调用

byteArrayDataSource.open(DataSpec dataSpec)。看代码;

public final class ByteArrayDataSource implements DataSource {

  private final byte[] data;

  private Uri uri;
  private int readPosition;
  private int bytesRemaining;

  /**
   * @param data The data to be read.
   */
  public ByteArrayDataSource(byte[] data) {
    Assertions.checkNotNull(data);
    Assertions.checkArgument(data.length > 0);
    this.data = data;
  }

  @Override
  public long open(DataSpec dataSpec) throws IOException {
    uri = dataSpec.uri;
    readPosition = (int) dataSpec.position;
    bytesRemaining = (int) ((dataSpec.length == C.LENGTH_UNSET)
        ? (data.length - dataSpec.position) : dataSpec.length);
    if (bytesRemaining <= 0 || readPosition + bytesRemaining > data.length) {
      throw new IOException("Unsatisfiable range: [" + readPosition + ", " + dataSpec.length
          + "], length: " + data.length);
    }
    return bytesRemaining;
  }

  @Override
  public int read(byte[] buffer, int offset, int readLength) throws IOException {
    if (readLength == 0) {
      return 0;
    } else if (bytesRemaining == 0) {
      return C.RESULT_END_OF_INPUT;
    }

    readLength = Math.min(readLength, bytesRemaining);
    System.arraycopy(data, readPosition, buffer, offset, readLength);
    readPosition += readLength;
    bytesRemaining -= readLength;
    return readLength;
  }

  @Override
  public Uri getUri() {
    return uri;
  }

  @Override
  public void close() throws IOException {
    uri = null;
  }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-18
    • 2020-02-29
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    相关资源
    最近更新 更多