NewPipeExtractor/extractor/src/main/java/org/schabi/newpipe/extractor/stream/VideoStream.java

486 lines
16 KiB
Java

package org.schabi.newpipe.extractor.stream;
/*
* Created by Christian Schabesberger on 04.03.16.
*
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* VideoStream.java is part of NewPipe Extractor.
*
* NewPipe Extractor is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe Extractor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe Extractor. If not, see <https://www.gnu.org/licenses/>.
*/
import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.services.youtube.ItagItem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class VideoStream extends Stream {
public static final String RESOLUTION_UNKNOWN = "";
/** @deprecated Use {@link #getResolution()} instead. */
@Deprecated
public final String resolution;
/** @deprecated Use {@link #isVideoOnly()} instead. */
@Deprecated
public final boolean isVideoOnly;
// Fields for DASH
private int itag = ITAG_NOT_AVAILABLE_OR_NOT_APPLICABLE;
private int bitrate;
private int initStart;
private int initEnd;
private int indexStart;
private int indexEnd;
private int width;
private int height;
private int fps;
private String quality;
private String codec;
@Nullable private ItagItem itagItem;
/**
* Class to build {@link VideoStream} objects.
*/
@SuppressWarnings("checkstyle:hiddenField")
public static final class Builder {
private String id;
private String content;
private boolean isUrl;
private DeliveryMethod deliveryMethod = DeliveryMethod.PROGRESSIVE_HTTP;
@Nullable
private MediaFormat mediaFormat;
@Nullable
private String manifestUrl;
// Use of the Boolean class instead of the primitive type needed for setter call check
private Boolean isVideoOnly;
private String resolution;
@Nullable
private ItagItem itagItem;
/**
* Create a new {@link Builder} instance with its default values.
*/
public Builder() {
}
/**
* Set the identifier of the {@link VideoStream}.
*
* <p>
* It must not be null, and should be non empty.
* </p>
*
* <p>
* If you are not able to get an identifier, use the static constant {@link
* Stream#ID_UNKNOWN ID_UNKNOWN} of the {@link Stream} class.
* </p>
*
* @param id the identifier of the {@link VideoStream}, which must not be null
* @return this {@link Builder} instance
*/
public Builder setId(@Nonnull final String id) {
this.id = id;
return this;
}
/**
* Set the content of the {@link VideoStream}.
*
* <p>
* It must not be null, and should be non empty.
* </p>
*
* @param content the content of the {@link VideoStream}
* @param isUrl whether the content is a URL
* @return this {@link Builder} instance
*/
public Builder setContent(@Nonnull final String content,
final boolean isUrl) {
this.content = content;
this.isUrl = isUrl;
return this;
}
/**
* Set the {@link MediaFormat} used by the {@link VideoStream}.
*
* <p>
* It should be one of the video {@link MediaFormat}s ({@link MediaFormat#MPEG_4 MPEG_4},
* {@link MediaFormat#v3GPP v3GPP}, or {@link MediaFormat#WEBM WEBM}) but can be {@code
* null} if the media format could not be determined.
* </p>
*
* <p>
* The default value is {@code null}.
* </p>
*
* @param mediaFormat the {@link MediaFormat} of the {@link VideoStream}, which can be null
* @return this {@link Builder} instance
*/
public Builder setMediaFormat(@Nullable final MediaFormat mediaFormat) {
this.mediaFormat = mediaFormat;
return this;
}
/**
* Set the {@link DeliveryMethod} of the {@link VideoStream}.
*
* <p>
* It must not be null.
* </p>
*
* <p>
* The default delivery method is {@link DeliveryMethod#PROGRESSIVE_HTTP}.
* </p>
*
* @param deliveryMethod the {@link DeliveryMethod} of the {@link VideoStream}, which must
* not be null
* @return this {@link Builder} instance
*/
public Builder setDeliveryMethod(@Nonnull final DeliveryMethod deliveryMethod) {
this.deliveryMethod = deliveryMethod;
return this;
}
/**
* Sets the URL of the manifest this stream comes from (if applicable, otherwise null).
*
* @param manifestUrl the URL of the manifest this stream comes from or {@code null}
* @return this {@link Builder} instance
*/
public Builder setManifestUrl(@Nullable final String manifestUrl) {
this.manifestUrl = manifestUrl;
return this;
}
/**
* Set whether the {@link VideoStream} is video-only.
*
* <p>
* This property must be set before building the {@link VideoStream}.
* </p>
*
* @param isVideoOnly whether the {@link VideoStream} is video-only
* @return this {@link Builder} instance
*/
public Builder setIsVideoOnly(final boolean isVideoOnly) {
this.isVideoOnly = isVideoOnly;
return this;
}
/**
* Set the resolution of the {@link VideoStream}.
*
* <p>
* This resolution can be used by clients to know the quality of the video stream.
* </p>
*
* <p>
* If you are not able to know the resolution, you should use {@link #RESOLUTION_UNKNOWN}
* as the resolution of the video stream.
* </p>
*
* <p>
* It must be set before building the builder and not null.
* </p>
*
* @param resolution the resolution of the {@link VideoStream}
* @return this {@link Builder} instance
*/
public Builder setResolution(@Nonnull final String resolution) {
this.resolution = resolution;
return this;
}
/**
* Set the {@link ItagItem} corresponding to the {@link VideoStream}.
*
* <p>
* {@link ItagItem}s are YouTube specific objects, so they are only known for this service
* and can be null.
* </p>
*
* <p>
* The default value is {@code null}.
* </p>
*
* @param itagItem the {@link ItagItem} of the {@link VideoStream}, which can be null
* @return this {@link Builder} instance
*/
public Builder setItagItem(@Nullable final ItagItem itagItem) {
this.itagItem = itagItem;
return this;
}
/**
* Build a {@link VideoStream} using the builder's current values.
*
* <p>
* The identifier, the content (and so the {@code isUrl} boolean), the {@code isVideoOnly}
* and the {@code resolution} properties must have been set.
* </p>
*
* @return a new {@link VideoStream} using the builder's current values
* @throws IllegalStateException if {@code id}, {@code content} (and so {@code isUrl}),
* {@code deliveryMethod}, {@code isVideoOnly} or {@code resolution} have been not set, or
* have been set as {@code null}
*/
@Nonnull
public VideoStream build() {
if (id == null) {
throw new IllegalStateException(
"The identifier of the video stream has been not set or is null. If you "
+ "are not able to get an identifier, use the static constant "
+ "ID_UNKNOWN of the Stream class.");
}
if (content == null) {
throw new IllegalStateException("The content of the video stream has been not set "
+ "or is null. Please specify a non-null one with setContent.");
}
if (deliveryMethod == null) {
throw new IllegalStateException(
"The delivery method of the video stream has been set as null, which is "
+ "not allowed. Pass a valid one instead with setDeliveryMethod.");
}
if (isVideoOnly == null) {
throw new IllegalStateException("The video stream has been not set as a "
+ "video-only stream or as a video stream with embedded audio. Please "
+ "specify this information with setIsVideoOnly.");
}
if (resolution == null) {
throw new IllegalStateException(
"The resolution of the video stream has been not set. Please specify it "
+ "with setResolution (use an empty string if you are not able to "
+ "get it).");
}
return new VideoStream(id, content, isUrl, mediaFormat, deliveryMethod, resolution,
isVideoOnly, manifestUrl, itagItem);
}
}
/**
* Create a new video stream.
*
* @param id the identifier which uniquely identifies the stream, e.g. for YouTube
* this would be the itag
* @param content the content or the URL of the stream, depending on whether isUrl is
* true
* @param isUrl whether content is the URL or the actual content of e.g. a DASH
* manifest
* @param format the {@link MediaFormat} used by the stream, which can be null
* @param deliveryMethod the {@link DeliveryMethod} of the stream
* @param resolution the resolution of the stream
* @param isVideoOnly whether the stream is video-only
* @param itagItem the {@link ItagItem} corresponding to the stream, which cannot be null
* @param manifestUrl the URL of the manifest this stream comes from (if applicable,
* otherwise null)
*/
@SuppressWarnings("checkstyle:ParameterNumber")
private VideoStream(@Nonnull final String id,
@Nonnull final String content,
final boolean isUrl,
@Nullable final MediaFormat format,
@Nonnull final DeliveryMethod deliveryMethod,
@Nonnull final String resolution,
final boolean isVideoOnly,
@Nullable final String manifestUrl,
@Nullable final ItagItem itagItem) {
super(id, content, isUrl, format, deliveryMethod, manifestUrl);
if (itagItem != null) {
this.itagItem = itagItem;
this.itag = itagItem.id;
this.bitrate = itagItem.getBitrate();
this.initStart = itagItem.getInitStart();
this.initEnd = itagItem.getInitEnd();
this.indexStart = itagItem.getIndexStart();
this.indexEnd = itagItem.getIndexEnd();
this.codec = itagItem.getCodec();
this.height = itagItem.getHeight();
this.width = itagItem.getWidth();
this.quality = itagItem.getQuality();
this.fps = itagItem.getFps();
}
this.resolution = resolution;
this.isVideoOnly = isVideoOnly;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equalStats(final Stream cmp) {
return super.equalStats(cmp)
&& cmp instanceof VideoStream
&& resolution.equals(((VideoStream) cmp).resolution)
&& isVideoOnly == ((VideoStream) cmp).isVideoOnly;
}
/**
* Get the video resolution.
*
* <p>
* It can be unknown for some streams, like for HLS master playlists. In this case,
* {@link #RESOLUTION_UNKNOWN} is returned by this method.
* </p>
*
* @return the video resolution or {@link #RESOLUTION_UNKNOWN}
*/
@Nonnull
public String getResolution() {
return resolution;
}
/**
* Return whether the stream is video-only.
*
* <p>
* Video-only streams have no audio.
* </p>
*
* @return {@code true} if this stream is video-only, {@code false} otherwise
*/
public boolean isVideoOnly() {
return isVideoOnly;
}
/**
* Get the itag identifier of the stream.
*
* <p>
* Always equals to {@link #ITAG_NOT_AVAILABLE_OR_NOT_APPLICABLE} for other streams than the
* ones of the YouTube service.
* </p>
*
* @return the number of the {@link ItagItem} passed in the constructor of the video stream.
*/
public int getItag() {
return itag;
}
/**
* Get the bitrate of the stream.
*
* @return the bitrate set from the {@link ItagItem} passed in the constructor of the stream.
*/
public int getBitrate() {
return bitrate;
}
/**
* Get the initialization start of the stream.
*
* @return the initialization start value set from the {@link ItagItem} passed in the
* constructor of the
* stream.
*/
public int getInitStart() {
return initStart;
}
/**
* Get the initialization end of the stream.
*
* @return the initialization end value set from the {@link ItagItem} passed in the constructor
* of the stream.
*/
public int getInitEnd() {
return initEnd;
}
/**
* Get the index start of the stream.
*
* @return the index start value set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public int getIndexStart() {
return indexStart;
}
/**
* Get the index end of the stream.
*
* @return the index end value set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public int getIndexEnd() {
return indexEnd;
}
/**
* Get the width of the video stream.
*
* @return the width set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public int getWidth() {
return width;
}
/**
* Get the height of the video stream.
*
* @return the height set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public int getHeight() {
return height;
}
/**
* Get the frames per second of the video stream.
*
* @return the frames per second set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public int getFps() {
return fps;
}
/**
* Get the quality of the stream.
*
* @return the quality label set from the {@link ItagItem} passed in the constructor of the
* stream.
*/
public String getQuality() {
return quality;
}
/**
* Get the codec of the stream.
*
* @return the codec set from the {@link ItagItem} passed in the constructor of the stream.
*/
public String getCodec() {
return codec;
}
/**
* {@inheritDoc}
*/
@Override
@Nullable
public ItagItem getItagItem() {
return itagItem;
}
}