red5流媒体服务器研究(1)——启动的秘密

red5流媒体服务器研究(一)——启动的秘密

如有转载,请注明出处,谢谢。

 

由于工作上面的需要,开始了对流媒体的研究。对于一个做了许久J2EE应用的人来说,关于流媒体的印象仅仅停留在边播边下载上(其实是点播),至于说到实时直播什么的一头雾水。。然后,找到了red5,看了licence,好吧,开源,java写的,果断开始研究。

下载RC版本,打开文件目录,跟tomcat的文件结构比较像,然后点开conf,大概超过20个配置文件,果断放一边,然后下载源代码,开始导入IDE。。。

 

打开red5.bat,第七行

 if NOT DEFINED RED5_MAINCLASS set ED5_MAINCLASS=org.red5.server.Bootstrap

启动的入口应该就在org.red5.server.Bootstrap这里了。OK,开始读源码去。

 

打开源码文件的第一印象,注释写得很全,看起来应该没有太大的问题了,松了口气。

 

		//retrieve path elements from system properties
		String root = getRed5Root();
		getConfigurationRoot(root);

 看到这个地方,以后编写java的可执行程序的时候,相关的jar包什么的看来不用去用shell脚本或者其他的脚本来管理了,可以在启动前开始加载。。

 

 

                // create a new instance of this class using new classloader
		Object boot = Class.forName("org.red5.server.Launcher", true, loader).newInstance();
		Method m1 = boot.getClass().getMethod("launch", (Class[]) null);
		m1.invoke(boot, (Object[]) null);

 设置各种环境后真正的启动,从org.red5.server.Launcher开始

 

打开到org.red5.server.Launcher文件

 

                        //create red5 app context
			FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(new String[] { "classpath:/red5.xml" }, false);
			//set the current threads classloader as the loader for the factory/appctx
			ctx.setClassLoader(Thread.currentThread().getContextClassLoader());
			//refresh must be called before accessing the bean factory
			ctx.refresh();

 直接采用spring进行加载, create red5 app context。

 

打开red5.xml配置文件

 

        <!-- This file just wires together the context tree. Its accessed by ContextSingletonBeanFactoryLocator -->
	
	<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:/red5.properties" />
	</bean>

	<!-- First we load the common context, its shared between all the other contexts -->
	<!-- Global context serves as the parent to all child contexts. -->
	<bean id="red5.common" class="org.springframework.context.support.FileSystemXmlApplicationContext">
    	<constructor-arg><list><value>classpath:/red5-common.xml</value></list></constructor-arg>
	</bean>
	
	<!-- Then we load the core context, with the common as parent --> 
	<!-- Context holding all the networking, users should need to edit. -->
	<bean id="red5.core" class="org.springframework.context.support.FileSystemXmlApplicationContext">
    	<constructor-arg><list><value>classpath:/red5-core.xml</value></list></constructor-arg>
    	<constructor-arg><ref bean="red5.common" /></constructor-arg>
	</bean>

	<!-- Then we load the global contexts, note its important this happens before app container loads -->
	<bean id="context.loader" class="org.red5.server.ContextLoader">
		<property name="parentContext" ref="red5.common" />
		<property name="contextsConfig" value="classpath:/red5.globals" />
		<property name="useShutdownHook" value="false" />
	</bean>	
	
    <bean id="pluginLauncher" class="org.red5.server.plugin.PluginLauncher" />
	
	<!-- Now we can load the JEE container / servlet engine -->
  	<import resource="classpath:/jee-container.xml"/>

 注释上写着:This file just wires together the context tree.按照个人习惯,打开red5-core.xml文件,看到第一行注释:<!-- This context holds all the networking: mina -->,里面应该包括了所有的关于mina,socket通信方面的内容。

 

 

	<!-- RTMP Mina Transport -->
	<bean id="rtmpTransport" class="org.red5.server.net.rtmp.RTMPMinaTransport" init-method="start" destroy-method="stop">
		<property name="ioHandler" ref="rtmpMinaIoHandler" />
        <property name="connectors">
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg index="0" type="java.lang.String" value="${rtmp.host}" />  
                    <constructor-arg index="1" type="int" value="${rtmp.port}" />  
                </bean>
                <!-- You can now add additional ports and ip addresses
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg index="0" type="java.lang.String" value="${rtmp.host}" />  
                    <constructor-arg index="1" type="int" value="1936" />  
                </bean>
                 -->
            </list>
        </property>
		<property name="ioThreads" value="${rtmp.io_threads}" />
        <property name="tcpNoDelay" value="${rtmp.tcp_nodelay}" />
		<!-- This is the interval at which the sessions are polled for stats. If mina monitoring is not
				enabled, polling will not occur. -->
		<property name="minaPollInterval" value="${jmx.mina.poll.interval}" />
		<property name="enableMinaMonitor" value="${jmx.mina.monitor.enable}" />
	</bean>

 从配置上看,org.red5.server.net.rtmp.RTMPMinaTransport就是启动mina的地方了。

 

 

	<!-- RTMP Mina IO Handler -->
	<bean id="rtmpMinaIoHandler" class="org.red5.server.net.rtmp.RTMPMinaIoHandler">
		<property name="handler" ref="rtmpHandler" />
		<property name="rtmpConnManager" ref="rtmpMinaConnManager" />
	</bean>

 启动mina后,关于数据上的处理,就在org.red5.server.net.rtmp.RTMPMinaIoHandler里面了。

 

 

