extern "C"
{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
#include<iostream>
#include<queue>
using namespace std;
void Time_base(AVPacket * pkt, AVFormatContext* &ic, AVFormatContext* &oc)
{
pkt->pts = av_rescale_q_rnd(pkt->pts,
ic->streams[pkt->stream_index]->time_base,
oc->streams[pkt->stream_index]->time_base,
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
);
pkt->dts = av_rescale_q_rnd(pkt->dts,
ic->streams[pkt->stream_index]->time_base,
oc->streams[pkt->stream_index]->time_base,
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
);
pkt->pos = -1;
pkt->duration = av_rescale_q_rnd(pkt->duration,
ic->streams[pkt->stream_index]->time_base,
oc->streams[pkt->stream_index]->time_base,
(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)
);
}
int Open_In_fine(const char* infile, int& videoidx, int& audioidx, AVFormatContext* &ic)
{
avformat_open_input(&ic, infile, 0, 0);
if (!ic)
{
//cout << "avformat_open_input failed!" << endl;
return -1;
}
for (int i = 0; i < ic->nb_streams; i++)
{
if (ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
videoidx = i;
if (ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
audioidx = i;
}
if (videoidx == -1)
{
//cout << "Codec find failed!" << endl;
return -1;
}
if (audioidx == -1)
{
//cout << "Codec find failed!" << endl;
return -1;
}
av_dump_format(ic, 0, infile, 0);
return 0;
}
int Open_out_file(const char* outfile, int& videoidx, int& audioidx, AVStream *videoStream, AVStream *audioStream, AVCodecContext* &encodec_video, AVCodecContext* &encodec_audio, AVFormatContext* &oc)
{
avformat_alloc_output_context2(&oc, NULL, NULL, outfile);
if (!oc)
{
cout << avformat_alloc_output_context2 << endl;
cin.get();
}
if (videoidx != -1) {
videoStream = avformat_new_stream(oc, NULL);
avcodec_parameters_from_context(videoStream->codecpar, encodec_video);
videoStream->codecpar->codec_tag = 0;
}
if (audioidx != -1) {
audioStream = avformat_new_stream(oc, NULL);
avcodec_parameters_from_context(audioStream->codecpar, encodec_audio);
audioStream->codecpar->codec_tag = 0;
}
av_dump_format(oc, 0, outfile, 1);
int ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);
if (ret < 0)
{
cout << avio_open << endl;
cin.get();
}
ret = avformat_write_header(oc, NULL);
if (ret < 0)
{
cout << "avformat_write_header" << endl;
cin.get();
}
return 0;
}
bool open_encodec(AVCodecContext* &encodec, AVCodec* &enc, AVCodecParameters *& codecpar) {
enc = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!enc) {
cout << "Find Decoder failed!" << endl;
cin.get();
}
encodec = avcodec_alloc_context3(enc);
encodec->bit_rate = 1000; //压缩比特率 越大文件越大
encodec->codec_type = AVMEDIA_TYPE_VIDEO;
encodec->width = codecpar->width; //视频宽
encodec->height = codecpar->height; //视频高
encodec->time_base = {1,25}; //时间基 设置可能会出现警告
encodec->framerate = { 25,1 }; //设置帧率 (和时间基准相反 可能被抛弃)
encodec->gop_size = 30; //设置画面组大小(关键帧 多少帧一帧,I贞)
encodec->max_b_frames = 30; //设置b帧(b帧越多压缩率越高)
encodec->pix_fmt = AV_PIX_FMT_YUV420P;
encodec->codec_id = AV_CODEC_ID_H264;
encodec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;//AV_CODEC_FLAG2_LOCAL_HEADER;//在每个关键帧放置全局标题,而不是在extradata中。
encodec->thread_count = 4; //ffmpeg新转码函数支持多线程 配置线程个数
if (encodec->codec_id == AV_CODEC_ID_H264)
{
//encodec->qmin = 10;
//encodec->qmax = 51;
//encodec->qcompress = 0.6;
}
if (encodec->codec_id == AV_CODEC_ID_MPEG2VIDEO)
encodec->max_b_frames = 2;
if (encodec->codec_id == AV_CODEC_ID_MPEG1VIDEO)
encodec->mb_decision = 2;
int ret = avcodec_open2(encodec, enc, NULL);
if (ret < 0) {
cout << "avcodec_open2" << endl;
cin.get();
}
return 0;
}
bool open_decodec(AVCodecContext* &decodec, AVCodec* &c, AVCodecID& codecID) {
c = avcodec_find_decoder(codecID);
if (!c) {
cout << avcodec_find_decoder << endl;
cin.get();
}
int ret = avcodec_open2(decodec, c, NULL);
if (ret < 0) {
cout << "avcodec_open2" << endl;
cin.get();
}
return 0;
}
int open_decodec(AVCodecContext * &decodec, AVFormatContext * ic, int videoidx, AVCodec * &dec)
{
decodec = avcodec_alloc_context3(NULL);
if (avcodec_parameters_to_context(decodec, ic->streams[videoidx]->codecpar) < 0)
{
cout << "Copy stream failed!" << endl;
return -1;
}
dec = avcodec_find_decoder(decodec->codec_id);
if (!dec) {
cout << "Find Decoder failed!" << endl;
return -1;
}
// 打开解码器
if (avcodec_open2(decodec, dec, NULL) != 0) {
cout << "Open codec failed!" << endl;
return -1;
}
return true;
}
int main(){
char path[] = "11.mp4"; //输入视频文件
char outfile[] = "Test.flv"; //输出视频文件
int videoidx = -1; //视频索引标志
int audioidx = -1; //音频索引标志
AVFormatContext *ic = nullptr; //输入上下文
AVFormatContext *oc = nullptr; //输出上下文
AVStream *videoStream = nullptr;//给输出上下文添加的视频流
AVStream *audioStream = nullptr;//给输出上下文添加的音频流
AVCodecContext *decodec_video = nullptr; //解码器上下文_视频
AVCodecContext *encodec_video = nullptr; //编解码器上下文_视频
AVCodec *enc = nullptr; //编码器
AVCodec *dec = nullptr; //解码器
Open_In_fine(path, videoidx, audioidx, ic);
open_encodec(encodec_video, enc, ic->streams[videoidx]->codecpar);
open_decodec(decodec_video, ic, videoidx, dec);
Open_out_file(outfile, videoidx, audioidx, videoStream, audioStream, encodec_video,ic->streams[audioidx]->codec, oc);
//FILE *fp_yuv = fopen("test_out123.yuv", "wb+");
//int y_size = decodec->width*decodec->height;
//fwrite(inyuv->data[0], 1, y_size, fp_yuv); // Y
//fwrite(inyuv->data[1], 1, y_size / 4, fp_yuv); // U
//fwrite(inyuv->data[2], 1, y_size / 4, fp_yuv); // V
//cout << "pkt->size ="<<pkt->size<<endl;
while (true) {
AVPacket* pkt = av_packet_alloc();
av_init_packet(pkt);
AVFrame *inyuv = av_frame_alloc();
if (!(av_read_frame(ic, pkt) >= 0)) {
break;
}
if (pkt->stream_index == videoidx) {
int iRes;
if ((iRes = avcodec_send_packet(decodec_video, pkt)) != 0)
{
cout << "Send video stream packet failed!" << iRes << endl;
continue;
}
if ((iRes = avcodec_receive_frame(decodec_video, inyuv)) != 0)
{
cout << "Receive video frame failed!" << iRes << endl;
continue;
}
iRes = avcodec_send_frame(encodec_video, inyuv);
if (iRes < 0)
{
cout << "编码错误" << endl;
continue;
cin.get();
}
AVPacket* outpkt = av_packet_alloc();
while (iRes >= 0)
{
iRes = avcodec_receive_packet(encodec_video, outpkt);
if (iRes == AVERROR(EAGAIN) || iRes == AVERROR_EOF)
continue;
else if (iRes < 0)
{
fprintf(stderr, "Error during encoding\n");
exit(1);
}
Time_base(outpkt, ic, oc);
av_write_frame(oc,outpkt);
cout << iRes << "**********************" << endl;
printf("Write packet %3lld(size=%5d)\n", outpkt->pts, outpkt->size);
}
av_packet_free(&outpkt);
//av_packet_free(&pkt);
av_frame_free(&inyuv);
}
if (pkt->stream_index == audioidx) {
Time_base(pkt, ic, oc);
av_write_frame(oc,pkt);
//av_packet_free(&pkt);
}
av_packet_free(&pkt);
}
av_write_trailer(oc);
//cin.get();
return 0;
}
ffmpeg视频转码示例
最新推荐文章于 2024-06-22 12:09:26 发布