出力する必要がある~ってことがわかりました。
東芝AT300がどの程度のスペックかと言いますと。
Tegra2 1GHz
メモリ 1GB
画面解像度 1280×800
再生可能動画 H263、H264、MPEG-4、WMV
まずはストリーミング再生可能なAndroidアプリが必要ですね。
幾つか試してみたら MX動画プレイヤー がいい感じでした。
ので、これを使います。
もちろん、このアプリでもソフトウェア再生だとカクカクなので、
ハードウェア再生できるように設定しておきます。
サーバーは以下の機能だけ持たせます。
・ファイルの一覧表示
・ffmpegで変換したデータをレスポンスとして出力
私がお風呂で見るだけなので、これで十分ですな。
mp4ファイルなどは作成時にファイルシークが必要で、
ストリーミングには使えません。
ので、出力するファイル形式は FLV、映像は H264、音声は AAC にしました。
ffmpegはこちらのを使用。
http://blog.k-tai-douga.com/article/60762366.html
ファイルの選択はブラウザで行います。
動画のリンクをクリックして、MX動画プレイヤーを選び再生します。
さてと、これで再生出来るところまで出来上がりました。
あとはAT300を風呂にどうやって持ち込むかですね。
防水タブレット買った方が手っ取り早い気がする...(;´д`)
とりあえずジップロックもどきに入れて、お風呂に持ち込んでみました。
環境は以下の通り。
サーバ:AMD PhenomII X6 1090T (3.2GHz)、メモリ8G、
無線LAN:11n
クライアント:東芝AT300
普通に再生出来ますね。
画質も十分、ブロックノイズもほとんど出ないです。
ただ、濡れた手だとタッチパネルの反応がイマイチですね。
しかも、本体が冷たいまま持ち込んだためか、中が湿っていて本体に水滴が...
やっぱ防水タブレット買うかなぁ~( ̄~ ̄;)
注:適当に作ったので、AT300からの接続しか正常に動作しません。
試しにGalaxyNote2でやったらダメでした。
MovieConvertor.java
package jp.my.home.ms.sevices; import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import jp.my.home.ms.common.AppProperties; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import com.sun.jersey.api.view.Viewable; @Path("/") public class MovieConvertor { @GET @Path("/list") public Viewable list(@QueryParam("dir") String dir) { List<FileInfo> list = new ArrayList<>(); if (StringUtils.isEmpty(dir)) { List<String> tmp = AppProperties.getShareDirs(); for (String str : tmp) { FileInfo fi = new FileInfo(); fi.setName(str); fi.setFullPath(str); fi.setFile(false); list.add(fi); } } else { File[] files = new File(dir).listFiles(); ArrayList<FileInfo> fileList = new ArrayList<>(); ArrayList<FileInfo> dirList = new ArrayList<>(); for (int i = 0; i < files.length; i++) { FileInfo fi = new FileInfo(); fi.setFullPath(files[i].getAbsolutePath()); fi.setName(files[i].getName()); fi.setFile(files[i].isFile()); if (fi.isFile()) { fileList.add(fi); } else { dirList.add(fi); } } dirList.addAll(fileList); list = dirList; } // 非表示ファイル除去 for (Iterator<FileInfo> iterator = list.iterator(); iterator.hasNext();) { FileInfo fi = iterator.next(); String tmp = fi.getName().toLowerCase(); if ("thumbs.db".equals(tmp)) { iterator.remove(); } } return new Viewable("/list.jsp", list); } @GET @Path("/play.flv") public Response playFlv(@QueryParam("fname") String fname, @Context HttpServletRequest req, @Context HttpServletResponse res) throws Exception { String s = req.getHeader("Range"); if (s == null) { System.out.println("range == null"); res.setStatus(200); return Response.status(200).build(); } if (s.startsWith("bytes=0") == false) { System.out.println("Range: bytes >= 0"); res.setStatus(206); return Response.status(206).build(); } String dummySize = "10737418240"; // 10G res.setStatus(206); res.setContentType("video/x-flv"); res.setHeader("Accept-Ranges", "bytes"); res.setHeader("Content-Length", dummySize); res.setHeader("Content-Range", "bytes 0-" + dummySize + "/" + dummySize); String path = AppProperties.getFfmpegPath(); ArrayList<String> list = new ArrayList<String>(); list.add(path + "ffmpeg.exe"); list.add("-i"); list.add(fname); list.add("-f"); list.add("flv"); list.add("-acodec"); list.add("libvo_aacenc"); list.add("-vcodec"); list.add("h264"); list.add("-s"); list.add("1280x720"); list.add("-deinterlace"); list.add("-threads"); list.add("8"); list.add("-loglevel"); list.add("quiet"); list.add("pipe:1"); ProcessBuilder pb = new ProcessBuilder(list); pb.directory(new File(path)); Process p = pb.start(); InputStream is = p.getInputStream(); System.out.println("動画出力開始"); ServletOutputStream out = null; try { out = res.getOutputStream(); byte[] b = new byte[2048000]; while (true) { int n = is.read(b); if (n < 0) { break; } out.write(b, 0, n); } } finally { IOUtils.closeQuietly(out); IOUtils.closeQuietly(is); System.out.println("動画出力停止"); } return Response.status(200).build(); } }
FileInfo.java
package jp.my.home.ms.sevices; public class FileInfo { private boolean file; private String name; private String fullPath; ...getter、settter... }
list.jsp
<%@ page contentType="text/html" pageEncoding="UTF-8" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no"> <title>ファイル一覧</title> </head> <body> <font size="6"> <c:forEach var="item" items="${it}"> <c:if test="${!item.file}"> <img src="/ms/img/f.png"> <a href=" <c:url value="/api/list" > <c:param name="dir" value="${item.fullPath}" /> </c:url> ">${fn:escapeXml( item.name )}</a><br/> </c:if> <c:if test="${item.file}"> <img src="/ms/img/m.png"> <a href=" <c:url value="/api/play.flv" > <c:param name="fname" value="${item.fullPath}" /> </c:url> ">${fn:escapeXml( item.name )}</a><br/> </c:if> </c:forEach> </font> </body> </html>
ソースの方は基本、前回と同じですね。
ffmpegのオプションが変わっています。
JAVA7、JSP、TOMCAT6、jersey、JSTL、apache commons、あたりを使用しています。
0 件のコメント:
コメントを投稿