简体   繁体   English

使用mediacodec进行PCM到AAC的转换

[英]PCM to AAC conversion using mediacodec

I am using a media codec class in Android (Jelly Bean) to encode PCM format to AAC. 我在Android(Jelly Bean)中使用媒体编解码器类将PCM格式编码为AAC。 The file was encoded but no music player is able to play that file. 该文件已编码,但没有音乐播放器能够播放该文件。 I was not able to find any working code or proper documentation on the net. 我无法在网上找到任何工作代码或适当的文档。

This is my code: 这是我的代码:

public void doConvert()
{

    new AsyncTask<Void, Void, Void>()
    {

        @Override
        protected Void doInBackground(Void... params) 
        {
            try
            {
                int codecCount = MediaCodecList.getCodecCount();

                for ( int i=0; i < codecCount; i++)
                {
                    MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
                    Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, info.getName());
                    for ( String type : info.getSupportedTypes() )
                    {
                        Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, type);
                    }

                }

                File inputFile = new File( Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Ghajini27_Mono_8Khz.wav");
                //File inputFile = new File( sampleFD.get);
                Log.e("File", String.valueOf(inputFile.length()));
                FileInputStream fis = new FileInputStream(inputFile);
                fis.skip(44);//remove wav header

                File outputFile = new File( Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/out.m4a");
                if ( outputFile.exists()) outputFile.delete();

                FileOutputStream fos = new FileOutputStream(outputFile);

                //BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(outputFile));
                MediaCodec codec = MediaCodec.createEncoderByType("audio/mp4a-latm");
                MediaFormat outputFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", 22050, 1);
                outputFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
             //  outputFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_CONFIGURATION_MONO);
                outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, 22050  );
                outputFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
                //outputFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length());
                double durationInMs = (inputFile.length()/16000)*1000;
                Log.e("duration",String.valueOf((long)durationInMs));
                outputFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs );


                codec.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE );
                codec.start();

                ByteBuffer[] inputBuffers = codec.getInputBuffers();
                ByteBuffer[] outputBuffer = codec.getOutputBuffers();

                boolean hasMoreData = true;   
                MediaCodec.BufferInfo outBuffInfo = new BufferInfo();
                byte readBuffer[] = new byte[48000];
                byte writeBuffer[] = new byte[48000];

                do
                {
                   int nextBuffer = codec.dequeueInputBuffer(5000);
                   Log.e("NextBuffer","nextInputBuffer = "+nextBuffer);

                    if ( nextBuffer >= 0 )
                    {



                        ByteBuffer inBuf = inputBuffers[nextBuffer];
                        inBuf.clear();
                        int bytesRead = fis.read( readBuffer,0, inBuf.capacity() );

                        Log.e("bytesread","Read = "+bytesRead);

                        if ( bytesRead < inBuf.capacity() )
                        {
                            hasMoreData = false;
                        }

                        inBuf.put(readBuffer, 0, bytesRead);

                        codec.queueInputBuffer(nextBuffer, 0, bytesRead, 0, hasMoreData?0:MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    }


                    int outputBufferIndex = codec.dequeueOutputBuffer( outBuffInfo, 3000);
                /*    logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex);
                    logger.log(Level.INFO,"outBuffInfo offset = "+outBuffInfo.offset);
                    logger.log(Level.INFO,"outBuffInfo size = "+outBuffInfo.size);
                    logger.log(Level.INFO,"outBuffInfo flags = "+outBuffInfo.flags);*/


                    //while ( outputBufferIndex > -1 )
                    //{ 

                        outputBuffer[outputBufferIndex].position(outBuffInfo.offset);
                        outputBuffer[outputBufferIndex].get(writeBuffer,0,outBuffInfo.size);

                        fos.write(writeBuffer,0, outBuffInfo.size);
                      //  logger.log(Level.INFO,"Writing = "+outBuffInfo.size+" bytes");


                        outputBuffer[outputBufferIndex].clear();

                        codec.releaseOutputBuffer(outputBufferIndex, false);

                        if ( outBuffInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM )
                        {
                            codec.flush();
                            codec.stop();
                            codec.release();
                            break;
                        }

                        //outputBufferIndex = codec.dequeueOutputBuffer( outBuffInfo, 1000 );
                        //logger.log(Level.INFO,"nextOutputBuffer = "+outputBufferIndex);
                    //}

                } while (outBuffInfo.flags != MediaCodec.BUFFER_FLAG_END_OF_STREAM);

                fis.close();
                fos.flush();
                fos.close();



            }
            catch ( Exception e)
            {
                //Logger.getLogger(MainActivity.class.getSimpleName()).log(Level.INFO, "Codec Error",e);
            }

            //logger.log(Level.INFO,"Done");

            return null;
        }

    }.execute();
}

You'll need to choose a container for it. 你需要为它选择一个容器。 I prefer adts. 我更喜欢adts。

Copy the the payload data into an aray that is large enough for your container, just add on your bits. 将有效负载数据复制到足够容纳您容器的aray中,只需添加您的位。 So after scouring the internet for my solution I worked some snippet into place 因此,在搜索了我的解决方案后,我将一些代码片段放到了适当的位置

method 'fillInADTSHeader' 方法'fillInADTSHeader'

    profile =( configParams[0]>>3 )&0x1f;

    frequency_index = (this.configParams[0]&0x7) <<1 | (this.configParams[1]>>7) &0x1;

    channel_config = (this.configParams[1]>>3) &0xf;

    int finallength = encoded_length + 7;       
    ENCodedByteArray[0] = (byte) 0xff;
    ENCodedByteArray[1] = (byte) 0xf1;
    ENCodedByteArray[2] = (byte) ( ((profile - 1) << 6) + (frequency_index << 2) +(channel_config >> 2));
    ENCodedByteArray[3] = (byte) (((channel_config & 0x3) << 6) + (finallength >> 11));
    ENCodedByteArray[4] = (byte)( (finallength & 0x7ff) >> 3);
    ENCodedByteArray[5] = (byte) (((finallength & 7) << 5) + 0x1f) ;
    ENCodedByteArray[6] = (byte) 0xfc;

Using something like 使用类似的东西

            byte chunkADTS[]=new byte[info.size + 7];
            fillInADTSHeader(chunkADTS,info.size);
            outputBuffers[bR].get(chunkADTS,7,info.size);
            buffer.pushData(chunkADTS);

Should play in shoutcast, etc... 应该播放shoutcast等...

There's an android AAC Library https://github.com/timsu/android-aac-enc 有一个Android AAC库https://github.com/timsu/android-aac-enc

Try passing your buffers through this library. 尝试通过此库传递缓冲区。 It might help. 它可能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM