public int ExecuteMediaCommand(int cmd, int len, byte[] cmddata, byte[] retbuf) { if (VerboseLogging.DETAILED_MEDIA_COMMAND) { if (VerboseLogging.DETAILED_MEDIA_COMMAND_PUSHBUFFER || cmd != MEDIACMD_PUSHBUFFER) log.debug("MEDIACMD='{}[{}]'", cmd, CMDMAP.get(cmd)); } switch (cmd) { case MEDIACMD_INIT: try { DESIRED_VIDEO_PREBUFFER_SIZE = client.properties().getInt(PrefStore.Keys.video_buffer_size, (4 * 1024 * 1024)); DESIRED_AUDIO_PREBUFFER_SIZE = client.properties().getInt(PrefStore.Keys.audio_buffer_size, (2 * 1024 * 1024)); } catch (Exception e) { log.error("MEDIACMD_INIT: ERROR", e); } readInt(0, cmddata); // video format code writeInt(1, retbuf, 0); return 4; case MEDIACMD_DEINIT: writeInt(1, retbuf, 0); close(); return 4; case MEDIACMD_OPENURL: int strLen = readInt(0, cmddata); String urlString = ""; bufferFilePushedBytes = 0; maxPrebufferSize = DESIRED_VIDEO_PREBUFFER_SIZE; if (strLen > 1) urlString = new String(cmddata, 4, strLen - 1); if (!urlString.startsWith("push:")) { if (urlString.startsWith("dvd:")) { log.error("DVD PlayBack not supported"); } else if (urlString.startsWith("file://")) { playa = myConn.newPlayerPlugin(); // new MiniMPlayerPlugin(myConn.getGfxCmd(), myConn); playa.setPushMode(false); playa.load((byte) 0, (byte) 0, "", urlString, null, false, 0); pushDataLeftBeforeInit = 0; pushMode = false; } else { playa = myConn.newPlayerPlugin(); // new MiniMPlayerPlugin(myConn.getGfxCmd(), myConn); // We always set it to be an active file because it'll get turned off by the streaming // code if it is not. // It's safe to say it's active when it's not (as long as it's a streamable file // format), but the opposite is not true. // So we always say it's active to avoid any problems loading the file if it's a // streamable file format. boolean isActive = urlString.toLowerCase().endsWith(".mpg") || urlString.toLowerCase().endsWith(".ts") || urlString.toLowerCase().endsWith(".flv"); playa.setPushMode(false); playa.load((byte) 0, (byte) 0, "", urlString, myConn.getServerName(), isActive, 0); pushDataLeftBeforeInit = 0; pushMode = false; } } else { pushMode = true; { if (urlString.indexOf("audio") != -1 && urlString.indexOf("bf=vid") == -1) { pushDataLeftBeforeInit = 1024 * 16; maxPrebufferSize = DESIRED_AUDIO_PREBUFFER_SIZE; } else { pushDataLeftBeforeInit = 1024 * 64; maxPrebufferSize = DESIRED_VIDEO_PREBUFFER_SIZE; } playa = myConn.newPlayerPlugin(); // new MiniMPlayerPlugin(myConn.getGfxCmd(), myConn); playa.setPushMode(true); playa.load((byte) 0, (byte) 0, "", urlString, null, true, 0); } } writeInt(1, retbuf, 0); return 4; case MEDIACMD_GETMEDIATIME: if (playa == null) return 0; long theTime = playa.getMediaTimeMillis(); writeInt((int) theTime, retbuf, 0); if (MiniClientConnection.detailedBufferStats) { if (playa != null) { retbuf[4] = (byte) (playa.getState() & 0xFF); } else { retbuf[4] = 0; } return 5; } else return 4; case MEDIACMD_SETMUTE: writeInt(1, retbuf, 0); if (playa == null) return 4; playa.setMute(readInt(0, cmddata) != 0); return 4; case MEDIACMD_STOP: writeInt(1, retbuf, 0); if (playa == null) return 4; playa.stop(); return 4; case MEDIACMD_PAUSE: writeInt(1, retbuf, 0); if (playa == null) return 4; playa.pause(); return 4; case MEDIACMD_PLAY: writeInt(1, retbuf, 0); if (playa == null) return 4; playa.play(); return 4; case MEDIACMD_FLUSH: writeInt(1, retbuf, 0); // TODO if (playa != null && pushMode && numPushedBuffers > 0) { numPushedBuffers = 0; playa.flush(); } return 4; case MEDIACMD_PUSHBUFFER: int buffSize = readInt(0, cmddata); int flags = readInt(4, cmddata); int bufDataOffset = 8; if (MiniClientConnection.detailedBufferStats && buffSize > 0 && len > buffSize + 13) { bufDataOffset += 10; statsChannelBWKbps = readShort(8, cmddata); statsStreamBWKbps = readShort(10, cmddata); statsTargetBWKbps = readShort(12, cmddata); serverMuxTime = readInt(14, cmddata); if (playa != null) { prebufferTime = serverMuxTime - playa.getMediaTimeMillis(); } // log.debug("STATS chanBW=" + statsChannelBWKbps + " streamBW=" + statsStreamBWKbps + " // targetBW=" + statsTargetBWKbps + " pretime=" + prebufferTime); } // sometimes pushbuffer is called to just get bandwidth so don't pass that along to the // player // boolean noMoreData = flags == 0x80 && playa != null; if (playa != null) { if (buffSize > 0) { bufferFilePushedBytes += buffSize; numPushedBuffers++; try { playa.pushData(cmddata, bufDataOffset, buffSize); } catch (IOException e) { log.error("Pushbuffer Error", e); client.closeConnection(); } } if (flags == 0x80 && playa != null) { playa.setServerEOS(); } } int rv; // Always indicate we have at least 512K of buffer...there's NO reason to stop buffering // additional // data since as playback goes on we keep writing to the filesystem anyways. Yeah, we could // recover some bandwidth // but that's not how any online video players work and we shouldn't be any different than // that. if (playa == null) rv = maxPrebufferSize; else { // rv = (int)(PushBufferDataSource.PIPE_SIZE - (bufferFilePushedBytes - // playa.getLastFileReadPos())); rv = playa.getBufferLeft(); // log.debug("PUSHBUFFER: bufSize: " + buffSize + " availSize=" + rv + " totalPushed=" + // bufferFilePushedBytes + "; Last Read: " + playa.getLastFileReadPos()); } if (rv < 0) { log.debug("PUSHBUFFER: We Letting Server know we are done: rv: {}"); } writeInt(rv, retbuf, 0); if (MiniClientConnection.detailedBufferStats) { if (playa != null) { writeInt((int) playa.getMediaTimeMillis(), retbuf, 4); retbuf[8] = (byte) (playa.getState() & 0xFF); } else { writeInt(0, retbuf, 4); retbuf[8] = 0; } if (playa != null) { retbuf[8] = (byte) (playa.getState() & 0xFF); } return 9; } else return 4; case MEDIACMD_GETVOLUME: if (playa == null) writeInt(65535, retbuf, 0); else writeInt(Math.round(playa.getVolume() * 65535), retbuf, 0); return 4; case MEDIACMD_SETVOLUME: if (playa == null) writeInt(65535, retbuf, 0); else writeInt(Math.round(playa.setVolume(readInt(0, cmddata) / 65535.0f) * 65535), retbuf, 0); return 4; case MEDIACMD_SETVIDEORECT: Rectangle srcRect = new Rectangle( readInt(0, cmddata), readInt(4, cmddata), readInt(8, cmddata), readInt(12, cmddata)); Rectangle destRect = new Rectangle( readInt(16, cmddata), readInt(20, cmddata), readInt(24, cmddata), readInt(28, cmddata)); if (playa != null) playa.setVideoRectangles(srcRect, destRect, false); myConn.getGfxCmd().setVideoBounds(srcRect, destRect); writeInt(0, retbuf, 0); return 4; case MEDIACMD_GETVIDEORECT: Dimension vidRect = null; if (playa != null) { vidRect = playa.getVideoDimensions(); writeShort((short) vidRect.width, retbuf, 0); writeShort((short) vidRect.height, retbuf, 2); } else { writeInt(0, retbuf, 0); } return 4; case MEDIACMD_SEEK: long seekTime = ((long) readInt(0, cmddata) << 32) | readInt(4, cmddata); if (playa != null) playa.seek(seekTime); return 0; case MEDIACMD_DVD_STREAMS: writeInt(0, retbuf, 0); return 4; default: log.error("MEDIACMD Unhandled Media Command: {}", cmd); return -1; } }
/** Creates a new instance of MediaCmd */ public MediaCmd(MiniClient client) { this.client = client; this.myConn = client.getCurrentConnection(); }