前期介绍:
对于Mac笔记本
*devicename = “0”;为采集视频
:0为只采集音频
0:0为同时采集音视频
0 代表机器摄像头
1 代表桌面
相关命令
查看设备支持格式:啊,简直了
ffmpeg -f dshow -i video="Lenovo EasyCamera"
实战
调用lenovo EasyCamera设备录像出错,就从开始菜单用它来录视频,然后打印录制完成的视频信息,结果
代码,没成功,
yuv保存下来为花屏,没影像,pkt.size改成640x320或是其两倍,指教为0大小的yuv,用pkt.size才有雪花数据
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include <libavutil/log.h>
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
}
#include <windows.h>
#include <vector>
#include <string>
#include <memory>
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "Winmm.lib")
using std::vector;
using std::string;
using std::shared_ptr;
void capture_audio()
{
/*
//windows api 获取音频设备列表(ffmpeg 好像没有提供获取音视频设备的api)
int nDeviceNum = waveInGetNumDevs();
vector<string> vecDeviceName;
for (int i = 0; i < nDeviceNum; ++i)
{
WAVEINCAPS wic;
waveInGetDevCaps(i, &wic, sizeof(wic));
//转成utf-8
int nSize = WideCharToMultiByte(CP_UTF8, 0, wic.szPname, wcslen(wic.szPname), NULL, 0, NULL, NULL);
shared_ptr<char> spDeviceName(new char[nSize + 1]);
memset(spDeviceName.get(), 0, nSize + 1);
WideCharToMultiByte(CP_UTF8, 0, wic.szPname, wcslen(wic.szPname), spDeviceName.get(), nSize, NULL, NULL);
vecDeviceName.push_back(spDeviceName.get());
av_log(NULL, AV_LOG_DEBUG, "video input device : %s \n", spDeviceName.get());
//printf("%s \n", spDeviceName.get());
}
if (vecDeviceName.size() <= 0)
{
av_log(NULL, AV_LOG_ERROR, "not find video input device.\n");
return;
}
*/
string sDeviceName = "video=Lenovo EasyCamera";
//printf("--z中-----%s \n", sDeviceName);
AVDictionary *options = NULL;
//ffmpeg
avdevice_register_all(); //注册所有输入输出设备
AVInputFormat* ifmt = av_find_input_format("dshow"); //设置采集方式 dshow,此为windows下
av_dict_set(&options, "video_size", "640x320", 0);
av_dict_set(&options, "framerate", "30", 0);//帧率
//av_dict_set(&options, "pixel_format", "30", 0);//帧率
if (ifmt == NULL)
{
av_log(NULL, AV_LOG_ERROR, "av_find_input_format for dshow fail.\n");
return;
}
AVFormatContext* fmt_ctx = NULL; //format 上下文
int ret = avformat_open_input(&fmt_ctx, sDeviceName.c_str(), ifmt, NULL); //"video=Lenovo EasyCamera"打开音频设备 sDeviceName.c_str()
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "avformat_open_input fail. return %d.\n", ret);
return;
}
AVPacket pkt;
FILE* fp = fopen("dst.yuv", "wb+");
int count = 0;
printf("--------------------------Record video is begin \n");
while (count++ < 60)
{
ret = av_read_frame(fmt_ctx, &pkt);
if (ret != 0)
{
av_log(NULL, AV_LOG_ERROR, "av_read_frame fail, return %d .\n", ret);
break;
}
printf("wxd_____pkt.size is %d \n",pkt.size);
//av_log(NULL, AV_LOG_INFO, "packet size is %d(%p)\n", pkt.size, pkt.data);
fwrite(pkt.data, 1, 409600, fp);//这里 pkt.size是相对音频,要改204800
av_packet_unref(&pkt);//必须释放pkt申请的内存,否则会内存泄露
}
printf("---------------------------Record video is over \n");
fflush(fp);//刷新文件io输出缓冲区
fclose(fp);
avformat_close_input(&fmt_ctx);
}
int main(int argc, char** argv)
{
av_log_set_level(AV_LOG_DEBUG); //设置ffmpeg日志库等级
printf("中文显示, chinese display \n");
capture_audio();
Sleep(1);
return 0;
}
bug解决
1.报错:无法查找或打开 PDB 文件,要仅加载指定符号
参考:https://blog.youkuaiyun.com/weixin_37662982/article/details/86631124
https://blog.youkuaiyun.com/sinat_33205914/article/details/87870378
其他注意:
-s 1280x720参数一定要在-i sample.yuv的前面,否则会报"Picture size 0x0 is invalid "的错误
删除或调小水印参考:https://blog.youkuaiyun.com/weixin_41217917/article/details/103274974
查看平台下的设备支持:https://blog.youkuaiyun.com/lwj_zeal/article/details/86564659