问题描述
我有自己的MediaDataSource
:
I have my own MediaDataSource
:
class MyDataSource extends MediaDataSource {
private static final String TAG = "MyDataSource";
private HttpURLConnection connection;
private BufferedInputStream inputStream;
MyDataSource(@NonNull URL streamURL) throws Throwable {
this.connection = (HttpURLConnection) streamURL.openConnection();
this.connection.setRequestMethod("GET");
this.connection.addRequestProperty("Icy-Metadata", "0");
this.connection.connect();
int responseCode = this.connection.getResponseCode();
if (responseCode != 200)
throw new IOException("http response code " + responseCode);
for (Map.Entry<String, List<String>> header: this.connection.getHeaderFields().entrySet()) {
for (String headerValue : header.getValue())
Log.v(TAG, "responseHeader(" + header.getKey() + ") = \"" + headerValue + "\"");
}
this.inputStream = new BufferedInputStream(connection.getInputStream());
}
@Override
public long getSize() {
return -1;
}
@Override
public int readAt(long position, @NonNull byte[] buffer, int offset, int size) throws IOException {
int bytesRead;
int bytesReadTotal = 0;
do {
bytesRead = this.inputStream.read(buffer, offset + bytesReadTotal, size - bytesReadTotal);
bytesReadTotal += bytesRead;
} while(bytesRead != 0 && bytesReadTotal < size);
return bytesReadTotal;
}
@Override
public void close() {
try {
if (inputStream != null) {
inputStream.close();
inputStream = null;
}
if (connection != null) {
connection.disconnect();
connection = null;
}
} catch(IOException e) {
Log.e(TAG, "close", e);
}
}
}
当我尝试播放MP3
流时(例如 A.0.0.00Radio ):
And when I'm trying to play MP3
stream (ex. A.0.0.00Radio):
MyDataSource dataSource = new MyDataSource(new URL("http://streaming.shoutcast.com/80sPlanet"));
MediaExtractor mediaExtractor = new MediaExtractor();
mediaExtractor.setDataSource();
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(0);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
Log.v("Player", "mime: " + mime);
mediaExtractor.selectTrack(0);
MediaCodec mediaCodec = MediaCodec.createDecoderByType(mime);
mediaCodec.configure(this.mediaFormat, null, null, 0);
int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
AudioTrack audioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT),
AudioTrack.MODE_STREAM);
mediaCodec.setCallback(new MyCodecCallback());
mediaCodec.start();
audioTrack.play();
我看到以下Logcat trace
:
I see the following Logcat trace
:
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(null) = "HTTP/1.1 200 OK"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Headers) = "Origin, Accept, X-Requested-With, Content-Type"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Methods) = "GET, OPTIONS, HEAD"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Access-Control-Allow-Origin) = "*"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Cache-Control) = "no-cache, no-store"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Connection) = "close"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Content-Type) = "audio/mpeg"
07-24 18:11:49.958 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Date) = "Mon, 24 Jul 2017 18:11:59 GMT"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Expires) = "Mon, 26 Jul 1997 05:00:00 GMT"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Decades,80s"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "A.0.0.00Radio:All 80s All The Time"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.5.1.725<BR>"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-pub) = "1"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-sr) = "44100"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(icy-url) = "http://a.0.00radio.com/80s/"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Pragma) = "no-cache"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(Server) = "Icecast 2.3.3-kh8"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500919909958"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.1"
07-24 18:11:49.959 7408-7671/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500919909816"
07-24 18:11:49.961 7408-7671/com.sample.sandbox E/WVMExtractor: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found
07-24 18:11:49.962 7408-7671/com.sample.sandbox V/Player: mime: audio/mpeg
07-24 18:11:49.964 7408-7681/com.sample.sandbox I/OMXClient: Using client-side OMX mux.
07-24 18:11:50.170 7408-7681/com.sample.sandbox I/MediaCodec: MediaCodec will operate in async mode
[...]
似乎一切正常(流实际上正在通过设备播放).
但是,如果我尝试打开AAC
流(例如 COOLfahrenheit 93 ):
It seems that everything is OK (the stream is actually playing through the device).
But if I try to open AAC
stream (ex. COOLfahrenheit 93):
MyDataSource dataSource = new MyDataSource(new URL("http://111.223.51.8:8005"));
[...]
MediaExtractor
发疯了:
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(null) = "HTTP/1.0 200 OK"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(content-type) = "audio/aacp"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-br) = "128"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-genre) = "Easy Listening, Pop"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-name) = "COOLfahrenheit 93 - (4)"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice1) = "<BR>This stream requires <a href="http://www.winamp.com">Winamp</a><BR>"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-notice2) = "SHOUTcast DNAS/posix(linux x64) v2.4.7.256<BR>"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-pub) = "1"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(icy-url) = "http://www.coolism.net"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Received-Millis) = "1500921523862"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Response-Source) = "NETWORK 200"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Selected-Protocol) = "http/1.0"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Android-Sent-Millis) = "1500921523387"
07-24 18:38:43.863 32284-32690/com.sample.sandbox V/MyDataSource: responseHeader(X-Clacks-Overhead) = "GNU Terry Pratchett"
07-24 18:38:45.424 32284-32690/com.sample.sandbox E/WVMExtractor: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found
07-24 18:38:45.425 32284-32690/com.sample.sandbox E/PlayerThread: error
java.io.IOException: Failed to instantiate extractor.
at android.media.MediaExtractor.setDataSource(Native Method)
at com.sample.sandbox.Player.open(Player.java:204)
at com.sample.sandbox.Player.<init>(Player.java:231)
at com.sample.sandbox.PlayerThread.run(PlayerThread.java:28)
有人知道这是什么问题吗?问题绝对不在流本身中,而是完全有效的.
Does anybody know what is the issue? The issue is definitely is not in the stream itself - it is fully valid.
推荐答案
我的主要错误是忽略MediaDataSource::readAt()
方法的position
自变量.
事实证明,MediaExtractor
在文件中执行了很多跳跃(向前和向后!-当您流式传输HLS时,这非常烦人).
我注意到这些跳过的数量(及其范围)取决于内容类型以及特定的编解码器.我在这个问题中的主要观点是"MediaExtractor
不理解aacp
",因为AAC编解码器强烈要求跳过,而MP3编解码器则不需要.
My main mistake was to ignore the position
argument of the MediaDataSource::readAt()
method.
It turned out that MediaExtractor
performs A LOT of skips through the file (forward as well as backward! - and this is very annoying when you are streaming HLS).
I've been noticed that amount of these skips (and its' range) depend on the content type as well as particular codec. And my main point in this question was "MediaExtractor
does not understand aacp
" because AAC codec strongly requires skipping, but MP3 codec does not.
这篇关于MediaExtractor无法理解音频/aacp流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!