ffmpeg新旧接口实现视频解码h264流并显示

旧接口示例

int test_ffmpeg_decode_show_old()
{
	av_register_all();   //API注册

#ifdef _MSC_VER
	const char* url = "";   //rtsp地址
#else
	const char* url = "/dev/video0";
#endif
	AVFormatContext* format_ctx = avformat_alloc_context();  //定义封装结构体
	int ret = avformat_open_input(&format_ctx, url, nullptr, nullptr);  //将url句柄挂载至format_ctx
	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;
        /*穷举所有的流信息,判断是否为VMEDIA_TYPE_VIDEO类型*/
	for (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;
	}
        /*查找解码器*/
        /*首先从输入的AVFormatContext中得到stream,然后从stream中根据编码器的CodeID获得对应的Decoder*/
	AVCodecContext* codec_ctx = format_ctx->streams[video_stream_index]->codec;
	AVCodec* codec = avcodec_find_decoder(codec_ctx->codec_id);
	if (!codec) {
		fprintf(stderr, "no decoder was found\n");
		return -1;
	}
        /*打开解码器*/
	ret = avcodec_open2(codec_ctx, codec, nullptr);
	if (ret != 0) {
		fprintf(stderr, "fail to init AVCodecContext: %d\n", ret);
		return -1;
	}

	AVFrame* frame = av_frame_alloc();  //用于存储解码后的数据
	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 (!frame || !packet || !sws_ctx) {
		fprintf(stderr, "fail to alloc\n");
		return -1;
	}

	int got_picture = -1;
	std::unique_ptr<uint8_t[]> data(new uint8_t[codec_ctx->width * codec_ctx->height * 3]);
	cv::Mat mat(codec_ctx->height, codec_ctx->width, CV_8UC3);
	int width_new = 640, height_new = 360;
	cv::Mat dst(height_new, width_new, CV_8UC3);
	const char* winname = "usb video1";
	cv::namedWindow(winname);

	while (1) {
		ret = av_read_frame(format_ctx, packet);  //从format_ctx读取音视频数据包
		if (ret < 0) {
			fprintf(stderr, "fail to av_read_frame: %d\n", ret);
			continue;
		}

		if (packet->stream_index == video_stream_index) {
                        /*帧解码*/
			ret = avcodec_decode_video2(codec_ctx, frame, &got_picture, packet);
			if (ret < 0) {
				fprintf(stderr, "fail to avcodec_decode_video2: %d\n", ret);
				av_free_packet(packet);
				continue;
			}

			if (got_picture) {
				uint8_t* p[1] = { data.get() };
				int dst_stride[1] = { frame->width * 3 };
				sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, p, dst_stride);
				mat.data = data.get();
				cv::resize(mat, dst, cv::Size(width_new, height_new));
				cv::imshow(winname, dst);
			}
		}

		av_free_packet(packet);

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

	cv::destroyWindow(winname);
	av_frame_free(&frame);
	sws_freeContext(sws_ctx);
	av_free(packet);
	avformat_close_input(&format_ctx);

	fprintf(stdout, "test finish\n");
	return 0;
}

 新接口示例

int test_ffmpeg_decode_show_new()
{
	avdevice_register_all();   //初始化libavdevice并注册所有输入和输出设备。

	AVDictionary* options = nullptr;
#ifdef _MSC_VER
	const char* url = "";  //rtsp地址
#else
	const char* url = "/dev/video0";
	av_dict_set(&options, "video_size", "640x480", 0);
	av_dict_set(&options, "input_format", "mjpeg", 0);
#endif

	//AVInputFormat* input_fmt = av_find_input_format(input_format_name);
	AVFormatContext* format_ctx = avformat_alloc_context();  //定义封装结构体
        
        /*将输入流媒体流链接为封装结构体的句柄,将url句柄挂载至format_ctx结构里,之后ffmpeg即可对format_ctx进行操作*/
	int ret = avformat_open_input(&format_ctx, url, nullptr, &options);
	if (ret != 0) {
		fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret);
		return -1;
	}
        
        /*查找音视频流信息,从format_ctx中建立输入文件对应的流信息*/
	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;
        /*穷举所有的音视频流信息,找出流编码类型为AVMEDIA_TYPE_VIDEO对应的索引*/
	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;
	}
        /*查找解码器*/
        /*首先从输入的AVFormatContext中得到stream,然后从stream中根据编码器的CodeID获得对应的Decoder*/
	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 = 4;
        //打开解码器
	ret = avcodec_open2(codec_ctx, codec, nullptr);
	if (ret != 0) {
		fprintf(stderr, "fail to avcodec_open2: %d\n", ret);
		return -1;
	}

	AVFrame* frame = av_frame_alloc();  //用于存放解码后的数据
	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 (!frame || !packet || !sws_ctx) {
		fprintf(stderr, "fail to alloc\n");
		return -1;
	}

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

	while (1) {
		ret = av_read_frame(format_ctx, packet);  //读取音视频数据包
		if (ret >= 0 && packet->stream_index == video_stream_index) {
			ret = avcodec_send_packet(codec_ctx, packet);  //解码
			if (ret < 0) {
				fprintf(stderr, "fail to avcodec_send_packet: %d\n", ret);
				av_packet_unref(packet);
				continue;
			}

			ret = avcodec_receive_frame(codec_ctx, frame);  //接收获取解码收的数据
			if (ret < 0) {
				fprintf(stderr, "fail to avcodec_receive_frame\n");
				av_packet_unref(packet);
				continue;
			}

			sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height, bgr_data, bgr_linesize);
			mat.data = bgr_data[0];
			cv::Mat tmp;
			cv::resize(mat, tmp, cv::Size(640, 360));
			cv::imshow(winname, tmp);
		}

		av_packet_unref(packet);

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

	//cv::destroyWindow(winname);
	av_frame_free(&frame);
	sws_freeContext(sws_ctx);
	av_dict_free(&options);
	avformat_close_input(&format_ctx);
	av_freep(packet);
	av_freep(&bgr_data[0]);

	fprintf(stdout, "test finish\n");
	return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nice七仔爱地球

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值