mina的启动先放一放,根据red5的相关文档,其中有集成tomcat容器,从red5.xml文件中可看到

	<!-- Now we can load the JEE container / servlet engine -->
  	<import resource="classpath:/jee-container.xml"/>

 所以,关于集成tomcat的地方,就在配置文件jee-container.xml文件中。

	<bean id="tomcat.server" class="org.red5.server.tomcat.TomcatLoader" init-method="init" destroy-method="shutdown" depends-on="context.loader">

		<property name="webappFolder" value="${red5.root}/webapps" />
			      
	    <property name="connector">
			<bean class="org.apache.catalina.connector.Connector">
				<!-- Blocking I/O -->
				<constructor-arg type="java.lang.String" value="org.apache.coyote.http11.Http11Protocol" />
				<!-- Non-blocking I/O -->
				<!--
				<constructor-arg type="java.lang.String" value="org.apache.coyote.http11.Http11NioProtocol" />	
				-->
                <property name="port"><value>${http.port}</value></property>
		        <property name="redirectPort"><value>${https.port}</value></property>
                <property name="enableLookups"><value>false</value></property>
                <property name="useIPVHosts"><value>true</value></property>
                <property name="URIEncoding"><value>${http.URIEncoding}</value></property>
			</bean>
	    </property>
	    	
        <property name="address">
            <bean class="java.net.InetSocketAddress">
                <constructor-arg index="0" type="java.lang.String" value="${http.host}" />  
                <constructor-arg index="1" type="int" value="${http.port}" />  
            </bean>	
        </property>
	    	
        <property name="baseHost">
	       <bean class="org.apache.catalina.core.StandardHost">
	           <property name="name" value="${http.host}" />
	           <property name="unpackWARs" value="true" />
	           <property name="autoDeploy" value="true" />
	           <property name="xmlValidation" value="false" />
	           <property name="xmlNamespaceAware" value="false" />
	       </bean>	   
	    </property>		

		<property name="valves">
      		<list>
	    		<bean id="valve.access" class="org.apache.catalina.valves.AccessLogValve">
	                <property name="directory" value="log" />
	                <property name="prefix" value="${http.host}_access." />
	                <property name="suffix" value=".log" />
	                <property name="pattern" value="common" />
	                <property name="resolveHosts" value="false" />
	                <property name="rotatable" value="true" />
	        	</bean>
        	</list>
        </property>
	    
	</bean>

 从上面的配置看,red5加载集成tomcat的主要入口就在org.red5.server.tomcat.TomcatLoader里面了,可惜源码包中没有这部分内容,在其他地方也没有找到,应该是不开源的一部分。

从配置的内容看,其主要包括 webappFolder 为发布应用的目录,相当于 tomcat中的webapp,其余部分都是http,https,baseHost等相关配置,相关内容在red5.properties文件中,可对应查找。

 

回到mina启动部分,根据配置的内容socket数据的处理入口在org.red5.server.net.rtmp.RTMPMinaIoHandler中

/**
 * Handles all RTMP protocol events fired by the MINA framework.
 */
public class RTMPMinaIoHandler extends IoHandlerAdapter implements ApplicationContextAware

 。

 

下一章  red5流媒体服务器研究(二)——RTMP协议和数据解析