mfc 中ffmpeg yuy2字节流转图片代码
时间: 2023-08-27 21:00:56 浏览: 103
MFC_SDL2_FFMPEG声音播放器例程
以下是在MFC中使用FFmpeg将YUY2格式的字节流转换为图片的代码示例:
```c++
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <exception>
#include <algorithm>
#include <functional>
#include <codecvt>
#include <locale>
#include "ffmpeg.h"
// YUV420P转RGB24
void YUV420P_to_RGB24(unsigned char* yuvData, unsigned char* rgbData, int width, int height)
{
unsigned char* yData = yuvData;
unsigned char* uData = yuvData + width * height;
unsigned char* vData = yuvData + width * height * 5 / 4;
int r, g, b, y, u, v;
for (int i = 0, j = 0; i < width * height; i++, j += 3)
{
y = (int)(yData[i] - 16);
u = (int)(uData[i / 4] - 128);
v = (int)(vData[i / 4] - 128);
r = (int)(1.164 * y + 1.596 * v);
g = (int)(1.164 * y - 0.813 * v - 0.391 * u);
b = (int)(1.164 * y + 2.018 * u);
r = std::max(0, std::min(255, r));
g = std::max(0, std::min(255, g));
b = std::max(0, std::min(255, b));
rgbData[j] = r;
rgbData[j + 1] = g;
rgbData[j + 2] = b;
}
}
// YUY2转RGB24
void YUY2_to_RGB24(unsigned char* yuy2Data, unsigned char* rgbData, int width, int height)
{
unsigned char* yData = yuy2Data;
unsigned char* uData = yuy2Data + 1;
unsigned char* vData = yuy2Data + 3;
int r, g, b, y, u, v;
for (int i = 0, j = 0; i < width * height / 2; i++, j += 6)
{
y = (int)(yData[i * 2] - 16);
u = (int)(uData[i] - 128);
v = (int)(vData[i] - 128);
r = (int)(1.164 * y + 1.596 * v);
g = (int)(1.164 * y - 0.813 * v - 0.391 * u);
b = (int)(1.164 * y + 2.018 * u);
r = std::max(0, std::min(255, r));
g = std::max(0, std::min(255, g));
b = std::max(0, std::min(255, b));
rgbData[j] = r;
rgbData[j + 1] = g;
rgbData[j + 2] = b;
y = (int)(yData[i * 2 + 1] - 16);
r = (int)(1.164 * y + 1.596 * v);
g = (int)(1.164 * y - 0.813 * v - 0.391 * u);
b = (int)(1.164 * y + 2.018 * u);
r = std::max(0, std::min(255, r));
g = std::max(0, std::min(255, g));
b = std::max(0, std::min(255, b));
rgbData[j + 3] = r;
rgbData[j + 4] = g;
rgbData[j + 5] = b;
}
}
// YUY2字节流转换为图片
bool YUY2ToImage(const char* yuy2Data, int dataSize, int width, int height, const char* imageFile)
{
bool ret = false;
try
{
// 初始化FFmpeg
av_register_all();
avcodec_register_all();
// 获取YUY2格式解码器
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_YUYV422);
if (!codec)
{
throw std::exception("avcodec_find_decoder failed");
}
// 创建解码器上下文
AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx)
{
throw std::exception("avcodec_alloc_context3 failed");
}
// 打开解码器
if (avcodec_open2(codecCtx, codec, NULL) < 0)
{
throw std::exception("avcodec_open2 failed");
}
// 创建AVPacket和AVFrame
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = (uint8_t*)yuy2Data;
pkt.size = dataSize;
AVFrame* frame = av_frame_alloc();
if (!frame)
{
throw std::exception("av_frame_alloc failed");
}
// 填充AVFrame数据
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_YUYV422;
avpicture_fill((AVPicture*)frame, (uint8_t*)yuy2Data, AV_PIX_FMT_YUYV422, width, height);
// 创建AVFrame用于存储转换后的RGB24数据
AVFrame* rgbFrame = av_frame_alloc();
if (!rgbFrame)
{
throw std::exception("av_frame_alloc failed");
}
// 设置AVFrame的参数
rgbFrame->width = width;
rgbFrame->height = height;
rgbFrame->format = AV_PIX_FMT_RGB24;
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, width, height);
uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture*)rgbFrame, buffer, AV_PIX_FMT_RGB24, width, height);
// 转换YUY2到RGB24
YUY2_to_RGB24(yuy2Data, rgbFrame->data[0], width, height);
// 创建输出文件
FILE* outFile = NULL;
fopen_s(&outFile, imageFile, "wb");
if (!outFile)
{
throw std::exception("open output file failed");
}
// 初始化AVFormatContext
AVFormatContext* formatCtx = avformat_alloc_context();
if (!formatCtx)
{
throw std::exception("avformat_alloc_context failed");
}
// 设置输出格式
AVOutputFormat* outputFmt = av_guess_format(NULL, imageFile, NULL);
if (!outputFmt)
{
throw std::exception("av_guess_format failed");
}
formatCtx->oformat = outputFmt;
// 创建AVIOContext
if (avio_open(&formatCtx->pb, imageFile, AVIO_FLAG_WRITE) < 0)
{
throw std::exception("avio_open failed");
}
// 创建AVStream
AVStream* stream = avformat_new_stream(formatCtx, codec);
if (!stream)
{
throw std::exception("avformat_new_stream failed");
}
// 设置AVCodecContext
AVCodecContext* outCodecCtx = stream->codec;
outCodecCtx->codec = codec;
outCodecCtx->codec_id = codec->id;
outCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
outCodecCtx->width = width;
outCodecCtx->height = height;
outCodecCtx->pix_fmt = AV_PIX_FMT_RGB24;
outCodecCtx->time_base.num = 1;
outCodecCtx->time_base.den = 25;
// 写入文件头
avformat_write_header(formatCtx, NULL);
// 写入视频帧
AVPacket packet;
av_init_packet(&packet);
packet.data = rgbFrame->data[0];
packet.size = numBytes;
packet.pts = 0;
packet.dts = 0;
packet.duration = 1;
packet.stream_index = stream->index;
av_interleaved_write_frame(formatCtx, &packet);
// 写入文件尾
av_write_trailer(formatCtx);
// 释放资源
av_frame_free(&rgbFrame);
av_free(buffer);
av_frame_free(&frame);
avcodec_close(codecCtx);
avcodec_free_context(&codecCtx);
avformat_free_context(formatCtx);
fclose(outFile);
ret = true;
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return ret;
}
```
在函数 `YUY2ToImage` 中,首先初始化FFmpeg库,并获取YUY2格式的解码器。然后创建解码器上下文,并打开解码器。接着创建AVPacket和AVFrame,填充AVFrame数据,并创建AVFrame用于存储转换后的RGB24数据。通过调用转换函数`YUY2_to_RGB24`,将YUY2格式的字节流转换为RGB24格式。然后创建输出文件,并初始化AVFormatContext,设置输出格式和AVIOContext。接着创建AVStream,设置AVCodecContext,并写入文件头。最后,将转换后的RGB24数据写入文件,并写入文件尾,最后释放资源。
请注意,在使用这个函数之前,在项目属性中添加FFmpeg库和头文件路径,以及链接FFmpeg库。
希望这可以帮助到你!
阅读全文