r44064 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r44063‎ | r44064 | r44065 >
Date:11:27, 30 November 2008
Author:maikmerten
Status:deferred
Tags:
Comment:
new class to determine the duration of Ogg streams
Modified paths:
  • /trunk/cortado/src/com/fluendo/player/DurationScanner.java (added) (history)

Diff [purge]

Index: trunk/cortado/src/com/fluendo/player/DurationScanner.java
@@ -0,0 +1,254 @@
 2+/* Copyright (C) <2008> Maik Merten <maikmerten@googlemail.com>
 3+ * Copyright (C) <2004> Wim Taymans <wim@fluendo.com> (HTTPSrc.java parts)
 4+ *
 5+ * This library is free software; you can redistribute it and/or
 6+ * modify it under the terms of the GNU Library General Public
 7+ * License as published by the Free Software Foundation; either
 8+ * version 2 of the License, or (at your option) any later version.
 9+ *
 10+ * This library is distributed in the hope that it will be useful,
 11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 13+ * Library General Public License for more details.
 14+ *
 15+ * You should have received a copy of the GNU Library General Public
 16+ * License along with this library; if not, write to the
 17+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 18+ * Boston, MA 02111-1307, USA.
 19+ */
 20+package com.fluendo.player;
 21+
 22+import com.fluendo.utils.Base64Converter;
 23+import com.fluendo.utils.Debug;
 24+import com.jcraft.jogg.Packet;
 25+import com.jcraft.jogg.Page;
 26+import com.jcraft.jogg.StreamState;
 27+import com.jcraft.jogg.SyncState;
 28+import java.io.ByteArrayInputStream;
 29+import java.io.ByteArrayOutputStream;
 30+import java.io.IOException;
 31+import java.io.InputStream;
 32+import java.net.URL;
 33+import java.net.URLConnection;
 34+import java.text.MessageFormat;
 35+import java.util.Hashtable;
 36+import java.util.Locale;
 37+
 38+/**
 39+ *
 40+ * @author maik
 41+ */
 42+public class DurationScanner {
 43+
 44+ final static int UNKNOWN = 0;
 45+ final static int VORBIS = 1;
 46+ final static int THEORA = 2;
 47+ private static Object comment;
 48+ private static Object info;
 49+ private static long contentLength = -1;
 50+
 51+ private static int determineType(Packet op) {
 52+
 53+ // try theora
 54+ com.fluendo.jheora.Comment tc = new com.fluendo.jheora.Comment();
 55+ com.fluendo.jheora.Info ti = new com.fluendo.jheora.Info();
 56+
 57+ tc.clear();
 58+ ti.clear();
 59+
 60+ int ret = ti.decodeHeader(tc, op);
 61+ if (ret == 0) {
 62+ comment = tc;
 63+ info = ti;
 64+ return THEORA;
 65+ }
 66+
 67+ // try vorbis
 68+ com.jcraft.jorbis.Comment vc = new com.jcraft.jorbis.Comment();
 69+ com.jcraft.jorbis.Info vi = new com.jcraft.jorbis.Info();
 70+
 71+ vc.init();
 72+ vi.init();
 73+
 74+ ret = vi.synthesis_headerin(vc, op);
 75+ if (ret == 0) {
 76+ comment = vc;
 77+ info = vi;
 78+ return VORBIS;
 79+ }
 80+
 81+ return UNKNOWN;
 82+ }
 83+
 84+ public static float getDurationForInputStream(InputStream is) throws IOException {
 85+ float time = -1;
 86+
 87+ SyncState oy = new SyncState();
 88+ Page og = new Page();
 89+ Packet op = new Packet();
 90+
 91+ Hashtable streamstates = new Hashtable();
 92+ Hashtable streamtype = new Hashtable();
 93+ Hashtable streamcomment = new Hashtable();
 94+ Hashtable streaminfo = new Hashtable();
 95+ Hashtable streamstartgranule = new Hashtable();
 96+
 97+ oy.init();
 98+
 99+ boolean eos = false;
 100+ while (!eos) {
 101+
 102+ int offset = oy.buffer(4096);
 103+ int read = is.read(oy.data, offset, 4096);
 104+ oy.wrote(read);
 105+ eos = read <= 0;
 106+
 107+ while (oy.pageout(og) == 1) {
 108+
 109+ int serialno = og.serialno();
 110+ StreamState os = (StreamState) streamstates.get(serialno);
 111+ if (os == null) {
 112+ os = new StreamState();
 113+ os.init(og.serialno());
 114+ streamstates.put(og.serialno(), os);
 115+ System.out.println("DurationScanner: created StreamState for stream no. " + serialno);
 116+ }
 117+
 118+ os.pagein(og);
 119+
 120+ while (os.packetout(op) == 1) {
 121+
 122+ Integer type = (Integer) streamtype.get(serialno);
 123+ if (type == null) {
 124+ type = determineType(op);
 125+ streamtype.put(serialno, type);
 126+ if (comment != null) {
 127+ streamcomment.put(serialno, comment);
 128+ }
 129+ if (info != null) {
 130+ streaminfo.put(serialno, info);
 131+ }
 132+ streamstartgranule.put(serialno, og.granulepos());
 133+ }
 134+
 135+ switch (type) {
 136+ case VORBIS:
 137+ {
 138+ com.jcraft.jorbis.Info i = (com.jcraft.jorbis.Info) streaminfo.get(serialno);
 139+ long startgranule = (Long) streamstartgranule.get(serialno);
 140+ float t = (float) (og.granulepos() - startgranule) / i.rate;
 141+ if (t > time) {
 142+ time = t;
 143+ }
 144+ }
 145+ break;
 146+ case THEORA:
 147+ {
 148+ com.fluendo.jheora.Info i = (com.fluendo.jheora.Info) streaminfo.get(serialno);
 149+ }
 150+ break;
 151+ }
 152+ }
 153+ }
 154+ }
 155+
 156+ return time;
 157+ }
 158+
 159+ private static InputStream openWithConnection(URL url, String userId, String password, long offset) throws IOException {
 160+ // lifted from HTTPSrc.java
 161+ InputStream dis = null;
 162+ String userAgent = "Cortado";
 163+
 164+ URLConnection uc = url.openConnection();
 165+
 166+ uc.setRequestProperty("Connection", "Keep-Alive");
 167+
 168+ String range;
 169+ if (offset != 0 && contentLength != -1) {
 170+ range = "bytes=" + offset + "-" + (contentLength - 1);
 171+ } else if (offset != 0) {
 172+ range = "bytes=" + offset + "-";
 173+ } else {
 174+ range = null;
 175+ }
 176+ if (range != null) {
 177+ Debug.info("doing range: " + range);
 178+ uc.setRequestProperty("Range", range);
 179+ }
 180+
 181+ uc.setRequestProperty("User-Agent", userAgent);
 182+ if (userId != null && password != null) {
 183+ String userPassword = userId + ":" + password;
 184+ String encoding = Base64Converter.encode(userPassword.getBytes());
 185+ uc.setRequestProperty("Authorization", "Basic " + encoding);
 186+ }
 187+ uc.setRequestProperty("Content-Type", "application/octet-stream");
 188+
 189+ /* This will send the request. */
 190+ dis = uc.getInputStream();
 191+
 192+ String responseRange = uc.getHeaderField("Content-Range");
 193+ long responseOffset;
 194+ if (responseRange == null) {
 195+ Debug.info("Response contained no Content-Range field, assuming offset=0");
 196+ responseOffset = 0;
 197+ } else {
 198+ try {
 199+ MessageFormat format = new MessageFormat("bytes {0,number}-{1,number}", Locale.US);
 200+ java.lang.Object parts[] = format.parse(responseRange);
 201+ responseOffset = ((Number) parts[0]).longValue();
 202+ if (responseOffset < 0) {
 203+ responseOffset = 0;
 204+ }
 205+ Debug.debug("Stream successfully with offset " + responseOffset);
 206+ } catch (Exception e) {
 207+ Debug.info("Error parsing Content-Range header");
 208+ responseOffset = 0;
 209+ }
 210+ }
 211+
 212+ contentLength = uc.getHeaderFieldInt("Content-Length", -1) + responseOffset;
 213+
 214+ return dis;
 215+ }
 216+
 217+ public static float getDurationForURL(URL url, String user, String password) throws IOException {
 218+ int headbytes = 16 * 1024;
 219+ int tailbytes = 80 * 1024;
 220+
 221+ byte[] buffer = new byte[1024];
 222+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
 223+ InputStream is = openWithConnection(url, user, password, 0);
 224+
 225+ int read = 0;
 226+ long pos = 0;
 227+ read = is.read(buffer);
 228+ while (pos < headbytes && read > 0) {
 229+ pos += read;
 230+ bos.write(buffer, 0, read);
 231+ read = is.read(buffer);
 232+ }
 233+
 234+ is = openWithConnection(url, null, null, contentLength - tailbytes);
 235+
 236+ read = is.read(buffer);
 237+ while (read > 0) {
 238+ bos.write(buffer, 0, read);
 239+ read = is.read(buffer);
 240+ }
 241+
 242+ return getDurationForInputStream(new ByteArrayInputStream(bos.toByteArray()));
 243+
 244+ }
 245+
 246+ public static void main(String[] args) throws IOException {
 247+
 248+ URL url;
 249+ url = new URL(args[0]);
 250+
 251+
 252+ System.out.println(getDurationForURL(url, null, null));
 253+
 254+ }
 255+}
Property changes on: trunk/cortado/src/com/fluendo/player/DurationScanner.java
___________________________________________________________________
Added: svn:eol-style
1256 + native

Status & tagging log