Android 视频转码

1、需求

1.1 要求上传时长5分钟内,大小200m内的mp4格式视频;

1.2 上传后能支持手机和电脑的浏览器播放。

2、上传逻辑

image.png

3、格式

mp4格式:H.264("video/avc")/H.265(“video/hevc”);

官方的Chrome浏览器是不支持h265格式的MP4播放;

4、转码(降低视频分辨率和比特率)

4.1 自定义录制可以控制录制时长,分辨率,码率等来生成体积很小的视频;

4.2 软件解码(ffmpeg)

优点:支持的视频格式较多,功能丰富,提供了多种受支持的编解码器和容器,并具有执行编辑操作(合并/拆分视频,合并/解复用轨道,修改帧等)的功能.

缺点:转码速度相对慢,可能会消耗大量电池和CPU。

4.3 硬件解码 (MediaCodec)

优点:支持的视频格式较少,对设备硬件有所要求,编解码器选择有限,但性能和功率效率更高;

缺点:转码速度相对快,速度与设备硬件有关。

官方示例:

|

MediaCodec codec = MediaCodec.createByCodecName(name);
MediaFormat mOutputFormat; 
// 设置回调方法
codec.setCallback(new MediaCodec.Callback() {
   /**
    * mediacodec 存在可用输入缓冲
    */
   @Override
   void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {
     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
     // 可通过 MediaExtractor 读取 video 或 audio 数据,然后填充数据到缓冲区
     …
     codec.queueInputBuffer(inputBufferId, …);
   }

   /**
    * 输出缓冲填充完数据后
    */
   @Override
   void onOutputBufferAvailable(MediaCodec mc, int outputBufferId, …) {
     // 获取输出缓冲(其中包含编解码后数据)
     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
     MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); 
     // 处理编解码后的数据
     …
     // 返还输出缓冲给 codec
     codec.releaseOutputBuffer(outputBufferId, …);
   }

    /**
     * 输出格式发生变化
     */
   @Override
   void onOutputFormatChanged(MediaCodec mc, MediaFormat format) {
     // Subsequent data will conform to new format.
     // Can ignore if using getOutputFormat(outputBufferId)
     mOutputFormat = format; 
   }

    /**
     * 发生错误
     */
   @Override
   void onError(@NonNull MediaCodec var1, @NonNull MediaCodec.CodecException var2) {

   }
 });

 codec.configure(format, …);
 mOutputFormat = codec.getOutputFormat(); 
 codec.start();
 // wait for processing to complete
 codec.stop();
 codec.release();

// 两种方式创建
mMediaCodec = MediaCodec.createDecoderByType(MIME_TYPE);
mMediaCodec = MediaCodec.createByCodecName(decoderCodecName);

MediaFormat mediaFormat = new MediaFormat();
// 视频编码格式
mediaFormat.setString(MediaFormat.KEY_MIME, MIME_TYPE_VIDEO_AVC);
// 视频宽度
mediaFormat.setInteger(MediaFormat.KEY_WIDTH, width);
// 视频高度
mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, height);
// 视频比特率/码率(数值越大视频质量越好)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
// 视频关键帧间隔时间
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameInterval);
// 视频帧率(单位时间内视频显示帧数)
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);

// 可以查找设备所支持的解码器
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
String decoderCodecName = mediaCodecList.findDecoderForFormat(mediaFormat);

说明:

1、码率:码率越大,视频文件越大;码率越小,视频文件越小

2、帧率:帧率与画面的流畅度成正比。帧率越大,画面越流畅;帧率越小,画面有卡顿感。

3、在编码的时候,保证WIDTH 与 HEIGHT两者是16的整数倍。

5、最后

第三方封装库:https://github.com/linkedin/LiTr

延伸阅读:https://engineering.linkedin.com/blog/2019/litr-a-lightweight-video-audio-transcoder-for-android

你可能感兴趣的:(Android 视频转码)