Android FFmpeg系列03--视频解码与渲染

2022-09-21 14:53:27 浏览数 (1)

在前面的文章中讲述了FFmpeg的编译&集成和音视频的一些基础概念

Android FFmpeg系列01--编译与集成

Android FFmpeg系列02--音视频基础

本文为FFmpeg系列的第三篇文章,主要内容为利用FFmpeg解码本地mp4文件的视频流并利用OpenGL进行上屏渲染

FFmpeg视频解码

一个音视频文件的播放流程大致需要经历解封装->解码->音视频同步->数据消费几个步骤,如下图所示

解封装并查找视频流

查找解码器并打开

循环解码

核心代码

代码语言:javascript复制
// step1: alloc format context
mFtx = avformat_alloc_context();

// step2: open input file
avformat_open_input(&mFtx, path.c_str(), nullptr, nullptr);

// step3: find video stream index
avformat_find_stream_info(mFtx, nullptr);
int videoIndex = -1;
for (int i = 0; i < mFtx->nb_streams; i  ) {
    if (mFtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        videoIndex = i;
        break;
    }
}

// step4: find decoder and open
mVideoCodec = avcodec_find_decoder(codecParameters->codec_id);

mVideoCodecContext = avcodec_alloc_context3(mVideoCodec);

avcodec_parameters_to_context(mVideoCodecContext, codecParameters);

avcodec_open2(mVideoCodecContext, mVideoCodec, nullptr);

// steop5: loop decode
while (true) {
    av_read_frame(mFtx, avPacket);
    // ....
    avcodec_send_packet(mVideoCodecContext, avPacket);
    // ....
    avcodec_receive_frame(mVideoCodecContext, avFrame);
    // ....
    sws_scale(...);
    // ....
    // clock sync and doRender
    // ....
}

时钟同步

每解码一帧就渲染上屏的话,可以发现视频播放就像按了快进键一样画面飞速闪过,要让画面正常速率显示的话就需要做时钟同步了,按照视频帧的pts来渲染这一帧

因为Demo只解码视频流上屏,所以时钟肯定就是参考系统时钟了,这里我们只是在pts比系统时钟晚的情况等待

代码语言:javascript复制
auto pts = avFrame->best_effort_timestamp;
// s -> us
pts = pts * av_q2d(mFtx->streams[mVideoDecoder->getStreamIndex()]->time_base) * 1000 * 1000;

int64_t elapsedTime;
if (mStartTime < 0) {
    mStartTime = av_gettime();
    elapsedTime = 0;
} else {
    elapsedTime = av_gettime() - mStartTime;
}
‍
int64_t diff = pts - elapsedTime;
if (diff > 0) {
    av_usleep(diff);
}

OpenGL渲染

解码出来的AVFrame经过sws context后统一转为YUV420P格式,然后抛到java层上传纹理并渲染

OpenGL如何渲染YUV buffer可以参考之前的两篇文章,这里就不赘述~

如何使用OpenGL渲染YUV数据

Android中如何使用OpenGL播放视频

Demo

https://github.com/sifutang/ffmpeg-demo

点击屏幕左右滑动会将视频划分为gray处理和原视频

~~END~~

0 人点赞