分类: 嵌入式 http://blog.chinaunix.net/uid-26851094-id-3276088.html
解决办法是将原有的img_convert函数改为sws_scale函数,原来的函数调用为:
// Convert the image from its native format to RGB img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
修改为
#include // other codes static struct SwsContext *img_convert_ctx; // other codes img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); // other codes // Convert the image from its native format to RGB sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);编译正常,测试后程序可用,搞定。
4.3 undefined reference to `avcodec_decode_video'
修改为avcodec_decode_video2(pCodecCtx, &pFrame, &frameFinished, &packet); 可是程序还是有错误,Segmentation fault。
4.4 X11/extensions/XShm.h: 没有那个文件或目录
在这里找到了解决方法http://hi.baidu.com/lmy0525/blog/item/5b7af500169f5391e950cda2.html
X11/extensions/XShm.h: No such file or directory
安装x11proto-xext-dev和libxext-dev 通过命令sudo apt-get install libxext-dev解决
4.5
/opt/webcam/vshow.cpp:111: undefined reference to `sws_getContext(int, int, PixelFormat, int, int, PixelFormat, int, SwsFilter*, SwsFilter*, double const*)'
/opt/webcam/vshow.cpp:111: undefined reference to `Ctx::sws'
/opt/webcam/vshow.cpp:128: undefined reference to `avpicture_alloc(AVPicture*, PixelFormat, int, int)'
vshow.o: In function `vs_show(void*, unsigned char**, int*)':
/opt/webcam/vshow.cpp:154: undefined reference to `avpicture_free(AVPicture*)'
/opt/webcam/vshow.cpp:155: undefined reference to `Ctx::sws'
/opt/webcam/vshow.cpp:155: undefined reference to `sws_freeContext(SwsContext*)'
/opt/webcam/vshow.cpp:159: undefined reference to `sws_getContext(int, int, PixelFormat, int, int, PixelFormat, int, SwsFilter*, SwsFilter*, double const*)'
/opt/webcam/vshow.cpp:159: undefined reference to `Ctx::sws'
/opt/webcam/vshow.cpp:160: undefined reference to `avpicture_alloc(AVPicture*, PixelFormat, int, int)'
/opt/webcam/vshow.cpp:184: undefined reference to `Ctx::sws'
/opt/webcam/vshow.cpp:184: undefined reference to `sws_scale(SwsContext*, unsigned char const* const*, int const*, int, int, unsigned char* const*, int const*)'
collect2: ld returned 1 exit status
make: *** [webcam_shower] 错误 1
点击(此处)折叠或打开
- void CheckAndSetFmt(int fd,char* Sformat)
- {
- int rc;
- struct v4l2_fmtdesc fmt_desc; //获取摄像头
- memset(&fmt_desc, 0, sizeof(fmt_desc));
- struct v4l2_format fmt; //设置获取视频的格式
- memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //视频数据流类型,永远都是V4L2_BUF_TYPE_VIDEO_CAPTURE既然是永远了为什么还要弄出个选项了
- fmt.fmt.pix.width = 320; //设置视频宽度
- fmt.fmt.pix.height = 240; //设置视频高度
- uint32_t i = 0;
- printf("Check the Camera format and Set the format\n");
- for(i=0;;i++)
- {
- fmt_desc.index = i;
- fmt_desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rc = ioctl(fd, VIDIOC_ENUM_FMT, &fmt_desc);
- if (rc < 0)
- break;
- printf("support {pixelformat= %c%c%c%c, description= %s}\n",
- fmt_desc.pixelformat & 0xFF,
- (fmt_desc.pixelformat >> 8) & 0xFF,
- (fmt_desc.pixelformat>> 16) & 0xFF,
- (fmt_desc.pixelformat >> 24) & 0xFF,
- fmt_desc.description);
- if (strcmp((const char*) fmt_desc.description, Sformat) == 0)//"YUV 4:2:2 (YUYV)"
- {
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //视频源的格式为YUYV
- if (ioctl(fd, VIDIOC_S_FMT, &fmt) >= 0) //使配置生效
- printf("Set format %s succeed\n",Sformat);
- else
- printf("Set format %s failed\n",Sformat);
- }
- }
- }
-
- //函数功能列出摄像头支持到格式,并且设置需要到格式
- int main(int argc, char** argv)
- {
- int fd = open("/dev/video0", O_RDWR); //打开摄像头设备,使用阻塞方式打开
- if (fd<0)
- {
- printf("open error\n");
- return -1;
- }
- CheckAndSetFmt(fd,"YUV 4:2:2 (YUYV)");
- return 0;
- }
点击(此处)折叠或打开
- // mmap
- v4l2_buffer buf;
- for (int i = 0; i < BUFSISE; i++) {
-
- memset(&buf, 0, sizeof(buf));
- buf.type = Rebufs.type;
- buf.memory = Rebufs.memory;
- buf.index = i;//如何不加这个会出现四个映射在同一个摄像头缓冲区上
- if (ioctl(id, VIDIOC_QUERYBUF, &buf) < 0) {
- fprintf(stderr, "%s: VIDIOC_QUERYBUF ERR\n", __func__);
- close(id);
- delete ctx;
- return 0;
- }
- ctx->bufs[i].length = buf.length;
- ctx->bufs[i].start= mmap(NULL, buf.length, PROT_READ|PROT_WRITE,MAP_SHARED, id, buf.m.offset);
- fprintf(stderr, "buf.length=%d buf.m.offset=%d\t ctx->bufs[i].start=%d\n",buf.length,buf.m.offset,ctx->bufs[i].start);
- }
对应AVPicture里面有data[4]和linesize[4]其中data是一个指向指针的指针(二级、二维指针),也就是指向视频数据缓冲区的首地址,而data[0]~data[3]是一级指针,可以用如下的图来表示:
data -->xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
^ ^ ^
| | |
data[0] data[1] data[2]
比如说,当pix_fmt=PIX_FMT_YUV420P时,data中的数据是按照YUV的格式存储的,也就是:
data -->YYYYYYYYYYYYYYUUUUUUUUUUUUUVVVVVVVVVVVV ^ ^ ^ | | | data[0] data[1] data[2]linesize是指对应于每一行的大小,为什么需要这个变量,是因为在YUV格式和RGB格式时,每行的大小不一定等于图像的宽度,对于RGB格式输出时,只有一个通道(bgrbgrbgr......)可用,即linesize[0],和data[0],so RGB24 : data[0] = packet rgb//bgrbgrbgr......
linesize[0] = width*3其他的如data[1][2][3]与linesize[1][2][3]无任何意义.
而对于YUV格式输出时,有三个通道可用,即data[0][1][2],与linesize[0][1][2],而yuv格式对于运动估计时,需要填充padding(right, bottom),故:linesize=width+padding size(16+16).
点击(此处)折叠或打开
- ctx->pic_src.data[0] = (unsigned char*)ctx->bufs[buf.index].start;
- ctx->pic_src.data[1] = ctx->pic_src.data[2] = ctx->pic_src.data[3] = 0;
- ctx->pic_src.linesize[0] = ctx->bytesperrow;
- ctx->pic_src.linesize[1] = ctx->pic_src.linesize[2] = ctx->pic_src.linesize[3] = 0;
- fprintf(stderr, "ctx->pic_src.data[1] =%d\n", ctx->pic_src.data[1]);
- // sws_scale
- int rs = sws_scale(ctx->sws, ctx->pic_src.data, ctx->pic_src.linesize,
- 0, ctx->rows, ctx->pic_target.data, ctx->pic_target.linesize);
- fprintf(stderr, "ctx->pic_target.data[1] =%d\n", ctx->pic_target.data[1]);
- // out
- for (int i = 0; i < 4; i++) {
- pic->data[i] = ctx->pic_target.data[i];
- pic->stride[i] = ctx->pic_target.linesize[i];
- fprintf(stderr, "pic_target.data[%d] =%d\n",i, ctx->pic_target.data[i]);
- fprintf(stderr, "ctx->pic_target.linesize[%d] =%d\n",i, ctx->pic_target.linesize[i]);
- }
解压修改config.armlinux 中第一行:CROSS_COMPILE?= arm-linux- 其他的没有变了。
然后./genMakefile armlinux。
再make,就OK了,它没有make install。
首先进入到VLC的安装目录下,执行类似如下的命令:
vlc –ttl 12 -vvv –color -I telnet –telnet-password videolan –rtsp-host 219.219.218.239:5554
对上述参数的解释:–ttl:是对hop的限制;-vvv选项用来输出错误信息,可以省略;219.219.218.239是RSTP点播服务器的主机地址; videolan 是telnet登录RTSP点播服务器时输入的口令,这两个部分用户可以根据自己的情况进行修改。
登录RTSP点播服务器在这里我是运用SecureCRT软件进行telnet登录。界面如下所示:
当点击连接后,要求输入密码:videolan,回车后如果显示:Welcome, Master,则表明登录成功。
在主机名栏输入:219.219.218.239,该内容必须与前面建立的RTSP点播服务器的主机地址一致;在端口栏输入:4212,该端口号在使用VLC默认设置时不能改为其他的数值。
接下来就可以设置点播文件了
在登录成功的界面上,输入以下的命令:
new Test vod enabled
setup Test input myVideo.mpg
最后,就可以在客户端观看视频,命令如下:
vlc rtsp://219.219.218.239:5554/Test
还可以通过VLC播放器的VLM进行可视化配制,并生成.vlm配置文件,然后利用SecureCRT工具登录到RTSP点播服务器,利用load命令将配置文件导入,使用show命令可以查看导入的文件信息。
测试结果:CDXA/MPEG-PS 未经过编码转换即可播放,但是仅可以用VLC播放器进行播放。原因是其他播放器无法解析rtsp://219.219.218.147:5554/Test 中的Test文件名。
7.3知己做的rtsp服务器和网上的rtsp服务器的区别
1)先说网上的rtsp服务器,我是通过千里眼(http://218.204.223.237:8081/wap/)获取的视频了进行抓包分析
rtsp://218.204.223.237:554/mobile/1/66251FC11353191F/syiubra2azl52x0g.sdp
如下图
产生的问题:1、RTP到底是用TCP发生还是用UDP发送,根据抓包的情况应该是通过TCP发发送的,(推测可能是应为远距离传输所以采用的是RTP打包为TCP)。
2)下面是对我自己的RTSP服务器抓包分析
可以看到我还没点击播放rstp服务器就向客户端发送UDP包了!
也就是说rtsp://172.19.72.110:8080/test.sdp只是让vlc知道如何去解析这些udp包
点击播放,就可以看到视频了
总结:我自己通过vlc做的简单的rstp服务器只是将视频同通过打包为RTP然后通过UDP发送到固定IP或者广播到局域网中,然后客户端通过vlc通过读取指定rtsp://172.19.72.110:8080/test.sdp的sdp文件对udp进行解析并播放,我都不清楚我的到底是不是rtsp流媒体服务器,服务器直接就发送了,好像都没看到过RTSP协议的影子,要是用3G网卡哪的多耗流量呀,还有就是估计远程传输得用TCP模式的RTP。希望我的这些猜测能在后面得到证实
7.4 RTSP传输方式由什么决定呢? TCP or UDP
请教一个问题:RTSP 中 SETUP 命令中传输方式是有什么指定呢? 是由服务器决定的吗?SETUP rtsp://www.loacl.com/sample.3gp
Transport: RTP/AVP/TCP 【TCP传输方式】 或
Transport: RTP/AVP 【UDP传输方式】
-------------------------
我用的是openRTSP,如果没有 -t 参数的话,就接受不到数据,加上-t 才能收到数据。
-t 参数为 TCP方式传输.
我用抓包工具观察
有-t 的话 Transport: RTP/AVP/TCP;
无-t 的话 Transport: RTP/AVP;
-----------------------
对于一个未知的服务器,这么判断服务器是什么方式传输呢? udp 还是 tcp
------解决方案--------------------------------------------------------
openRTSP有-t参数说明使用tcp接收数据;
无-t默认是UDP接收数据,而无-t参数接收不到数据,大概是因为你机器狮子内网,而rtsp server是在外网吧?
如果rtsp server在外网,外网udp数据自然无法到达你所在的内网的;
rtsp协议本身不支持似网穿透、UDP打洞等;
------解决方案--------------------------------------------------------
貌似发describ的时候,服务器会返回一些信息的吧,貌似就能知道是tcp还是udp了。
------解决方案--------------------------------------------------------
openRTSP有-t是TCP方式。
用vlc2.0.1做rtsp服务器,vlc-0.9.9没有rtsp这个选项,
早知道vlc很强大, 但是流媒体功能一直没有成功过, 今天终于成功了, 分享经验给大家
举例, 本地有一视频文件
打开vlc, [media]->streaming-> load your media file-> press[streaming]
output类型选mmsh, 地址选你本机的ip地址, 端口可以不用变 1234
[方案 或 档案]选 video- wma wmv 或 windows(wmv or asf)
然后点击[streaming]
接下来在ie的地址栏里写入mms://your ip address:1234就可以看到你现在正在播放的视频流媒体了
官方文档:Android Supported Media Formats提到
The following network protocols are supported for audio and video playback:
RTSP (RTP, SDP)
HTTP/HTTPS progressive streaming
HTTP/HTTPS live streaming draft protocol:
MPEG-2 TS media files only
Protocol version 3 (Android 4.0 and above)
Protocol version 2 (Android 3.x)
Not supported before Android 3.0