ffmpeg 将流保存为视频c++示例
时间: 2023-08-10 22:03:28 浏览: 227
FFmpeg - 保存拉流视频
以下是使用FFmpeg将流保存为视频的C++示例代码:
首先,您需要包含FFmpeg的头文件和库文件:
```c++
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swscale.lib")
```
然后,您可以使用以下代码片段将流保存为视频:
```c++
// 打开输入流
AVFormatContext* inputFormatCtx = nullptr;
if (avformat_open_input(&inputFormatCtx, "input_stream_url", nullptr, nullptr) < 0) {
return -1;
}
// 查找流信息
if (avformat_find_stream_info(inputFormatCtx, nullptr) < 0) {
avformat_close_input(&inputFormatCtx);
return -1;
}
// 找到视频流
int videoStreamIndex = -1;
AVCodecParameters* codecPar = nullptr;
for (int i = 0; i < inputFormatCtx->nb_streams; i++) {
if (inputFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
codecPar = inputFormatCtx->streams[i]->codecpar;
break;
}
}
if (videoStreamIndex == -1) {
avformat_close_input(&inputFormatCtx);
return -1;
}
// 初始化解码器和解码器上下文
AVCodec* decoder = avcodec_find_decoder(codecPar->codec_id);
if (decoder == nullptr) {
avformat_close_input(&inputFormatCtx);
return -1;
}
AVCodecContext* decoderCtx = avcodec_alloc_context3(decoder);
if (decoderCtx == nullptr) {
avformat_close_input(&inputFormatCtx);
return -1;
}
if (avcodec_parameters_to_context(decoderCtx, codecPar) < 0) {
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
return -1;
}
if (avcodec_open2(decoderCtx, decoder, nullptr) < 0) {
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
return -1;
}
// 创建输出格式上下文
AVFormatContext* outputFormatCtx = nullptr;
if (avformat_alloc_output_context2(&outputFormatCtx, nullptr, "mp4", "output_video.mp4") < 0) {
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
return -1;
}
// 创建输出视频流
AVStream* videoStream = avformat_new_stream(outputFormatCtx, nullptr);
if (videoStream == nullptr) {
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
AVCodecParameters* videoCodecPar = videoStream->codecpar;
if (avcodec_parameters_copy(videoCodecPar, codecPar) < 0) {
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
videoCodecPar->codec_tag = 0;
// 初始化编码器和编码器上下文
AVCodec* encoder = avcodec_find_encoder(videoCodecPar->codec_id);
if (encoder == nullptr) {
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
AVCodecContext* encoderCtx = avcodec_alloc_context3(encoder);
if (encoderCtx == nullptr) {
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
if (avcodec_parameters_to_context(encoderCtx, videoCodecPar) < 0) {
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
if (avcodec_open2(encoderCtx, encoder, nullptr) < 0) {
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
// 初始化图像转换器
SwsContext* swsCtx = sws_getContext(codecPar->width, codecPar->height, decoderCtx->pix_fmt,
videoCodecPar->width, videoCodecPar->height, encoderCtx->pix_fmt, SWS_BILINEAR, nullptr, nullptr, nullptr);
if (swsCtx == nullptr) {
avcodec_close(encoderCtx);
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
// 打开输出文件
if (!(outputFormatCtx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&outputFormatCtx->pb, "output_video.mp4", AVIO_FLAG_WRITE) < 0) {
avcodec_close(encoderCtx);
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
}
// 写入文件头
if (avformat_write_header(outputFormatCtx, nullptr) < 0) {
avcodec_close(encoderCtx);
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
return -1;
}
// 处理每一帧
AVPacket inputPacket, outputPacket;
av_init_packet(&inputPacket);
av_init_packet(&outputPacket);
inputPacket.data = nullptr;
inputPacket.size = 0;
while (av_read_frame(inputFormatCtx, &inputPacket) >= 0) {
if (inputPacket.stream_index == videoStreamIndex) {
// 解码
int ret = avcodec_send_packet(decoderCtx, &inputPacket);
if (ret < 0) {
av_packet_unref(&inputPacket);
break;
}
while (ret >= 0) {
AVFrame* frame = av_frame_alloc();
ret = avcodec_receive_frame(decoderCtx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_free(&frame);
break;
}
else if (ret < 0) {
av_frame_free(&frame);
av_packet_unref(&inputPacket);
break;
}
// 转换图像格式
AVFrame* outFrame = av_frame_alloc();
outFrame->format = encoderCtx->pix_fmt;
outFrame->width = videoCodecPar->width;
outFrame->height = videoCodecPar->height;
av_frame_get_buffer(outFrame, 0);
sws_scale(swsCtx, frame->data, frame->linesize, 0, codecPar->height, outFrame->data, outFrame->linesize);
// 编码
ret = avcodec_send_frame(encoderCtx, outFrame);
if (ret < 0) {
av_frame_free(&outFrame);
break;
}
while (ret >= 0) {
av_init_packet(&outputPacket);
ret = avcodec_receive_packet(encoderCtx, &outputPacket);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_packet_unref(&outputPacket);
break;
}
else if (ret < 0) {
av_packet_unref(&outputPacket);
av_frame_free(&outFrame);
break;
}
// 写入输出文件
av_packet_rescale_ts(&outputPacket, encoderCtx->time_base, videoStream->time_base);
outputPacket.stream_index = videoStream->index;
av_interleaved_write_frame(outputFormatCtx, &outputPacket);
av_packet_unref(&outputPacket);
}
av_frame_free(&outFrame);
av_frame_free(&frame);
}
}
av_packet_unref(&inputPacket);
}
// 写入文件尾
av_write_trailer(outputFormatCtx);
// 释放资源
avcodec_close(encoderCtx);
avcodec_free_context(&encoderCtx);
avcodec_close(decoderCtx);
avcodec_free_context(&decoderCtx);
avformat_close_input(&inputFormatCtx);
avformat_free_context(outputFormatCtx);
sws_freeContext(swsCtx);
```
需要注意的是,此示例代码仅适用于保存单个视频流。如果您需要保存多个视频流或音频流,请在代码中进行相应的修改。
阅读全文