首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >无法通过Android MediaCodec API转换音频

无法通过Android MediaCodec API转换音频
EN

Stack Overflow用户
提问于 2015-06-25 09:09:38
回答 1查看 1.5K关注 0票数 3

我正在尝试编写一个基本的原始AAC数据到一个文件,希望我可以使用mp4parser封装它的视频轨道。为此,我需要将任何给定的音频文件编码成该格式。从API 16开始就可以使用MediaCodec API,因此我决定将其用于编解码器操作。

我不知道为什么网上没有很多关于这方面的资源,可能是因为相关的复杂性。虽然,我已经学会了基本的方法应该是:

通过MediaExtractor ->队列解码器输入缓冲区->去队列输出缓冲器获取样本数据,得到解码数据,-> Enqueue编码器输入缓冲区,->去队列编码器输出缓冲器->,将编码数据写入文件。

代码语言:javascript
运行
AI代码解释
复制
private void transcodeFile(File source, File destination) throws IOException {
    FileInputStream inputStream = new FileInputStream(source);
    FileOutputStream outputStream = new FileOutputStream(destination);

    log("Transcoding file: " + source.getName());

    MediaExtractor extractor;
    MediaCodec encoder;
    MediaCodec decoder;

    ByteBuffer[] encoderInputBuffers;
    ByteBuffer[] encoderOutputBuffers;
    ByteBuffer[] decoderInputBuffers;
    ByteBuffer[] decoderOutputBuffers;

    int noOutputCounter = 0;
    int noOutputCounterLimit = 10;

    extractor = new MediaExtractor();
    extractor.setDataSource(inputStream.getFD());
    extractor.selectTrack(0);

    log(String.format("TRACKS #: %d", extractor.getTrackCount()));
    MediaFormat format = extractor.getTrackFormat(0);
    String mime = format.getString(MediaFormat.KEY_MIME);
    log(String.format("MIME TYPE: %s", mime));


    final String outputType = MediaFormat.MIMETYPE_AUDIO_AAC;
    encoder = MediaCodec.createEncoderByType(outputType);
    MediaFormat encFormat = MediaFormat.createAudioFormat(outputType, 44100, 2);
    encFormat.setInteger(MediaFormat.KEY_BIT_RATE, 64000);
    encoder.configure(encFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

    decoder = MediaCodec.createDecoderByType(mime);
    decoder.configure(format, null, null, 0);

    encoder.start();
    decoder.start();

    encoderInputBuffers = encoder.getInputBuffers();
    encoderOutputBuffers = encoder.getOutputBuffers();

    decoderInputBuffers = decoder.getInputBuffers();
    decoderOutputBuffers = decoder.getOutputBuffers();

    int timeOutUs = 1000;
    long presentationTimeUs = 0;

    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    boolean inputEOS = false;
    boolean outputEOS = false;

    while(!outputEOS && noOutputCounter < noOutputCounterLimit) {
        noOutputCounter++;

        if(!inputEOS) {
            int decInputBufferIndex = decoder.dequeueInputBuffer(timeOutUs);
            log("decInputBufferIndex: " + decInputBufferIndex);
            if (decInputBufferIndex >= 0) {
                ByteBuffer dstBuffer = decoderInputBuffers[decInputBufferIndex];

                //Getting sample with MediaExtractor
                int sampleSize = extractor.readSampleData(dstBuffer, 0);
                if (sampleSize < 0) {
                    inputEOS = true;
                    log("Input EOS");
                    sampleSize = 0;
                } else {
                    presentationTimeUs = extractor.getSampleTime();
                }

                log("Input sample size: " + sampleSize);

                //Enqueue decoder input buffer
                decoder.queueInputBuffer(decInputBufferIndex, 0, sampleSize, presentationTimeUs, inputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
                if (!inputEOS) extractor.advance();

            } else {
                log("decInputBufferIndex: " + decInputBufferIndex);
            }
        }

        //Dequeue decoder output buffer
        int res = decoder.dequeueOutputBuffer(info, timeOutUs);
        if(res >= 0) {
            if(info.size > 0) noOutputCounter = 0;

            int decOutputBufferIndex = res;
            log("decOutputBufferIndex: " + decOutputBufferIndex);

            ByteBuffer buffer = decoderOutputBuffers[decOutputBufferIndex];
            buffer.position(info.offset);
            buffer.limit(info.offset + info.size);

            final int size = buffer.limit();
            if(size > 0) {
                //audioTrack.write(buffer, buffer.limit(), AudioTrack.MODE_STATIC);

                int encInputBufferIndex = encoder.dequeueInputBuffer(-1);
                log("encInputBufferIndex: " + encInputBufferIndex);
                //fill the input buffer with the decoded data
                if(encInputBufferIndex >= 0) {
                    ByteBuffer dstBuffer = encoderInputBuffers[encInputBufferIndex];
                    dstBuffer.clear();
                    dstBuffer.put(buffer);

                    encoder.queueInputBuffer(encInputBufferIndex, 0, info.size, info.presentationTimeUs, 0);
                    int encOutputBufferIndex = encoder.dequeueOutputBuffer(info, timeOutUs);
                    if(encOutputBufferIndex >= 0) {
                        log("encOutputBufferIndex: " + encOutputBufferIndex);
                        ByteBuffer outBuffer = encoderOutputBuffers[encOutputBufferIndex];
                        byte[] out = new byte[outBuffer.remaining()];
                        outBuffer.get(out);
                        //write data to file
                        outputStream.write(out);
                    }
                }
            }
            decoder.releaseOutputBuffer(decOutputBufferIndex, false);
            if((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                outputEOS = true;
                log("Output EOS");
            }
        } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            decoderOutputBuffers = decoder.getOutputBuffers();
            log("Output buffers changed.");
        } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            log("Output format changed.");
        } else {
            log("Dequeued output buffer returned: " + res);
        }
    }

    log("Stopping..");
    releaseCodec(decoder);
    releaseCodec(encoder);
    inputStream.close();
    outputStream.close();

}

由于某些原因,输出文件无效。为什么?

编辑:成功修复了一个异常,问题仍然存在。

编辑2:我通过将缓冲区大小设置为编码器格式设置中的比特率来防止缓冲区溢出。目前有两个问题: 1.经过很短的时间间隔后,它会被困在这里,可能会无限期地等待。int encInputBufferIndex = dequeueInputBuffer(-1); 2.解码所需的时间长短,为什么要考虑样本的实际间隔?

编辑3:使用AudioTrack.write()进行测试,音频播放得很好,但这并不是有意的,它表明解码是与被喂入的媒体文件同步进行的,这应该尽可能快地进行,以便编码器能够快速完成其工作。在decoder.queueInputBuffer()中更改presentationTimeUs没有任何作用。

EN

回答 1

Stack Overflow用户

发布于 2015-06-25 11:14:37

在正确的道路上,缺少的部分是使用MediaMuxer将编码的帧复制到有效的MediaMuxer文件中。在大片状上有一个很好的(也是唯一的)例子。有关这一问题的大多数相关实例如下

您将不得不合并和简化/修改它们,以处理音频而不是视频。您将需要上面的API 18

编辑:如何将解码器缓冲区转发给编码器(或多或少)。到目前为止,我还没有遇到缓冲区溢出的情况,只是希望理智的实现具有相同容量的编码器和解码器缓冲区:

代码语言:javascript
运行
AI代码解释
复制
int decoderStatus = audioDecoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
  if (decoderStatus >= 0) {
      // no output available yet
      if (VERBOSE) Log.d(TAG, "no output from audio decoder available");
...
   } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            audioDecoderOutputBuffers = audioDecoder.getOutputBuffers();
            if (VERBOSE) Log.d(TAG, "decoder output buffers changed (we don't care)");
    } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            // expected before first buffer of data
            if (VERBOSE) {
                    MediaFormat newFormat = audioDecoder.getOutputFormat();
                    Log.d(TAG, "decoder output format changed: " + newFormat);
                }
    } else if (decoderStatus < 0) {
            Log.e(TAG, "unexpected result from decoder.dequeueOutputBuffer: "+decoderStatus);
            throw new RuntimeException("Issue with dencoding audio");
    } else { // decoderStatus >= 0
            if (VERBOSE) Log.d(TAG, "audio decoder produced buffer "
                                + decoderStatus + " (size=" + info.size + ")");

            if (info.size! = 0) {                           
                // Forward decoder buffer to encoder
                ByteBuffer decodedData = audioDecoderOutputBuffers[decoderStatus];
                decodedData.position(info.offset);
                decodedData.limit(info.offset + info.size);

                 // Possibly edit buffer data

                // Send it to the audio encoder.
                int encoderStatus = audioEncoder.dequeueInputBuffer(-1);
                if (encoderStatus < 0) {
                    throw new RuntimeException("Could not get input buffer for audio encoder!!!");
                }
            audioEncoderInputBuffers[encoderStatus].clear();
            audioEncoderInputBuffers[encoderStatus].put(decodedData);
         }
audioEncoder.queueInputBuffer(encoderStatus, 0, info.size, mAudioMediaTime, 0);
     if (VERBOSE) Log.d(TAG, "Submitted to AUDIO encoder frame, size=" + info.size + " time=" + mAudioMediaTime);
    }
 audioDecoder.releaseOutputBuffer(decoderStatus, false);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31056576

