平台:君正T20(带硬件编码)
sensor: ov9732
最近在君正T20平台上实现了WIFI摄像头功能,将方法和思路记录下来。刚接触流媒体这块,欢迎这方面的专家批评指正。对于和我一样的初学者,希望能起到抛砖引玉的作用:
a、连接方式:T20可以与手机(或电脑)直连,也可以通过路由器。
直连:在君正T20平台上,无线网卡设置成AP模式,创建WIFI热点,PC机通过热点与T20直连。具体操作可以参考这里
通过路由器:T20与手机(或电脑)都连接路由器提供的WIFI热点。
b、RTSP服务器:T20端移植live555,作为RTSP服务器。
c、客户端:用VLC作为客户端
一、Live555框架简介:
Live555是一个实现了RTSP协议的开源流媒体框架,Live555包含RTSP服务器端的实现以及RTSP客户端的实现。Live555可以
将若干种格式的视频文件或者音频文件转换成视频流或者音频流在网络中通过RTSP协议分发传播,这便是流媒体服务器最核心
的功能。
二、具体实现:
基本流程:视频采集编码模块将采集的数据送给Live555 RTSP server,Live555 RTSP server将数据发送出去。
实现思路:将视频采集模块和Live555 RTSP server分别放到两个进程中,这两个进程通过fifo传输视频数据。具体流程如下图
所示:
代码结构:
├── capture_and_encoding.cpp //基于君正采集编码API,编写采集编码模块
├── capture_and_encoding.h
├── h264_video_streamer.cpp //Live555 RTSP服务器,多播形式
├── imp-common.c
├── imp-common.h
├── imp-common.o
├── include
│ ├── imp_sys //君正T20API头文件
. . . . . . .//此处省略N行. . .
│ │ ├── glibc
. . . . . . .//此处省略N行. . .
│ │ └── uclibc
. . . . . . .//此处省略N行. . .
on_demand_rtsp_server.cpp代码分析:
on_demand_rtsp_server.cpp是在Live555源码live/testProgs/testOnDemandRTSPServer.cpp的基础上修改而来。
主要修改:1、删掉了.m4e、h265、.mpg等格式文件的点播模块,只保留了h264
2、引入父子进程,将视频采集编码模块添加到父进程,将Live555 RTSP server添加到子进程。
/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See .)
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
more details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
**********/
// Copyright (c) 1996-2018, Live Networks, Inc. All rights reserved
// A test program that demonstrates how to stream - via unicast RTP
// - various kinds of file on demand, using a built-in RTSP server.
// main program
#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include
#include
#include
#include "capture_and_encoding.h"
UsageEnvironment* env;
// To make the second and subsequent client for each stream reuse the same
// input stream as the first client (rather than playing the file from the
// start for each client), change the following "False" to "True":
Boolean reuseFirstSource = False;
// To stream *only* MPEG-1 or 2 video "I" frames
// (e.g., to reduce network bandwidth),
// change the following "False" to "True":
Boolean iFramesOnly = False;
char const* inputFileName = "/tmp/h264_fifo";
static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms,
char const* streamName, char const* inputFileName); // fwd
static char newDemuxWatchVariable;
static MatroskaFileServerDemux* matroskaDemux;
static void onMatroskaDemuxCreation(MatroskaFileServerDemux* newDemux, void* /*clientData*/) {
matroskaDemux = newDemux;
newDemuxWatchVariable = 1;
}
static OggFileServerDemux* oggDemux;
static void onOggDemuxCreation(OggFileServerDemux* newDemux, void* /*clientData*/) {
oggDemux = newDemux;
newDemuxWatchVariable = 1;
}
int main(int argc, char** argv) {
// Begin by setting up our usage environment:
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
env = BasicUsageEnvironment::createNew(*scheduler);
UserAuthenticationDatabase* authDB = NULL;
#ifdef ACCESS_CONTROL
// To implement client access control to the RTSP server, do the following:
authDB = new UserAuthenticationDatabase;
authDB->addUserRecord("username1", "password1"); // replace these with real strings
// Repeat the above with each , that you wish to allow
// access to the server.
#endif
int fd;
capture_and_encoding();//基于君正提供的API初始化视频采集和编码模块
unlink(inputFileName);
if (mkfifo(inputFileName, 0777) < 0) {
*env << "mkfifo Failed\n";
exit(1);;
}
if (fork() > 0) {
fd = open(inputFileName, O_RDWR | O_CREAT | O_TRUNC, 0777);
if (fd < 0) {
*env << "Failed open fifo\n";
exit(1);;
}
while (1) {
get_stream(fd ,0);//基于君正提供的API实现视频采集和编码,并将编码后的视频数据保存到fifo中。
}
} else {
// Create the RTSP server:
RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);
if (rtspServer == NULL) {
*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
exit(1);
}
char const* descriptionString
= "Session streamed by \"testOnDemandRTSPServer\"";
// Set up each of the possible streams that can be served by the
// RTSP server. Each such stream is implemented using a
// "ServerMediaSession" object, plus one or more
// "ServerMediaSubsession" objects for each audio/video substream.
// A H.264 video elementary stream:
char const* streamName = "stream";
ServerMediaSession* sms
= ServerMediaSession::createNew(*env, streamName, streamName,
descriptionString);
sms->addSubsession(H264VideoFileServerMediaSubsession
::createNew(*env, inputFileName, reuseFirstSource));
rtspServer->addServerMediaSession(sms);
announceStream(rtspServer, sms, streamName, inputFileName);
}
env->taskScheduler().doEventLoop(); // does not return
return 0; // only to prevent compiler warning
}
static void announceStream(RTSPServer* rtspServer, ServerMediaSession* sms,
char const* streamName, char const* inputFileName) {
char* url = rtspServer->rtspURL(sms);
UsageEnvironment& env = rtspServer->envir();
env << "\n\"" << streamName << "\" stream, from the file \""
<< inputFileName << "\"\n";
env << "Play this stream using the URL \"" << url << "\"\n";
delete[] url;
}
h264_video_streamer.cpp与on_demand_rtsp_server.cpp类似,是基于Live555源码live/testProgstestH264VideoStreamer.cpp修改而来。区别在于h264_video_streamer.cpp是多播形式。
由于商业保密原因,君正的采集编码部分的代码不便公开。
后续我会用X264编码取代君正的硬件编码,届时将开放所有源码,敬请期待!
效果展示:
在windows上用VLC播放:
在手机上用VLC播放: