赞
踩
视频转码
视频转流程图
转码步骤
①转码类设计,数据的初始化
②构造函数中进行开辟内存空间和组件的注册
③封装函数用于接收需要转码的视频文件
打开视频文件,并判断是否打开成功
查找文件中的数据流,判断是否找到数据流
找到后从中找出视频流,判断是否有视频流
④封装函数用于对视频文件进行转码的一系列操作,并输出一个转码后的视频文件
猜测编码器,并判断有无数据文件并设置视频信息最终的输出格式
打开文件流(打开格式:写入的方式打开),并判断是否打开成功
新建视频流,并判断是否新建成功
编辑器对应的设置,使用函数进行拷贝,并判断是否拷贝成功
写入头部信息,并判断是否写入成功
开始读取码流数据,用一个while循环读取一帧一帧的数据
解码时间基真正的转换
while循环结束后记得写入尾巴帧
最后进行关闭流操作
⑤测试
创建转码类对象,调用两个函数
在工程文件中查看生产的cover.mp4文件
转码类package_coverH264代码
package_coverh264.h
#ifndef PACKAGE_COVERH264_H
#define PACKAGE_COVERH264_H
#include <QDebug>
#include <QImage>
#include <QThread>
#include <QString>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libswresample/swresample.h>
#include <libavfilter/avfilter.h>
#include <libavutil/adler32.h>
#include <libswscale/swscale.h>
}
class package_coverH264
{
public:
package_coverH264();
void openfile(QString file);
void output(QString fileout);
private:
AVFormatContext *forContext;
AVFormatContext *formatOut;
AVPacket *pkt;
AVOutputFormat * avformat;
AVStream *newStream;
int videoType;
};
#endif // PACKAGE_COVERH264_H
package_coverh264.cpp
#include "package_coverh264.h"
package_coverH264::package_coverH264()
{
av_register_all();
forContext =avformat_alloc_context();
formatOut =avformat_alloc_context();
videoType=-1;
pkt=(AVPacket *)malloc(sizeof (AVPacket));
}
void package_coverH264::openfile(QString file)
{
//打开视频文件
int res=avformat_open_input(&forContext,file.toStdString().c_str(),nullptr,nullptr);
if(res<0)
{
qDebug()<<"打开失败";
}
//查找流数据
res=avformat_find_stream_info(forContext,nullptr);
if(res<0)
{
qDebug()<<"没有流数据";
}
//从查找到的流信息中找到视频码流信息
for(int i=0;i<forContext->nb_streams;i++)
{
if(forContext->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)//视频流
{
videoType=i;
break;
}
}
if(videoType==-1)
{
qDebug()<<"没有视频流数据";
}
}
void package_coverH264::output(QString fileout)
{
//猜测编码器
avformat =av_guess_format(nullptr,fileout.toStdString().c_str(),nullptr);
if(avformat==nullptr)//判断有无数据文件(.h264)
{
qDebug()<<"没有数据文件";
return;
}
//设置视频信息最终的输出格式
formatOut->oformat=avformat;
//打开文件流(打开格式:写入的方式打开)
int res=avio_open(&formatOut->pb,fileout.toStdString().c_str(),AVIO_FLAG_WRITE);
if(res<0)
{
qDebug()<<"打开文件流对象失败";
return;
}
//新建视频流
newStream=avformat_new_stream(formatOut,nullptr);
if(newStream==nullptr)
{
qDebug()<<"新建流失败";
return;
}
//编辑器对应的设置
res =avcodec_parameters_copy(newStream->codecpar,
forContext->streams[videoType]->codecpar);
if(res<0)
{
qDebug()<<"拷贝参数失败";
}
newStream->codecpar->codec_tag=0;
//写入头部信息
res=avformat_write_header(formatOut,nullptr);
if(res<0)
{
qDebug()<<"写入失败";
}
//开始读取码流数据
int size=newStream->codec->width*newStream->codec->height;
av_new_packet(pkt,size);
//一帧一帧的读取
int frameCount=0;//计算第几帧
while(av_read_frame(forContext,pkt)==0)
{
//判断这一帧是否为视频流
if(pkt->stream_index==videoType)
{
frameCount++;
//如果是视频流,判断有没有设置过时间基
if(pkt->pts==AV_NOPTS_VALUE)//没有设置过
{
//时间基的转换
AVRational timeBase=forContext->streams[videoType]->time_base;
//计算帧与帧之间的长度
int64_t duration=(double)AV_TIME_BASE/av_q2d(forContext->streams[videoType]->r_frame_rate);
//计算显示时间基:(当前帧数*两帧之间的长度)/(输入时间基*AV_TIME_BASE)
pkt->pts=(double)(frameCount*duration)/(av_q2d(timeBase)*AV_TIME_BASE);
//解码时间基(没有设置过,时间基相等)
pkt->dts=pkt->pts;
//目标两帧之间的长度
pkt->duration=duration/(double)(av_q2d(timeBase)*AV_TIME_BASE);
}
else if(pkt->pts<pkt->dts)//显示时间基小于解码时间基
{
continue;
}
//解码时间基真正的转换
//显示时间基转换
pkt->pts=av_rescale_q_rnd(pkt->pts,forContext->streams[videoType]->time_base,
newStream->time_base,
(AVRounding)(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
//解码时间基转换
pkt->dts=av_rescale_q_rnd(pkt->dts,forContext->streams[videoType]->time_base,
newStream->time_base,
(AVRounding)(AV_ROUND_INF|AV_ROUND_PASS_MINMAX));
//设置数据时长
pkt->duration=av_rescale_q(pkt->duration,forContext->streams[videoType]->time_base,
newStream->time_base);
//数据在流信息中的位置设置
pkt->pos=-1;
//数据包的标记
pkt->flags |=AV_PKT_FLAG_KEY;
//标记下当前写入的这一帧是视频流
pkt->stream_index=0;
//转码后的数据包写入目标视频结构体中
av_interleaved_write_frame(formatOut,pkt);
}
av_packet_unref(pkt);//使用完之后记得重置
}
av_write_trailer(formatOut);//写入尾巴帧
//关闭流和文件的操作
avio_close(formatOut->pb);
av_free(formatOut);
avformat_close_input(&forContext);
av_free(forContext);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。