复制
相关文章
AngularJS进阶(五)Angular实现下拉菜单多选
http://ngmodules.org/modules/angularjs-dropdown-multiselect
全栈程序员站长
2022/09/15
2.3K0
AngularJS进阶(五)Angular实现下拉菜单多选
最好用的 5 个 React select 多选下拉菜单组件测评推荐
本文完整版:《最好用的 5 个 React select 多选下拉菜单组件测评推荐》
蒋川@卡拉云
2022/06/01
7.7K0
最好用的 5 个 React select 多选下拉菜单组件测评推荐
CSS 下拉菜单_下拉菜单html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/01
7K0
MVC3教程之新手入门
你还可以通过Web Platform Installer将这些软件一起安装到本地。
拓荒者IT
2019/09/26
1.5K0
MVC3教程之新手入门
MVC 3.0 的新特性 摘要
MVC经过其1.0和2.0版本的发展,现在已经到了3.0的领军时代,随着技术的不断改进,MVC也越来越成熟。使开发也变得简洁人性化艺术化。
Isaac Zhang
2019/09/10
2.7K0
MVC 3.0 的新特性

            摘要
javascript下拉菜单代码(用jquery做下拉菜单)
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/126047.html原文链接:https://javaforall.cn
全栈程序员站长
2022/08/01
11.6K0
javascript下拉菜单代码(用jquery做下拉菜单)
vs2010 mvc3
asp.net mvc确实是好东西,VS2010在升级sp1的前提下只能最多安装mvc3.
py3study
2020/01/14
1.2K0
bootstrap 下拉菜单
<!doctype html> <html> <head> <meta charset="utf-8"> <title>联想控股</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="css/bootstrap.css" rel="stylesheet" type="text/css"> <script src="http://code.jquery.com/jquery.js"></script> <script src="js/bootstrap.min.js"></script> </head> <body>  <div class="dropdown"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> 下拉菜单<span class="caret"></span> </button> <ul class="dropdown-menu"> <li><a href="#">菜单项1</a></li> <li><a href="#">菜单项2</a></li> <li><a href="#">菜单项3</a></li> </ul> </div> </body> </html>
用户5760343
2019/07/05
4.6K0
Asp.Net MVC3 简单入门第一季(二)详解Asp.Net MVC3项目
在上一篇文章Asp.Net MVC3 简单入门第一季(一)环境准备中我简单介绍了Asp.Net MVC3项目的安装和第一个Asp.Net MVC3项目的基本情况。没有详细介绍项目中各个文件夹的作用,以及创建的第一个页面是怎样运行起来的?还有好多的疑问,那在这篇文章中我们将详细介绍项目中各个文件夹的作用,并真的第一个项目我们简要介绍一下Asp.Net MVC的URL驱动的是怎么回事。
老马
2022/11/28
9930
Asp.Net MVC3 简单入门第一季(二)详解Asp.Net MVC3项目
Asp.Net MVC3 简单入门第一季(一)环境准备
大家好,从今天开始我将写一个关于AspNet MVC3方面学习的总结,并跟初学者一起分享一些基本的基础知识,作者本身也很愿意跟大家一起交流技术,一起交流一起进步,欢迎高手不吝赐教,欢迎大家不同的意见和建议,作者的学识和见识当然有自己的局限性,希望自己能成为不闷骚型的技术人员,而不是只自己享受技术,而不让更多的人来分享你的成果的人。
老马
2022/05/10
5170
Asp.Net MVC3 简单入门第一季(一)环境准备
奥卡姆剃刀和数据简化理念
数据资源DataRes导读:《数据资源概论》数据资源类型和数据产品类型概述,从数据和信息的专业领域常识,到常见的几十种数据资源相关概念和类型,全面总结数据产学研用多个方面相关概念的内涵及差异、标准和应用。
秦陇纪
2020/04/21
7240
奥卡姆剃刀 - 如无必要,勿增实体
奥卡姆剃刀法则,又被称为“简约之法则”,它是由14世纪圣方济各会修道士奥卡姆(英格兰的一个地方)的威廉(William of Occam)提出来的,他说过这样一段话:
石云升
2022/08/25
3580
jenkins 多选框
背景 jenkins自带的参数化不支持多选框,不过有插件支持:Extended Choice Parameter Plug-In 插件地址: https://plugins.jenkins.io/ex
千往
2018/01/24
3.8K0
jenkins 多选框
bootstrap select 多选,最多选择两项 常用
image.png <!doctype html> <html> <head> <meta charset="utf-8"> <title>联想控股</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="css/bootstrap.css" rel="stylesheet" type="text/css"> <link href="css/bootstrap-
用户5760343
2019/07/08
3.5K0
bootstrap select 多选,最多选择两项 常用
vue + iview/elementUi --城市多选
最近收到了一个需求,管理系统需要上线一个活动,但是活动是根据地区上线的,最小范围到市,于是有了下面这个组件 页面展示如图:
super.x
2019/04/12
1.8K0
vue + iview/elementUi --城市多选
bootstrap select 多选 常用
<!doctype html> <html> <head> <meta charset="utf-8"> <title>联想控股</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="css/bootstrap.css" rel="stylesheet" type="text/css"> <link href="css/bootstrap-select.css" rel="stylesheet" type="text/css"> <script src="http://code.jquery.com/jquery.js"></script> <script src="js/bootstrap.min.js"></script> <script src="js/bootstrap-select.js"></script> </head> <body> <div class="container"> <div class="row"> <label class="col-sm-3 control-label" style="line-height: 34px;margin-bottom: 20px;">选择用户:</label> <div class="col-sm-6"> <select class="selectpicker" multiple> <option value="苹果">苹果</option>   <option value="菠萝">菠萝</option>   <option value="香蕉">香蕉</option>   <option value="火龙果">火龙果</option>   <option value="梨子">梨子</option>   <option value="草莓">草莓</option>   <option value="哈密瓜">哈密瓜</option>   <option value="椰子">椰子</option>   <option value="猕猴桃">猕猴桃</option>   <option value="桃子">桃子</option> </select> </div> </div> </div>
用户5760343
2019/07/07
1.6K0
精通MVC3摘译(4)-使用Area
MVC Framework支持将一个web application放入一个area,每个area表示一个特殊功能的应用程序片段,比如管理,账单,客户支持等等。这对大型项目很有用,如果大型项目中所有的controller,View和model都只有相应的一个文件夹,那么很难管理,那么此时使用area会很有帮助。
py3study
2020/01/10
6690
html中下拉菜单(html做下拉菜单栏)
使用html5或者jQuery如何实现文本框下拉效果,如下图 CSS布局HTML小编今天和大家分享大神详解最好有可以使用HTML5 list 属性。list 属性需要应用到 input 框上,然后内容写一个自定义的 id 然后在任意位置放一对 datalist 标签,并给 datalist 框一个 id,和 list 属性指向的 id 一致即可。 在 datalist 标签下放列表项。
全栈程序员站长
2022/08/02
11.6K0
html中下拉菜单(html做下拉菜单栏)
ElementUI Checkbox 多选框
https://element.eleme.io/#/zh-CN/component/checkbox
py3study
2021/03/12
3K0
ElementUI Checkbox 多选框
input file多选 multiple[通俗易懂]
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/160959.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/09
2.5K0

相似问题

Ajax在Chrome中工作,但在Firefox和IE中不起作用

16

Javascript / Ajax在Mozilla firefox中工作,但在Google Chrome和IE中不起作用

20

JQuery代码在Firefox中工作,但在Chrome和IE中不工作

11

代码在Chrome和Firefox中工作,但在IE中不起作用

13

$.ajax在chrome和firefox中不起作用,但在IE中起作用

33
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档