All Downloads are FREE. Search and download functionalities are using the official Maven repository.

christophedelory.playlist.asx.Asx Maven / Gradle / Ivy

Go to download

Multimedia playlist parser, supporting a wide range of playlist file formats.

There is a newer version: 4.1.1
Show newest version
/*
 * Copyright (c) 2008, Christophe Delory
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY CHRISTOPHE DELORY ``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 CHRISTOPHE DELORY 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 christophedelory.playlist.asx;

import java.io.OutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import christophedelory.content.Content;
import christophedelory.lang.StringUtils;
import christophedelory.playlist.Media;
import christophedelory.playlist.Playlist;
import christophedelory.playlist.Sequence;
import christophedelory.playlist.SpecificPlaylist;
import christophedelory.playlist.SpecificPlaylistProvider;
import christophedelory.xml.XmlSerializer;

/**
 * A Windows Media metafile.
 * Defines a file as an Advanced Stream Redirector (ASX) file.
 * @version $Revision: 92 $
 * @author Christophe Delory
 * @castor.class xml="asx"
 */
public class Asx extends AsxOrEntryElement implements SpecificPlaylist, AsxElementContainer
{
    /**
     * The provider of this specific playlist.
     */
    private transient SpecificPlaylistProvider _provider = null;

    /**
     * Decimal number representing the version number of the syntax for the metafile.
     */
    private String _version = "3.0";

    /**
     * Value indicating whether Windows Media Player enters preview mode before playing the first clip.
     */
    private boolean _previewMode = false;

    /**
     * Value indicating whether Windows Media Player reserves space for a banner graphic.
     */
    private String _bannerBar = null;

    /**
     * The list of ASX elements of the metafile.
     */
    private final List _asxElements = new ArrayList();

    @Override
    public void setProvider(final SpecificPlaylistProvider provider)
    {
        _provider = provider;
    }

    @Override
    public SpecificPlaylistProvider getProvider()
    {
        return _provider;
    }

    @Override
    public void writeTo(final OutputStream out, final String encoding) throws Exception
    {
        // Marshal the ASX playlist.
        final StringWriter writer = new StringWriter();
        final XmlSerializer serializer = XmlSerializer.getMapping("christophedelory/playlist/asx"); // May throw Exception.
        // Specifies whether XML documents (as generated at marshalling) should use indentation or not. Default is false.
        serializer.getMarshaller().setProperty("org.exolab.castor.indent", "true");
        serializer.marshal(this, writer, false); // May throw Exception.

        String enc = encoding;

        if (enc == null)
        {
            enc = "UTF-8"; // FIXME US-ASCII?
        }

        final byte[] bytes = writer.toString().getBytes(enc); // May throw UnsupportedEncodingException.
        out.write(bytes); // Throws NullPointerException if out is null. May throw IOException.
        out.flush(); // May throw IOException.
    }

    @Override
    public Playlist toPlaylist()
    {
        final Playlist ret = new Playlist();

        for (AsxElement asxElement : _asxElements)
        {
            addToSequence(asxElement, ret.getRootSequence());
        }

        ret.normalize();

        return ret;
    }

    /**
     * Adds the specified ASX element, and its childs if appropriate, to the given sequence.
     * @param asxElement the ASX element to handle. Shall not be null.
     * @param currentSequence the parent sequence. Shall not be null.
     * @throws NullPointerException if asxElement is null.
     * @throws NullPointerException if currentSequence is null.
     */
    private void addToSequence(final AsxElement asxElement, final Sequence currentSequence)
    {
        if (asxElement instanceof Repeat) // Throws NullPointerException if asxElement is null.
        {
            final Repeat repeat = (Repeat) asxElement;
            final Sequence seq = new Sequence();
            seq.setRepeatCount((repeat.getCount() == null) ? -1 : (repeat.getCount().intValue() + 1));
            currentSequence.addComponent(seq);

            for (AsxElement asxElem : repeat.getAsxElements())
            {
                addToSequence(asxElem, seq);
            }
        }
        else if (asxElement instanceof Entry)
        {
            final Entry entry = (Entry) asxElement;

            for (Reference reference : entry.getReferences())
            {
                // We keep only the first valid one.
                if (reference.getHref() != null)
                {
                    Duration duration = reference.getDuration();

                    if (duration == null)
                    {
                        duration = entry.getDuration();
                    }

                    if ((duration == null) || (duration.getValue() > 0L))
                    {
                        final Media media = new Media(); // NOPMD Avoid instantiating new objects inside loops
                        media.setSource(new Content(reference.getHref())); // NOPMD Avoid instantiating new objects inside loops

                        if (duration != null) // NOPMD Deeply nested if..then statements are hard to read
                        {
                            // FIXME We can't check here if the expressed duration is in fact the effective media duration
                            // (in which case we don't need to specify it, and we would be more compatible to simple playlist formats).
                            media.setDuration(duration.getValue()); // Shall not throw IllegalArgumentException.
                        }

                        currentSequence.addComponent(media);
                        break;
                    }
                }
            }
        }
        else if (asxElement instanceof Entryref)
        {
            final Entryref entryRef = (Entryref) asxElement;

            if (entryRef.getHref() != null)
            {
                final Media media = new Media();
                media.setSource(new Content(entryRef.getHref()));
                currentSequence.addComponent(media);
            }
        }
    }

