/*
* DefineVideo.java
* Transform
*
* Copyright (c) 2001-2010 Flagstone Software Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Flagstone Software Ltd. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package com.flagstone.transform.video;
import java.io.IOException;
import com.flagstone.transform.Constants;
import com.flagstone.transform.DefineTag;
import com.flagstone.transform.MovieTypes;
import com.flagstone.transform.coder.Coder;
import com.flagstone.transform.coder.Context;
import com.flagstone.transform.coder.SWFDecoder;
import com.flagstone.transform.coder.SWFEncoder;
import com.flagstone.transform.exception.IllegalArgumentRangeException;
/**
* The DefineVideo class is used to define a video stream within a Flash file.
*
* <p>
* Video objects contain a unique identifier and are treated in the same way as
* shapes, buttons, images, etc. The video data displayed is define using the
* VideoFrame class. Each frame of video is displayed whenever display list is
* updated using the ShowFrame object - any timing information stored within the
* video data is ignored. The actual video data is encoded using the VideoFrame
* class.
* </p>
*/
public final class DefineVideo implements DefineTag {
/** Format string used in toString() method. */
private static final String FORMAT = "DefineVideo: { identifier=%d;"
+ " frameCount=%d; width=%d; height=%d; deblocking=%s;"
+ " smoothing=%s; codec=%s}";
/** The unique identifier for this object. */
private int identifier;
/** The number of frames in the video. */
private int frameCount;
/** The width of the frame. */
private int width;
/** The height of the frame. */
private int height;
/** Code indicating whether deblocking is applied. */
private int deblocking;
/** Is smoothing applied. */
private boolean smoothed;
/** Code representing the codec used. */
private int codec;
/** The length of the object, minus the header, when it is encoded. */
private transient int length;
/**
* Creates and initialises a DefineVideo object using values encoded in the
* Flash binary format.
*
* @param coder
* an SWFDecoder object that contains the encoded Flash data.
*
* @throws IOException
* if an error occurs while decoding the data.
*/
public DefineVideo(final SWFDecoder coder) throws IOException {
length = coder.readUnsignedShort() & Coder.LENGTH_FIELD;
if (length == Coder.IS_EXTENDED) {
length = coder.readInt();
}
coder.mark();
identifier = coder.readUnsignedShort();
frameCount = coder.readUnsignedShort();
width = coder.readUnsignedShort();
height = coder.readUnsignedShort();
final int info = coder.readByte();
deblocking = (info & 0x06) >> 1;
smoothed = (info & 0x01) == 1;
codec = coder.readByte();
coder.check(length);
coder.unmark();
}
/**
* Creates a DefineVideo object with the specified parameters.
*
* @param uid
* the unique identifier for this object. Must be in the range
* 1..65535.
* @param count
* the number of video frames. Must be in the range 0..65535.
* @param frameWidth
* the width of each frame in pixels. Must be in the range
* 0..65535.
* @param frameHeight
* the height of each frame in pixels. Must be in the range
* 0..65535.
* @param deblock
* controls whether the Flash Player's deblocking filter is used,
* either Off, On or UseVideo to allow the video data to specify
* whether the deblocking filter is used.
* @param smoothing
* turns smoothing on or off to improve the quality of the
* displayed image.
* @param videoCodec
* the format of the video data. Flash 6 supports H263. Support
* for Macromedia's ScreenVideo format was added in Flash 7.
*/
public DefineVideo(final int uid, final int count, final int frameWidth,
final int frameHeight, final Deblocking deblock,
final boolean smoothing, final VideoFormat videoCodec) {
setIdentifier(uid);
setFrameCount(count);
setWidth(frameWidth);
setHeight(frameHeight);
setDeblocking(deblock);
setSmoothed(smoothing);
setCodec(videoCodec);
}
/**
* Creates and initialises an DefineVideo object using the values
* copied from another DefineVideo object.
*
* @param object
* a DefineVideo object from which the values will be
* copied.
*/
public DefineVideo(final DefineVideo object) {
identifier = object.identifier;
frameCount = object.frameCount;
width = object.width;
height = object.height;
deblocking = object.deblocking;
smoothed = object.smoothed;
codec = object.codec;
}
/** {@inheritDoc} */
public int getIdentifier() {
return identifier;
}
/** {@inheritDoc} */
public void setIdentifier(final int uid) {
if ((uid < 1) || (uid > Coder.USHORT_MAX)) {
throw new IllegalArgumentRangeException(
1, Coder.USHORT_MAX, uid);
}
identifier = uid;
}
/**
* Get the number of frames in the video.
*
* @return the number of frames.
*/
public int getFrameCount() {
return frameCount;
}
/**
* Sets the number of frames in the video.
*
* @param count
* the number of video frames. Must be in the range 0..65535.
*/
public void setFrameCount(final int count) {
if ((count < 0) || (count > Coder.USHORT_MAX)) {
throw new IllegalArgumentRangeException(
0, Coder.USHORT_MAX, count);
}
frameCount = count;
}
/**
* Get the width of each frame in pixels.
*
* @return the frame width.
*/
public int getWidth() {
return width;
}
/**
* Sets the width of each frame in pixels.
*
* @param size
* the width of the frame. Must be in the range 0..65535.
*/
public void setWidth(final int size) {
if ((size < 0) || (size > Coder.USHORT_MAX)) {
throw new IllegalArgumentRangeException(
0, Coder.USHORT_MAX, size);
}
width = size;
}
/**
* Get the height of each frame in pixels.
*
* @return the frame height.
*/
public int getHeight() {
return height;
}
/**
* Sets the height of each frame in pixels.
*
* @param size
* the height of the frame. Must be in the range 0..65535.
*/
public void setHeight(final int size) {
if ((size < 0) || (size > Coder.USHORT_MAX)) {
throw new IllegalArgumentRangeException(
0, Coder.USHORT_MAX, size);
}
height = size;
}
/**
* Get the method used to control the Flash Player's deblocking filter,
* either OFF, ON or USE_VIDEO.
*
* @return the deblocking applied to the frame.
*/
public Deblocking getDeblocking() {
Deblocking value;
switch (deblocking) {
case 1:
value = Deblocking.OFF;
break;
case 2:
value = Deblocking.ON;
break;
case 3:
value = Deblocking.LEVEL2;
break;
case 4:
value = Deblocking.LEVEL3;
break;
case 5:
value = Deblocking.LEVEL4;
break;
default:
value = Deblocking.VIDEO;
break;
}
return value;
}
/**
* Sets the method used to control the Flash Player's deblocking filter.
*
* @param value
* the deblocking filter control, either OFF, ON or USE_VIDEO to
* allow the video data to specify whether the deblocking filter
* is used.
*/
public void setDeblocking(final Deblocking value) {
switch (value) {
case VIDEO:
deblocking = 0;
break;
case OFF:
deblocking = 1;
break;
case ON:
deblocking = 2;
break;
case LEVEL2:
deblocking = 3;
break;
case LEVEL3:
deblocking = 4;
break;
case LEVEL4:
deblocking = 5;
break;
default:
throw new IllegalArgumentException();
}
}
/**
* Will the Flash Player will apply smoothing to the video when it is
* played.
*
* @return true if smoothing is applied.
*/
public boolean isSmoothed() {
return smoothed;
}
/**
* Sets whether Flash Player's smoothing filter is on or off when the video
* is played.
*
* @param smoothing
* true if smoothing is turned on, false if it is turned off.
*/
public void setSmoothed(final boolean smoothing) {
smoothed = smoothing;
}
/**
* Get the format used to encode the video data.
*
* @return the format used to encode the video.
*/
public VideoFormat getCodec() {
VideoFormat value;
switch (codec) {
case Coder.BIT2 | Coder.BIT0:
value = VideoFormat.VP6ALPHA;
break;
case Coder.BIT2:
value = VideoFormat.VP6;
break;
case Coder.BIT1:
value = VideoFormat.H263;
break;
case Coder.BIT0 | Coder.BIT1:
value = VideoFormat.SCREEN;
break;
default:
throw new IllegalStateException();
}
return value;
}
/**
* Set the format used to encode the video data.
*
* @param format
* the format used encode the video, either VideoFormat.H263,
* VideoFormat.SCREEN, VideoFormat.VP6 or VideoFormat.VP6ALPHA.
*/
public void setCodec(final VideoFormat format) {
switch (format) {
case H263:
codec = Coder.BIT1;
break;
case SCREEN:
codec = Coder.BIT0 | Coder.BIT1;
break;
case VP6:
codec = Coder.BIT2;
break;
case VP6ALPHA:
codec = Coder.BIT2 | Coder.BIT0;
default:
throw new IllegalArgumentException();
}
}
/** {@inheritDoc} */
public DefineVideo copy() {
return new DefineVideo(this);
}
/** {@inheritDoc} */
@Override
public String toString() {
return String.format(FORMAT, identifier, frameCount, width, height,
deblocking, smoothed, codec);
}
/** {@inheritDoc} */
public int prepareToEncode(final Context context) {
// CHECKSTYLE IGNORE MagicNumberCheck FOR NEXT 1 LINES
length = 10;
return Coder.SHORT_HEADER + length;
}
/** {@inheritDoc} */
public void encode(final SWFEncoder coder, final Context context)
throws IOException {
if (length > Coder.HEADER_LIMIT) {
coder.writeShort((MovieTypes.DEFINE_VIDEO
<< Coder.LENGTH_FIELD_SIZE) | Coder.IS_EXTENDED);
coder.writeInt(length);
} else {
coder.writeShort((MovieTypes.DEFINE_VIDEO
<< Coder.LENGTH_FIELD_SIZE) | length);
}
if (Constants.DEBUG) {
coder.mark();
}
coder.writeShort(identifier);
coder.writeShort(frameCount);
coder.writeShort(width);
coder.writeShort(height);
int bits = deblocking << 1;
bits |= smoothed ? Coder.BIT0 : 0;
coder.writeByte(bits);
coder.writeByte(codec);
if (Constants.DEBUG) {
coder.check(length);
coder.unmark();
}
}
}