输入视频的封装格式是FLV,视频编码标准是H.264,音频编码标准是AAC;输出视频的封装格式是AVI,视频编码标准是MPEG2,音频编码标准是MP3

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

- #ifndef TRANSCODINGVIDEO_H
- #define TRANSCODINGVIDEO_H
-
- #include <QObject>
- #include<QThread>
-
- //当前C++兼容C语言
- extern "C"
- {
- //avcodec:编解码(最重要的库)
- #include <libavcodec/avcodec.h>
- //avformat:封装格式处理
- #include <libavformat/avformat.h>
- //swscale:视频像素数据格式转换
- #include <libswscale/swscale.h>
- //avdevice:各种设备的输入输出
- #include <libavdevice/avdevice.h>
- //avutil:工具库(大部分库都需要这个库的支持)
- #include <libavutil/avutil.h>
- }
-
- class transcodingVideo : public QThread
- {
- Q_OBJECT
- public:
-
- transcodingVideo();
-
- //打开H264视频文件
- void openFile(QString file);
- //根据我们需要的封装格式进行处理
- void outPut(QString fileout);
-
- AVFormatContext *forContext,*formatout;//保存数据的结构体 forContext存输入进来的视频信息;formatout存储最终输出的视频信息
- AVPacket *pkt;//pkt
- int videoType;
-
-
-
- signals:
-
- public slots:
- };
-
- #endif // TRANSCODINGVIDEO_H
4.2 转码具体实现过程如下
- #include "transcodingvideo.h"
- #include<QDebug>
-
- transcodingVideo::transcodingVideo()
- {
- //注册组件
- av_register_all();
- forContext= avformat_alloc_context();
- }
-
- void transcodingVideo::openFile(QString file)
- {
- //打开输入视频
- int res=avformat_open_input(&forContext,file.toStdString().c_str(),nullptr,nullptr);
- //判断是否打开成功
- if(res<0)
- {
- qDebug()<<"打开失败";
- return;
- }
-
- //打开视频文件成功,获取文件信息
- res = avformat_find_stream_info(forContext,nullptr);//查看有没有相关视频流信息
- if(res<0)//判断是否有流媒体
- {
- qDebug()<<"没有流媒体信息"<<endl;
- return;
- }
-
- //一个视频流有多股码流,存在forContentext中streams数组中
- int videoType=-1;
- for(int i=0;i<forContext->nb_streams;i++) //i小于流的个数
- {
- if(forContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)//视频流
- {
- videoType=i;//标识类型
- break;
- }
- }
- if(videoType==-1)
- {
- qDebug()<<"没有视频流相关信息"<<endl;
- return;
- }
- qDebug()<<"输入的准备已经完成";
- }
-
- void transcodingVideo::outPut(QString fileout)
- {
- //猜测编码器
- AVOutputFormat *avformat = av_guess_format(nullptr,fileout.toStdString().c_str(),nullptr);
- if(avformat==nullptr)
- {
- qDebug()<<"没有编码器!";
- return;
- }
- qDebug()<<"AVOutputFormat";
-
- //保存输出视频信息的结构体
- formatout = avformat_alloc_context();
- //设置输出格式
- formatout->oformat = avformat;
-
- //打开视频流 文件流
- //参数1:输入输出的上下文对象
- //参数2:文件流路径
- //参数3:文件打开格式 写的方式
- int res=avio_open(&formatout->pb,fileout.toStdString().c_str(),AVIO_FLAG_WRITE);
- if(res<0)
- {
- qDebug()<<"open file error";
- return;
- }
- qDebug()<<"avio_open";
- //新建视频流
- //参数1:视频信息结构体
- //参数2:新建流 的 返回新建流 的地址
- AVStream *newStream =avformat_new_stream(formatout,nullptr);
- if(newStream==nullptr)
- {
- qDebug()<<"打开视频流失败";
- return;
- }
- qDebug()<<"newStream";
- //编码器对应参数设置 拷贝参数设置 newStream:输入进入流的参数设置
- res = avcodec_parameters_copy(newStream->codecpar,forContext->streams[videoType]->codecpar);
- qDebug()<<"res="<<res;
- if(res<0)
- {
- qDebug()<<"拷贝失败!";
- return;
- }
- qDebug()<<"res="<<res;
- //设置新的流里面 codec_tag 设置为0
- newStream->codecpar->codec_tag = 0;
-
- //头部信息写入----写入成功与否
- res = avformat_write_header(formatout,nullptr);//formatout封装格式的结构体
- //判断写入成功与否
- if(res<0)
- {
- qDebug()<<"写入头部信息失败!";
- return;
- }
- qDebug()<<"res="<<res;
-
- //开始读取码流数据
- pkt = (AVPacket*)malloc(sizeof(AVPacket));
- //算出这张图有多大
- int size = newStream->codecpar->width*newStream->codecpar->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)
- {
- //时间基 time_base AVRational属性
- AVRational timebase=forContext->streams[videoType]->time_base;
- //计算帧之间的长度(duration) double强制转换
- int64_t duration=(double)AV_TIME_BASE/av_q2d(forContext->streams[videoType]->r_frame_rate);
- //计算显示时间基(pts):公式:(当前帧数*两帧之间的长度))/(输入时间基*AV_TIME_BASE)
- pkt->pts = (double)(frameCount*duration)/(av_q2d(timebase)*AV_TIME_BASE);
- //解码时间基(dts)
- 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;
- //数据包的标记:结合AV_PKT_FLAG_KEY使用 最小为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);//对应avio_open()
- qDebug()<<"avio_close";
-
- //释放malloc的空间 释放保存信息的结构体
- av_free(formatout);
- qDebug()<<"av_free";
-
- //关闭输入流
- avformat_close_input(&forContext);//对应avformat_open_inpu
- qDebug()<<"avformat_close_input";
-
- //释放forContext结构体空间
- av_free(forContext);
- qDebug()<<"av_free";
- }
4.3 转码结果测试如下
- //视频转码操作
- transcodingVideo *p = new transcodingVideo; //转码
- p->openFile("outfile.h264");
- p->outPut("outfile.mp4");
编码所得到的.h264文件经过转码操作生成.mp4文件,可打开.mp4文件进行播放

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