使用媒体编解码器将 PCM 转换为 AAC

2024-04-26

我正在 Android (Jelly Bean) 中使用媒体编解码器类将 PCM 格式编码为 AAC。该文件已编码,但没有音乐播放器能够播放该文件。我在网上找不到任何工作代码或正确的文档。

这是我的代码:

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();
}

您需要为其选择一个容器。我更喜欢adt。

将有效负载数据复制到一个足以容纳您的容器的数组中,只需添加您的位即可。在互联网上搜索我的解决方案后,我将一些片段放在适当的位置

方法“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;

使用类似的东西

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

应该在喊话中播放,等等......

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

使用媒体编解码器将 PCM 转换为 AAC 的相关文章

  • 如何在android studio中使用maven

    我想用底部栏 https github com roughike BottomBar我的项目中的库 当我添加正确的gradle命令在build gradle文件和sync 我收到此错误 Failed to resolve com rough
  • 使用 OAuth2 对应用程序*和*网站进行身份验证

    我正在开发一个主要通过应用程序访问的网站 我想使用 OAuth2 进行用户注册和身份验证 由于它是一个 Android 应用程序 我将开始使用 Google 的 OAuth2 东西 因为它在 Android 上提供了一个不错的 UI 谷歌表
  • SysUtils:ApplicationStatus(WebView)中的ApplicationContext为空

    我可以在基于 WebView 的应用程序启动时看到一些奇怪的东西 它根本不影响应用程序 但我很好奇为什么会出现错误 没有任何崩溃 一切似乎都很好 但是错误 这是日志猫 Loading com google android webview v
  • 为什么无法将 INT 保存到 SharedPreferences 中?

    我有一个奇怪的问题 我以前从未有过 当我尝试将 int 值保存到我的 SharedPreference 中 然后在其他 Activity 中恢复时 即使我保存其他值 例如 1 值也始终为 0 private String Number pr
  • 无法使用 Android 版 VLC 设置字幕

    启动 Android 版 VLC 的 VideoPlayerActivity 时 我在设置字幕位置时遇到问题 我的目标是 API 27 并使用 FileProvider 来允许访问文件 根据文档here https wiki videola
  • 搜索栏小部件未启动可搜索活动

    我正在尝试使用操作栏中的搜索栏小部件在我的 Android 应用程序上实现搜索 我正在关注 http developer android com guide topics search search dialog html http dev
  • Android 中如何获取帧

    实际上 我需要从视频中获取所有帧 但在使用 Mediametadataretriever 缩略图 时间戳获取帧时 我经常重复获取第一帧 然后获取特定时间帧 我通过更改所有 GetFrameAtTime options 尝试了很多修复 但仍然
  • 如何在 AsyncTask 的 postExecute 方法中获取 Map 的结果?

    如何在AsyncTask的postExecute方法中获取Map的结果 我无法在结果中获取结果 Override protected void onPostExecute Map
  • Android:使用 putExtra 从片段访问容器活动对象?

    我正在使用操作栏和片段构建选项卡界面 我需要帮助将数据从容器活动发送到片段 详细地说 我在容器活动中有作业对象 我根据工作对象中的信息创建了几个选项卡 如公司详细信息 经验详细信息等 我需要将作业对象传递给这些片段 以便它可以显示相应的信息
  • 设置数据漫游开/关

    如何在 Android 应用程序中以编程方式设置数据漫游开 关 提前为重新打开一个死帖子表示歉意 但我已经通过调用此可执行文件成功实现了它 su c settings put global data roaming0 1 另外 要获取第一张
  • 如何以编程方式在 Genymotion 上刷新 zip

    我正在尝试将谷歌应用程序刷新到 genymotion 模拟器中 我可以使用拖放功能来完成此操作 但我的项目需要 google apps zip 已加载到 genymotion 机器中并且在内部闪烁 以避免与桌面交互 我检查过类似的问题thi
  • 不兼容的类型:HomeFragment 无法转换为 Android 中的 Fragment

    我在这部分代码中遇到错误 private void displayView int position update the main content by replacing fragments Fragment fragment null
  • Android快速查找网络上所有本地设备

    我正在制作一个 Android 应用程序 需要能够查看本地网络设备 名称或 IP 目前我可以扫描网络并找到设备的本地IP 然而 由于时间太长 用户在搜索网络时会看到黑屏加载几分钟 这是我当前正在使用的代码 private ArrayList
  • 如何将测试文件夹添加到旧的 Android Studio 项目

    我在将用于测试的项目结构添加到 Android Studio 中的旧 Android 项目中时遇到一些问题 当您在 Android Studio 中创建新项目时 您将获得从一开始就创建的用于测试的目录 src test java for u
  • 会话“app”:安装 APK 时出错

    尝试按照说明在真实设备上安装应用程序 http developer android com tools device html http developer android com tools device html 最后 Android
  • 纹理不适用于网格 - OpenGL

    我正在使用 OpenGL Es 我已成功加载 obj 文件 网格 并且显示良好 但当我应用纹理时 它不显示 我添加了下面的代码 public void draw GL10 gl bind the previously generated t
  • org.apache.http.entity.FileEntity 在 Android 6 (Marshmallow) 中已弃用

    我正在将应用程序升级到 API 23 其中org apache http已弃用 我当前 已弃用 的代码如下所示 HttpClient httpClient new DefaultHttpClient File file new File a
  • 在Fragment中第一次调用时SharedPreferences为空

    我有一个示例 Android 应用程序 根据位置 邮政编码 和设置 SharedPreference 中设置的温度单位 该应用程序显示 7 天的天气 当应用程序第一次获取温度并检查 SharedPreference 中设置的温度单位时 它似
  • 如何在聚焦或单击时突出显示 ImageView?

    一个很好的例子是 Twitter 启动屏幕 首次启动应用程序时看到的带有大图标的屏幕 甚至当您聚焦应用程序图标时只需查看应用程序托盘 基本上 我需要突出显示 ImageView 其中突出显示 ImageView 中图像的轮廓 并且看起来像是
  • 在android中重叠屏幕

    在下面的布局中 我有一个名为扫描设备的文本视图 其中显示设备名称 但我的设备列表显示在屏幕上方 任何人都可以帮助我如何滚动视图应该在设备列表内 滚动屏幕时 它显示设备列表 但它显示在屏幕上方 想要显示在屏幕内

随机推荐