帮我编程实现视频的编解码应用:使用现有编解码器ffmpeg,将原始视频进行编码、解码得到重建视频,分析压缩码率与视频质量的关系。打开的原始视频为CIF格式,使用opencv,C++语言
时间: 2024-06-08 07:08:37 浏览: 152
Delphi FFmpeg VCL Components-音视频编解码.rar
好的,下面是一个简单的使用ffmpeg进行视频编解码的示例代码。请注意,此代码仅支持CIF格式的视频,如果需要处理其他格式的视频,需要进行相应的修改。
```c++
#include <iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
using namespace std;
int main(int argc, char* argv[])
{
// 打开原始视频文件
AVFormatContext* pFormatCtx = NULL;
if (avformat_open_input(&pFormatCtx, "input.cif", NULL, NULL) != 0)
{
cout << "无法打开视频文件!" << endl;
return -1;
}
// 获取视频流信息
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
cout << "无法获取视频流信息!" << endl;
return -1;
}
// 找到视频流
int videoStream = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if (videoStream == -1)
{
cout << "无法找到视频流!" << endl;
return -1;
}
// 获取视频编解码器
AVCodecParameters* pCodecParams = pFormatCtx->streams[videoStream]->codecpar;
AVCodec* pCodec = avcodec_find_decoder(pCodecParams->codec_id);
if (pCodec == NULL)
{
cout << "无法找到视频编解码器!" << endl;
return -1;
}
// 打开视频编解码器
AVCodecContext* pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx, pCodecParams) < 0)
{
cout << "无法打开视频编解码器!" << endl;
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
cout << "无法打开视频编解码器!" << endl;
return -1;
}
// 获取视频的帧率、宽度和高度
double frameRate = av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate);
int width = pCodecCtx->width;
int height = pCodecCtx->height;
// 创建SwsContext对象,用于图像格式转换
SwsContext* pSwsCtx = sws_getContext(width, height, pCodecCtx->pix_fmt,
width, height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
if (pSwsCtx == NULL)
{
cout << "无法创建SwsContext对象!" << endl;
return -1;
}
// 创建输出视频文件
AVFormatContext* pOutputFormatCtx = NULL;
if (avformat_alloc_output_context2(&pOutputFormatCtx, NULL, NULL, "output.mp4") < 0)
{
cout << "无法创建输出视频文件!" << endl;
return -1;
}
// 添加视频流
AVStream* pOutputStream = avformat_new_stream(pOutputFormatCtx, NULL);
if (pOutputStream == NULL)
{
cout << "无法创建视频流!" << endl;
return -1;
}
pOutputStream->time_base = av_inv_q(av_d2q(frameRate, 1000000));
// 获取视频编码器
AVCodec* pOutputCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (pOutputCodec == NULL)
{
cout << "无法找到视频编码器!" << endl;
return -1;
}
// 设置视频编码器参数
AVCodecContext* pOutputCodecCtx = avcodec_alloc_context3(pOutputCodec);
pOutputCodecCtx->width = width;
pOutputCodecCtx->height = height;
pOutputCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
pOutputCodecCtx->time_base = pOutputStream->time_base;
pOutputCodecCtx->gop_size = 10;
if (pOutputFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
{
pOutputCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
if (avcodec_open2(pOutputCodecCtx, pOutputCodec, NULL) < 0)
{
cout << "无法打开视频编码器!" << endl;
return -1;
}
// 打开输出视频文件
if (!(pOutputFormatCtx->oformat->flags & AVFMT_NOFILE))
{
if (avio_open(&pOutputFormatCtx->pb, "output.mp4", AVIO_FLAG_WRITE) < 0)
{
cout << "无法打开输出视频文件!" << endl;
return -1;
}
}
// 写入输出文件头
if (avformat_write_header(pOutputFormatCtx, NULL) < 0)
{
cout << "无法写入输出文件头!" << endl;
return -1;
}
// 循环读取原始视频帧并编码
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
int frameCount = 0;
AVFrame* pFrame = av_frame_alloc();
while (av_read_frame(pFormatCtx, &pkt) >= 0)
{
if (pkt.stream_index == videoStream)
{
// 解码视频帧
int ret = avcodec_send_packet(pCodecCtx, &pkt);
while (ret >= 0)
{
ret = avcodec_receive_frame(pCodecCtx, pFrame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
cout << "无法解码视频帧!" << endl;
return -1;
}
// 转换图像格式
AVFrame* pOutputFrame = av_frame_alloc();
pOutputFrame->width = width;
pOutputFrame->height = height;
pOutputFrame->format = AV_PIX_FMT_YUV420P;
av_frame_get_buffer(pOutputFrame, 0);
sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, height,
pOutputFrame->data, pOutputFrame->linesize);
// 编码视频帧
pOutputFrame->pts = av_rescale_q(frameCount++, av_make_q(1, frameRate), pOutputCodecCtx->time_base);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
ret = avcodec_send_frame(pOutputCodecCtx, pOutputFrame);
while (ret >= 0)
{
ret = avcodec_receive_packet(pOutputCodecCtx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
cout << "无法编码视频帧!" << endl;
return -1;
}
// 写入输出文件
pkt.stream_index = pOutputStream->index;
av_packet_rescale_ts(&pkt, pOutputCodecCtx->time_base, pOutputStream->time_base);
av_interleaved_write_frame(pOutputFormatCtx, &pkt);
av_packet_unref(&pkt);
}
av_frame_free(&pOutputFrame);
}
}
av_packet_unref(&pkt);
}
// 刷新编码器缓冲区
int ret = avcodec_send_frame(pOutputCodecCtx, NULL);
while (ret >= 0)
{
ret = avcodec_receive_packet(pOutputCodecCtx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
cout << "无法编码视频帧!" << endl;
return -1;
}
// 写入输出文件
pkt.stream_index = pOutputStream->index;
av_packet_rescale_ts(&pkt, pOutputCodecCtx->time_base, pOutputStream->time_base);
av_interleaved_write_frame(pOutputFormatCtx, &pkt);
av_packet_unref(&pkt);
}
// 写入输出文件尾
av_write_trailer(pOutputFormatCtx);
// 释放资源
avcodec_free_context(&pCodecCtx);
avformat_close_input(&pFormatCtx);
avformat_free_context(pOutputFormatCtx);
sws_freeContext(pSwsCtx);
av_frame_free(&pFrame);
return 0;
}
```
你可以在此基础上进行修改,添加压缩码率和视频质量的分析部分。
阅读全文