    /**
     * Returns the decimal number representing the version number of the syntax for the metafile.
     * Acceptable values include both "3.0" and "3" (with or without the decimal point).
     * Defaults to "3.0".
     * @return a version string. Shall not be null.
     * @see #setVersion
     * @castor.field
     *  get-method="getVersion"
     *  set-method="setVersion"
     *  required="true"
     * @castor.field-xml
     *  name="version"
     *  node="attribute"
     */
    public String getVersion()
    {
        return _version;
    }

    /**
     * Initializes the decimal number representing the version number of the syntax for the metafile.
     * @param version a version string. Shall not be null.
     * @throws NullPointerException if version is null.
     * @see #getVersion
     */
    public void setVersion(final String version)
    {
        _version = version.trim(); // Throws NullPointerException if version is null.
    }

    /**
     * Returns a value indicating whether Windows Media Player reserves space for a banner graphic.
     * A banner is a graphic that is displayed in the video display area while media content is playing
     * (use the BANNER element to add a banner to the content).
     * 
* Must be one of the following values: *
*
AUTO
The default value. Windows Media Player reserves space for the banner bar only when a piece of content includes one.
*
FIXED
Windows Media Player reserves a fixed space for a banner graphic for every piece of content played, whether or not there is an associated banner.
*
* If the value of BANNERBAR is FIXED, Windows Media Player reserves banner space for every piece of media content, whether or not the media content has a banner. * If a piece of media content does not have a banner associated with it, the space reserved for one is black. * If the value of the BANNERBAR attribute is AUTO, Windows Media Player reserves space for the banner only when the media content includes one. *
* If you create a metafile with multiple clips (ENTRY or ENTRYREF elements) and set the value of the BANNERBAR attribute to AUTO, * Windows Media Player might resize to allow space for a banner graphic for one clip, * and then resize again if the next clip does not contain a banner graphic. * If you want the size of the window to stay the same (except when the video size changes), use the FIXED value for the BANNERBAR attribute. *
* The space reserved for a banner graphic is 32 pixels high by 194 pixels wide. * The reserved space appears below any rendered video content and 6 pixels above the lower edge of the video area, * allowing space for the 6-pixel video area border. * The reserved banner space is centered horizontally. *
* Windows Media Player renders the graphic beginning in the leftmost pixel of the banner space. * If the graphic fills the entire space, it will appear centered horizontally. * Otherwise there will be trailing space. * Note that the minimum width of Windows Media Player is always wider than the size of the video clip, * regardless of the value of the BANNERBAR attribute. *
* As banners are not supported in Windows CE, this attribute is set to "AUTO" and any attempts to change it are ignored. * Even if content includes a banner, no space is reserved for it. * @return a banner bar indicator. May be null. * @see #setBannerBar * @castor.field * get-method="getBannerBar" * set-method="setBannerBar" * @castor.field-xml * name="bannerbar" * node="attribute" */ public String getBannerBar() { return _bannerBar; } /** * Initializes the value indicating whether Windows Media Player reserves space for a banner graphic. * @param bannerBar a banner bar indicator. May be null. * @see #getBannerBar */ public void setBannerBar(final String bannerBar) { final String banner = StringUtils.normalize(bannerBar); _bannerBar = "FIXED".equalsIgnoreCase(banner) ? "FIXED" : null; } /** * Returns a value indicating whether Windows Media Player enters preview mode before playing the first clip. * Must be one of the following values: *
*
YES
Windows Media Player enters preview mode before playing the first clip.
*
NO
The default value. Windows Media Player does not enter preview mode before playing the first clip.
*
* If the value of the PREVIEWMODE attribute is YES, Windows Media Player immediately enters preview mode before playing the first clip. * When Windows Media Player enters preview mode, it previews each clip referenced in the metafile. * The PREVIEWDURATION element determines the duration of each preview. * As preview mode is not supported in Microsoft® Windows® CE .NET, this attribute is set to "NO" and any attempts to change it are ignored. * @return the preview mode. May be null. * @see #setPreviewModeString * @see #isPreviewMode * @castor.field * get-method="getPreviewModeString" * set-method="setPreviewModeString" * @castor.field-xml * name="previewmode" * node="attribute" */ public String getPreviewModeString() { String ret = null; if (_previewMode) { ret = "YES"; } return ret; } /** * Initializes the value indicating whether Windows Media Player enters preview mode before playing the first clip. * @param previewMode a preview mode. May be null. * @see #getPreviewModeString * @see #setPreviewMode */ public void setPreviewModeString(final String previewMode) { final String preview = StringUtils.normalize(previewMode); _previewMode = "YES".equalsIgnoreCase(preview); } /** * Indicates whether Windows Media Player enters preview mode before playing the first clip. * @return the preview mode. * @see #setPreviewMode * @see #getPreviewModeString */ public boolean isPreviewMode() { return _previewMode; } /** * Indicates whether Windows Media Player enters preview mode before playing the first clip. * @param previewMode the preview mode. * @see #isPreviewMode * @see #setPreviewModeString */ public void setPreviewMode(final boolean previewMode) { _previewMode = previewMode; } @Override public void addAsxElement(final AsxElement asxElement) { if (asxElement instanceof Asx) // Throws NullPointerException if asxElement is null. { throw new IllegalStateException("Element not valid here: " + asxElement); } asxElement.setParent(this); _asxElements.add(asxElement); } /** * @castor.field * get-method="getAsxElements" * set-method="addAsxElement" * type="christophedelory.playlist.asx.AsxElement" * collection="arraylist" * @castor.field-xml * auto-naming="deriveByClass" * node="element" */ @Override public List getAsxElements() { return _asxElements; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy