如何使用ffmpeg 摄像头进行摄像头录像

基于USB摄像头视频数据采集和利用FFMPEG库函数进行视频数据压缩
Linux系统中提供的视频设备驱动程序V4L2编程可以提供我们操作视频设备,比如摄像头。同时我们可以用开源的ffmpeg库中的函数实现所采集的视频数据进行压缩编码,生成我们需要的视频格式。下面的代码,是将USB摄像头所采集的视频数据最后压缩封装成FLV格式,这里所采用的ffmpeg的版本是1.1.2.*/#include &stdio.h&
#include &stdlib.h&
#include &string.h&
#include &math.h&
#include &errno.h&
#include &fcntl.h&
#include &unistd.h&
#include &sys/mman.h&
#include &sys/ioctl.h&
#include &sys/stat.h&
#include &linux/videodev2.h&
#include &libavcodec/avcodec.h&
#include &libavformat/avformat.h&
#include &libavformat/avio.h&
#include &libavutil/opt.h&
#include &libswscale/swscale.h&
#include &libavutil/mathematics.h&
#define VIDEO_WIDTH 640
#define VIDEO_HEIGHT 480
#define VIDEO_FORMAT V4L2_PIX_FMT_YUYV
#define BUFFER_COUNT 4
#define URL_WRONLY 1
struct fimc_buffer {
} framebuf[BUFFER_COUNT];
unsigned char yuv] = { 0 };
unsigned char yuv] = { 0 };
AVFormatContext* pFormatCtxE
AVCodecContext* pCodecCtxE
AVFrame* pFrameE
void register_init();
int open_device();
int capability();
int set_v4l2_format();
int request_buffers();
int get_camera_data();
void unregister_all();
void video_encode_init();
int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,
int height);
void register_init() {
avcodec_register_all();
av_register_all();
int open_device() {
char camera_device[20];
for (i = 0; i & 10; i++) {
sprintf(camera_device, &/dev/video%i&, i);
if (stat(camera_device, &buf) == 0) {
fd = open(camera_device, O_RDWR, 0); //设备以非阻塞方式打开
if (fd & 0) {
printf(&Cannot open camera_device\n&);
return -1;
int set_v4l2_format() {
struct v4l2_ //设置视频制式和帧格式
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = VIDEO_WIDTH;
fmt.fmt.pix.height = VIDEO_HEIGHT;
fmt.fmt.pix.pixelformat = VIDEO_FORMAT;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
if (ret & 0) {
printf(&VIDIOC_S_FMT failed\n&);
ret = ioctl(fd, VIDIOC_G_FMT, &fmt); //获取视频制式和帧格式的实际值,看是否设置正确
if (ret & 0) {
printf(&VIDIOC_G_FMT failed (%d)/n&, ret);
int request_buffers() {
struct v4l2_r //向驱动申请帧缓冲
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
reqbuf.count = BUFFER_COUNT;
ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
if (ret & 0) {
printf(&VIDIOC_REQBUFS failed \n&);
struct v4l2_ //获取帧缓冲地址
for (i = 0; i & BUFFER_COUNT; i++) {
buf.index =
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_QUERYBUF, &buf);
if (ret & 0) {
printf(&VIDIOC_QUERYBUF failed\n&);
framebuf[i].length = buf.
framebuf[i].start = (char *) mmap(0, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, buf.m.offset); //将申请到的帧缓冲映射到用户空间,&就能直接操作采集的帧
if (framebuf[i].start == MAP_FAILED) {
printf(&mmap (%d) failed: %s/n&, i, strerror(errno));
return -1;
ret = ioctl(fd, VIDIOC_QBUF, &buf); //将申请到的帧缓冲全部入队列,以便存放数据
if (ret & 0) {
printf(&VIDIOC_QBUF (%d) failed (%d)/n&, i, ret);
return -1;
int get_camera_data() {
struct v4l2_ //获取帧缓冲地址
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //开始视频采集
ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (ret & 0) {
printf(&VIDIOC_STREAMON failed (%d)\n&, ret);
video_encode_init();
while (1) {
static int delayFrame = 0;
int got_packet = 0;
printf(&-----------seconds = %d----------\n&, ++i);
for (k = 0; k & 25; k++) {
ret = ioctl(fd, VIDIOC_DQBUF, &buf); //出队列以取得已采集数据的帧缓冲,取得原始数据
if (ret & 0) {
printf(&VIDIOC_DQBUF failed (%d)/n&, ret);
strncpy(yuv4220, framebuf[buf.index].start,
framebuf[buf.index].length);
yuv422_2_yuv420(yuv4200, yuv, 480);
av_image_alloc(pFrameEnc-&data, pFrameEnc-&linesize,
pCodecCtxEnc-&width, pCodecCtxEnc-&height,
pCodecCtxEnc-&pix_fmt, 1);
pFrameEnc-&data[0] = yuv4200;
pFrameEnc-&data[1] = pFrameEnc-&data[0]
+ pCodecCtxEnc-&width * pCodecCtxEnc-&
pFrameEnc-&data[2] = pFrameEnc-&data[1]
+ pCodecCtxEnc-&width * pCodecCtxEnc-&height / 4;
pFrameEnc-&linesize[0] = pCodecCtxEnc-&
pFrameEnc-&linesize[1] = pCodecCtxEnc-&width / 2;
pFrameEnc-&linesize[2] = pCodecCtxEnc-&width / 2;
pFrameEnc-&pts = (k + (i - 1) * 25) * 40;
pFrameEnc-&width = 640;
pFrameEnc-&height = 480;
if (!pFormatCtxEnc-&nb_streams) {
printf(&output file does not contain any stream\n&);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
printf(&encoding frame %d-------&, k);
ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, pFrameEnc,
&got_packet);
if (ret & 0) {
av_log(NULL, AV_LOG_FATAL, &Video encoding failed\n&);
if (got_packet) {
printf(&output frame %d size = %d\n&, k - delayFrame, pkt.size);
ret = av_interleaved_write_frame(pFormatCtxEnc, &pkt);
if (ret != 0) {
fprintf(stderr, &write frame into file is failed\n&);
printf(&encode and write one frame success\n&);
delayFrame++;
printf(&no frame output\n&);
av_free_packet(&pkt);
ret = ioctl(fd, VIDIOC_QBUF, &buf); //将缓冲重新入对尾,可以循环采集
if (ret & 0) {
printf(&VIDIOC_QBUF failed (%d)\n&, ret);
/* get the delayed frames */
for (got_packet = 1; got_ k++) {
fflush(stdout);
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
ret = avcodec_encode_video2(pCodecCtxEnc, &pkt, NULL, &got_packet);
if (ret & 0) {
fprintf(stderr, &error encoding frame\n&);
if (got_packet) {
printf(&output delayed frame %3d (size=%5d)\n&, k - delayFrame,
pkt.size);
av_interleaved_write_frame(pFormatCtxEnc, &pkt);
av_free_packet(&pkt);
av_write_trailer(pFormatCtxEnc);
if (!(pFormatCtxEnc-&flags & AVFMT_NOFILE))
avio_close(pFormatCtxEnc-&pb);
for (i = 0; i & BUFFER_COUNT; i++) {
munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存
close(fd);
int capability() {
struct v4l2_
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap); //摄像头主要获取功能
if (ret & 0) {
printf(&VIDIOC_QUERYCAP failed \n&);
int yuv422_2_yuv420(unsigned char* yuv420, unsigned char* yuv422, int width,
int height) {
int imgSize = width * height * 2;
int widthStep422 = width * 2;
unsigned char* p422 = yuv422;
unsigned char* p420y = yuv420;
unsigned char* p420u = yuv420 + imgSize / 2;
unsigned char* p420v = p420u + imgSize / 8;
for (i = 0; i & i += 2) {
p422 = yuv422 + i * widthStep422;
for (j = 0; j & widthStep422; j += 4) {
*(p420y++) = p422[j];
*(p420u++) = p422[j + 1];
*(p420y++) = p422[j + 2];
p422 += widthStep422;
for (j = 0; j & widthStep422; j += 4) {
*(p420y++) = p422[j];
*(p420v++) = p422[j + 3];
*(p420y++) = p422[j + 2];
void unregister_all() {
for (i = 0; i & BUFFER_COUNT; i++) {
munmap(framebuf[i].start, framebuf[i].length); //取消映射,释放内存
close(fd);
printf(&Camera test Done.\n&);
void video_encode_init() {
char* filename = &./264.flv&;
AVCodec* pCodecE
AVOutputFormat* pOutputF
AVStream* video_
av_register_all();
pOutputFormat = av_guess_format(NULL, filename, NULL);
if (pOutputFormat == NULL) {
fprintf(stderr, &Could not guess the format from file\n&);
printf(&guess the format from file success\n&);
pFormatCtxEnc = avformat_alloc_context();
if (pFormatCtxEnc == NULL) {
fprintf(stderr, &could not allocate AVFormatContex\n&);
printf(&allocate AVFormatContext success\n&);
pFormatCtxEnc-&oformat = pOutputF
sprintf(pFormatCtxEnc-&filename, &%s&, filename);
printf(&filename is %s\n&, pFormatCtxEnc-&filename);
video_st = avformat_new_stream(pFormatCtxEnc, 0);
if (!video_st) {
fprintf(stderr, &could not allocate AVstream\n&);
printf(&allocate AVstream success\n&);
pCodecCtxEnc = video_st-&
pCodecCtxEnc-&codec_id = pOutputFormat-&video_
pCodecCtxEnc-&codec_type = AVMEDIA_TYPE_VIDEO;
pCodecCtxEnc-&bit_rate = 1000000;
pCodecCtxEnc-&bit_rate_tolerance = ; //表示有多少bit的视频流可以偏移出目前的设定.这里的&设定&是指的cbr或者vbr.
pCodecCtxEnc-&width = 640;
pCodecCtxEnc-&height = 480;
pCodecCtxEnc-&time_base = (AVRational) {1,25};
//pCodecCtxEnc-&time_base.num = 1;
//pCodecCtxEnc-&time_base.den = 25;
pCodecCtxEnc-&pix_fmt = PIX_FMT_YUV420P;
pCodecCtxEnc-&gop_size = 10;
pCodecCtxEnc-&max_b_frames = 0;
av_opt_set(pCodecCtxEnc-&priv_data, &preset&, &superfast&, 0);
av_opt_set(pCodecCtxEnc-&priv_data, &tune&, &zerolatency&, 0);
pCodecCtxEnc-&pre_me = 2;
pCodecCtxEnc-&lmin = 10;
pCodecCtxEnc-&lmax = 50;
pCodecCtxEnc-&qmin = 20;
pCodecCtxEnc-&qmax = 80;
pCodecCtxEnc-&qblur = 0.0;
pCodecCtxEnc-&spatial_cplx_masking = 0.3;
pCodecCtxEnc-&me_pre_cmp = 2;
pCodecCtxEnc-&rc_qsquish = 1;
pCodecCtxEnc-&b_quant_factor = 4.9;
pCodecCtxEnc-&b_quant_offset = 2;
pCodecCtxEnc-&i_quant_factor = 0.1;
pCodecCtxEnc-&i_quant_offset = 0.0;
pCodecCtxEnc-&rc_strategy = 2;
pCodecCtxEnc-&b_frame_strategy = 0;
pCodecCtxEnc-&dct_algo = 0;
pCodecCtxEnc-&lumi_masking = 0.0;
pCodecCtxEnc-&dark_masking = 0.0;
if (!strcmp(pFormatCtxEnc-&oformat-&name, &flv&)) {
pCodecCtxEnc-&flags |= CODEC_FLAG_GLOBAL_HEADER;
printf(&output format is %s\n&, pFormatCtxEnc-&oformat-&name);
pCodecEnc = avcodec_find_encoder(pCodecCtxEnc-&codec_id);
if (!pCodecEnc) {
fprintf(stderr, &could not find suitable video encoder\n&);
printf(&find the encoder success\n&);
if (avcodec_open2(pCodecCtxEnc, pCodecEnc, NULL) & 0) {
fprintf(stderr, &could not open video codec\n&);
printf(&open the video codec success\n&);
pFrameEnc = avcodec_alloc_frame();
if (pFrameEnc == NULL) {
fprintf(stderr, &could not allocate pFrameEnc\n&);
printf(&allocate pFrameEnc success\n&);
ret = avio_open(&pFormatCtxEnc-&pb, filename, AVIO_FLAG_WRITE);
if (ret & 0) {
fprintf(stderr, &could not open '%s': %s\n&, filename, av_err2str(ret));
printf(&open filename = %s success\n&, filename);
ret = avformat_write_header(pFormatCtxEnc, NULL);
if (ret & 0) {
fprintf(stderr, &error occurred when opening outputfile: %s\n&,
av_err2str(ret));
printf(&write the header success\n&);
int main() {
register_init();
open_device();
capability();
set_v4l2_format();
request_buffers();
get_camera_data();
unregister_all();
看过本文的人也看了:
我要留言技术领域:
取消收藏确定要取消收藏吗?
删除图谱提示你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?
删除节点提示无法删除该知识节点,因该节点下仍保存有相关知识内容!
删除节点提示你确定要删除该知识节点吗?FFMPEG 摄像头 命令行参数 录像 直播 rtmp
FFMPEG 摄像头 命令行参数 录像 直播 rtmp
发布时间: 19:55:42
编辑:www.fx114.net
本篇文章主要介绍了"FFMPEG 摄像头 命令行参数 录像 直播 rtmp",主要涉及到FFMPEG 摄像头 命令行参数 录像 直播 rtmp方面的内容,对于FFMPEG 摄像头 命令行参数 录像 直播 rtmp感兴趣的同学可以参考一下。
解决FFMPEG采集音视频时不同步的问题:
添加参数&-copyinkf&
ffmpeg.exe&-copyinkf&-f dshow -i video=&USB2.0 UVC VGA WebCam&:audio=&麦克风 (Realtek High Definition Au& -q 4 -s 640*480 -aspect 4:3 -r 10 -vcodec flv &-ar 22050
-ab 64k -ac 1 -acodec libmp3lame -threads 4 -f flv rtmp://127.0.0.1/RTMP/RtmpVideo
其实这个问题,应该看后面的 -re 参数相关,而不是像上面那样解决;
关于Windows上的AAC编码:从官方网站得到的ffmpeg库,用的是VisualOn AAC,所以编码命令是:-acodec libvo_aacenc&
雷霄骅 专栏
这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘。本文所述的方法主要是对应Windows平台的。
1.&&&&&& 列设备
命令执行后输出的结果如下(注:中文的设备会出现乱码的情况)。列表显示设备的名称很重要,输入的时候都是使用“-f dshow -i video=&{设备名}&”的方式。
我自己的机器上列出了以下设备:
下文的测试中,使用其中的两个视频输入:&Integrated Camera&和&screen-capture-recorder&。
&注:音频设备出现乱码,这个问题的解决方法会随后提到。
2.&&&&&& 获取摄像头数据(保存为本地文件或者发送实时流)
2.1. 编码为H.264,保存为本地文件
下面这条命令,实现了从摄像头读取数据并编码为H.264,最后保存成mycamera.mkv。
2.2. 直接播放摄像头的数据
使用ffplay可以直接播放摄像头的数据,命令如下:
如果设备名称正确的话,会直接打开本机的摄像头,如图所示。
注:除了使用DirectShow作为输入外,使用VFW也可以读取到摄像头的数据,例如下述命令可以播放摄像头数据:
此外,可以使用FFmpeg的list_options查看设备的选项:
输出如下:
可以通过输出信息设置摄像头的参数。
例如,设置摄像头分辨率为
设置分辨率为424x240
2.3. 编码为H.264,发布UDP
下面这条命令,实现了:获取摄像头数据-&编码为H.264-&封装为UDP并发送至组播地址。
注1:考虑到提高libx264的编码速度,添加了-preset:v ultrafast和-tune:v zerolatency两个选项。
注2:高分辨率的情况下,使用UDP可能出现丢包的情况。为了避免这种情况,可以添加–s 参数(例如-s 320x240)调小分辨率。
2.4. 编码为H.264,发布RTP
下面这条命令,实现了:获取摄像头数据-&编码为H.264-&封装为RTP并发送至组播地址。
注1:考虑到提高libx264的编码速度,添加了-preset:v ultrafast和-tune:v zerolatency两个选项。
注2:结尾添加“&test.sdp”可以在发布的同时生成sdp文件。该文件可以用于该视频流的播放。
2.5. 编码为H.264,发布RTMP
下面这条命令,实现了:获取摄像头数据-&编码为H.264-&并发送至RTMP服务器。
2.6. 编码为MPEG2,发布UDP
与编码为H.264类似,指明-vcodec即可。
播放MPEG2的UDP流如下。指明-vcodec为mpeg2video即可
3.&&&&&& 屏幕录制(Windows平台下保存为本地文件或者发送实时流)
Linux下使用FFmpeg进行屏幕录制相对比较方便,可以使用x11grab,使用如下的命令:
详细时使用方式可以参考这篇文章:
Linux录屏在这里不再赘述。在Windows平台下屏幕录像则要稍微复杂一些。在Windows平台下,使用-dshow取代x11grab。一句话介绍:注册录屏dshow滤镜(例如screen-capture-recorder),然后通过dshow获取录屏图像然后编码处理。
因此,在使用FFmpeg屏幕录像之前,需要先安装dshow滤镜。在这里推荐一个软件:screen capture recorder。安装这个软件之后,就可以通过FFmpeg屏幕录像了。
screen capture recorder项目主页:
下载地址:
下载完后,一路“Next”即可安装完毕。注意,需要Java运行环境(Java Runtime Environment),如果没有的话下载一个就行。
screen capture recorder本身就可以录屏,不过这里我们使用FFmpeg进行录屏。
3.1. 编码为H.264,保存为本地文件
下面的命令可以将屏幕录制后编码为H.264并保存为本地文件。
注:“-r 5”的意思是把帧率设置成5。 & & & &&
最后得到的效果如下图。
此外,也可以录声音,声音输入可以分成两种:一种是真人说话的声音,通过话筒输入;一种是虚拟的声音,即录屏的时候电脑耳机里的声音。下面两条命令可以分别录制话筒的声音和电脑耳机里的声音。
录屏,伴随话筒输入的声音
上述命令有问题:audio那里有乱码,把乱码ANSI转UTF-8之后,开始测试不行,后来发现是自己疏忽大意,乱码部分转码后为“内装麦克风 ”,然后接可以正常使用了。因此,命令应该如下图所示:
如果不熟悉ANSI转码UTF-8的话,还有一种更简单的方式查看设备的名称。即不使用FFmpeg查看系统DirectShow输入设备的名称,而使用DirectShow SDK自带的工具GraphEdit(或者网上下一个GraphStudioNext)查看输入名称。
打开GraphEdit选择“图像-&插入滤镜”
然后就可以通过查看Audio Capture Sources来查看音频输入设备的简体中文名称了。从图中可以看出是“内装麦克风 (Conexant 20672 SmartAudi”。
PS:感觉这条命令适合做讲座之类的时候使用
录屏,伴随耳机输入的声音
PS:测这条命令的时候,这在听歌,因此录制的视频中的音频就是那首歌曲。
3.2. 编码为H.264,发布UDP
下面的命令可以将屏幕录制后编码为H.264并封装成UDP发送到组播地址
注1:考虑到提高libx264的编码速度,添加了-preset:v ultrafast和-tune:v zerolatency两个选项。
注2:高分辨率的情况下,使用UDP可能出现丢包的情况。为了避免这种情况,可以添加–s 参数(例如-s 320x240)调小分辨率。
3.3. 编码为H.264,发布RTP
下面的命令可以将屏幕录制后编码为H.264并封装成RTP并发送到组播地址
注1:考虑到提高libx264的编码速度,添加了-preset:v ultrafast和-tune:v zerolatency两个选项。
注2:结尾添加“&test.sdp”可以在发布的同时生成sdp文件。该文件可以用于该视频流的播放。如下命令即可播放:
3.4. 编码为H.264,发布RTMP
原理同上,不再赘述。
注意:播放RTMP的时候,-max_delay参数会比较明显的影响延迟,将此参数值设定小一些,有利于降低延时。
4.另一种屏幕录制的方式(更新)
最近发现FFmpeg还有一个专门用于Windows下屏幕录制的设备:gdigrab。
gdigrab是基于GDI的抓屏设备,可以用于抓取屏幕的特定区域。在这里记录一下gdigrab的用法。
gdigrab通过设定不同的输入URL,支持两种方式的屏幕抓取:
(1)“desktop”:抓取整张桌面。或者抓取桌面中的一个特定的区域。
(2)“title={窗口名称}”:抓取屏幕中特定的一个窗口。
下面举几个例子。
最简单的抓屏:
从屏幕的(10,20)点处开始,抓取640x480的屏幕,设定帧率为5
一、Windows下面编译ffmpeg
首先需要解决的问题是:在windows下面编译 ffmpeg, 并让其支持dshow, 本人把ffmpeg编译成功了, 但是编译出来的ffmpeg不支持dshow, 在网上找了有文章介绍如何编译ffmpeg让其支持dhsow, 按照文章说的方法试了N次, 终究没有成功。无奈只有找现成的windows下面的exe了。
在这里找到了可用的ffmpeg.exe, 测试了一下,支持dshow。
下载地址为:&&
请下载适合自己操作系统的压缩包, 我的系统是Win7 64Bit 的,所以选择的是&&
下载解压到C盘根目录。
二、测试FFMPEG支持dshow的情况
原文出处请参考 :
执行下面的命令 , 即可显示你的系统支持音频捕获设备,视频捕获设备:
我们下来使用 视频捕获设备 &Integraged Camera& 保存为MP4文件:
嘿嘿,摄像头灯亮了,文件已经输出到了和 ffmpeg.exe 相同的路径下面。 用VLC播放 out.mp4文件,正常。
用下面的命令可以查看视频捕获设备支持的图片大小等详细信息。
用下面的命令我们可以把视频分辨率存储为,& FPS为15帧/秒, 输出为 out.avi 文件。是不是很方便啊 ?
三、测试FFMPEG对DSHOW支持的另外一种方法
原文出处 :&
用下面的命令我们也可以输出视频捕获设备,只不过不是名字,而是ID的形式。
输出如下 :
从上面看出 vfwcap的索引号为0, 用下面的命令即可捕获视频数据。其中 -i 0 就代表使用ID为0的视频采集设备, -r 25代表帧率为25帧/秒
四、Apple公司的HLS文件切片相关资料
原文出处为 :&
下面是相关的技术资料的地址 :
Index of /src/mpegts-segmenter/
Last Modified
2012-Feb-07 10:13:38
application/octet-stream
2012-Feb-07 10:13:38
application/octet-stream
2012-Feb-07 10:13:38
application/octet-stream
还附带文件切片源码。
下面的地址也可以下载 切片工具的源码,这个工具可能比较完善一点吧。
这个是C的切片工具
这个是ruby语言写的转码和切片
五、用FFMPEG实现iPhone的HTTP Stream技术步骤
原文出处 :
Step 1: 获取最新版本的 FFMpeg
The FFMpeg&& 从该地址获取最新版本的ffmpeg
使用下面的命令进行配置,生成Makefile文件,然后make吧。
configure --enable-gpl --enable-nonfree --enable-pthreads --enable-libfaac --enable-libfaad --enable-libmp3lame --enable-libx264
其中最重要的事情是注意 --enable-libx264& 这个编译选项。
Step 2: 转码视频格式,让 iPhone 可以使用
我们必须让ffmpeg创建 X264编码格式的视频流, iPhone才能播放,有几个步骤需要注意:
视频文件的码率必须在: 100 Kbps to 1.6 Mbps&&& 这个范围
苹果公司建议的视频流为:
Low – 96 Kbps video, 64 Kbps audioMedium – 256 Kbps video, 64 Kbps audioHigh – 800 Kbps video, 64 Kbps audio
iPhone 的屏幕视频播放尺寸设置为: 480×320
建议使用下面的参数进行视频转码:
ffmpeg -i &in file& -f mpegts -acodec libmp3lame -ar 48000 -ab 64k -s 320×240 -vcodec libx264 -b 96k -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -subq 5 -trellis 1 -refs 1 -coder
0 -me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -bt 200k -maxrate 96k -bufsize 96k -rc_eq 'blurCplx^(1-qComp)' -qcomp 0.6 -qmin 10 -qmax 51 -qdiff 4 -level 30 -aspect 320:240 -g 30 -async 2 &output file&
假如你想知道这些命令参数的更详细的信息,请参考&& 和&&, 上面例子设置的码率为98k, 你可以修改为你想设置的码率。
要更改的参数为&& “ &&-b, -maxrate,& -bufsize values & ”
Step 3: 下载并编译 segmenter&
现在,你已经完成了视频采集的工作,但是还没有完成整个构建HTTP& Streaming 的过程。 你需要一种方法来把视频文件切成小块,你可以下载苹果的 segmenter 。
下载切片源码的SVN地址为 :&&.&&
下载下来后用下面的命令即可编译 :
& & & & gcc -Wall -g segmenter.c -o segmenter -lavformat -lavcodec -lavutil -lbz2 -lm -lz -lfaac -lmp3lame -lx264 -lfaad
& & & & rm segmenter
在编译完成了 segmenter 工具之后, 你就可以创建你的 HTTP& Streaming 内容了。
命令格式为:
segmenter &input MPEG-TS file& &segment duration in seconds& &output MPEG-TS file prefix& &output m3u8 index file& &http prefix&
下面是一个使用的例子,从视频文件创建一个流, 每个切片文件10秒:
segmenter sample_low.ts 10 sample_low stream_low.m3u8 http://www.ioncannon.net/
Step 4: 准备 HTTP server 服务器
进行到这一步的时候, 你应该已经有好多视频流的切片文件了,这些文件可以上传到web服务器, 但是这里有一个比较重要的事情需要注意,那就是mime types的设置。
.m3u8 && application/x-mpegURL
.ts & && video/MP2T
假如你使用的是Apache服务器的话,你需要添加如下的代码到 httpd.conf 配置文件里:
AddType application/x-mpegURL .m3u8
AddType video/MP2T .ts
假如你使用的是 lighttpd& 服务器的话,你需要添加下面的代码到你的配置文件中:
mimetype.assign = ( &.m3u8& =& &application/x-mpegURL&, &.ts& =& &video/MP2T& )
Step 5: 测试 stream
万事俱备只欠东风了,下来需要使用 HTML5 的 video 标签,例子如下:
& &&&&Video Test&/&
& &&&name=&viewport&content=&width=320;
initial-scale=1.0; maximum-scale=1.0; user-scalable=0;&/&
&&&style=&background-color:#FFFFFF;
& & &&&video&width='150'height='150'src=&stream-128k.m3u8&/&
上面所有的步骤都正确的话,你现在应该已经看到视频了。
假如你想在应用程序里面测试上面的视频流的话,你需要下载苹果公司的视频播放器,下载地址为:&&。&
Step 6: 自动化的 stream 编码和切片 segmentation
这是一个小脚本,可以把输入文件编码转换后再切片为10秒一个的文件小块。
ffmpeg&-i&$1&-f&mpegts&-acodec&libmp3lame&-ar&48000-ab&64k-s&320×240-vcodec&libx264-b$BR-flags+loop-cmp&+chroma-partitions&+parti4x4+partp8x8+partb8x8-subq&5-trellis&1-refs&1-coder&0
-me_range 16 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71-bt&200k-maxrate$BR-bufsize$BR&-rc_eq'blurCplx^(1-qComp)'-qcomp&0.6-qmin&10-qmax&51-qdiff&4-level&30-aspect&320:240-g&30-async&2
sample_$BR_pre.ts
segmenter sample_$BR_pre.ts 10 sample_$BR&stream-$BR.m3u8 http://www.ioncannon.net/
rm&-f&sample_$BR_pre.ts
Step 7: 创建不同码率 rate 的 HTTP stream
之前将的例子都是创建单一码率的HTTP Stream, 我们需要创建不同码率的视频流, 下面是一个简单的小例子。
六、让nginx支持MP4文件的直接播放
这是nginx的第三方模块的网址 :&
在上面可以找到支持MP4的模块,我们也可以直接从下面的网址下载 :
编译的时候可能会有点小错误:
解决错误:
因为在新版本的nginx中废弃了& zero_in_uri& 这个flag,稍微修改一下 nginx_mod_h264_streaming 的源代码
vim /usr/local/src/nginx_mod_h264_streaming-2.2.7/src/ngx_http_streaming_module.c
把158到161行注释掉
157&&&/*&TODO: Win32&*/
158&&&//if&(r-&zero_in_uri)
160&&&//&&return&NGX_DECLINED;
然后再make就正常了,make install 完成安装
在nginx配置文件中加入
location ~ .mp4$&{
& & & & & & & & mp4;
下面的命令从摄像头采集数据后发送到服务器进行切片
下面的命令时以文件gd.flv为输入数据流, 转码后发送到服务器进行切片
虚拟切片:
摄像头采集后的数据直接切片 :
ffmpeg.exe -f dshow -i video=&Integrated Camera&:audio=&麦克风 (Realtek High Definition Au& -s 640*480 -vcodec& libx264 -acodec libmp3lame -flags -global_header -map 0 -f segment -segment_time 10 -segment_list
live.m3u8 -segment_format mpegts live%05d.ts
FMPEG 把文件传送到rtmp的速度不正常的问题:
ffmpeg&-re&-i &输入文件&-qscale 3 -s 720*360 -aspect 16:9 -r 25 -threads 4 -vcodec flv-acodec libmp3lame -ar 44100 -ab 128k -ac 2 -f flvrtmp://127.0.0.1/rtmpsvr/RtmpVideo
关键是&-re解决同步压缩和办法的速度同步问题,而且要放在前面,不然不一定起作用!
首先应该感谢(天下文章一大抄),也不知道他是抄过来的还是自己写的,他给了我启发,当然不是抄的启发,而是里面内容确实让我完成了ffmpeg对rtmp直播流截图的处理,之前都有试过用opencv写个程序截图,但是写完发现,在使用载入视频流函数的时间比较长,这个也就容忍了,竟然在输入错误的流地址的时候,程序竟然死了,对,就是死掉了!!!我这样对程序严谨的人,怎么能允许这个错误呢,果断抛弃。废话不多说,先看我的一系列参数:
可能,也许,差不多后面的参数少的话就出现什么流找不到啊,什么的,下面来分析一下参数
-probesize 32768 :没有查到这个参数什么意思,不过字面意思是探针的大小,可能是内存申请32768大小的内存把
-i “rtmp。。。”&&& :后接地址
-y&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&:覆盖输出文件,即如果1.***文件已经存在的话,不经提示就覆盖掉了
-t&0.001&&&&&&&&&&&&&&&&&& :设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持
-ss 1&&&&&&&&&&&&&&&&&&&&&&&:延迟1秒后开始
-f image2&&&&&&&&&&&&&& :以图片格式保存
-r&1&&&&&&&&&&&&&&&&&&&&&&&&& :帧数,此处为截取一帧
最重要的要说一下: 在-i 后的地址,要用双引号括起来,如果是rtmp直播流,双引号里面要加上live=1
如果还不行的话,估计就是ffmpeg这个sdk有问题了,可能是里面没有兼容rtmp的东西,看看第一行链接里面的东西把,希望对你们有帮助。
当上述命令可以执行以后,会发现,录制的视频或者直播的视频图像质量非常不好,这是因为没有设置视频码率;
设置视频码率命令为:&-s 640x360 -b:v 580k ;
可以根据具体的分辨率设置具体的码率;
也可以通过&-qscale,设置图像质量;
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:

我要回帖

更多关于 ffmpeg 获取摄像头 的文章

 

随机推荐