ffmpeg采集摄像头保存为h264裸流文件,可以用potplayer、VLC播放

网上根本没这方面的代码,要不就是opencv的,要不就是保存yuv的,或者mp4/avi的,不多说了,直接上代码,懒  :)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <Windows.h>
#include <thread>
#include <mutex>
 
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include "libavfilter/avfilter.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/avutil.h"
#include "libavutil/pixfmt.h"
#include "libavutil/error.h"
#include "libavutil/imgutils.h"
}
 
using namespace std;
 
static void encode(AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt,
                   FILE* outfile)
{
	int ret;
 
	/* send the frame to the encoder */
	if (frame)
		printf("Send frame %3", frame->pts);
 
	ret = avcodec_send_frame(enc_ctx, frame);
	if (ret < 0)
	{
		fprintf(stderr, "Error sending a frame for encoding\n");
		exit(1);
	}
 
	while (ret >= 0)
	{
		ret = avcodec_receive_packet(enc_ctx, pkt);
		if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
			return;
		else if (ret < 0)
		{
			fprintf(stderr, "Error during encoding\n");
			exit(1);
		}
 
		printf("Write packet %d size=%d \n", pkt->size, pkt->pts);
		fwrite(pkt->data, 1, pkt->size, outfile);
		av_packet_unref(pkt);
	}
}
 
int main()
{
	avdevice_register_all();
 
	AVFormatContext* camFmtCtx = avformat_alloc_context();
	AVDictionary* options = NULL;
	//av_dict_set(&options, "list_devices", "true", 0);
	//av_dict_set_int(&options, "rtbufsize", 18432000, 0);
	AVInputFormat* iformat = av_find_input_format("dshow");
	puts("Device Option Info======");
	int ret = avformat_open_input(&camFmtCtx, "video=Vimicro USB 2.0 PC Camera (Venus)", iformat, &options);
	if (ret != 0)
	{
		av_dict_free(&options);
		return -1;
	}
	//查找输入流
	ret = avformat_find_stream_info(camFmtCtx, NULL);
	if (ret < 0)
	{
		cout << "无法获取流的信息" << endl;
		return -1;
	}
	int videoindex = -1;
	for (int i = 0; i < camFmtCtx->nb_streams; i++)
	{
		if (camFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoindex = i;
			break;
		}
	}
	//查找摄像头可用解码器
	AVCodecContext* camDecodeCtx = camFmtCtx->streams[videoindex]->codec;
	AVCodecID codecID = camFmtCtx->streams[videoindex]->codecpar->codec_id;
	// cout << "codecID = " << codecID << endl;
	AVCodec* codec = avcodec_find_decoder(codecID);
	if (codec == NULL)
	{
		cout << "没有解码器" << endl;
		return -1;
	}
 
	ret = avcodec_open2(camDecodeCtx, codec,NULL);
	if (ret < 0)
	{
		cout << "avodec_open2 error" << endl;
		return -1;
	}
	cout << "解码器打开成功" << endl;
 
	//H264编码器,encode函数使用
	AVCodecID encodeID = AV_CODEC_ID_H264;
	AVCodec* encodec = avcodec_find_encoder(encodeID);
	//avcodec_find_encoder_by_name();
	if (!encodec)
	{
		cout << "encodec == NULL" << endl;
	}
	AVCodecContext* encodeCtx = avcodec_alloc_context3(encodec);
	if (!encodeCtx)
	{
		cout << "enc == NULL" << endl;
	}
 
	encodeCtx->bit_rate = 400000;
	encodeCtx->width = camDecodeCtx->width;
	encodeCtx->height = camDecodeCtx->height;
	encodeCtx->time_base = {1, 25};
	encodeCtx->framerate = {25, 1};
	encodeCtx->gop_size = 10;
	encodeCtx->max_b_frames = 1;
	encodeCtx->pix_fmt = AV_PIX_FMT_YUV420P;
	//加载预设
	av_opt_set(encodeCtx->priv_data, "preset", "slow", 0);
	av_opt_set(encodeCtx->priv_data, "tune", "zerolatency", 0);
 
	ret = avcodec_open2(encodeCtx, encodec,NULL);
	if (ret < 0)
	{
		cout << "encodec open error" << endl;
		exit(-1);
	}
 
	FILE* fp = nullptr;
	fopen_s(&fp, "1.h264", "wb");
 
	AVPacket* packetIn = av_packet_alloc();
	AVPacket* packetOut = av_packet_alloc();
	AVFrame* pFrameOut = av_frame_alloc();
 
	int got_picture;
 
	struct SwsContext* img_convert_ctx = sws_getContext(camDecodeCtx->width, camDecodeCtx->height,
	                                                    camDecodeCtx->pix_fmt, camDecodeCtx->width,
	                                                    camDecodeCtx->height, AV_PIX_FMT_YUV420P,
	                                                    /*SWS_FAST_BILINEAR*/SWS_BICUBIC, NULL, NULL, NULL);
 
	unsigned char* out_buffer = (unsigned char*)av_malloc(
		av_image_get_buffer_size(AV_PIX_FMT_YUV420P, camDecodeCtx->width, camDecodeCtx->height, 16));
 
	for (int i = 0; i < 250; i++)
	{
		ret = av_read_frame(camFmtCtx, packetIn); //摄像头取到packet,要转为pFrameYUV的yuv格式
 
		if (ret >= 0 && packetIn->stream_index == videoindex)
		{
			AVFrame* pFrameYUV = av_frame_alloc();
 
			pFrameYUV->format = AV_PIX_FMT_YUV420P;
			pFrameYUV->width = camDecodeCtx->width;
			pFrameYUV->height = camDecodeCtx->height;
 
			avpicture_fill((AVPicture*)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, camDecodeCtx->width,
			               camDecodeCtx->height);
 
			avcodec_decode_video2(camDecodeCtx, pFrameOut, &got_picture, packetIn);
			if (got_picture)
			{
				sws_scale(img_convert_ctx, (const unsigned char* const*)pFrameOut->data, pFrameOut->linesize, 0,
				          camDecodeCtx->height,
				          pFrameYUV->data, pFrameYUV->linesize);
			}
			unsigned int untime = GetTickCount();
			pFrameYUV->pts = untime;
 
			encode(encodeCtx, pFrameYUV, packetOut, fp); //编码yuv
 
			av_free(pFrameYUV);
		}
	}
	
	av_free(pFrameOut);
	av_packet_free(&packetIn);
	av_packet_free(&packetOut);
	sws_freeContext(img_convert_ctx);
	avcodec_free_context(&encodeCtx);
	av_free(out_buffer);
	
	fclose(fp);
 
	//avcodec_free_context(&camDecodeCtx);
	avformat_free_context(camFmtCtx);
	av_dict_free(&options);
}
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值