MediaCodec结合FFmpeg实现视频加图片水印

本文介绍了如何在Android上利用MediaCodec进行硬解码和编码,结合FFmpeg的AVFilter实现视频加图片水印。通过FFmpeg的滤镜功能,可以在GPU级别高效地处理水印,提高性能。详细步骤包括视频信息提取、解码器和编码器创建、解码编码流程,以及加水印的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、前言

最近在研究FFmepg滤镜方面的知识,索性就准备尝试一下代码给视频添加水印。

一开始想直接FFmpeg直接c代码加水印,写完后测试了一下比较慢,毕竟软解得看CPU即使设置了多线程编解码还是一个吊样,然后想到了另一条路硬解码然后ffmpeg数据处理水印接着送入硬编码这样效率会很高,毕竟GPU还是很快的。软解永远是兜底方案

注:这不是一篇单纯的FFmpeg水印命令文章 注:本篇使用JNI开发

2、效果

 3、流程

仅核心流程具体细节参照示例

原视频AAC解码H264编码YUV编码H264合成MediaCodecAVFilterMediaCodecMediaMuxerAudioAACMPEG4

AVFilter是FFmpeg库下的一个流媒体过滤器,它用于对组件常用于多媒体处理与编辑,包含多种滤镜,比如旋转,加水印,多宫格等等,源码位于ffmpeg/libavfilter中。

4、准备

5、示例

5.1 提取音频/视频流轨道MediaFormat

//视频流提取器
MediaExtractor mediaExtractor = new MediaExtractor();
//设置视频源
mediaExtractor.setDataSource(path);
//寻找视频流
for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
    MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i);
    if (mediaFormat.getString(MediaFormat.KEY_MIME).contains("video/")) {
        //视频流
        videoMediaFmt = mediaFormat;
        //选择当前视频轨道
        mediaExtractor.selectTrack(i);
    } else if (mediaFormat.getString(MediaFormat.KEY_MIME).contains("audio/")) {
        //音频流
        readAudioMediaFormat = mediaFormat;
        //记录音频流索引
        audioExtractorSelectIndex = i;
    }
}
//音频流提取器
MediaExtractor audioMediaExtractor = new MediaExtractor();
audioMediaExtractor.setDataSource(path);
//直接选择音频流
audioMediaExtractor.selectTrack(audioExtractorSelectIndex);

MediaExtractor视频信息的提取类:

  • selectTrack 选择轨道 完毕后所有API都将基于改轨道进行信息提取

  • getTrackFormat 根据索引获取当前轨道的MediaFormat

5.2 创建视频解码器

int colorFmtType = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
//设置解码器解码的YUV类型
videoMediaFmt.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFmtType);
//重新设置缓冲区大小
videoMediaFmt.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, videoMediaFmt.getInteger(MediaFormat.KEY_WIDTH) * videoMediaFmt.getInteger(MediaFormat.KEY_HEIGHT) * 3 / 2);
//根据类型创建合适的硬解码器
MediaCodec decode = MediaCodec.createDecoderByType(videoMediaFmt.getString(MediaFormat.KEY_MIME));
finalVideoMediaFmt = videoMediaFmt;
decode.configure(finalVideoMediaFmt, null, null, 0);
//设置解码异步回调
decode.setCallback(mediaCallback);
decode.start();

5.3 创建视频编码器

MediaCodec encode = MediaCodec.createEncoderByType(videoMediaFmt.getString(MediaFormat.KEY_MIME));
MediaCodec mediaFormat = MediaFormat.createVideoFormat(videoMediaFmt.getString(MediaFormat.KEY_MIME),videoMediaFmt.getInteger(MediaFormat.KEY_WIDTH), videoMediaFmt.getInteger(MediaFormat.KEY_HEIGHT));
// 编码器接受的YUV格式
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
//设置比特率 越大越清晰
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, videoMediaFmt.getInteger(MediaFormat.KEY_WIDTH) * videoMediaFmt.getInteger(MediaFormat.KEY_HEIGHT) * 3);
//设置帧率FPS
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, videoMediaFmt.getInteger(MediaFormat.KEY_FRAME_RATE));
//设置I帧
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
//设置采样率
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
//设置csd-0 1 H264需要写入头部
mediaFormat.setByteBuffer("csd-0", 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值