Android多媒体框架(5)—— MediaMuxer.jara源码分析

[USACO2023-JAN-Bronze] T2 Air Cownditioning II 题解 [USACO2023-JAN-Bronze] T2 Air Cownditioning II题解 阅读详情

MediaMuxer.jara源码分析

音视频通过Codec(编码器)编码之后,还需要经过MediaMuxer(混合器)“混合”。混合器在framework的实现就是MediaMuxer类。MediaMuxer中又个内部类OutputFormat:

public static final class OutputFormat {
80        /* Do not change these values without updating their counterparts
81         * in include/media/stagefright/MediaMuxer.h!
82         */
83        private OutputFormat() {}
84        /** MPEG4 media file format*/
85        public static final int MUXER_OUTPUT_MPEG_4 = 0;
86        public static final int MUXER_OUTPUT_WEBM   = 1;
87    };

从这里看到,目前MediaMuxer支持的输出格式只有mp4和webm两种。Muxer有一些状态,一共有以下几种:

private static final int MUXER_STATE_UNINITIALIZED  = -1;
113    private static final int MUXER_STATE_INITIALIZED    = 0;
114    private static final int MUXER_STATE_STARTED        = 1;
115    private static final int MUXER_STATE_STOPPED        = 2;
116
117    private int mState = MUXER_STATE_UNINITIALIZED;

MUXER_STATE_UNINITIALIZED是默认状态。MediaMuxer的构造函数中,也会将mState设置为MUXER_STATE_UNINITIALIZED。
类中的方法setOrientationHint(int degrees)会设置输出视频的角度。这个角度并不会改变输入视频帧的角度,只是告诉播放器在播放的时候选择正确的角度。默认的角度是0。类中还有个setLocation方法,会设置和保存拍摄视频时的经纬度。
与生命周期相关的方法有start,stop,release等。

public void start() {
227        if (mNativeObject == 0) {
228            throw new IllegalStateException("Muxer has been released!");
229        }
230        if (mState == MUXER_STATE_INITIALIZED) {
231            nativeStart(mNativeObject);
232            mState = MUXER_STATE_STARTED;
233        } else {
234            throw new IllegalStateException("Can't start due to wrong state.");
235        }
236    }
237
238    /**
239     * Stops the muxer.
240     * <p>Once the muxer stops, it can not be restarted.</p>
241     * @throws IllegalStateException if muxer is in the wrong state.
242     */
243    public void stop() {
244        if (mState == MUXER_STATE_STARTED) {
245            nativeStop(mNativeObject);
246            mState = MUXER_STATE_STOPPED;
247        } else {
248            throw new IllegalStateException("Can't stop due to wrong state.");
249        }
250    }
public void release() {
484        if (mState == MUXER_STATE_STARTED) {
485            stop();
486        }
487        if (mNativeObject != 0) {
488            nativeRelease(mNativeObject);
489            mNativeObject = 0;
490            mCloseGuard.close();
491        }
492        mState = MUXER_STATE_UNINITIALIZED;
493    }

这些方法最终都需要调用对应的native方法,并且设置分mState为对应的状态。start方法必须在MUXER_STATE_INITIALIZED状态下调用,stop和release方法必须在MUXER_STATE_STARTED状态下调用,否则,都会抛出IllegalStateException异常。release方法,在调用stop方法之后,还需要关闭CloseGuard。
addTrack方法以指定的格式,添加一个track。

public int addTrack(@NonNull MediaFormat format) {
392        if (format == null) {
393            throw new IllegalArgumentException("format must not be null.");
394        }
395        if (mState != MUXER_STATE_INITIALIZED) {
396            throw new IllegalStateException("Muxer is not initialized.");
397        }
398        if (mNativeObject == 0) {
399            throw new IllegalStateException("Muxer has been released!");
400        }
401        int trackIndex = -1;
402        // Convert the MediaFormat into key-value pairs and send to the native.
403        Map<String, Object> formatMap = format.getMap();
404
405        String[] keys = null;
406        Object[] values = null;
407        int mapSize = formatMap.size();
408        if (mapSize > 0) {
409            keys = new String[mapSize];
410            values = new Object[mapSize];
411            int i = 0;
412            for (Map.Entry<String, Object> entry : formatMap.entrySet()) {
413                keys[i] = entry.getKey();
414                values[i] = entry.getValue();
415                ++i;
416            }
417            trackIndex = nativeAddTrack(mNativeObject, keys, values);
418        } else {
419            throw new IllegalArgumentException("format must not be empty.");
420        }
421
422        // Track index number is expected to incremented as addTrack succeed.
423        // However, if format is invalid, it will get a negative trackIndex.
424        if (mLastTrackIndex >= trackIndex) {
425            throw new IllegalArgumentException("Invalid format.");
426        }
427        mLastTrackIndex = trackIndex;
428        return trackIndex;
429    }

参数format不能为null,否则会抛出IllegalArgumentException异常。而且addTrack方法必须在MUXER_STATE_INITIALIZED状态下调用,也就是在start之前,否则,也会抛出IllegalStateException异常。如果mNativeObject等于0,同样会抛出IllegalStateException异常,说明Muxer已经被释放了。从参数format分解出format map,最后调用nativeAddTrack(mNativeObject, keys, values),发送到native,并且返回track index。如果format没有成功分解出format map,抛出IllegalArgumentException异常。更新mLastTrackIndex为之前返回的track index。
通过方法writeSampleData把已经编码的音视频采样数据写入muxer。

public void writeSampleData(int trackIndex, @NonNull ByteBuffer byteBuf,
446            @NonNull BufferInfo bufferInfo) {
447        if (trackIndex < 0 || trackIndex > mLastTrackIndex) {
448            throw new IllegalArgumentException("trackIndex is invalid");
449        }
450
451        if (byteBuf == null) {
452            throw new IllegalArgumentException("byteBuffer must not be null");
453        }
454
455        if (bufferInfo == null) {
456            throw new IllegalArgumentException("bufferInfo must not be null");
457        }
458        if (bufferInfo.size < 0 || bufferInfo.offset < 0
459                || (bufferInfo.offset + bufferInfo.size) > byteBuf.capacity()
460                || bufferInfo.presentationTimeUs < 0) {
461            throw new IllegalArgumentException("bufferInfo must specify a" +
462                    " valid buffer offset, size and presentation time");
463        }
464
465        if (mNativeObject == 0) {
466            throw new IllegalStateException("Muxer has been released!");
467        }
468
469        if (mState != MUXER_STATE_STARTED) {
470            throw new IllegalStateException("Can't write, muxer is not started");
471        }
472
473        nativeWriteSampleData(mNativeObject, trackIndex, byteBuf,
474                bufferInfo.offset, bufferInfo.size,
475                bufferInfo.presentationTimeUs, bufferInfo.flags);
476    }

参数trackIndex不能小于0,也不能大于mLastTrackIndex,byteBuffer和bufferInfo不能为null,bufferInfo的size不能小于0,bufferInfo的offset不能小于0,offset加上size不能大于byteBuffer的capacity,presentationTimeUs不能小于0,mNativeObject不能等于0,状态不能是MUXER_STATE_STARTED,否则,都会抛出IllegalArgumentException。最后,调用native方法nativeWriteSampleData输出sample data。

相关推荐

spark 适配达梦数据库

spark 适配达梦数据库 版本 spark3.0.0 scala2.12.10 DM Database Server 64 V8 步骤一: 引驱动包: SBT方式: "com.dameng" % "Dm8JdbcDriver18" % "8.1.0.157", maven方式: <dependency> <groupId>com.dameng</groupId> <artifactId>Dm8JdbcDriver18</artifac

_@Eva@_的博客 2090

Android MediaMuxer使用遇到的问题

1.IllegalStateException问题 MediaMuxer的使用必须严格遵循如下顺序: addTrack->start->writeSampleData->stop->release 如果有顺序冲突或者多次调用start、stop、release,会导致IllegalStateException 在使用MediaMuxer时,经常遇到的场景是在两个不同的Thread中分别执行

@甘道夫@的专栏 6317

STM32F407硬件SPI驱动ADS1220避坑指南:从寄存器读不到数据到采样值异常的完整解决流程

本文详细解析了STM32F407硬件SPI驱动ADS1220的常见问题与解决方案,包括SPI配置、寄存器读取异常、采样值优化等关键环节。通过CubeMX配置技巧和Keil调试经验,帮助开发者快速排查从通信失败到数据异常的各种问题,实现高精度数据采集系统的稳定运行。

weixin_26878995的博客 158

Android硬编码后muxer写文件部分手机(findx)崩溃的解法

try { HardMediaData data=cache.poll(50, TimeUnit.MILLISECONDS); synchronized (Lock){ Log.d(TAG,"data is null?"+(data==null)); if(muxStarted&&data!=null){ L...

u010029439的博客 317

静态时序分析(STA)_深入解析Data to Data Checks的零周期挑战

本文深入解析了静态时序分析(STA)中Data to Data Checks的核心概念与零周期挑战。重点探讨了当Setup要求值超过时钟周期时,工具如何调整发射沿,并导致Hold检查的发射与捕获沿“分裂”这一反直觉现象。文章通过案例详细解读了时序报告,并提供了通过调整约束或接受多周期保持两种策略来应对这一挑战,帮助工程师正确理解和处理此类复杂时序检查。

weixin_29204205的博客 351

用Python进行GEO数据挖掘(学习笔记四):富集分析

该笔记详细解释了富集分析的工作原理,并简要地利用gseapy在python中进行富集分析的操作。

m0_64111502的博客 5649

Android多媒体框架(6)—— MediaMuxer的jni代码分析

MediaMuxer的jni代码分析 jni方法的定义 MediaMuxer jni方法的定义在frameworks/base/media/jni/android_media_MediaMuxer.cpp中。 static const JNINativeMethod gMethods[] = { { &quot;nativeAddTrack&quot;, &quot;(J[Ljava/lang/String;[Lja...

hunter800421的专栏 1488

效果炸裂_安装midscene_copw基于midscene操作电脑_基于视觉的软件测试执行_MIDSCENE的安装和使用---AI大模型应用探索0012

摘要:本文介绍了如何通过安装MidSceneJS来增强Copaw的屏幕操作能力。首先需要安装Node.js和npm,并配置淘宝镜像源加速安装。然后全局安装MidScene CLI工具(npm install @midscene/cli -g)。接着配置视觉大模型服务,通过设置环境变量指定模型API密钥、名称、基础URL和家族类型(如qwen3.5-27b),配置文件需存放在C:\Users\Administrator.copaw目录。安装成功后,MidScene已能成功识别并操作屏幕,使用效果良好。文中还提

添柴程序猿的专栏 640

Android多媒体框架(7)—— stagefright中MediaMuxer源码分析

stagefright中MediaMuxer源码分析 私有属性定义 MediaMuxer.h中定义了一些类的属性: const OutputFormat mFormat; sp&amp;lt;MediaWriter&amp;gt; mWriter; Vector&amp;lt; sp&amp;lt;MediaAdapter&amp;gt; &amp;gt; mTrackList; // Each track has its...

hunter800421的专栏 955

C#串口通信上位机开发实战:轻松实现硬件控制与数据交互

摘要:本文介绍如何使用C#开发串口通信上位机应用,实现与硬件设备(如传感器、PLC等)的数据交互。文章涵盖串口通信原理、开发环境配置、功能实现(串口连接管理、数据收发、实时显示)及UI设计,重点讲解SerialPort类的应用、多线程数据接收处理和错误优化。通过Windows Forms构建直观界面,帮助开发者快速掌握工业控制和自动化系统中的串口通信技术,为物联网和智能设备开发提供实用解决方案。全文约150字。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 3029

直驱风机并网系统次同步振荡机理与振荡源定位方法研究

摘要: 本文针对直驱风机并网系统次同步振荡问题,研究了其产生机理与振荡源定位方法。通过建立系统小信号模型,采用特征值分析法揭示了次同步振荡的产生机制,并分析了电网强度、控制器参数对振荡特性的影响。基于暂态能量流理论,提出了通过计算各元件耗散能量来定位振荡源的方法。在MATLAB/Simulink平台搭建仿真系统验证了所提方法的有效性,为直驱风电场次同步振荡的分析与抑制提供了理论依据。 关键词:直驱风机;次同步振荡;小信号模型;暂态能量;振荡源定位

huanghm88的专栏 101

MediaMuxer Stop抛异常崩溃

java.lang.IllegalStateException: Failed to stop the muxer at android.media.MediaMuxer.nativeStop(Native Method) at android.media.MediaMuxer.stop(MediaMuxer.java:225) MediaMuxer在录制完成时调用stop接口抛异常崩溃

zh_zhen的专栏 1万+

基于YOLOv8的城市违建识别系统:从数据集构建到UI界面实现

YOLOv8是Ultralytics公司于2023年推出的最新一代YOLO(You Only Look Once)系列目标检测算法。更高效的骨干网络设计改进的锚框机制更精确的损失函数支持分类、检测、分割等多任务YOLOv8特别适合像违建识别这样的实时检测任务,能够在保持高精度的同时实现快速推理。

YOLO 675

Android 音视频深入 五 Android原生API完美的录视频(附源码下载)

本篇项目地址,求starhttps://github.com/979451341/Audio-and-video-learning-materials/tree/master/%E5%BD%95%E8%A7%86%E9%A2%91这一次的代码录视频在各个播放器都可以用,有时长显示,对比上一次的代码说说为何两者效果不同,但是我先补充一些之前漏掉的MediaCodec的官方说明还有MediaCodec...

z979451341的博客 3439

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

[SteamVR] Not Initialized (109)报错解决

VR设备:HTC VIVE COSMOSVR插件:SteamVR Plugin 2.7.3unity版本:2019.4.40f1。

xiaonan1996的博客 5895

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

完美的解决如何让AsyncTask终止操作

启动一个AsyncTask   如何终止该操作呢? 单纯的onCancelled(true)是不行的 AsyncTask简介:它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。 举例:实现登录功能 package com.isummation.exampleapp; im

huangdroid的专栏---不要让任何事情成为你不去学习的理由! 964

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

android native层使用mediacodec(硬编解码) mediamuxer mediaExtractor做转码工具。

native mediacodec

cf125313的专栏 1458

MediaMuxer录制文件错误总结

问题1 The number of recorded samples is 0 Failed to stop the muxer 报以上错误 后来经过排查发现 在 add videotrack 和audiotrack 后只写入了 videodata 然而音频数据没有写入。 后写入音频数据可正确录制。所以遇到该错误 可以查看writesampledata是否正确的写入了 音频和视频...

qq_25186111的博客 3695

关于 error: Operation is not valid due to the current state of the object。

今天碰到一个特别的异常。 Operation is not valid due to the current state of the object. at System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded() at System.Web.HttpValueCollection.FillFro...

aoxi0033的博客 1112

MediaMuxer+MediaCodec生成MP4视频报错

项目中遇到一个问题,现象是录制视频时,录制一段时间后应用会crash。我们项目中是用MediaMuxer+MediaCodec来录制,最后生成一个MP4格式视频。 关键报错信息如下:E/AndroidRuntime(23507): java.lang.IllegalStateException: writeSampleData returned an error E/AndroidRuntime(

三代肉山大人的博客 1万+

音视频开发之旅(五)MediaExtractor MediaMuxer 实现视频的解封装与合成

目录 MediaExtractor MediaMuxer 能做什么 视频解封装和合成的API以及流程介绍 三个实践(视频解封装提取纯音轨和视频轨文件、再合成新视频、给视频换个背景音) 遇到的问题 收获 一、有什么实际应用 在我们日常使用短视频软件的时候,对视频的裁剪,拼凑,加入背景是很常用的操作,这些功能是如何实现的呐?其实是将视频多信道的分离出来,比如音轨和视频轨道分隔出来,可以做到二次合成。 今天我们通过对来MediaExtractor和MediaM

yabin的专栏 2393

Android原生编解码接口 MediaCodec 之——踩坑

关键帧 MediaCodec 有两种方式触发输出关键帧,一是由配置时设置的 KEY_FRAME_RATE和KEY_I_FRAME_INTERVAL参数自动触发,二是运行过程中通过 setParameters 手动触发输出关键帧。 自动触发输出关键帧 在MediaCodec硬编码中设置I(关键帧)时间间隔,在 api 中是这么设置的 mediaFormat.setInteger(MediaF.........

小口锅 3万+

Android多媒体框架总结(1) - 利用MediaMuxer合成音视频数据流程分析

场景介绍:   设备端通过服务器传向客户端(Android手机)实时发送视频数据(H.264)和音频数据(g711a或g711u), 需要在客户端将音视频数据保存为MP4文件存放在本地,用户可以通过APP或者直接在手机上观看MP4文件. 解决方案:   通过AndroidMultiMedia Framework提供的MediaMuxer类对音视频数据进行同步合成. 流程图: 流程分...

weixin_30345055的博客 389

串联整个音视频录制流程,完成音视频的采集、编码、封包成 mp4 输出

音频采集:AudioRecord 视频采集:Camera预览回调YUV数据 编码:MediaCodec 合成封包MP4:MediaMuxer 首先确定几条线程处理任务 1.audioThread 音频采集和编码 2.videoThread 视频编码 3.muxerThread 合成 示例代码:Kotlin 所有详细代码已上传github,后面会给出地址,示例Activity是Camera1Pr...

One_Month的博客 3629

audio录音在JAVA层的调用

用android 7.0版本的录音应用为例进行跟进下。   STEP 1: \packages\apps\SoundRecorder\src\com\android\soundrecorder\SoundRecorder.java      public void onCreate(Bundle icycle) {        super.onCreate(icycle);  

liyanfei123456的博客 1545
上一篇: Android多媒体框架(4)—— AMessage,AHandler和ALooper源码分析
下一篇: Android多媒体框架(6)—— MediaMuxer的jni代码分析
hunter800421
博客等级 码龄22年 60粉丝 97原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值