`

网站实现视频上传、转码、截图及在线播放功能

 
阅读更多
       早些天一老同学问到怎么在网站上传自己制作的视频并在线播放呢?当时想了想自己还真没进行过这方面的应用开发。上传并在线播放视频现在应用非常广泛,优酷、土豆等在这方面应用得非常成熟。正好趁这几天不忙整理了一下这方面的知识。      
    在线视频播放网站主流播放格式为FLV。我们顺便了解一下什么是FLV       
    FLVFLASHVIDEO的简称,FLV流媒体格式是一种新的视频格式,全称为FlashVideo。由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能,它的出现有效地解决了视频文件导入Flash后,使导出的SWF文件体积庞大,不能在网络上很好的使用等缺点。 目前各在线视频网站均采用此视频格式。如新浪播客、56、土豆、酷6youtube等,无一例外。FLV已经成为当前视频文件的主流格式。

    FLV就是随着FlashMX的推出发展而来的视频格式,目前被众多新一代视频分享网站所采用,是目前增长最快、最为广泛的视频传播格式。是在sorenson公司的压缩算法的基础上开发出来的。FLV格式不仅可以轻松的导入Flash中,速度极快,并且能其到保护版权的作用,并且可以不通过本地的微软或者REAL播放器播放视频。

说到底需要实现在线播放视频,就需要上传的视频格式转换成FLV格式。因此我们可以总结出实现视频在线播放功能有4大基本步骤:

1、上传视频

      对于视频上传在这里我就不详细说了,跟我们平时做的文件上传功能差不多。一般都是用第三方开源工具commons-fileupload.jar。具体需要用到的jar如下:

    上传页面表单配置必须为multipart/form-data格式,如下例子:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  </head>  
  
  <body>
     <!-- enctype 默认是 application/x-www-form-urlencoded -->
     <form action="FileUpLoad" enctype="multipart/form-data" method="post" >
        
                 普通表单:<input type="text" name="usename"> <br/>
               上传文件1:<input type="file" name="file1"><br/>
               上传文件2: <input type="file" name="file2"><br/>
              <input type="submit" value="提交"/>
     
     </form>   
  </body>
</html>

    上传处理后台servlet一般如一下代码:

package com.mediaplayer.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/** 
 *  
 * @author Administrator 
 * 文件上传 
 * 具体步骤: 
 * 1)获得磁盘文件条目工厂 DiskFileItemFactory 要导包 
 * 2) 利用 request 获取 真实路径 ,供临时文件存储,和 最终文件存储 ,这两个存储位置可不同,也可相同 
 * 3)对 DiskFileItemFactory 对象设置一些 属性 
 * 4)上层API文件上传处理  ServletFileUpload upload = new ServletFileUpload(factory); 
 * 目的是调用 parseRequest(request)方法  获得 FileItem 集合list , 
 *      
 * 5)在 FileItem 对象中 获取信息,   遍历, 判断 表单提交过来的信息 是否是 普通文本信息  另做处理 
 * 6) 
 *    第一种. 用第三方 提供的  item.write( new File(path,filename) ); 直接写到磁盘上 
 *    第二种. 手动处理   
 * 
 */ 
public class FileUpLoad extends HttpServlet {  
	  
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void doPost(HttpServletRequest request, HttpServletResponse response)  
            throws ServletException, IOException {  
          
        request.setCharacterEncoding("utf-8");  //设置编码  
          
        //获得磁盘文件条目工厂  
        DiskFileItemFactory factory = new DiskFileItemFactory();  
        //获取文件需要上传到的路径  
        String path = request.getRealPath("/upload");  
          
        //如果没以下两行设置的话,上传大的 文件 会占用 很多内存,  
        //设置暂时存放的 存储室 , 这个存储室,可以和 最终存储文件 的目录不同  
        /** 
         * 原理 它是先存到 暂时存储室,然后在真正写到 对应目录的硬盘上,  
         * 按理来说 当上传一个文件时,其实是上传了两份,第一个是以 .tem 格式的  
         * 然后再将其真正写到 对应目录的硬盘上 
         */  
        factory.setRepository(new File(path));  
        //设置 缓存的大小,当上传文件的容量超过该缓存时,直接放到 暂时存储室  
        factory.setSizeThreshold(1024*1024) ;  
          
        //上层API文件上传处理  
        ServletFileUpload upload = new ServletFileUpload(factory);  
          
        try {  
            //可以上传多个文件  
            List<FileItem> list = (List<FileItem>)upload.parseRequest(request);  
              
            for(FileItem item : list)  
            {  
                //获取表单的属性名字  
                String name = item.getFieldName();  
                  
                //如果获取的 表单信息是普通的 文本 信息  
                if(item.isFormField())  
                {                     
                    //获取用户具体输入的字符串 ,名字起得挺好,因为表单提交过来的是 字符串类型的  
                    String value = item.getString() ;  
                      
                    request.setAttribute(name, value);  
                }  
                //对传入的非 简单的字符串进行处理 ,比如说二进制的 图片,电影这些  
                else  
                {  
                    /** 
                     * 以下三步,主要获取 上传文件的名字 
                     */  
                    //获取路径名  
                    String value = item.getName() ;  
                    //索引到最后一个反斜杠  
                    int start = value.lastIndexOf("\\");  
                    //截取 上传文件的 字符串名字,加1是 去掉反斜杠,  
                    String filename = value.substring(start+1);  
                      
                    request.setAttribute(name, filename);  
                      
                    //真正写到磁盘上  
                    //它抛出的异常 用exception 捕捉  
                      
                    //item.write( new File(path,filename) );//第三方提供的  
                      
                    //手动写的  
                    OutputStream out = new FileOutputStream(new File(path,filename));  
                      
                    InputStream in = item.getInputStream() ;  
                      
                    int length = 0 ;  
                    byte [] buf = new byte[1024] ;  
                      
                    System.out.println("获取上传文件的总共的容量:"+item.getSize());  
  
                    // in.read(buf) 每次读到的数据存放在   buf 数组中  
                    while( (length = in.read(buf) ) != -1)  
                    {  
                        //在   buf 数组中 取出数据 写到 (输出流)磁盘上  
                        out.write(buf, 0, length);  
                          
                    }  
                      
                    in.close();  
                    out.close();  
                }  
            }  
              
              
              
        } catch (FileUploadException e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  
        catch (Exception e) {  
            // TODO Auto-generated catch block  
              
            //e.printStackTrace();  
        }  
        request.getRequestDispatcher("filedemo.jsp").forward(request, response);  
    }  
  
}  
2、转换上传视频格式

       当后台接收到上传的视频文件后我们需要将视频格式进行转换,将其他格式转换成flv就需要一个解码器的支持。比较通用的是多媒体视频处理工具ffmpeg。我们先了解一下ffmpeg能够做的事情,ffmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。ffmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP的流媒体服务器,支持直播应用。

   1.能支持的格式

   ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)

   2.不能支持的格式

    对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式。

    下面我们看看视频转换代码如何实现:

   

package com.mediaplayer.dao;
/**
 * 
 * 功能说明:视频处理dao
 * @author ljf  email: liangjf@hundsun.com  
 * @date 2014-10-14 上午10:32:31
 * @version 2.0.0
 * @since JDK1.6 
 *
 */
public interface MediaDao {
	
	/**
	 * 视频转码
	 * @param srcFilePath  用于指定要转换格式的文件,要截图的视频源文件
	 * @param codcFilePath 格式转换后的的文件保存路径
	 * @param mediaPicPath 截图保存路径
	 * @return
	 */
	public boolean executeCodecs(String srcFilePath, String codcFilePath, String mediaPicPath);
	
	/**
	 * 可转换为FLV视频文件
	 * @param file
	 * @return
	 */
	public boolean isConvertFLV(String file);
	
	/**
	 * 可转换为AVI视频文件
	 * @param file
	 * @return
	 */
	public boolean isConvertAVI(String file);
	
	/**
	 * 删除中间转换视频文件
	 * @param tempFile
	 */
	public void deleteAVIFile(String tempFile);
}

 

package com.mediaplayer.dao;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class MediaDaoImpl implements MediaDao {

	public boolean isConvertFLV(String file) {
		boolean result = false;
		String ext = file.substring(file.lastIndexOf(".") + 1,   
	    		  file.length()).toLowerCase();
		// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等) 
		if (ext.equals("avi")) {  
			result = true;  
		} else if (ext.equals("mpg")) {  
			result = true;  
		} else if (ext.equals("wmv")) {  
			result = true;  
		} else if (ext.equals("3gp")) {  
			result = true;  
        } else if (ext.equals("mov")) {  
        	result = true;  
        } else if (ext.equals("mp4")) {  
        	result = true;  
        } else if (ext.equals("asf")) {  
        	result = true;  
        } else if (ext.equals("asx")) {  
        	result = true;   
        } else if (ext.equals("flv")) {  
        	result = true;    
        }  
		return result;
	}

	public boolean isConvertAVI(String file) {
		boolean result = false;
		String ext = file.substring(file.lastIndexOf(".") + 1,   
	    		  file.length()).toLowerCase();
		// 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),  
        // 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式.  
        if (ext.equals("wmv9")) {  
        	result = true;  
        } else if (ext.equals("rm")) {  
        	result = true; 
        } else if (ext.equals("rmvb")) {  
        	result = true; 
        }  
		return result;
	}

	public boolean executeCodecs(String srcFilePath, String codcFilePath,
			String mediaPicPath) {
		String basePath = System.getProperty("user.dir");
		String mencoderPath = "D:\\bbsp\\work\\MediaPlayer\\src\\main\\resources\\tools\\mencoder.exe";
		String ffmpegPath = "D:\\bbsp\\work\\MediaPlayer\\src\\main\\resources\\tools\\ffmpeg.exe";
		boolean mark = true;
		String tempPath = basePath + File.separator + "temp" + File.separator + String.valueOf(System.currentTimeMillis())+ ".avi";
		if(isConvertAVI(srcFilePath)){
			mark = this.convertAVI(mencoderPath, srcFilePath, tempPath);
			srcFilePath = tempPath;
		}
		if(isConvertFLV(srcFilePath) && mark){
			mark = this.convertFLV(ffmpegPath, srcFilePath, codcFilePath);
			mark = this.cutPic(ffmpegPath, srcFilePath, mediaPicPath);
		}else{
			System.out.println("该视频格式无法转换");
			mark = false;
		}
		this.deleteAVIFile(tempPath);
		return mark;
	}
	
	private boolean convertFLV(String ffmpegPath,String srcFilePath, String codcFilePath) {
		File file = new File(ffmpegPath);
		File srcFile = new File(srcFilePath);
		if(file.exists()){
			System.out.println("转换工具存在");
		}
		if(srcFile.exists()){
			System.out.println("源视频存在");
		}
		// 创建一个List集合来保存转换视频文件为flv格式的命令
        List<String> convert = new ArrayList<String>();
        convert.add(ffmpegPath); // 添加转换工具路径
        convert.add("-i"); // 添加参数"-i",该参数指定要转换的文件
        convert.add(srcFilePath); // 添加要转换格式的视频文件的路径
        convert.add("-ab");        //设置音频码率
        convert.add("128");
        convert.add("-ac");        //设置声道数
        convert.add("2");
        convert.add("-qscale");       
        convert.add("6");
        convert.add("-ar");        //设置声音的采样频率
        convert.add("22050");
        convert.add("-r");        //设置帧频
        convert.add("29.97");
        convert.add("-b");
        convert.add("5942.13");
        convert.add("-s");
        convert.add("1280x720");
        convert.add("-y"); // 添加参数"-y",该参数指定将覆盖已存在的文件
        convert.add(codcFilePath);

        boolean mark = true;
        try {
            Process proc = new ProcessBuilder(convert).redirectErrorStream(true).start();
            BufferedReader stdout = new BufferedReader(  
                    new InputStreamReader(proc.getInputStream()));  
            String line;  
            while ((line = stdout.readLine()) != null) {  
            	System.out.println(line);
            }   
        } catch (Exception e) {
            mark = false;
            System.out.println(e);
            e.printStackTrace();
        }
        return mark;
	}
	
	private Boolean cutPic(String ffmpegPath, String srcFilePath, String mediaPicPath) {
		// 创建一个List集合来保存从视频中截取图片的命令
        List<String> cutpic = new ArrayList<String>();
        cutpic.add(ffmpegPath);
        cutpic.add("-i");
        cutpic.add(srcFilePath); // 同上(指定的文件即可以是转换为flv格式之前的文件,也可以是转换的flv文件)
        cutpic.add("-y");
        cutpic.add("-f");
        cutpic.add("image2");
        cutpic.add("-ss"); // 添加参数"-ss",该参数指定截取的起始时间
        cutpic.add("7"); // 添加起始时间为第17秒
        cutpic.add("-t"); // 添加参数"-t",该参数指定持续时间
        cutpic.add("0.001"); // 添加持续时间为1毫秒
        cutpic.add("-s"); // 添加参数"-s",该参数指定截取的图片大小
        cutpic.add("800*280"); // 添加截取的图片大小为350*240
        cutpic.add(mediaPicPath); // 添加截取的图片的保存路径

        boolean mark = true;
        ProcessBuilder builder = new ProcessBuilder();
        try {
            builder.command(cutpic);
            builder.redirectErrorStream(true);
            // 如果此属性为 true,则任何由通过此对象的 start() 方法启动的后续子进程生成的错误输出都将与标准输出合并,
            //因此两者均可使用 Process.getInputStream() 方法读取。这使得关联错误消息和相应的输出变得更容易
            builder.start();
        } catch (Exception e) {
            mark = false;
            System.out.println(e);
            e.printStackTrace();
        }
        return mark;
	}
	
	private boolean convertAVI(String mencoderPath,String srcFilePath, String codcFilePath) {  
        List<String> commend = new ArrayList<String>();  
        commend.add(mencoderPath);  
        commend.add(srcFilePath);  
        commend.add("-oac");  
        commend.add("lavc");  
        commend.add("-lavcopts");  
        commend.add("acodec=mp3:abitrate=64");  
        commend.add("-ovc");  
        commend.add("xvid");  
        commend.add("-xvidencopts");  
        commend.add("bitrate=600");  
        commend.add("-of");  
        commend.add("avi");  
        commend.add("-o");  
        commend.add(codcFilePath);  
        try {  
            ProcessBuilder builder = new ProcessBuilder();  
            builder.command(commend);  
            builder.redirectErrorStream(true);//后续子进程错误输出与标准输出合并
            Process p = builder.start();  
            p.getInputStream();
            //后续进程等待Mencoder进程转换结束后才可进行
            p.waitFor(); 
            return true;
        } catch (Exception e) {  
            e.printStackTrace();  
            return false;  
        }  
    }

	public void deleteAVIFile(String tempFile) {
		File file = new File(tempFile);
		if(file.exists()){
			file.delete();
		}
	}  

}

 

package com.mediaplayer.service;

public interface MediaService {
	
	/**
	 * 视频转码
	 * @param srcFilePath  用于指定要转换格式的文件,要截图的视频源文件
	 * @param codcFilePath 格式转换后的的文件保存路径
	 * @param mediaPicPath 截图保存路径
	 * @return
	 */
	public boolean executeCodecs(String srcFilePath, String codcFilePath, String mediaPicPath);
}

 

package com.mediaplayer.service;

import com.mediaplayer.dao.MediaDao;

public class MediaServiceImpl implements MediaService {

	private MediaDao mediaDao;
	
	public MediaDao getMediaDao() {
		return mediaDao;
	}

	public void setMediaDao(MediaDao mediaDao) {
		this.mediaDao = mediaDao;
	}

	public boolean executeCodecs(String srcFilePath, String codcFilePath,
			String mediaPicPath) {
		return mediaDao.executeCodecs(srcFilePath, codcFilePath, mediaPicPath);
	}

}

   接下来我们再写一个测试类:

package com.mediaplayer.test;

import com.mediaplayer.dao.MediaDao;
import com.mediaplayer.dao.MediaDaoImpl;
import com.mediaplayer.service.MediaServiceImpl;

public class TestMediaPlayer {

	public static void main(String[] args) {
		//自定义方式产生文件名
        String serialName = String.valueOf(System.currentTimeMillis());
		String srcFilePath ="D:\\bbsp\\work\\MediaPlayer\\src\\main\\resources\\videos\\Wildlife.wmv";
		String codcFilePath = "D:\\bbsp\\work\\MediaPlayer\\src\\main\\resources\\videos\\" + serialName + ".flv";
		String mediaPicPath = "D:\\bbsp\\work\\MediaPlayer\\src\\main\\resources\\images\\" + serialName + ".jpg";
		MediaDao mediaDao = new MediaDaoImpl();
		MediaServiceImpl mediaService = new MediaServiceImpl();
		mediaService.setMediaDao(mediaDao);
		mediaService.executeCodecs(srcFilePath, codcFilePath, mediaPicPath);
	}

}

 最后我们可以看到转换出来的flv视频文件与视频截图出来的jpg文件:

 

 

 

3、截图预览

     截图预览就不多说了,只需要建立一个<img>标签指向需要显示的图片url就可以了:

<img alt="图片预览" src="D:/bbsp/work/MediaPlayer/src/main/resources/images/1413339390664.jpg">
 

 

4、实现在线播放

   最后需要使用flv播放器进行在线播放flv视频。常见的播放器有同感Flash制作出来的player.sef播放器跟vcastr2.swf播放器。我这里就使用vcastr2.swf作为例子,我们需要在页面中嵌入播放器跟视频地址相关配置信息:

 

<%@page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<script type="text/javascript">
var swf_width="95%";  
var swf_height="90%";  
var files='1413339390664.flv';  
var config='0:自动播放|1:连续播放|100:默认音量|0:控制栏位置|2:控制栏显示|0x000033:主体颜色|60:主体透明度|0x66ff00:光晕颜色|0xffffff:图标颜色|0xffffff:文字颜色|:logo文字|:logo地址|:结束swf地址';  
var texts='Flv视频在线播放测试';  
document.write('<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" width="'+swf_width+'" height="'+swf_height+'">');  
document.write('<param name="movie" value="vcastr2.swf"/>');  
document.write('<param name="quality" value="high"/>');  
document.write('<param name="menu" value="false"/>');  
document.write('<param name=wmode value="opaque"/>');  
document.write('<param name="FlashVars" value="vcastr_file='+files+'&vcastr_title='+texts+'&vcastr_config='+config+'">');  
document.write('<embed src="vcastr2.swf"/>" wmode="opaque" FlashVars="vcastr_file='+files+'&vcastr_title='+texts+'&vcastr_config='+config+'" menu="false" quality="high" width="'+swf_width+'" height="'+swf_height+'" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />');  
document.write('</object>');  
</script>
<html>
<body>
</body>
</html>

 播放效果如下:

 至此整个视频上传-转码-在线播放功能就基本实现了。

5、附上测试用的ffmpeg.exe跟vcastr2.swf
  • 大小: 4.3 KB
  • 大小: 15.3 KB
  • 大小: 27.9 KB
  • 大小: 258.6 KB
分享到:
评论

相关推荐

    视频上传ffmpeg转码flv、截图播放点播播客解决方案代码

    现在这个视频转码系统可以轻松解决这一技术难题,你无需懂得程序代码,三步即可轻松实现视频上传、转码、播放,完美整合到任何CMS系统、论坛、博客等系统,实现视频点播功能,让你的网站更丰富、强大。

    PHP双码率视频云转码服务系统源码 m3u8切片支持秒切及api上传和防盗功能,亲测极速播放

    php可以利用FFmpeg 视频切片,这里分享一套PHP双码率视频云转码服务系统源码 m3u8切片支持秒切及api上传和防盗功能的系统。本系统亲测极致切片可极速播放,做到秒播,并且支持秒切。 PHP 双速率视频云代码转换服务...

    【智影CMS】网站视频系统分享,创新功能秒杀市面上的视频系统源码

    结合云转码软件实现站长/用户上传视频支持任意格式转码,生成视频图片、名称、播放地址、完全自动   每天签到 用户每天签到可得到系统自动奖励的金币,24小时允许签到一次,从而提高用户对网站的黏贴度哦   分享...

    xhd视频录制 v2.5.zip

    是用户实现视频录制功能的好帮手。 xhd视频录制功能说明 xhd视频录制--三位一体视频录制软件,全新的模式革新录制软件!! ①市面独家重金打造系统最底层真正的桌面,视频音频三合一 高度优化录制系统,配置低的...

    缤纷影视系统 v3.5.518.rar

    2、视频上传、视频在线录制功能,用户可发布自己的视频简介。 3、视频文件上传转码全自动处理,支持多服务器分布式部署。 4、视频大头贴功能,即拍即存,相册加密功能。 5、先进数据缓存技术,提高程序执行效率...

    毕设&课设&项目&实训-基于编译的适用于 Android 平台的音视频编辑、视频剪辑的快速处理框架.zip

    是基于 ( FFmpeg 4.0 + X264 + mp3lame + fdk-aac + opencore-amr + openssl ) 编译的适用于 Android 平台的音视频编辑、视频剪辑的快速处理框架,包含以下功能:视频拼接,转码,压缩, 【项目资源】: 包含前端、...

    用Python的Django框架完成视频处理任务的教程

    我过去曾经参与过一个项目,客户需要视频转码功能,这实在不是个容易达成的需求。需要大量的读取每一个视频、音讯与视频容器的格式再输出符合网页使用与喜好的视频格式。 考虑到这一点,我们决定将转码的工作交给 ...

    网络书店 ASP.NET网站

    09、上传图片,在服务器端对图片进行截取,实现 图片截取功能,客户端运用第三方插件 10、动态生成验证码 11、定制错误页 12、用户自定义控件 13、WebServer 14、MD5加密 15、利用存储过程 进行分页 16、Log4Net ...

    02408仿天涯论坛模板的免费论坛系统(php在线问答系统源码)v2.0.zip

    除了适合做论坛和在线问答系统之外,博客、文章系统、商城、企业网站等,各种类型网站都可以使用,所以将来网站无论如何转型或拓展,只需要修改模板就可以实现,无需抛弃重建网站,直接更换模板就可以了。...

    缤纷影视系统源码 v3.5.518

    2、视频上传、视频在线录制功能,用户可发布自己的视频简介。 3、视频文件上传转码全自动处理,支持多服务器分布式部署。 4、视频大头贴功能,即拍即存,相册加密功能。 5、先进数据缓存技术,提高程序执行效率,...

    牛叉内容管理系统(NiuXcms) v1.07.rar

    2. 推荐文章功能改进:自动转码功能增强,过滤掉特殊字符。 3. 更改所有样板模板的默认主题为start。 4. 安装增加浏览器版本判断,低于IE8提示更换浏览器。后台登陆浏览器版本推荐IE8 ,Chrome,Firefox等等。  ...

    傲游浏览器3(Maxthon) 3.1.8.1000 正式版

    傲游3功能丰富,拥有在线收藏、鼠标手势、广告过滤、智能地址栏、多重搜索、页面截图、即时翻译等数十种实用功能,并且独有"快应用"、"团购指数"等创新性功能,充分让用户体验到基于新式浏览器的一站式互联网服务的...

    Wordpress 博客主题/模板 阿里百秀XIU主题 2.1最新版CMS高级主题

    如果后台有链接功能的说明已经可以实现了,没有链接功能的请安装wp官方自己的插件link-manager即可 1.1版本升级: 解决no-category有可能失效的问题; 解决列表作者名前加网站名的样式问题; 解决相关文章缩略图...

    WordPress主题 大前端 阿里百秀 XIU ALIBAIXIU 小清新CMS高级主题[更新v3.2]

    如果后台有链接功能的说明已经可以实现了,没有链接功能的请安装wp官方自己的插件link-manager即可 1.1版本升级: 解决no-category有可能失效的问题; 解决列表作者名前加网站名的样式问题; 解决相关文章缩略图...

    陈老师云点播 5.0

    1:陈老师云点播源自迅雷云播,利用目前风靡全球的云端存储技术来实现视频文件直接在线播放。 2:陈老师云点播支持ed2k、magnet、thunder链接,http、ftp链接,BT种子40位Hash值,xlpan地址(xlpan://),同时,您更...

Global site tag (gtag.js) - Google Analytics