Commit 02f1efd1 by Oliver Woodman

Add bitrate to MediaFormat.

Issue: #514
parent ff201db9
......@@ -68,6 +68,7 @@ import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
......@@ -450,16 +451,21 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
if (format.adaptive) {
return "auto";
} else if (MimeTypes.isVideo(format.mimeType)) {
return format.width + "x" + format.height;
return format.width + "x" + format.height + buildBitrateString(format);
} else if (MimeTypes.isAudio(format.mimeType)) {
return format.channelCount + "ch, " + format.sampleRate + "Hz";
return format.channelCount + "ch, " + format.sampleRate + "Hz" + buildBitrateString(format);
} else if (MimeTypes.isText(format.mimeType) && !TextUtils.isEmpty(format.language)) {
return format.language;
return format.language + buildBitrateString(format);
} else {
return "unknown";
return "unknown" + buildBitrateString(format);
}
}
private static String buildBitrateString(MediaFormat format) {
return format.bitrate == MediaFormat.NO_VALUE ? ""
: String.format(Locale.US, " (%.2fMbit)", format.bitrate / 1000000f);
}
private boolean onTrackItemClick(MenuItem item, int type) {
if (player == null || item.getGroupId() != MENU_GROUP_TRACKS) {
return false;
......
......@@ -45,17 +45,17 @@ public final class MediaFormatTest extends TestCase {
initData.add(initData2);
testConversionToFrameworkFormatV16(MediaFormat.createVideoFormat(
"video/xyz", 102400, 1000L, 1280, 720, 1, initData));
"video/xyz", 5000, 102400, 1000L, 1280, 720, 1, initData));
testConversionToFrameworkFormatV16(MediaFormat.createVideoFormat(
"video/xyz", MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 1280, 720, 1, null));
"video/xyz", 5000, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 1280, 720, 1, null));
testConversionToFrameworkFormatV16(MediaFormat.createAudioFormat(
"audio/xyz", 128, 1000L, 5, 44100, initData));
"audio/xyz", 500, 128, 1000L, 5, 44100, initData));
testConversionToFrameworkFormatV16(MediaFormat.createAudioFormat(
"audio/xyz", MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 5, 44100, null));
"audio/xyz", 500, MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, 5, 44100, null));
testConversionToFrameworkFormatV16(
MediaFormat.createTextFormat("text/xyz", "eng", 1000L));
MediaFormat.createTextFormat("text/xyz", MediaFormat.NO_VALUE, "eng", 1000L));
testConversionToFrameworkFormatV16(
MediaFormat.createTextFormat("text/xyz", null, C.UNKNOWN_TIME_US));
MediaFormat.createTextFormat("text/xyz", MediaFormat.NO_VALUE, null, C.UNKNOWN_TIME_US));
}
@SuppressLint("InlinedApi")
......
......@@ -91,7 +91,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
public void testMaxVideoDimensions() {
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
null, null, null);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, 1, null);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 5000, 1, 1, 1, 1, 1, null);
format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, format.maxWidth);
......@@ -121,7 +121,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, 1, null);
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 5000, 1, 1, 1, 1, 1, null);
format = chunkSource.getWithMaxVideoDimensions(format);
assertEquals(WIDE_WIDTH, format.maxWidth);
......
......@@ -315,10 +315,10 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
}
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
MediaFormat mediaFormat = new MediaFormat(mimeType, maxInputSize, durationUs, width, height,
rotationDegrees, MediaFormat.NO_VALUE, channelCount, sampleRate, language,
MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData, false, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE);
MediaFormat mediaFormat = new MediaFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize,
durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE, channelCount, sampleRate,
language, MediaFormat.OFFSET_SAMPLE_RELATIVE, initializationData, false,
MediaFormat.NO_VALUE, MediaFormat.NO_VALUE);
mediaFormat.setFrameworkFormatV16(format);
return mediaFormat;
}
......
......@@ -148,7 +148,8 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
*/
// TODO: This method should be abstract. This implementation is provided as an interim step only.
protected MediaFormat getFormat(int track) {
return MediaFormat.createFormatForMimeType("application/octet-stream", getDurationUs());
return MediaFormat.createFormatForMimeType("application/octet-stream", MediaFormat.NO_VALUE,
getDurationUs());
}
/**
......
......@@ -264,7 +264,7 @@ public class DashChunkSource implements ChunkSource {
? TrackRenderer.UNKNOWN_TIME_US : representations[0].periodDurationMs * 1000;
// TODO: Remove this and pass proper formats instead (b/22996976).
this.mediaFormat = MediaFormat.createFormatForMimeType(getMediaMimeType(representations[0]),
periodDurationUs);
MediaFormat.NO_VALUE, periodDurationUs);
this.formats = new Format[representations.length];
this.representationHolders = new HashMap<>();
......@@ -652,9 +652,11 @@ public class DashChunkSource implements ChunkSource {
long sampleOffsetUs = representation.periodStartMs * 1000
- representation.presentationTimeOffsetUs;
if (representation.format.mimeType.equals(MimeTypes.TEXT_VTT)) {
MediaFormat mediaFormat = MediaFormat.createTextFormat(MimeTypes.TEXT_VTT,
MediaFormat.NO_VALUE, representation.format.language);
return new SingleSampleMediaChunk(dataSource, dataSpec, Chunk.TRIGGER_INITIAL,
representation.format, startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment,
MediaFormat.createTextFormat(MimeTypes.TEXT_VTT, representation.format.language), null);
mediaFormat, null);
} else {
return new ContainerMediaChunk(dataSource, dataSpec, trigger, representation.format,
startTimeUs, endTimeUs, absoluteSegmentNum, isLastSegment, sampleOffsetUs,
......
......@@ -312,8 +312,8 @@ public final class Mp3Extractor implements Extractor {
setupSeeker(extractorInput, headerPosition);
extractorOutput.seekMap(seeker);
trackOutput.format(MediaFormat.createAudioFormat(synchronizedHeader.mimeType,
MpegAudioHeader.MAX_FRAME_SIZE_BYTES, seeker.getDurationUs(), synchronizedHeader.channels,
synchronizedHeader.sampleRate, null));
MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, seeker.getDurationUs(),
synchronizedHeader.channels, synchronizedHeader.sampleRate, null));
}
return headerPosition;
......
......@@ -376,14 +376,14 @@ import java.util.List;
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, durationUs,
out, i);
} else if (childAtomType == Atom.TYPE_TTML) {
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, language,
durationUs);
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML,
MediaFormat.NO_VALUE, language, durationUs);
} else if (childAtomType == Atom.TYPE_tx3g) {
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TX3G, language,
durationUs);
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TX3G,
MediaFormat.NO_VALUE, language, durationUs);
} else if (childAtomType == Atom.TYPE_stpp) {
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, language,
durationUs, 0 /* subsample timing is absolute */);
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML,
MediaFormat.NO_VALUE, language, durationUs, 0 /* subsample timing is absolute */);
}
stsd.setPosition(childStartPosition + childAtomSize);
}
......@@ -453,8 +453,9 @@ import java.util.List;
return;
}
out.mediaFormat = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, durationUs,
width, height, rotationDegrees, pixelWidthHeightRatio, initializationData);
out.mediaFormat = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE,
MediaFormat.NO_VALUE, durationUs, width, height, rotationDegrees, pixelWidthHeightRatio,
initializationData);
}
private static AvcCData parseAvcCFromParent(ParsableByteArray parent, int position) {
......@@ -643,8 +644,8 @@ import java.util.List;
return;
}
out.mediaFormat = MediaFormat.createAudioFormat(mimeType, sampleSize, durationUs, channelCount,
sampleRate,
out.mediaFormat = MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, sampleSize,
durationUs, channelCount, sampleRate,
initializationData == null ? null : Collections.singletonList(initializationData));
}
......
......@@ -171,7 +171,7 @@ import java.util.Collections;
audioSpecificConfig);
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MimeTypes.AUDIO_AAC,
MediaFormat.NO_VALUE, audioParams.second, audioParams.first,
MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, audioParams.second, audioParams.first,
Collections.singletonList(audioSpecificConfig));
frameDurationUs = (C.MICROS_PER_SECOND * 1024L) / mediaFormat.sampleRate;
output.format(mediaFormat);
......
......@@ -211,7 +211,7 @@ import java.util.List;
// Construct and output the format.
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, 0,
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, 0,
parsedSpsData.pixelWidthAspectRatio, initializationData));
hasOutputFormat = true;
}
......
......@@ -295,8 +295,8 @@ import java.util.Collections;
}
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE,
C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, 0, pixelWidthHeightRatio,
Collections.singletonList(csd)));
MediaFormat.NO_VALUE, C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, 0,
pixelWidthHeightRatio, Collections.singletonList(csd)));
hasOutputFormat = true;
}
......
......@@ -35,7 +35,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public Id3Reader(TrackOutput output) {
super(output);
output.format(MediaFormat.createFormatForMimeType(MimeTypes.APPLICATION_ID3));
output.format(MediaFormat.createFormatForMimeType(MimeTypes.APPLICATION_ID3,
MediaFormat.NO_VALUE));
}
@Override
......
......@@ -161,8 +161,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
if (!hasOutputFormat) {
frameDurationUs = (C.MICROS_PER_SECOND * header.samplesPerFrame) / header.sampleRate;
MediaFormat mediaFormat = MediaFormat.createAudioFormat(header.mimeType,
MpegAudioHeader.MAX_FRAME_SIZE_BYTES, C.UNKNOWN_TIME_US, header.channels,
header.sampleRate, null);
MediaFormat.NO_VALUE, MpegAudioHeader.MAX_FRAME_SIZE_BYTES, C.UNKNOWN_TIME_US,
header.channels, header.sampleRate, null);
output.format(mediaFormat);
hasOutputFormat = true;
}
......
......@@ -32,7 +32,8 @@ import com.google.android.exoplayer.util.ParsableByteArray;
public SeiReader(TrackOutput output) {
super(output);
output.format(MediaFormat.createTextFormat(MimeTypes.APPLICATION_EIA608, null));
output.format(MediaFormat.createTextFormat(MimeTypes.APPLICATION_EIA608, MediaFormat.NO_VALUE,
null));
}
@Override
......
......@@ -1123,11 +1123,11 @@ public final class WebmExtractor implements Extractor {
}
if (MimeTypes.isAudio(mimeType)) {
return MediaFormat.createAudioFormat(mimeType, maxInputSize, durationUs, channelCount,
sampleRate, initializationData);
return MediaFormat.createAudioFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize,
durationUs, channelCount, sampleRate, initializationData);
} else if (MimeTypes.isVideo(mimeType)) {
return MediaFormat.createVideoFormat(mimeType, maxInputSize, durationUs, pixelWidth,
pixelHeight, 0, initializationData);
return MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, maxInputSize,
durationUs, pixelWidth, pixelHeight, 0, initializationData);
} else {
throw new ParserException("Unexpected MIME type.");
}
......
......@@ -374,7 +374,7 @@ public class SmoothStreamingChunkSource implements ChunkSource,
maxHeight = Math.max(maxHeight, mediaFormat.height);
}
Arrays.sort(formats, new DecreasingBandwidthComparator());
MediaFormat adaptiveMediaFormat = maxHeightMediaFormat.copyWithAdaptive(true);
MediaFormat adaptiveMediaFormat = maxHeightMediaFormat.copyAsAdaptive();
tracks.add(new ExposedTrack(adaptiveMediaFormat, element, formats, maxWidth, maxHeight));
}
......@@ -404,8 +404,9 @@ public class SmoothStreamingChunkSource implements ChunkSource,
int mp4TrackType;
switch (element.type) {
case StreamElement.TYPE_VIDEO:
mediaFormat = MediaFormat.createVideoFormat(format.mimeType, MediaFormat.NO_VALUE,
durationUs, format.width, format.height, 0, Arrays.asList(csdArray));
mediaFormat = MediaFormat.createVideoFormat(format.mimeType, format.bitrate,
MediaFormat.NO_VALUE, durationUs, format.width, format.height, 0,
Arrays.asList(csdArray));
mp4TrackType = Track.TYPE_vide;
break;
case StreamElement.TYPE_AUDIO:
......@@ -416,12 +417,13 @@ public class SmoothStreamingChunkSource implements ChunkSource,
csd = Collections.singletonList(CodecSpecificDataUtil.buildAacAudioSpecificConfig(
format.audioSamplingRate, format.audioChannels));
}
mediaFormat = MediaFormat.createAudioFormat(format.mimeType, MediaFormat.NO_VALUE,
durationUs, format.audioChannels, format.audioSamplingRate, csd);
mediaFormat = MediaFormat.createAudioFormat(format.mimeType, format.bitrate,
MediaFormat.NO_VALUE, durationUs, format.audioChannels, format.audioSamplingRate, csd);
mp4TrackType = Track.TYPE_soun;
break;
case StreamElement.TYPE_TEXT:
mediaFormat = MediaFormat.createTextFormat(format.mimeType, format.language, durationUs);
mediaFormat = MediaFormat.createTextFormat(format.mimeType, format.bitrate, format.language,
durationUs);
mp4TrackType = Track.TYPE_text;
break;
default:
......
......@@ -49,7 +49,7 @@ public final class Ac3Util {
channelCount++;
}
return MediaFormat.createAudioFormat(MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE,
channelCount, sampleRate, null);
MediaFormat.NO_VALUE, channelCount, sampleRate, null);
}
/**
......@@ -72,7 +72,7 @@ public final class Ac3Util {
channelCount++;
}
return MediaFormat.createAudioFormat(MimeTypes.AUDIO_EC3, MediaFormat.NO_VALUE,
channelCount, sampleRate, null);
MediaFormat.NO_VALUE, channelCount, sampleRate, null);
}
/**
......@@ -100,7 +100,7 @@ public final class Ac3Util {
}
boolean lfeon = data.readBit();
return MediaFormat.createAudioFormat(MimeTypes.AUDIO_AC3, MediaFormat.NO_VALUE,
CHANNEL_COUNTS[acmod] + (lfeon ? 1 : 0), SAMPLE_RATES[fscod], null);
MediaFormat.NO_VALUE, CHANNEL_COUNTS[acmod] + (lfeon ? 1 : 0), SAMPLE_RATES[fscod], null);
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment