You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Mp4Parser给高码率视频添加水印并解决Pexels视频编码报错问题

问题根因

你遇到的0xfffffc0e错误属于Android MediaCodec硬编码器配置失败,触发原因是Pexels平台提供的视频参数超出了当前设备硬编码器的支持范围:

  • YouTube、Instagram等平台的下载视频都经过了平台统一转码处理,分辨率、码率、编码规格都适配了绝大多数移动设备的硬编能力,所以可以正常处理
  • Pexels的素材为了保留原始画质,通常会采用4K分辨率、10Mbps以上高码率、H.264 High Profile等高规格参数,很容易超出中低端Android设备的硬编上限
修复方案

1. 等比缩放输出分辨率

硬编码器对输入分辨率有明确上限,绝大多数移动设备硬编最大支持1080P分辨率,所以需要先读取原视频宽高,等比缩放到1080P以内,同时确保宽高为16的倍数(MediaCodec编码要求)。

2. 手动指定输出码率

不要使用Mp4Composer默认的原视频码率继承逻辑,手动将输出码率设置为设备兼容的范围:1080P视频对应4-8Mbps,720P视频对应2-4Mbps即可满足常规使用清晰度要求。

3. 可选适配项

如果修改分辨率和码率后仍报错,可以修改Mp4Composer源码中VideoComposer类的MediaFormat配置,强制指定兼容性最高的H.264 Main Profile和Level 4.1:

mediaFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileMain);
mediaFormat.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel41);
修改后代码示例
// 先获取原视频参数,计算适配后的输出分辨率
val retriever = MediaMetadataRetriever()
retriever.setDataSource(videoPath)
val originWidth = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)!!.toInt()
val originHeight = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)!!.toInt()
val maxSupportedSide = 1080
var targetWidth = originWidth
var targetHeight = originHeight

// 等比缩放到最大边不超过1080
if (originWidth > originHeight && originWidth > maxSupportedSide) {
    targetWidth = maxSupportedSide
    targetHeight = (originHeight * (maxSupportedSide.toFloat() / originWidth)).toInt()
} else if (originHeight > maxSupportedSide) {
    targetHeight = maxSupportedSide
    targetWidth = (originWidth * (maxSupportedSide.toFloat() / originHeight)).toInt()
}

// 对齐16的倍数,符合硬编要求
targetWidth = targetWidth / 16 * 16
targetHeight = targetHeight / 16 * 16

Mp4Composer(videoPath!!, getDestinationPath())
    .size(targetWidth, targetHeight) // 指定适配后的输出分辨率
    .bitrate(6 * 1024 * 1024) // 指定6Mbps的输出码率,可根据需求调整
    .filter(GlWatermarkFilter(bitmap, getRepostWatermarkPosition()))
    .listener(object : Mp4Composer.Listener {
        override fun onProgress(progress: Double) {
            mainScoopLauncher {
                loadStateEnable(true)
                val progressValue = (progress * 100).toString()
                val isUnder10Percentage = progressValue.take(2).contains(".")
                val under10PercentageValue = "${progress * 100}".take(1) + "%"
                val upto10PercentageValue = progressValue.take(2) + "%"
                val loadValue =
                    if (isUnder10Percentage) under10PercentageValue else upto10PercentageValue
                binding.txtPercentage.text = loadValue
            }
        }

        override fun onCurrentWrittenVideoTime(timeUs: Long) {
            mainScoopLauncher { loadStateEnable(true) }
        }

        override fun onCompleted() {
            mainScoopLauncher {
                loadStateEnable(false)
                toast("Repost Video Complete")
            }
        }

        override fun onCanceled() {
            logger("cancelled")
            mainScoopLauncher {
                loadStateEnable(false)
                toast("Repost Process Cancel..")
            }
        }

        override fun onFailed(exception: Exception?) {
            mainScoopLauncher {
                loadStateEnable(false)
                toast("Repost Process Failed..")
            }
        }
    }).start()
兜底兼容方案

如果硬编方案仍有设备兼容性问题,可以切换为FFmpeg软编实现水印添加,软编不受硬件能力限制,兼容性100%,仅处理速度比硬编慢30%-50%左右。


内容的提问来源于stack exchange,提问作者Ravi Sorathiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 07:24:01