mirror of
https://github.com/samsonjs/media.git
synced 2026-04-08 11:45:51 +00:00
Add frame rate to Format for use in format selection (when known).
This commit is contained in:
parent
a7e2b719c5
commit
1a9bf018a4
8 changed files with 77 additions and 43 deletions
|
|
@ -107,7 +107,7 @@ public class SmoothFrameReleaseTimeHelper implements FrameReleaseTimeHelper, Fra
|
|||
if (frameCount >= MIN_FRAMES_FOR_ADJUSTMENT) {
|
||||
// We're synced and have waited the required number of frames to apply an adjustment.
|
||||
// Calculate the average frame time across all the frames we've seen since the last sync.
|
||||
// This will typically give us a framerate at a finer granularity than the frame times
|
||||
// This will typically give us a frame rate at a finer granularity than the frame times
|
||||
// themselves (which often only have millisecond granularity).
|
||||
long averageFrameTimeNs = (unadjustedFrameTimeNs - syncFrameTimeNs) / frameCount;
|
||||
// Project the adjusted frame time forward using the average.
|
||||
|
|
|
|||
|
|
@ -47,34 +47,39 @@ public class Format {
|
|||
public final String mimeType;
|
||||
|
||||
/**
|
||||
* The codecs used to decode the format, or {@code null} if they are not specified.
|
||||
* The average bandwidth in bits per second.
|
||||
*/
|
||||
public final String codecs;
|
||||
public final int bitrate;
|
||||
|
||||
/**
|
||||
* The width of the video in pixels, or -1 for non-video formats.
|
||||
* The width of the video in pixels, or -1 if unknown or not applicable.
|
||||
*/
|
||||
public final int width;
|
||||
|
||||
/**
|
||||
* The height of the video in pixels, or -1 for non-video formats.
|
||||
* The height of the video in pixels, or -1 if unknown or not applicable.
|
||||
*/
|
||||
public final int height;
|
||||
|
||||
/**
|
||||
* The number of audio channels, or -1 for non-audio formats.
|
||||
* The video frame rate in frames per second, or -1 if unknown or not applicable.
|
||||
*/
|
||||
public final float frameRate;
|
||||
|
||||
/**
|
||||
* The number of audio channels, or -1 if unknown or not applicable.
|
||||
*/
|
||||
public final int numChannels;
|
||||
|
||||
/**
|
||||
* The audio sampling rate in Hz, or -1 for non-audio formats.
|
||||
* The audio sampling rate in Hz, or -1 if unknown or not applicable.
|
||||
*/
|
||||
public final int audioSamplingRate;
|
||||
|
||||
/**
|
||||
* The average bandwidth in bits per second.
|
||||
* The codecs used to decode the format. Can be {@code null} if unknown.
|
||||
*/
|
||||
public final int bitrate;
|
||||
public final String codecs;
|
||||
|
||||
/**
|
||||
* The language of the format. Can be null if unknown.
|
||||
|
|
@ -87,50 +92,58 @@ public class Format {
|
|||
/**
|
||||
* @param id The format identifier.
|
||||
* @param mimeType The format mime type.
|
||||
* @param width The width of the video in pixels, or -1 for non-video formats.
|
||||
* @param height The height of the video in pixels, or -1 for non-video formats.
|
||||
* @param numChannels The number of audio channels, or -1 for non-audio formats.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 for non-audio formats.
|
||||
* @param width The width of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param height The height of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param frameRate The frame rate of the video in frames per second, or -1 if unknown or not
|
||||
* applicable.
|
||||
* @param numChannels The number of audio channels, or -1 if unknown or not applicable.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 if unknown or not applicable.
|
||||
* @param bitrate The average bandwidth of the format in bits per second.
|
||||
*/
|
||||
public Format(String id, String mimeType, int width, int height, int numChannels,
|
||||
public Format(String id, String mimeType, int width, int height, float frameRate, int numChannels,
|
||||
int audioSamplingRate, int bitrate) {
|
||||
this(id, mimeType, width, height, numChannels, audioSamplingRate, bitrate, null, null);
|
||||
this(id, mimeType, width, height, frameRate, numChannels, audioSamplingRate, bitrate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id The format identifier.
|
||||
* @param mimeType The format mime type.
|
||||
* @param width The width of the video in pixels, or -1 for non-video formats.
|
||||
* @param height The height of the video in pixels, or -1 for non-video formats.
|
||||
* @param numChannels The number of audio channels, or -1 for non-audio formats.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 for non-audio formats.
|
||||
* @param width The width of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param height The height of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param frameRate The frame rate of the video in frames per second, or -1 if unknown or not
|
||||
* applicable.
|
||||
* @param numChannels The number of audio channels, or -1 if unknown or not applicable.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 if unknown or not applicable.
|
||||
* @param bitrate The average bandwidth of the format in bits per second.
|
||||
* @param language The language of the format.
|
||||
*/
|
||||
public Format(String id, String mimeType, int width, int height, int numChannels,
|
||||
public Format(String id, String mimeType, int width, int height, float frameRate, int numChannels,
|
||||
int audioSamplingRate, int bitrate, String language) {
|
||||
this(id, mimeType, width, height, numChannels, audioSamplingRate, bitrate, language, null);
|
||||
this(id, mimeType, width, height, frameRate, numChannels, audioSamplingRate, bitrate, language,
|
||||
null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param id The format identifier.
|
||||
* @param mimeType The format mime type.
|
||||
* @param width The width of the video in pixels, or -1 for non-video formats.
|
||||
* @param height The height of the video in pixels, or -1 for non-video formats.
|
||||
* @param numChannels The number of audio channels, or -1 for non-audio formats.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 for non-audio formats.
|
||||
* @param width The width of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param height The height of the video in pixels, or -1 if unknown or not applicable.
|
||||
* @param frameRate The frame rate of the video in frames per second, or -1 if unknown or not
|
||||
* applicable.
|
||||
* @param numChannels The number of audio channels, or -1 if unknown or not applicable.
|
||||
* @param audioSamplingRate The audio sampling rate in Hz, or -1 if unknown or not applicable.
|
||||
* @param bitrate The average bandwidth of the format in bits per second.
|
||||
* @param language The language of the format.
|
||||
* @param codecs The codecs used to decode the format.
|
||||
*/
|
||||
public Format(String id, String mimeType, int width, int height, int numChannels,
|
||||
public Format(String id, String mimeType, int width, int height, float frameRate, int numChannels,
|
||||
int audioSamplingRate, int bitrate, String language, String codecs) {
|
||||
this.id = Assertions.checkNotNull(id);
|
||||
this.mimeType = mimeType;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.frameRate = frameRate;
|
||||
this.numChannels = numChannels;
|
||||
this.audioSamplingRate = audioSamplingRate;
|
||||
this.bitrate = bitrate;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A parser of media presentation description files.
|
||||
|
|
@ -48,6 +50,8 @@ import java.util.List;
|
|||
public class MediaPresentationDescriptionParser extends DefaultHandler
|
||||
implements NetworkLoadable.Parser<MediaPresentationDescription> {
|
||||
|
||||
private static final Pattern FRAME_RATE_PATTERN = Pattern.compile("(\\d+)(?:/(\\d+))??");
|
||||
|
||||
private final String contentId;
|
||||
private final XmlPullParserFactory xmlParserFactory;
|
||||
|
||||
|
|
@ -296,6 +300,22 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
int audioSamplingRate = parseInt(xpp, "audioSamplingRate");
|
||||
int width = parseInt(xpp, "width");
|
||||
int height = parseInt(xpp, "height");
|
||||
|
||||
float frameRate = -1;
|
||||
String frameRateAttribute = xpp.getAttributeValue(null, "frameRate");
|
||||
if (frameRateAttribute != null) {
|
||||
Matcher frameRateMatcher = FRAME_RATE_PATTERN.matcher(frameRateAttribute);
|
||||
if (frameRateMatcher.matches()) {
|
||||
int numerator = Integer.parseInt(frameRateMatcher.group(1));
|
||||
String denominatorString = frameRateMatcher.group(2);
|
||||
if (!TextUtils.isEmpty(denominatorString)) {
|
||||
frameRate = (float) numerator / Integer.parseInt(denominatorString);
|
||||
} else {
|
||||
frameRate = numerator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mimeType = parseString(xpp, "mimeType", mimeType);
|
||||
String codecs = parseString(xpp, "codecs", null);
|
||||
|
||||
|
|
@ -318,16 +338,16 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|||
}
|
||||
} while (!isEndTag(xpp, "Representation"));
|
||||
|
||||
Format format = buildFormat(id, mimeType, width, height, numChannels, audioSamplingRate,
|
||||
bandwidth, language, codecs);
|
||||
Format format = buildFormat(id, mimeType, width, height, frameRate, numChannels,
|
||||
audioSamplingRate, bandwidth, language, codecs);
|
||||
return buildRepresentation(periodStartMs, periodDurationMs, contentId, -1, format,
|
||||
segmentBase != null ? segmentBase : new SingleSegmentBase(baseUrl));
|
||||
}
|
||||
|
||||
protected Format buildFormat(String id, String mimeType, int width, int height, int numChannels,
|
||||
int audioSamplingRate, int bandwidth, String language, String codecs) {
|
||||
return new Format(id, mimeType, width, height, numChannels, audioSamplingRate, bandwidth,
|
||||
language, codecs);
|
||||
protected Format buildFormat(String id, String mimeType, int width, int height, float frameRate,
|
||||
int numChannels, int audioSamplingRate, int bandwidth, String language, String codecs) {
|
||||
return new Format(id, mimeType, width, height, frameRate, numChannels, audioSamplingRate,
|
||||
bandwidth, language, codecs);
|
||||
}
|
||||
|
||||
protected Representation buildRepresentation(long periodStartMs, long periodDurationMs,
|
||||
|
|
|
|||
|
|
@ -676,7 +676,7 @@ public class HlsChunkSource {
|
|||
|
||||
public HlsFormat(String id, int width, int height, int bitrate, String codecs,
|
||||
int variantIndex) {
|
||||
super(id, MimeTypes.APPLICATION_M3U8, width, height, -1, -1, bitrate, null, codecs);
|
||||
super(id, MimeTypes.APPLICATION_M3U8, width, height, -1, -1, -1, bitrate, null, codecs);
|
||||
this.variantIndex = variantIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
|
|||
|
||||
public SmoothStreamingFormat(String id, String mimeType, int width, int height,
|
||||
int numChannels, int audioSamplingRate, int bitrate, int trackIndex) {
|
||||
super(id, mimeType, width, height, numChannels, audioSamplingRate, bitrate);
|
||||
super(id, mimeType, width, height, -1, numChannels, audioSamplingRate, bitrate);
|
||||
this.trackIndex = trackIndex;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ public class TtmlParser implements SubtitleParser {
|
|||
* <a href="http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
|
||||
*
|
||||
* @param time A string that includes the time expression.
|
||||
* @param frameRate The framerate of the stream.
|
||||
* @param subframeRate The sub-framerate of the stream
|
||||
* @param frameRate The frame rate of the stream.
|
||||
* @param subframeRate The sub-frame rate of the stream
|
||||
* @param tickRate The tick rate of the stream.
|
||||
* @return The parsed timestamp in microseconds.
|
||||
* @throws ParserException If the given string does not contain a valid time expression.
|
||||
|
|
|
|||
|
|
@ -65,11 +65,12 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
|
|||
private static final int TALL_HEIGHT = 200;
|
||||
private static final int WIDE_WIDTH = 400;
|
||||
|
||||
private static final Format REGULAR_VIDEO = new Format("1", "video/mp4", 480, 240, -1, -1, 1000);
|
||||
private static final Format TALL_VIDEO = new Format("2", "video/mp4", 100, TALL_HEIGHT, -1, -1,
|
||||
1000);
|
||||
private static final Format WIDE_VIDEO = new Format("3", "video/mp4", WIDE_WIDTH, 50, -1, -1,
|
||||
1000);
|
||||
private static final Format REGULAR_VIDEO =
|
||||
new Format("1", "video/mp4", 480, 240, -1, -1, -1, 1000);
|
||||
private static final Format TALL_VIDEO =
|
||||
new Format("2", "video/mp4", 100, TALL_HEIGHT, -1, -1, -1, 1000);
|
||||
private static final Format WIDE_VIDEO =
|
||||
new Format("3", "video/mp4", WIDE_WIDTH, 50, -1, -1, -1, 1000);
|
||||
|
||||
@Mock private DataSource mockDataSource;
|
||||
@Mock private ManifestFetcher<MediaPresentationDescription> mockManifestFetcher;
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ public class RepresentationTest extends TestCase {
|
|||
public void testGetCacheKey() {
|
||||
String uri = "http://www.google.com";
|
||||
SegmentBase base = new SingleSegmentBase(new RangedUri(uri, null, 0, 1), 1, 0, uri, 1, 1);
|
||||
Format format = new Format("0", MimeTypes.VIDEO_MP4, 1920, 1080, 0, 0, 2500000);
|
||||
Format format = new Format("0", MimeTypes.VIDEO_MP4, 1920, 1080, -1, 0, 0, 2500000);
|
||||
Representation representation = Representation.newInstance(-1, -1, "test_stream_1", 3,
|
||||
format, base);
|
||||
assertEquals("test_stream_1.0.3", representation.getCacheKey());
|
||||
|
||||
format = new Format("150", MimeTypes.VIDEO_MP4, 1920, 1080, 0, 0, 2500000);
|
||||
format = new Format("150", MimeTypes.VIDEO_MP4, 1920, 1080, -1, 0, 0, 2500000);
|
||||
representation = Representation.newInstance(-1, -1, "test_stream_1", -1, format, base);
|
||||
assertEquals("test_stream_1.150.-1", representation.getCacheKey());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue