FFmpeg中编码类型为rawvideo无须解码直接显示测试代码

在 https://blog.csdn.net/fengbingchun/article/details/93975325 中介绍过通过FFmpeg可以直接获取usb视频流并解码显示的测试代码,当时通过usb获取到的视频流编码类型为AV_CODEC_ID_RAWVIDEO,像素格式为AV_PIX_FMT_YUYV422,其实编码类型为rawvideo的视频流可以不经过解码操作直接就可进行显示,测试代码如下:

#include "funset.hpp"
#include 
#include 
#include 
#include 

#ifdef __cplusplus
extern "C" {
#endif

#include 
#include 
#include 
#include 
#include 
#include 

#ifdef __cplusplus
}
#endif

#include 

int test_ffmpeg_stream_show()
{
	avdevice_register_all();

#ifndef _MSC_VER
	const char* input_format_name = "video4linux2";
	const char* url = "/dev/video0";

	AVInputFormat* input_fmt = av_find_input_format(input_format_name);
	AVFormatContext* format_ctx = avformat_alloc_context();

	int ret = avformat_open_input(&format_ctx, url, input_fmt, nullptr);
	if (ret != 0) {
		fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret);
		return -1;
	}

	ret = avformat_find_stream_info(format_ctx, nullptr);
	if (ret < 0) {
		fprintf(stderr, "fail to get stream information: %d\n", ret);
		return -1;
	}

	int video_stream_index = -1;
	for (unsigned int i = 0; i < format_ctx->nb_streams; ++i) {
		const AVStream* stream = format_ctx->streams[i];
		if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
			video_stream_index = i;
			fprintf(stdout, "type of the encoded data: %d, dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n",
				stream->codecpar->codec_id, stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
		}
	}

	if (video_stream_index == -1) {
		fprintf(stderr, "no video stream\n");
		return -1;
	}

	AVCodecParameters* codecpar = format_ctx->streams[video_stream_index]->codecpar;
	const AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
	if (!codec) {
		fprintf(stderr, "fail to avcodec_find_decoder\n");
		return -1;
	}

	AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
	if (!codec_ctx) {
		fprintf(stderr, "fail to avcodec_alloc_context3\n");
		return -1;
	}

	codec_ctx->pix_fmt = AVPixelFormat(codecpar->format);
	codec_ctx->height = codecpar->height;
	codec_ctx->width = codecpar->width;
	codec_ctx->thread_count = 16;
	ret = avcodec_open2(codec_ctx, codec, nullptr);
	if (ret != 0) {
		fprintf(stderr, "fail to avcodec_open2: %d\n", ret);
		return -1;
	}

	AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
	SwsContext* sws_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24, 0, nullptr, nullptr, nullptr);
	if (!packet || !sws_ctx) {
		fprintf(stderr, "fail to alloc\n");
		return -1;
	}

	uint8_t *bgr_data[4], *yuyv422_data[4];
	int bgr_linesize[4], yuyv422_linesize[4];
	av_image_alloc(bgr_data, bgr_linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_BGR24, 1);
	av_image_alloc(yuyv422_data, yuyv422_linesize, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_YUYV422, 1);
	cv::Mat mat(codec_ctx->height, codec_ctx->width, CV_8UC3);
	const char* winname = "usb video";
	cv::namedWindow(winname);
	const uint8_t *srcSlice[1];

	while (1) {
		ret = av_read_frame(format_ctx, packet);
		if (ret >= 0 && packet->stream_index == video_stream_index) {
			srcSlice[0] = packet->data;
			sws_scale(sws_ctx, srcSlice, yuyv422_linesize, 0, codec_ctx->height, bgr_data, bgr_linesize);
			mat.data = bgr_data[0];
			cv::imshow(winname, mat);
		}

		av_packet_unref(packet);

		int key = cv::waitKey(25);
		if (key == 27) break;
	}

	cv::destroyWindow(winname);
	sws_freeContext(sws_ctx);
	avformat_close_input(&format_ctx);
	av_freep(packet);
	av_freep(&bgr_data[0]);
	av_freep(&yuyv422_data[0]);

	fprintf(stdout, "test finish\n");

	return 0;
#else
	fprintf(stderr, "Error: this interface only support usb camera: encode type: rawvideo\n");
	return -1;
#endif
}

执行结果如下:

FFmpeg中编码类型为rawvideo无须解码直接显示测试代码_第1张图片

GitHub:https://github.com//fengbingchun/OpenCV_Test

你可能感兴趣的:(ffmpeg,usb)