FFmpeg中libswscale库简介及测试代码

libswscale库功能主要包括高度优化的图像缩放、颜色空间和像素格式转换操作。

以下是测试代码(test_ffmpeg_libswscale.cpp):

#include "funset.hpp"
#include <string.h>
#include <iostream>
#include <string>
#include <memory>
#include <fstream>

#include <opencv2/opencv.hpp>

#ifdef __cplusplus
extern "C" {
#endif

#include <libswscale/swscale.h>
#include <libavutil/mem.h>
#include <libavutil/imgutils.h>

#ifdef __cplusplus
}
#endif


int test_ffmpeg_libswscale_bgr_yuv()
{
#ifdef _MSC_VER
	const char* image_name = "E:/GitCode/OpenCV_Test/test_images/lena.png";
#else
	const char* image_name = "test_images/lena.png";
#endif
	cv::Mat mat = cv::imread(image_name, 1);
	if (!mat.data || mat.channels() != 3) {
		fprintf(stdout, "fail to read image: %s\n", image_name);
		return -1;
	}

	int width = mat.cols, height = mat.rows;
	std::unique_ptr<unsigned char[]> data(new unsigned char[width * height * 3 / 2]);
	std::unique_ptr<unsigned char[]> data2(new unsigned char[width * height * 3 / 2]);

{ // bgr --> yuv420p
	int align = 1;
	uint8_t *bgr_data[4], *yuv420p_data[4];
	int bgr_linesize[4], yuv420p_linesize[4];
	int bytes1 = av_image_alloc(bgr_data, bgr_linesize, width, height, AV_PIX_FMT_BGR24, align);
	memcpy(bgr_data[0], mat.data, width*height * 3);
	int bytes2 = av_image_alloc(yuv420p_data, yuv420p_linesize, width, height, AV_PIX_FMT_YUV420P, align);
	fprintf(stdout, "bgr size: %d, linesize: %d, %d, %d, yuv420p size: %d, linesize: %d, %d, %d\n",
		bytes1, bgr_linesize[0], bgr_linesize[1], bgr_linesize[2], bytes2, yuv420p_linesize[0], yuv420p_linesize[1], yuv420p_linesize[2]);
	if (bytes1 < 0 || bytes2 < 0) {
		fprintf(stderr, "bgr or yuv420p alloc buffer failed: %d, %d\n", bytes1, bytes2);
		return -1;
	}

	SwsContext* sws_ctx = sws_getContext(width, height, AV_PIX_FMT_BGR24, width, height, AV_PIX_FMT_YUV420P, 0, nullptr, nullptr, nullptr);
	if (!sws_ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}

	sws_scale(sws_ctx, bgr_data, bgr_linesize, 0, height, yuv420p_data, yuv420p_linesize);

#ifdef _MSC_VER
	const char* name = "E:/GitCode/OpenCV_Test/test_images/512w_512h.yuv420p";
#else
	const char* name = "test_images/512w_512h.yuv420p";
#endif
	std::ofstream fout(name, std::ios::out | std::ios::binary);
	if (!fout.is_open()) {
		fprintf(stderr, "fail to open file: %s\n", name);
		return -1;
	}

	memcpy(data.get(), yuv420p_data[0], width*height);
	memcpy(data.get() + width*height, yuv420p_data[1], width*height / 4);
	memcpy(data.get() + width*height * 5 / 4, yuv420p_data[2], width*height / 4);

	fout.write((char*)data.get(), width * height * 3 / 2);

	fout.close();
	av_freep(&bgr_data[0]);
	av_freep(&yuv420p_data[0]);
	sws_freeContext(sws_ctx);
}

{ // yuv420p --> bgr24
	int align = 1;
	uint8_t *bgr_data[4], *yuv420p_data[4];
	int bgr_linesize[4], yuv420p_linesize[4];
	int bytes1 = av_image_alloc(bgr_data, bgr_linesize, width, height, AV_PIX_FMT_BGR24, align);
	int bytes2 = av_image_alloc(yuv420p_data, yuv420p_linesize, width, height, AV_PIX_FMT_YUV420P, align);
	memcpy(yuv420p_data[0], data.get(), width*height);
	memcpy(yuv420p_data[1], data.get() + width*height, width*height / 4);
	memcpy(yuv420p_data[2], data.get() + width*height * 5 / 4, width*height / 4);
	fprintf(stdout, "bgr size: %d, linesize: %d, %d, %d, yuv420p size: %d, linesize: %d, %d, %d\n",
		bytes1, bgr_linesize[0], bgr_linesize[1], bgr_linesize[2], bytes2, yuv420p_linesize[0], yuv420p_linesize[1], yuv420p_linesize[2]);
	if (bytes1 < 0 || bytes2 < 0) {
		fprintf(stderr, "bgr or yuv420p alloc buffer failed: %d, %d\n", bytes1, bytes2);
		return -1;
	}

	SwsContext* sws_ctx = sws_getContext(width, height, AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_BGR24, 0, nullptr, nullptr, nullptr);
	if (!sws_ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}

	sws_scale(sws_ctx, yuv420p_data, yuv420p_linesize, 0, height, bgr_data, bgr_linesize);

#ifdef _MSC_VER
	const char* name = "E:/GitCode/OpenCV_Test/test_images/yuv420ptobgr24.jpg";
#else
	const char* name = "test_images/yuv420ptobgr24.jpg";
#endif

	cv::Mat dst(height, width, CV_8UC3, bgr_data[0]);
	cv::imwrite(name, dst);

	av_freep(&bgr_data[0]);
	av_freep(&yuv420p_data[0]);
	sws_freeContext(sws_ctx);
}

{ // bgr --> nv12
	int align = 1;
	uint8_t *bgr_data[4], *nv12_data[4];
	int bgr_linesize[4], nv12_linesize[4];
	int bytes1 = av_image_alloc(bgr_data, bgr_linesize, width, height, AV_PIX_FMT_BGR24, align);
	memcpy(bgr_data[0], mat.data, width*height * 3);
	int bytes2 = av_image_alloc(nv12_data, nv12_linesize, width, height, AV_PIX_FMT_NV12, align);
	fprintf(stdout, "bgr size: %d, linesize: %d, %d, %d, nv12 size: %d, linesize: %d, %d, %d\n",
		bytes1, bgr_linesize[0], bgr_linesize[1], bgr_linesize[2], bytes2, nv12_linesize[0], nv12_linesize[1], nv12_linesize[2]);
	if (bytes1 < 0 || bytes2 < 0) {
		fprintf(stderr, "bgr or nv12 alloc buffer failed: %d, %d\n", bytes1, bytes2);
		return -1;
	}

	SwsContext* sws_ctx = sws_getContext(width, height, AV_PIX_FMT_BGR24, width, height, AV_PIX_FMT_NV12, 0, nullptr, nullptr, nullptr);
	if (!sws_ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}

	sws_scale(sws_ctx, bgr_data, bgr_linesize, 0, height, nv12_data, nv12_linesize);

#ifdef _MSC_VER
	const char* name = "E:/GitCode/OpenCV_Test/test_images/512w_512h.nv12";
#else
	const char* name = "test_images/512w_512h.nv12";
#endif
	std::ofstream fout(name, std::ios::out | std::ios::binary);
	if (!fout.is_open()) {
		fprintf(stderr, "fail to open file: %s\n", name);
		return -1;
	}

	memcpy(data2.get(), nv12_data[0], width*height);
	memcpy(data2.get() + width*height, nv12_data[1], width*height / 2);

	fout.write((char*)data2.get(), width * height * 3 / 2);

	fout.close();
	av_freep(&bgr_data[0]);
	av_freep(&nv12_data[0]);
	sws_freeContext(sws_ctx);
}

{ // nv12 --> bgr24
	int align = 1;
	uint8_t *bgr_data[4], *nv12_data[4];
	int bgr_linesize[4], nv12_linesize[4];
	int bytes1 = av_image_alloc(bgr_data, bgr_linesize, width, height, AV_PIX_FMT_BGR24, align);
	int bytes2 = av_image_alloc(nv12_data, nv12_linesize, width, height, AV_PIX_FMT_NV12, align);
	memcpy(nv12_data[0], data2.get(), width*height);
	memcpy(nv12_data[1], data2.get() + width*height, width*height / 2);
	fprintf(stdout, "bgr size: %d, linesize: %d, %d, %d, nv12 size: %d, linesize: %d, %d, %d\n",
		bytes1, bgr_linesize[0], bgr_linesize[1], bgr_linesize[2], bytes2, nv12_linesize[0], nv12_linesize[1], nv12_linesize[2]);
	if (bytes1 < 0 || bytes2 < 0) {
		fprintf(stderr, "bgr or nv12 alloc buffer failed: %d, %d\n", bytes1, bytes2);
		return -1;
	}

	SwsContext* sws_ctx = sws_getContext(width, height, AV_PIX_FMT_NV12, width, height, AV_PIX_FMT_BGR24, 0, nullptr, nullptr, nullptr);
	if (!sws_ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}

	sws_scale(sws_ctx, nv12_data, nv12_linesize, 0, height, bgr_data, bgr_linesize);

#ifdef _MSC_VER
	const char* name = "E:/GitCode/OpenCV_Test/test_images/nv12tobgr24.jpg";
#else
	const char* name = "test_images/nv12tobgr24.jpg";
#endif

	cv::Mat dst(height, width, CV_8UC3, bgr_data[0]);
	cv::imwrite(name, dst);

	av_freep(&bgr_data[0]);
	av_freep(&nv12_data[0]);
	sws_freeContext(sws_ctx);
}

	return 0;
}

int test_ffmpeg_libswscale_scale()
{
	// bgr to rgb and resize
#ifdef _MSC_VER
	const char* image_name = "E:/GitCode/OpenCV_Test/test_images/lena.png";
#else
	const char* image_name = "test_images/lena.png";	
#endif
	cv::Mat src = cv::imread(image_name, 1); 
	if (!src.data || src.channels() != 3) {
		fprintf(stderr, "fail to read image: %s\n", image_name);
		return -1;
	}
	
	int width_src = src.cols, height_src = src.rows;
	int width_dst = width_src / 1.5, height_dst = height_src / 1.2;
	std::unique_ptr<uint8_t[]> data(new uint8_t[width_dst * height_dst * 3]);

	SwsContext* ctx = sws_getContext(width_src, height_src, AV_PIX_FMT_BGR24, width_dst, height_dst, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
	if (!ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}
	
	const uint8_t* p1[1] = {(const uint8_t*)src.data};
	uint8_t* p2[1] = {data.get()};
	int src_stride[1] = {width_src * 3};
	int dst_stride[1] = {width_dst * 3};
	sws_scale(ctx, p1, src_stride, 0, height_src, p2, dst_stride);
#ifdef _MSC_VER
	const char* result_image_name = "E:/GitCode/OpenCV_Test/test_images/lena_resize_rgb_libswscale.png";
#else
	const char* result_image_name = "test_images/lena_resize_rgb_libswscale.png";
#endif
	cv::Mat dst(height_dst, width_dst, CV_8UC3, (unsigned char*)data.get());
	cv::imwrite(result_image_name, dst);

	sws_freeContext(ctx);
	
	return 0;
}

int test_ffmpeg_libswscale_colorspace()
{
	fprintf(stdout, "swscale configuration: %s\n", swscale_configuration());
	fprintf(stdout, "swscale license: %s\n", swscale_license());

	AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
	fprintf(stdout, "is supported input:: %d\n", sws_isSupportedInput(pix_fmt));

	pix_fmt = AV_PIX_FMT_BGR24;
	fprintf(stdout, "is supported output: %d\n", sws_isSupportedOutput(pix_fmt));

	pix_fmt = AV_PIX_FMT_GRAY8;
	fprintf(stdout, "is supported endianness conversion: %d\n", sws_isSupportedEndiannessConversion(pix_fmt));

	// bgr to gray
#ifdef _MSC_VER
	const char* image_name = "E:/GitCode/OpenCV_Test/test_images/lena.png";
#else
	const char* image_name = "test_images/lena.png";	
#endif
	cv::Mat src = cv::imread(image_name, 1); 
	if (!src.data || src.channels() != 3) {
		fprintf(stderr, "fail to read image: %s\n", image_name);
		return -1;
	}
	
	int width = src.cols, height = src.rows;
	std::unique_ptr<uint8_t[]> data(new uint8_t[width * height]);

	SwsContext* ctx = sws_getContext(width, height, AV_PIX_FMT_BGR24, width, height, AV_PIX_FMT_GRAY8, 0, nullptr, nullptr, nullptr);
	if (!ctx) {
		fprintf(stderr, "fail to sws_getContext\n");
		return -1;
	}
	
	const uint8_t* p1[1] = {(const uint8_t*)src.data};
	uint8_t* p2[1] = {data.get()};
	int src_stride[1] = {width*3};
	int dst_stride[1] = {width};
	sws_scale(ctx, p1, src_stride, 0, height, p2, dst_stride);
#ifdef _MSC_VER
	const char* result_image_name = "E:/GitCode/OpenCV_Test/test_images/lena_gray_libswscale.png";
#else
	const char* result_image_name = "test_images/lena_gray_libswscale.png";
#endif
	cv::Mat dst(height, width, CV_8UC1, (unsigned char*)data.get());
	cv::imwrite(result_image_name, dst);

	sws_freeContext(ctx);

	return 0;
}

其中test_ffmpeg_libswscale_scale的执行结果如下:

GitHubhttps://github.com/fengbingchun/OpenCV_Test

你可以使用 FFmpeg 来进行帧的纯色检测。下面是一个示例代码,它使用 FFmpeg 的 C API 来实现纯色检测: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <libavutil/avutil.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> #define FRAME_THRESHOLD 0.95 // 帧的纯色阈值 int is_frame_pure_color(uint8_t *data, int linesize, int width, int height) { int i, j; int r, g, b; int count = 0; int total_pixels = width * height; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { r = data[i * linesize + j * 3]; g = data[i * linesize + j * 3 + 1]; b = data[i * linesize + j * 3 + 2]; if (r == g && g == b) { count++; } } } double ratio = (double)count / total_pixels; return ratio >= FRAME_THRESHOLD ? 1 : 0; } int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s input_file\n", argv[0]); return -1; } const char *input_file = argv[1]; av_log_set_level(AV_LOG_ERROR); // 设置日志级别为错误 AVFormatContext *format_ctx = NULL; AVCodecContext *codec_ctx = NULL; AVCodec *codec = NULL; AVFrame *frame = NULL; AVPacket packet; struct SwsContext *sws_ctx = NULL; if (avformat_open_input(&format_ctx, input_file, NULL, NULL) != 0) { printf("Failed to open input file\n"); return -1; } if (avformat_find_stream_info(format_ctx, NULL) < 0) { printf("Failed to find stream information\n"); return -1; } int video_stream_index = -1; for (int i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; break; } } if (video_stream_index == -1) { printf("Failed to find video stream\n"); return -1; } codec = avcodec_find_decoder(format_ctx->streams[video_stream_index]->codecpar->codec_id); if (!codec) { printf("Failed to find decoder\n"); return -1; } codec_ctx = avcodec_alloc_context3(codec); if (!codec_ctx) { printf("Failed to allocate codec context\n"); return -1; } if (avcodec_parameters_to_context(codec_ctx, format_ctx->streams[video_stream_index]->codecpar) < 0) { printf("Failed to copy codec parameters to codec context\n"); return -1; } if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("Failed to open codec\n"); return -1; } frame = av_frame_alloc(); if (!frame) { printf("Failed to allocate frame\n"); return -1; } sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, 0, NULL, NULL, NULL); if (!sws_ctx) { printf("Failed to initialize sws context\n"); return -1; } int frame_count = 0; while (av_read_frame(format_ctx, &packet) >= 0) { if (packet.stream_index == video_stream_index) { if (avcodec_send_packet(codec_ctx, &packet) < 0) { printf("Failed to send packet for decoding\n"); break; } while (avcodec_receive_frame(codec_ctx, frame) >= 0) { AVFrame *rgb_frame = av_frame_alloc(); if (!rgb_frame) { printf("Failed to allocate RGB frame\n"); break; } uint8_t *rgb_buffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1)); av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, rgb_buffer, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height, 1); sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, rgb_frame->data, rgb_frame->linesize); int is_pure_color = is_frame_pure_color(rgb_frame->data[0], rgb_frame->linesize[0], codec_ctx->width, codec_ctx->height); printf("Frame %d is %s\n", frame_count, is_pure_color ? "pure color" : "not pure color"); av_frame_free(&rgb_frame); av_free(rgb_buffer); frame_count++; } } av_packet_unref(&packet); } av_frame_free(&frame); avcodec_close(codec_ctx); avformat_close_input(&format_ctx); return 0; } ``` 这段代码使用了 FFmpeg 的 C API 来读取视频帧,并将每一帧转换为 RGB 格式,然后进行纯色检测。你可以将视频文件路径作为命令行参数传递给程序来进行测试。程序会输出每一帧是否为纯色帧。 这只是一个简单的示例代码,你可以根据自己的需求进行修改和扩展。请确保已正确安装 FFmpeg ,并在编译时链接相应的文件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值