/** * * @param filePath */ public void startPlay(string path) { eosReceived = false; mExtractor = new MediaExtractor(); try { mExtractor.SetDataSource(path); } catch (IOException e) { e.PrintStackTrace(); } int channel = 0; for (int i = 0; i < mExtractor.TrackCount; i++) { MediaFormat format = mExtractor.GetTrackFormat(i); string mime = format.GetString(MediaFormat.KeyMime); if (mime.StartsWith("audio/")) { mExtractor.SelectTrack(i); Log.Debug("TAG", "format : " + format); ByteBuffer csd = format.GetByteBuffer("csd-0"); for (int k = 0; k < csd.Capacity(); ++k) { Log.Error("TAG", "csd : " + csd.ToArray<Byte>()[k]); } mSampleRate = format.GetInteger(MediaFormat.KeySampleRate); channel = format.GetInteger(MediaFormat.KeyChannelCount); break; } } MediaFormat format2 = makeAACCodecSpecificData(MediaCodecInfo.CodecProfileLevel.AACObjectLC, mSampleRate, channel); if (format2 == null) return; mDecoder = MediaCodec.createDecoderByType("audio/mp4a-latm"); mDecoder.configure(format, null, null, 0); if (mDecoder == null) { Log.e("DecodeActivity", "Can't find video info!"); return; } mDecoder.start(); new Thread(AACDecoderAndPlayRunnable).start(); }
protected static void PrintFormatInfo(MediaFormat format) { var csd0 = format.GetByteBuffer("csd-0"); var csd1 = format.GetByteBuffer("csd-1"); if (csd0 == null || csd1 == null) { return; } Log.Debug("csd0 buff len: ", csd0.Limit().ToString()); Log.Debug("csd0 buff pos: ", csd0.Position().ToString()); var sOut = "{ "; byte[] buff0 = new byte[csd0.Limit()]; //int buffi = 0; csd0.Get(buff0, 0, buff0.Length); sOut = "{"; foreach (byte b in buff0) { sOut += " " + b + ", "; } sOut = sOut.TrimEnd(",".ToCharArray()) + "}"; Log.Debug("csd-0[] data: ", sOut); //while (csd0.HasRemaining) //{ // buff0[buffi] = csd0.Get(); // Log.Debug("csd-0[" + buffi + "] data: ", // string.Format("0x{0:X}", buff0[buffi])); // ++buffi; //} csd0.Position(0); Log.Debug("csd1 buff len: ", csd0.Limit().ToString()); Log.Debug("csd1 buff pos: ", csd0.Position().ToString()); byte[] buff1 = new byte[csd1.Limit()]; //buffi = 0; csd1.Get(buff1, 0, buff1.Length); sOut = "{"; foreach (byte b in buff1) { sOut += " " + b + ","; } sOut = sOut.TrimEnd(",".ToCharArray()) + "}"; Log.Debug("csd-1[] data: ", sOut); //while (csd1.HasRemaining) //{ // buff1[buffi] = csd1.Get(); // Log.Debug("csd-1[] data: ", // string.Format("0x{0:X}", buff1[buffi])); // ++buffi; //} csd1.Position(0); }
/** * Tries to obtain the SPS and the PPS for the encoder. */ private long searchSPSandPPS() { ByteBuffer[] inputBuffers = mEncoder.GetInputBuffers(); ByteBuffer[] outputBuffers = mEncoder.GetOutputBuffers(); BufferInfo info = new BufferInfo(); byte[] csd = new byte[128]; int len = 0, p = 4, q = 4; long elapsed = 0, now = timestamp(); while (elapsed < 3000000 && (mSPS == null || mPPS == null)) { // Some encoders won't give us the SPS and PPS unless they receive something to encode first... int bufferIndex = mEncoder.DequeueInputBuffer(1000000 / FRAMERATE); if (bufferIndex >= 0) { check(inputBuffers[bufferIndex].Capacity() >= mData.Length, "The input buffer is not big enough."); inputBuffers[bufferIndex].Clear(); inputBuffers[bufferIndex].Put(mData, 0, mData.Length); mEncoder.QueueInputBuffer(bufferIndex, 0, mData.Length, timestamp(), 0); } else { if (VERBOSE) { Log.e(TAG, "No buffer available !"); } } // We are looking for the SPS and the PPS here. As always, Android is very inconsistent, I have observed that some // encoders will give those parameters through the MediaFormat object (that is the normal behaviour). // But some other will not, in that case we try to find a NAL unit of type 7 or 8 in the byte stream outputed by the encoder... int index = mEncoder.DequeueOutputBuffer(info, 1000000 / FRAMERATE); if (index == (int)MediaCodecInfoState.OutputFormatChanged) { // The PPS and PPS shoud be there MediaFormat format = mEncoder.OutputFormat; ByteBuffer spsb = format.GetByteBuffer("csd-0"); ByteBuffer ppsb = format.GetByteBuffer("csd-1"); mSPS = new byte[spsb.Capacity() - 4]; spsb.Position(4); spsb.Get(mSPS, 0, mSPS.Length); mPPS = new byte[ppsb.Capacity() - 4]; ppsb.Position(4); ppsb.Get(mPPS, 0, mPPS.Length); break; } else if (index == (int)MediaCodecInfoState.OutputBuffersChanged) { outputBuffers = mEncoder.GetOutputBuffers(); } else if (index >= 0) { len = info.Size; if (len < 128) { outputBuffers[index].Get(csd, 0, len); if (len > 0 && csd[0] == 0 && csd[1] == 0 && csd[2] == 0 && csd[3] == 1) { // Parses the SPS and PPS, they could be in two different packets and in a different order //depending on the phone so we don't make any assumption about that while (p < len) { while (!(csd[p + 0] == 0 && csd[p + 1] == 0 && csd[p + 2] == 0 && csd[p + 3] == 1) && p + 3 < len) { p++; } if (p + 3 >= len) { p = len; } if ((csd[q] & 0x1F) == 7) { mSPS = new byte[p - q]; JavaSystem.Arraycopy(csd, q, mSPS, 0, p - q); } else { mPPS = new byte[p - q]; JavaSystem.Arraycopy(csd, q, mPPS, 0, p - q); } p += 4; q = p; } } } mEncoder.ReleaseOutputBuffer(index, false); } elapsed = timestamp() - now; } check(mPPS != null && mSPS != null, "Could not determine the SPS & PPS."); mB64PPS = Base64.EncodeToString(mPPS, 0, mPPS.Length, Base64Flags.NoWrap); mB64SPS = Base64.EncodeToString(mSPS, 0, mSPS.Length, Base64Flags.NoWrap); return(elapsed); }