c++ ffmpeg 取一帧存为jgp
时间: 2024-01-29 10:10:45 浏览: 126
C++源码 使用Ffmpeg 获取 视频流中的关键帧
以下是使用C++和FFmpeg将一帧YUV数据保存为JPEG图片的示例代码:
```cpp
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <fstream>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
void save_frame_as_jpeg(uint8_t* frame_data, int width, int height, const char* output_filename) {
AVCodec* codec;
AVCodecContext* codec_context;
AVFrame* frame;
AVPacket packet;
struct SwsContext* sws_context;
av_register_all();
// 初始化输入帧
frame = av_frame_alloc();
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_YUV420P;
// 分配缓冲区
int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
uint8_t* buffer = (uint8_t*)av_malloc(buffer_size);
av_image_fill_arrays(frame->data, frame->linesize, buffer, AV_PIX_FMT_YUV420P, width, height, 1);
// 将YUV数据复制到输入帧
int y_size = width * height;
memcpy(frame->data[0], frame_data, y_size); // Y
memcpy(frame->data[1], frame_data + y_size, y_size / 4); // U
memcpy(frame->data[2], frame_data + y_size + y_size / 4, y_size / 4); // V
// 初始化输出文件
AVFormatContext* format_context = nullptr;
avformat_alloc_output_context2(&format_context, nullptr, nullptr, output_filename);
if (!format_context) {
std::cerr << "Failed to allocate output format context" << std::endl;
return;
}
// 查找JPEG编码器
codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG);
if (!codec) {
std::cerr << "Failed to find JPEG encoder" << std::endl;
return;
}
// 初始化编码器上下文
codec_context = avcodec_alloc_context3(codec);
codec_context->pix_fmt = AV_PIX_FMT_YUVJ420P;
codec_context->width = width;
codec_context->height = height;
codec_context->time_base = {1, 25}; // 假设帧率为25fps
// 打开编码器
if (avcodec_open2(codec_context, codec, nullptr) < 0) {
std::cerr << "Failed to open JPEG encoder" << std::endl;
return;
}
// 创建输出流
AVStream* stream = avformat_new_stream(format_context, codec);
if (!stream) {
std::cerr << "Failed to create output stream" << std::endl;
return;
}
// 将编码器上下文复制到输出流
avcodec_parameters_from_context(stream->codecpar, codec_context);
// 打开输出文件
if (avio_open(&format_context->pb, output_filename, AVIO_FLAG_WRITE) < 0) {
std::cerr << "Failed to open output file" << std::endl;
return;
}
// 写入文件头
avformat_write_header(format_context, nullptr);
// 初始化SWS上下文
sws_context = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_YUVJ420P, 0, nullptr, nullptr, nullptr);
if (!sws_context) {
std::cerr << "Failed to initialize SWS context" << std::endl;
return;
}
// 将输入帧转换为输出帧
AVFrame* output_frame = av_frame_alloc();
output_frame->width = width;
output_frame->height = height;
output_frame->format = AV_PIX_FMT_YUVJ420P;
av_image_fill_arrays(output_frame->data, output_frame->linesize, nullptr, AV_PIX_FMT_YUVJ420P, width, height, 1);
sws_scale(sws_context, frame->data, frame->linesize, 0, height, output_frame->data, output_frame->linesize);
// 编码并写入输出文件
av_init_packet(&packet);
packet.data = nullptr;
packet.size = 0;
avcodec_send_frame(codec_context, output_frame);
while (avcodec_receive_packet(codec_context, &packet) == 0) {
av_write_frame(format_context, &packet);
av_packet_unref(&packet);
}
// 写入文件尾
av_write_trailer(format_context);
// 清理资源
av_frame_free(&frame);
av_frame_free(&output_frame);
avcodec_free_context(&codec_context);
avformat_free_context(format_context);
av_free(buffer);
sws_freeContext(sws_context);
}
int main() {
// 假设已经获取到一帧YUV数据,存储在frame_data中
uint8_t* frame_data = nullptr;
int width = 640;
int height = 480;
// 保存为JPEG图片
save_frame_as_jpeg(frame_data, width, height, "output.jpg");
return 0;
}
```
阅读全文