软解码
1.构建输入AVFormatContext
AVFormatContext* avFormatContext = avformat_alloc_context();
int res = avformat_open_input(&avFormatContext,filename.toUtf8().data(), NULL, NULL);//打开文件
if (res < 0) {
qCritical()<<__FUNCTION__<<__LINE__<<"error "<<res<<"in avformat_open_input";
return res;
}
2.查找视频信息流
res = avformat_find_stream_info(avFormatContext, nullptr);//取出流信息
if (res < 0)
{
return res;
}
//查找视频流和音频流
av_dump_format(avFormatContext, 0,filename.toUtf8().data(), 0);//列出输入文件的相关流信息
for (unsigned int i = 0; i < avFormatContext->nb_streams; i++)
{
if (avFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
if(video_index==-1)
{
video_index = i;
}
}
}
m_width = avFormatContext->streams[video_index]->codec->width;
m_height = avFormatContext->streams[video_index]->codec->height;
3.初始化软解码
AVCodecContext *avCodecContext = avFormatContext->streams[video_index]->codec;
AVCodec* m_codec = avcodec_find_decoder(avCodecContext->codec_id);
if (avcodec_open2(avCodecContext, m_codec, NULL) < 0)
{
return false;
}
4.初始化SwsContext图像转换上下文
img_convert_ctx = sws_getContext(
m_width,
m_height,
avCodecContext->pix_fmt,
m_width,
m_height,
AV_PIX_FMT_BGRA,
SWS_BICUBIC,
NULL, NULL, NULL);
5.循环读取数据
while (true)
{
int ret = av_read_frame(avFormatContext, avPacket);
if (ret < 0){
qDebug()<< "read end";
break;
}
else if (avPacket->stream_index == video_index){
decode_to_photo(avPacket);
}
av_packet_unref(avPacket);
}
void decode_to_photo(const AVPacket *avPacket)
{
int ret = avcodec_send_packet(avCodecContext, avPacket);
if (ret < 0) {
char error[1024];
av_strerror(ret, error, 1024);
qDebug() << "发送解码失败:" << error;
}
while (true)
{
ret = avcodec_receive_frame(avCodecContext, avFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
//qDebug() << "avcodec_receive_frame end:" << ret;
break;
}
else if (ret < 0)
{
//qDebug()<< "获取解码数据失败"<<ret;
return;
}
else
{
QImage pixLogo2;
int m_rotat = getRotateAngle(avFormatContext->streams[video_index]);
if(dec_st == AV_SOFTWARE_DECODER)
{
sws_scale(img_convert_ctx,
(const unsigned char* const*)avFrame->data,
avFrame->linesize, 0,
avFrame->height,
bgrFrame->data,
bgrFrame->linesize);
QImage pixLogo(bgrFrame->data[0],bgrFrame->width,bgrFrame->height,
bgrFrame->width * 4, QImage::Format_ARGB32);
QMatrix matrix;
matrix.rotate(m_rotat);
pixLogo2 = pixLogo.transformed(matrix,Qt::FastTransformation);
/*这里可以进行必要的图片处理操作*/
}
curcount++;
av_frame_unref(sw_frame);
av_frame_unref(avFrame);
}
}
}
tips:
根据pts来计算一桢在整个视频中的时间位置
timestamp(秒) = pts * av_q2d(st->time_base)
timestamp(毫秒) = pts * av_q2d(st->time_base) * 1000
计算视频长度的方法
time(秒) = st->duration * av_q2d(st->time_base)