ffmpeg录像代码

录像代码

#include <stdio.h>

extern "C"
{
	#include <libavcodec/avcodec.h>
	#include<libavformat/avformat.h>
	#include <libswscale/swscale.h>
	#include <libavdevice/avdevice.h>
	#include <libavutil/opt.h>
}
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swscale.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avdevice.lib")
//AVFormatContext* pFormat = NULL;

//AVDictionary* opt = NULL;
AVPacket* packet = NULL;
const char* path = "11.mp4";
SwsContext * swsCtx = NULL;
AVFrame*  frame = NULL;
AVFrame*  frameYUV = NULL;

int main()
{
	AVFormatContext* pFormat = NULL;
	//const char* path = "11.mp4";
	AVDictionary* opt = NULL;
	AVPacket* packet = NULL;
	SwsContext * swsCtx = NULL;
	AVFrame*  frame = NULL;
	AVFrame*  frameYUV = NULL;
	//寻找流
	int VideoStream = -1;
	int AudioStream = -1;
	//读帧
	int go = 0;
	int FrameCount = 0;
	int ret = 0;
	int width = 0;
	int height = 0;
	int fmt = 0;

	const int win_width = 720;
	const int win_height = 480;
	printf("%s\n",avcodec_configuration());

	//测试DLL
	printf("%s\n", avcodec_configuration());
	//注册DLL
	av_register_all();
	//网络
	avformat_network_init();
	
	avdevice_register_all();


	AVInputFormat* ifmt = av_find_input_format("dshow");

	ret = avformat_open_input(&pFormat, "/dev/video0", ifmt, &opt);
	if (ret)
	{
		printf(" avformat_open_input failed\n");
	}
	printf(" avformat_open_input success\n");

	//寻找流信息 =》 H264  width  height
/*
	ret = avformat_find_stream_info(pFormat, NULL);
	if (ret)
	{
		printf(" avformat_find_stream_info failed\n");
		return -1;
	}
	printf(" avformat_find_stream_info success\n");
	int time = pFormat->duration;
	int mbittime = (time / 1000000) / 60;
	int mmintime = (time / 1000000) % 60;
	printf("%d min :%d second\n", mbittime, mmintime);
	//av_dump_format(pFormat, NULL, path, 1);
*/


	VideoStream = av_find_best_stream(pFormat, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
	AudioStream = av_find_best_stream(pFormat, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, NULL); //难道不能得到吗?
	printf("VideoStream  is %d,AudioStream is %d\n",VideoStream,AudioStream);
	AVCodec* vCodec = avcodec_find_decoder(pFormat->streams[VideoStream]->codec->codec_id);
	if (!vCodec)
	{
		printf(" avcodec_find_decoder failed\n");
		return -1;
	}
	//avcodec_find_decoder success, codec name: rawvideo, codec long name :raw video (实际打印)
	printf(" avcodec_find_decoder success, codec name: %s, codec long name :%s  \n",vCodec->name,vCodec->long_name);

	ret = avcodec_open2(pFormat->streams[VideoStream]->codec,
		vCodec, NULL);
	if (ret)
	{
		printf(" avcodec_open2 failed\n");
		return -1;
	}
	printf(" avcodec_open2 success\n");

	//开始解码视频
	//申请原始空间  =》创建帧空间
	frame = av_frame_alloc();
	frameYUV = av_frame_alloc();
	width = pFormat->streams[VideoStream]->codec->width;
	height = pFormat->streams[VideoStream]->codec->height;
	printf("width is %d,height is %d\n",width,height);
	fmt = pFormat->streams[VideoStream]->codec->pix_fmt;
	//分配空间  进行图像转换
	int nSize = avpicture_get_size(AV_PIX_FMT_YUV420P,
		width, height);
	uint8_t* buff = NULL;
	buff = (uint8_t*)av_malloc(nSize);

	//一帧图像
	avpicture_fill((AVPicture*)frameYUV, buff, AV_PIX_FMT_YUV420P, width, height);

	//av_malloc 等价于 malloc()
	packet = (AVPacket*)av_malloc(sizeof(AVPacket));

	//转换上下文
	//swsCtx = sws_getCachedContext(swsCtx,XXXX)

	swsCtx = sws_getContext(width, height, (AVPixelFormat)fmt,
		width, height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
	FILE* yuv = fopen("1.yuv","wb+");

	while (av_read_frame(pFormat, packet) >= 0)
	{
		//判断stream_index
		if (packet->stream_index == AVMEDIA_TYPE_VIDEO)
		{
			//vCodec  pFormat->streams[VideoStream]->codec
			ret = avcodec_decode_video2(pFormat->streams[VideoStream]->codec, frame, &go, packet);
			if (ret<0)
			{
				printf(" avcodec_decode_video2 failed\n");
				return -1;
			}
			if (go)
			{
				sws_scale(swsCtx,
					(const uint8_t**)frame->data,
					frame->linesize,
					0,
					height,
					frameYUV->data,
					frameYUV->linesize
				);
				int size = width* height;
				fwrite(frameYUV->data[0], 1,  size,yuv);
				fwrite(frameYUV->data[1], 1,  size/4, yuv);
				fwrite(frameYUV->data[2], 1,  size/4, yuv);
				FrameCount++;
				printf("frame index:%d \n", FrameCount++);
			}
		}
		av_free_packet(packet);
	}
	fclose(yuv);
	sws_freeContext(swsCtx);
	av_frame_free(&frame);
	av_frame_free(&frameYUV);
	avformat_close_input(&pFormat);

	return 0;
}

可参考代码:
FFMPEG使用摄像头录像并编码

函数分析

AVInputFormat *av_find_input_format(const char *short_name)
{
    AVInputFormat *fmt = NULL;
    while ((fmt = av_iformat_next(fmt)))
        if (av_match_name(short_name, fmt->name))
            return fmt;
    return NULL;
}

我第一眼看上去,吓了一跳。这个函数返回一个局部变量地址。
仔细看了一下,原来返回的是一个 已经搞好了的链表的成员地址。

int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options);
ps:函数调用成功之后处理过的AVFormatContext结构体。
file:打开的视音频流的URL。
fmt:强制指定AVFormatContext中AVInputFormat的。这个参数一般情况下可以设置为NULL,这样FFmpeg可以自动检测AVInputFormat。
dictionay:附加的一些选项,一般情况下可以设置为NULL

avformat_open_input 函数参考:
FFmpeg源代码简单分析:avformat_open_input()

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用FFmpeg API来录制音频和视频需要进行一些编程工作。以下是一个基本的示例来录制音频和视频: ```C #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <libavformat/avformat.h> #include <libavdevice/avdevice.h> int main() { int ret; // 注册所有的设备和格式 avdevice_register_all(); // 打开音频设备 AVFormatContext* audioFmtCtx = NULL; ret = avformat_open_input(&audioFmtCtx, "default", av_find_input_format("alsa"), NULL); if (ret < 0) { fprintf(stderr, "无法打开音频设备: %s\n", av_err2str(ret)); return ret; } // 打开视频设备 AVFormatContext* videoFmtCtx = NULL; ret = avformat_open_input(&videoFmtCtx, "/dev/video0", av_find_input_format("video4linux2"), NULL); if (ret < 0) { fprintf(stderr, "无法打开视频设备: %s\n", av_err2str(ret)); return ret; } // 创建输出文件上下文 AVFormatContext* outputFmtCtx = NULL; ret = avformat_alloc_output_context2(&outputFmtCtx, NULL, NULL, "output.mp4"); if (!outputFmtCtx) { fprintf(stderr, "无法创建输出文件上下文\n"); return AVERROR_UNKNOWN; } // 添加音频流 AVStream* audioStream = avformat_new_stream(outputFmtCtx, NULL); if (!audioStream) { fprintf(stderr, "无法创建音频流\n"); return AVERROR_UNKNOWN; } // 复制音频参数 avcodec_parameters_copy(audioStream->codecpar, audioFmtCtx->streams[0]->codecpar); // 添加视频流 AVStream* videoStream = avformat_new_stream(outputFmtCtx, NULL); if (!videoStream) { fprintf(stderr, "无法创建视频流\n"); return AVERROR_UNKNOWN; } // 复制视频参数 avcodec_parameters_copy(videoStream->codecpar, videoFmtCtx->streams[0]->codecpar); // 打开输出文件 ret = avio_open(&outputFmtCtx->pb, outputFmtCtx->filename, AVIO_FLAG_WRITE); if (ret < 0) { fprintf(stderr, "无法打开输出文件: %s\n", av_err2str(ret)); return ret; } // 写文件头 ret = avformat_write_header(outputFmtCtx, NULL); if (ret < 0) { fprintf(stderr, "无法写入文件头: %s\n", av_err2str(ret)); return ret; } // 录制音频和视频 AVPacket packet; while (1) { // 从音频设备读取音频 ret = av_read_frame(audioFmtCtx, &packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; if (ret < 0) { fprintf(stderr, "无法从音频设备读取音频: %s\n", av_err2str(ret)); return ret; } // 写入音频包 packet.stream_index = audioStream->index; ret = av_interleaved_write_frame(outputFmtCtx, &packet); av_packet_unref(&packet); if (ret < 0) { fprintf(stderr, "无法写入音频包: %s\n", av_err2str(ret)); return ret; } } while (1) { // 从视频设备读取视频 ret = av_read_frame(videoFmtCtx, &packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; if (ret < 0) { fprintf(stderr, "无法从视频设备读取视频: %s\n", av_err2str(ret)); return ret; } // 写入视频包 packet.stream_index = videoStream->index; ret = av_interleaved_write_frame(outputFmtCtx, &packet); av_packet_unref(&packet); if (ret < 0) { fprintf(stderr, "无法写入视频包: %s\n", av_err2str(ret)); return ret; } } // 写文件尾 ret = av_write_trailer(outputFmtCtx); if (ret < 0) { fprintf(stderr, "无法写入文件尾: %s\n", av_err2str(ret)); return ret; } // 清理资源 avformat_close_input(&audioFmtCtx); avformat_close_input(&videoFmtCtx); avformat_free_context(audioFmtCtx); avformat_free_context(videoFmtCtx); avio_closep(&outputFmtCtx->pb); avformat_free_context(outputFmtCtx); return 0; } ``` 请注意,这只是一个简单的示例,您可能需要根据您的需求进行更多的自定义设置和错误处理。您还需要在编译时链接FFmpeg库并包含相关的头文件。有关更多详细信息和选项,请参考FFmpeg的文档和示例代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值