parent
8db1331021
commit
d3995eaa7a
@ -76,8 +76,10 @@ public class EventLogger implements DemoPlayer.Listener, DemoPlayer.InfoListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
|
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
Log.d(TAG, "videoSizeChanged [" + width + ", " + height + ", " + pixelWidthHeightRatio + "]");
|
float pixelWidthHeightRatio) {
|
||||||
|
Log.d(TAG, "videoSizeChanged [" + width + ", " + height + ", " + unappliedRotationDegrees
|
||||||
|
+ ", " + pixelWidthHeightRatio + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// DemoPlayer.InfoListener
|
// DemoPlayer.InfoListener
|
||||||
|
@ -341,7 +341,8 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, float pixelWidthAspectRatio) {
|
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
|
float pixelWidthAspectRatio) {
|
||||||
shutterView.setVisibility(View.GONE);
|
shutterView.setVisibility(View.GONE);
|
||||||
videoFrame.setAspectRatio(
|
videoFrame.setAspectRatio(
|
||||||
height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
|
height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
|
||||||
|
@ -89,7 +89,8 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
|||||||
public interface Listener {
|
public interface Listener {
|
||||||
void onStateChanged(boolean playWhenReady, int playbackState);
|
void onStateChanged(boolean playWhenReady, int playbackState);
|
||||||
void onError(Exception e);
|
void onError(Exception e);
|
||||||
void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio);
|
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
|
float pixelWidthHeightRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -449,9 +450,10 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio) {
|
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
|
float pixelWidthHeightRatio) {
|
||||||
for (Listener listener : listeners) {
|
for (Listener listener : listeners) {
|
||||||
listener.onVideoSizeChanged(width, height, pixelWidthHeightRatio);
|
listener.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
|
|||||||
public void testMaxVideoDimensions() {
|
public void testMaxVideoDimensions() {
|
||||||
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
|
DashChunkSource chunkSource = new DashChunkSource(generateVodMpd(), AdaptationSet.TYPE_VIDEO,
|
||||||
null, null, null);
|
null, null, null);
|
||||||
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, 1, null);
|
||||||
format = chunkSource.getWithMaxVideoDimensions(format);
|
format = chunkSource.getWithMaxVideoDimensions(format);
|
||||||
|
|
||||||
assertEquals(WIDE_WIDTH, format.maxWidth);
|
assertEquals(WIDE_WIDTH, format.maxWidth);
|
||||||
@ -121,7 +121,7 @@ public class DashChunkSourceTest extends InstrumentationTestCase {
|
|||||||
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
|
Representation.newInstance(0, 0, null, 0, WIDE_VIDEO, segmentBase2);
|
||||||
|
|
||||||
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
|
DashChunkSource chunkSource = new DashChunkSource(null, null, representation1, representation2);
|
||||||
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, null);
|
MediaFormat format = MediaFormat.createVideoFormat("video/h264", 1, 1, 1, 1, 1, null);
|
||||||
format = chunkSource.getWithMaxVideoDimensions(format);
|
format = chunkSource.getWithMaxVideoDimensions(format);
|
||||||
|
|
||||||
assertEquals(WIDE_WIDTH, format.maxWidth);
|
assertEquals(WIDE_WIDTH, format.maxWidth);
|
||||||
|
@ -77,8 +77,9 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
+ "000000000000000000000000000003");
|
+ "000000000000000000000000000003");
|
||||||
|
|
||||||
/** String of hexadecimal bytes containing a tkhd payload with an unknown duration. */
|
/** String of hexadecimal bytes containing a tkhd payload with an unknown duration. */
|
||||||
private static final byte[] TKHD_PAYLOAD =
|
private static final byte[] TKHD_PAYLOAD = getByteArray(
|
||||||
getByteArray("0000000000000000000000000000000000000000FFFFFFFF");
|
"00000007D1F0C7BFD1F0C7BF0000000000000000FFFFFFFF00000000000000000000000000000000000100"
|
||||||
|
+ "0000000000000000000000000000010000000000000000000000000000400000000780000004380000");
|
||||||
|
|
||||||
/** Video frame timestamps in time units. */
|
/** Video frame timestamps in time units. */
|
||||||
private static final int[] SAMPLE_TIMESTAMPS = {0, 2, 3, 5, 6, 7};
|
private static final int[] SAMPLE_TIMESTAMPS = {0, 2, 3, 5, 6, 7};
|
||||||
@ -87,7 +88,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
/** Indices of key-frames. */
|
/** Indices of key-frames. */
|
||||||
private static final boolean[] SAMPLE_IS_SYNC = {true, false, false, false, true, true};
|
private static final boolean[] SAMPLE_IS_SYNC = {true, false, false, false, true, true};
|
||||||
/** Indices of video frame chunk offsets. */
|
/** Indices of video frame chunk offsets. */
|
||||||
private static final int[] CHUNK_OFFSETS = {1080, 2000, 3000, 4000};
|
private static final int[] CHUNK_OFFSETS = {1200, 2120, 3120, 4120};
|
||||||
/** Numbers of video frames in each chunk. */
|
/** Numbers of video frames in each chunk. */
|
||||||
private static final int[] SAMPLES_IN_CHUNK = {2, 2, 1, 1};
|
private static final int[] SAMPLES_IN_CHUNK = {2, 2, 1, 1};
|
||||||
/** The mdat box must be large enough to avoid reading chunk sample data out of bounds. */
|
/** The mdat box must be large enough to avoid reading chunk sample data out of bounds. */
|
||||||
@ -399,7 +400,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
atom(Atom.TYPE_stsc, getStsc()),
|
atom(Atom.TYPE_stsc, getStsc()),
|
||||||
atom(Atom.TYPE_stsz, getStsz()),
|
atom(Atom.TYPE_stsz, getStsz()),
|
||||||
atom(Atom.TYPE_stco, getStco())))))),
|
atom(Atom.TYPE_stco, getStco())))))),
|
||||||
atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 1048 : 1038, !mp4vFormat)));
|
atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 1168 : 1158, !mp4vFormat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a valid MP4 file with audio/video tracks and without a synchronization table. */
|
/** Gets a valid MP4 file with audio/video tracks and without a synchronization table. */
|
||||||
@ -435,7 +436,7 @@ public final class Mp4ExtractorTest extends TestCase {
|
|||||||
atom(Atom.TYPE_stsc, getStsc()),
|
atom(Atom.TYPE_stsc, getStsc()),
|
||||||
atom(Atom.TYPE_stsz, getStsz()),
|
atom(Atom.TYPE_stsz, getStsz()),
|
||||||
atom(Atom.TYPE_stco, getStco())))))),
|
atom(Atom.TYPE_stco, getStco())))))),
|
||||||
atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 992 : 982, !mp4vFormat)));
|
atom(Atom.TYPE_mdat, getMdat(mp4vFormat ? 1112 : 1102, !mp4vFormat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mp4Atom atom(int type, Mp4Atom... containedMp4Atoms) {
|
private static Mp4Atom atom(int type, Mp4Atom... containedMp4Atoms) {
|
||||||
|
@ -302,6 +302,7 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
int maxInputSize = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_MAX_INPUT_SIZE);
|
int maxInputSize = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_MAX_INPUT_SIZE);
|
||||||
int width = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_WIDTH);
|
int width = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_WIDTH);
|
||||||
int height = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_HEIGHT);
|
int height = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_HEIGHT);
|
||||||
|
int rotationDegrees = getOptionalIntegerV16(format, "rotation-degrees");
|
||||||
int channelCount = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_CHANNEL_COUNT);
|
int channelCount = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_CHANNEL_COUNT);
|
||||||
int sampleRate = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_SAMPLE_RATE);
|
int sampleRate = getOptionalIntegerV16(format, android.media.MediaFormat.KEY_SAMPLE_RATE);
|
||||||
ArrayList<byte[]> initializationData = new ArrayList<>();
|
ArrayList<byte[]> initializationData = new ArrayList<>();
|
||||||
@ -314,9 +315,9 @@ public final class FrameworkSampleSource implements SampleSource, SampleSourceRe
|
|||||||
}
|
}
|
||||||
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
|
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
|
||||||
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
|
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
|
||||||
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, MediaFormat.NO_VALUE,
|
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, rotationDegrees,
|
||||||
channelCount, sampleRate, language, initializationData, MediaFormat.NO_VALUE,
|
MediaFormat.NO_VALUE, channelCount, sampleRate, language, initializationData,
|
||||||
MediaFormat.NO_VALUE);
|
MediaFormat.NO_VALUE, MediaFormat.NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(16)
|
@TargetApi(16)
|
||||||
|
@ -26,6 +26,7 @@ import android.media.MediaCrypto;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.view.TextureView;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
@ -59,11 +60,19 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
*
|
*
|
||||||
* @param width The video width in pixels.
|
* @param width The video width in pixels.
|
||||||
* @param height The video height in pixels.
|
* @param height The video height in pixels.
|
||||||
|
* @param unappliedRotationDegrees For videos that require a rotation, this is the clockwise
|
||||||
|
* rotation in degrees that the application should apply for the video for it to be rendered
|
||||||
|
* in the correct orientation. This value will always be zero on API levels 21 and above,
|
||||||
|
* since the renderer will apply all necessary rotations internally. On earlier API levels
|
||||||
|
* this is not possible. Applications that use {@link TextureView} can apply the rotation by
|
||||||
|
* calling {@link TextureView#setTransform}. Applications that do not expect to encounter
|
||||||
|
* rotated videos can safely ignore this parameter.
|
||||||
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
|
* @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case
|
||||||
* of square pixels this will be equal to 1.0. Different values are indicative of anamorphic
|
* of square pixels this will be equal to 1.0. Different values are indicative of anamorphic
|
||||||
* content.
|
* content.
|
||||||
*/
|
*/
|
||||||
void onVideoSizeChanged(int width, int height, float pixelWidthHeightRatio);
|
void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
|
||||||
|
float pixelWidthHeightRatio);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when a frame is rendered to a surface for the first time following that surface
|
* Invoked when a frame is rendered to a surface for the first time following that surface
|
||||||
@ -129,12 +138,15 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
private long droppedFrameAccumulationStartTimeMs;
|
private long droppedFrameAccumulationStartTimeMs;
|
||||||
private int droppedFrameCount;
|
private int droppedFrameCount;
|
||||||
|
|
||||||
|
private int pendingRotationDegrees;
|
||||||
|
private float pendingPixelWidthHeightRatio;
|
||||||
private int currentWidth;
|
private int currentWidth;
|
||||||
private int currentHeight;
|
private int currentHeight;
|
||||||
|
private int currentUnappliedRotationDegrees;
|
||||||
private float currentPixelWidthHeightRatio;
|
private float currentPixelWidthHeightRatio;
|
||||||
private float pendingPixelWidthHeightRatio;
|
|
||||||
private int lastReportedWidth;
|
private int lastReportedWidth;
|
||||||
private int lastReportedHeight;
|
private int lastReportedHeight;
|
||||||
|
private int lastReportedUnappliedRotationDegrees;
|
||||||
private float lastReportedPixelWidthHeightRatio;
|
private float lastReportedPixelWidthHeightRatio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,6 +386,8 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
super.onInputFormatChanged(holder);
|
super.onInputFormatChanged(holder);
|
||||||
pendingPixelWidthHeightRatio = holder.format.pixelWidthHeightRatio == MediaFormat.NO_VALUE ? 1
|
pendingPixelWidthHeightRatio = holder.format.pixelWidthHeightRatio == MediaFormat.NO_VALUE ? 1
|
||||||
: holder.format.pixelWidthHeightRatio;
|
: holder.format.pixelWidthHeightRatio;
|
||||||
|
pendingRotationDegrees = holder.format.rotationDegrees == MediaFormat.NO_VALUE ? 0
|
||||||
|
: holder.format.rotationDegrees;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,6 +409,20 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
? outputFormat.getInteger(KEY_CROP_BOTTOM) - outputFormat.getInteger(KEY_CROP_TOP) + 1
|
? outputFormat.getInteger(KEY_CROP_BOTTOM) - outputFormat.getInteger(KEY_CROP_TOP) + 1
|
||||||
: outputFormat.getInteger(android.media.MediaFormat.KEY_HEIGHT);
|
: outputFormat.getInteger(android.media.MediaFormat.KEY_HEIGHT);
|
||||||
currentPixelWidthHeightRatio = pendingPixelWidthHeightRatio;
|
currentPixelWidthHeightRatio = pendingPixelWidthHeightRatio;
|
||||||
|
if (Util.SDK_INT >= 21) {
|
||||||
|
// On API level 21 and above the decoder applies the rotation when rendering to the surface.
|
||||||
|
// Hence currentUnappliedRotation should always be 0. For 90 and 270 degree rotations, we need
|
||||||
|
// to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
|
||||||
|
if (pendingRotationDegrees == 90 || pendingRotationDegrees == 270) {
|
||||||
|
int rotatedHeight = currentWidth;
|
||||||
|
currentWidth = currentHeight;
|
||||||
|
currentHeight = rotatedHeight;
|
||||||
|
currentPixelWidthHeightRatio = 1 / currentPixelWidthHeightRatio;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// On API level 20 and below the decoder does not apply the rotation.
|
||||||
|
currentUnappliedRotationDegrees = pendingRotationDegrees;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -520,22 +548,26 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
|
|||||||
private void maybeNotifyVideoSizeChanged() {
|
private void maybeNotifyVideoSizeChanged() {
|
||||||
if (eventHandler == null || eventListener == null
|
if (eventHandler == null || eventListener == null
|
||||||
|| (lastReportedWidth == currentWidth && lastReportedHeight == currentHeight
|
|| (lastReportedWidth == currentWidth && lastReportedHeight == currentHeight
|
||||||
|
&& lastReportedUnappliedRotationDegrees == currentUnappliedRotationDegrees
|
||||||
&& lastReportedPixelWidthHeightRatio == currentPixelWidthHeightRatio)) {
|
&& lastReportedPixelWidthHeightRatio == currentPixelWidthHeightRatio)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Make final copies to ensure the runnable reports the correct values.
|
// Make final copies to ensure the runnable reports the correct values.
|
||||||
final int currentWidth = this.currentWidth;
|
final int currentWidth = this.currentWidth;
|
||||||
final int currentHeight = this.currentHeight;
|
final int currentHeight = this.currentHeight;
|
||||||
|
final int currentUnappliedRotationDegrees = this.currentUnappliedRotationDegrees;
|
||||||
final float currentPixelWidthHeightRatio = this.currentPixelWidthHeightRatio;
|
final float currentPixelWidthHeightRatio = this.currentPixelWidthHeightRatio;
|
||||||
eventHandler.post(new Runnable() {
|
eventHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
eventListener.onVideoSizeChanged(currentWidth, currentHeight, currentPixelWidthHeightRatio);
|
eventListener.onVideoSizeChanged(currentWidth, currentHeight,
|
||||||
|
currentUnappliedRotationDegrees, currentPixelWidthHeightRatio);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Update the last reported values.
|
// Update the last reported values.
|
||||||
lastReportedWidth = currentWidth;
|
lastReportedWidth = currentWidth;
|
||||||
lastReportedHeight = currentHeight;
|
lastReportedHeight = currentHeight;
|
||||||
|
lastReportedUnappliedRotationDegrees = currentUnappliedRotationDegrees;
|
||||||
lastReportedPixelWidthHeightRatio = currentPixelWidthHeightRatio;
|
lastReportedPixelWidthHeightRatio = currentPixelWidthHeightRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ public final class MediaFormat {
|
|||||||
|
|
||||||
public final int width;
|
public final int width;
|
||||||
public final int height;
|
public final int height;
|
||||||
|
public final int rotationDegrees;
|
||||||
public final float pixelWidthHeightRatio;
|
public final float pixelWidthHeightRatio;
|
||||||
|
|
||||||
public final int channelCount;
|
public final int channelCount;
|
||||||
@ -64,19 +65,21 @@ public final class MediaFormat {
|
|||||||
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, int width,
|
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, int width,
|
||||||
int height, List<byte[]> initializationData) {
|
int height, List<byte[]> initializationData) {
|
||||||
return createVideoFormat(
|
return createVideoFormat(
|
||||||
mimeType, maxInputSize, C.UNKNOWN_TIME_US, width, height, initializationData);
|
mimeType, maxInputSize, C.UNKNOWN_TIME_US, width, height, NO_VALUE, initializationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
|
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
|
||||||
int width, int height, List<byte[]> initializationData) {
|
int width, int height, int rotationDegrees, List<byte[]> initializationData) {
|
||||||
return createVideoFormat(
|
return createVideoFormat(
|
||||||
mimeType, maxInputSize, durationUs, width, height, 1, initializationData);
|
mimeType, maxInputSize, durationUs, width, height, rotationDegrees, NO_VALUE,
|
||||||
|
initializationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
|
public static MediaFormat createVideoFormat(String mimeType, int maxInputSize, long durationUs,
|
||||||
int width, int height, float pixelWidthHeightRatio, List<byte[]> initializationData) {
|
int width, int height, int rotationDegrees, float pixelWidthHeightRatio,
|
||||||
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio,
|
List<byte[]> initializationData) {
|
||||||
NO_VALUE, NO_VALUE, null, initializationData, NO_VALUE, NO_VALUE);
|
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, rotationDegrees,
|
||||||
|
pixelWidthHeightRatio, NO_VALUE, NO_VALUE, null, initializationData, NO_VALUE, NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, int channelCount,
|
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, int channelCount,
|
||||||
@ -88,7 +91,7 @@ public final class MediaFormat {
|
|||||||
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, long durationUs,
|
public static MediaFormat createAudioFormat(String mimeType, int maxInputSize, long durationUs,
|
||||||
int channelCount, int sampleRate, List<byte[]> initializationData) {
|
int channelCount, int sampleRate, List<byte[]> initializationData) {
|
||||||
return new MediaFormat(mimeType, maxInputSize, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new MediaFormat(mimeType, maxInputSize, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
channelCount, sampleRate, null, initializationData, NO_VALUE, NO_VALUE);
|
NO_VALUE, channelCount, sampleRate, null, initializationData, NO_VALUE, NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MediaFormat createTextFormat(String mimeType, String language) {
|
public static MediaFormat createTextFormat(String mimeType, String language) {
|
||||||
@ -97,7 +100,7 @@ public final class MediaFormat {
|
|||||||
|
|
||||||
public static MediaFormat createTextFormat(String mimeType, String language, long durationUs) {
|
public static MediaFormat createTextFormat(String mimeType, String language, long durationUs) {
|
||||||
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, language, null, NO_VALUE, NO_VALUE);
|
NO_VALUE, NO_VALUE, NO_VALUE, language, null, NO_VALUE, NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MediaFormat createFormatForMimeType(String mimeType) {
|
public static MediaFormat createFormatForMimeType(String mimeType) {
|
||||||
@ -106,17 +109,19 @@ public final class MediaFormat {
|
|||||||
|
|
||||||
public static MediaFormat createFormatForMimeType(String mimeType, long durationUs) {
|
public static MediaFormat createFormatForMimeType(String mimeType, long durationUs) {
|
||||||
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
return new MediaFormat(mimeType, NO_VALUE, durationUs, NO_VALUE, NO_VALUE, NO_VALUE,
|
||||||
NO_VALUE, NO_VALUE, null, null, NO_VALUE, NO_VALUE);
|
NO_VALUE, NO_VALUE, NO_VALUE, null, null, NO_VALUE, NO_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ MediaFormat(String mimeType, int maxInputSize, long durationUs, int width,
|
/* package */ MediaFormat(String mimeType, int maxInputSize, long durationUs, int width,
|
||||||
int height, float pixelWidthHeightRatio, int channelCount, int sampleRate, String language,
|
int height, int rotationDegrees, float pixelWidthHeightRatio, int channelCount,
|
||||||
List<byte[]> initializationData, int maxWidth, int maxHeight) {
|
int sampleRate, String language, List<byte[]> initializationData, int maxWidth,
|
||||||
|
int maxHeight) {
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
this.maxInputSize = maxInputSize;
|
this.maxInputSize = maxInputSize;
|
||||||
this.durationUs = durationUs;
|
this.durationUs = durationUs;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
this.rotationDegrees = rotationDegrees;
|
||||||
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
|
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
|
||||||
this.channelCount = channelCount;
|
this.channelCount = channelCount;
|
||||||
this.sampleRate = sampleRate;
|
this.sampleRate = sampleRate;
|
||||||
@ -128,8 +133,9 @@ public final class MediaFormat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MediaFormat copyWithMaxVideoDimension(int maxWidth, int maxHeight) {
|
public MediaFormat copyWithMaxVideoDimension(int maxWidth, int maxHeight) {
|
||||||
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, pixelWidthHeightRatio,
|
return new MediaFormat(mimeType, maxInputSize, durationUs, width, height, rotationDegrees,
|
||||||
channelCount, sampleRate, language, initializationData, maxWidth, maxHeight);
|
pixelWidthHeightRatio, channelCount, sampleRate, language, initializationData, maxWidth,
|
||||||
|
maxHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -145,6 +151,7 @@ public final class MediaFormat {
|
|||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize);
|
||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_WIDTH, width);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_WIDTH, width);
|
||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_HEIGHT, height);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_HEIGHT, height);
|
||||||
|
maybeSetIntegerV16(format, "rotation-degrees", rotationDegrees);
|
||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_WIDTH, maxWidth);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_WIDTH, maxWidth);
|
||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_HEIGHT, maxHeight);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_MAX_HEIGHT, maxHeight);
|
||||||
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_CHANNEL_COUNT, channelCount);
|
maybeSetIntegerV16(format, android.media.MediaFormat.KEY_CHANNEL_COUNT, channelCount);
|
||||||
@ -163,8 +170,8 @@ public final class MediaFormat {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "MediaFormat(" + mimeType + ", " + maxInputSize + ", " + width + ", " + height + ", "
|
return "MediaFormat(" + mimeType + ", " + maxInputSize + ", " + width + ", " + height + ", "
|
||||||
+ pixelWidthHeightRatio + ", " + channelCount + ", " + sampleRate + ", " + language + ", "
|
+ rotationDegrees + ", " + pixelWidthHeightRatio + ", " + channelCount + ", " + sampleRate
|
||||||
+ durationUs + ", " + maxWidth + ", " + maxHeight + ")";
|
+ ", " + language + ", " + durationUs + ", " + maxWidth + ", " + maxHeight + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -175,6 +182,7 @@ public final class MediaFormat {
|
|||||||
result = 31 * result + maxInputSize;
|
result = 31 * result + maxInputSize;
|
||||||
result = 31 * result + width;
|
result = 31 * result + width;
|
||||||
result = 31 * result + height;
|
result = 31 * result + height;
|
||||||
|
result = 31 * result + rotationDegrees;
|
||||||
result = 31 * result + Float.floatToRawIntBits(pixelWidthHeightRatio);
|
result = 31 * result + Float.floatToRawIntBits(pixelWidthHeightRatio);
|
||||||
result = 31 * result + (int) durationUs;
|
result = 31 * result + (int) durationUs;
|
||||||
result = 31 * result + maxWidth;
|
result = 31 * result + maxWidth;
|
||||||
@ -213,6 +221,7 @@ public final class MediaFormat {
|
|||||||
|
|
||||||
private boolean equalsInternal(MediaFormat other, boolean ignoreMaxDimensions) {
|
private boolean equalsInternal(MediaFormat other, boolean ignoreMaxDimensions) {
|
||||||
if (maxInputSize != other.maxInputSize || width != other.width || height != other.height
|
if (maxInputSize != other.maxInputSize || width != other.width || height != other.height
|
||||||
|
|| rotationDegrees != other.rotationDegrees
|
||||||
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio
|
|| pixelWidthHeightRatio != other.pixelWidthHeightRatio
|
||||||
|| (!ignoreMaxDimensions && (maxWidth != other.maxWidth || maxHeight != other.maxHeight))
|
|| (!ignoreMaxDimensions && (maxWidth != other.maxWidth || maxHeight != other.maxHeight))
|
||||||
|| channelCount != other.channelCount || sampleRate != other.sampleRate
|
|| channelCount != other.channelCount || sampleRate != other.sampleRate
|
||||||
|
@ -50,9 +50,8 @@ import java.util.List;
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<Integer, Long> header = parseTkhd(trak.getLeafAtomOfType(Atom.TYPE_tkhd).data);
|
TkhdData tkhdData = parseTkhd(trak.getLeafAtomOfType(Atom.TYPE_tkhd).data);
|
||||||
int id = header.first;
|
long duration = tkhdData.duration;
|
||||||
long duration = header.second;
|
|
||||||
long movieTimescale = parseMvhd(mvhd.data);
|
long movieTimescale = parseMvhd(mvhd.data);
|
||||||
long durationUs;
|
long durationUs;
|
||||||
if (duration == -1) {
|
if (duration == -1) {
|
||||||
@ -64,10 +63,10 @@ import java.util.List;
|
|||||||
.getContainerAtomOfType(Atom.TYPE_stbl);
|
.getContainerAtomOfType(Atom.TYPE_stbl);
|
||||||
|
|
||||||
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
|
Pair<Long, String> mdhdData = parseMdhd(mdia.getLeafAtomOfType(Atom.TYPE_mdhd).data);
|
||||||
StsdDataHolder stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, durationUs,
|
StsdData stsdData = parseStsd(stbl.getLeafAtomOfType(Atom.TYPE_stsd).data, durationUs,
|
||||||
mdhdData.second);
|
tkhdData.rotationDegrees, mdhdData.second);
|
||||||
return stsdData.mediaFormat == null ? null
|
return stsdData.mediaFormat == null ? null
|
||||||
: new Track(id, trackType, mdhdData.first, durationUs, stsdData.mediaFormat,
|
: new Track(tkhdData.id, trackType, mdhdData.first, durationUs, stsdData.mediaFormat,
|
||||||
stsdData.trackEncryptionBoxes, stsdData.nalUnitLengthFieldLength);
|
stsdData.trackEncryptionBoxes, stsdData.nalUnitLengthFieldLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,19 +267,17 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* Parses a tkhd atom (defined in 14496-12).
|
* Parses a tkhd atom (defined in 14496-12).
|
||||||
*
|
*
|
||||||
* @return A {@link Pair} consisting of the track id and duration (in the timescale indicated in
|
* @return An object containing the parsed data.
|
||||||
* the movie header box). The duration is set to -1 if the duration is unspecified.
|
|
||||||
*/
|
*/
|
||||||
private static Pair<Integer, Long> parseTkhd(ParsableByteArray tkhd) {
|
private static TkhdData parseTkhd(ParsableByteArray tkhd) {
|
||||||
tkhd.setPosition(Atom.HEADER_SIZE);
|
tkhd.setPosition(Atom.HEADER_SIZE);
|
||||||
int fullAtom = tkhd.readInt();
|
int fullAtom = tkhd.readInt();
|
||||||
int version = Atom.parseFullAtomVersion(fullAtom);
|
int version = Atom.parseFullAtomVersion(fullAtom);
|
||||||
|
|
||||||
tkhd.skipBytes(version == 0 ? 8 : 16);
|
tkhd.skipBytes(version == 0 ? 8 : 16);
|
||||||
|
|
||||||
int trackId = tkhd.readInt();
|
int trackId = tkhd.readInt();
|
||||||
tkhd.skipBytes(4);
|
|
||||||
|
|
||||||
|
tkhd.skipBytes(4);
|
||||||
boolean durationUnknown = true;
|
boolean durationUnknown = true;
|
||||||
int durationPosition = tkhd.getPosition();
|
int durationPosition = tkhd.getPosition();
|
||||||
int durationByteCount = version == 0 ? 4 : 8;
|
int durationByteCount = version == 0 ? 4 : 8;
|
||||||
@ -298,7 +295,27 @@ import java.util.List;
|
|||||||
duration = version == 0 ? tkhd.readUnsignedInt() : tkhd.readUnsignedLongToLong();
|
duration = version == 0 ? tkhd.readUnsignedInt() : tkhd.readUnsignedLongToLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair.create(trackId, duration);
|
tkhd.skipBytes(16);
|
||||||
|
int a00 = tkhd.readInt();
|
||||||
|
int a01 = tkhd.readInt();
|
||||||
|
tkhd.skipBytes(4);
|
||||||
|
int a10 = tkhd.readInt();
|
||||||
|
int a11 = tkhd.readInt();
|
||||||
|
|
||||||
|
int rotationDegrees;
|
||||||
|
int fixedOne = 65536;
|
||||||
|
if (a00 == 0 && a01 == fixedOne && a10 == -fixedOne && a11 == 0) {
|
||||||
|
rotationDegrees = 90;
|
||||||
|
} else if (a00 == 0 && a01 == -fixedOne && a10 == fixedOne && a11 == 0) {
|
||||||
|
rotationDegrees = 270;
|
||||||
|
} else if (a00 == -fixedOne && a01 == 0 && a10 == 0 && a11 == -fixedOne) {
|
||||||
|
rotationDegrees = 180;
|
||||||
|
} else {
|
||||||
|
// Only 0, 90, 180 and 270 are supported. Treat anything else as 0.
|
||||||
|
rotationDegrees = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TkhdData(trackId, duration, rotationDegrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,11 +350,16 @@ import java.util.List;
|
|||||||
return Pair.create(timescale, language);
|
return Pair.create(timescale, language);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StsdDataHolder parseStsd(ParsableByteArray stsd, long durationUs,
|
/**
|
||||||
|
* Parses a stsd atom (defined in 14496-12).
|
||||||
|
*
|
||||||
|
* @return An object containing the parsed data.
|
||||||
|
*/
|
||||||
|
private static StsdData parseStsd(ParsableByteArray stsd, long durationUs, int rotationDegrees,
|
||||||
String language) {
|
String language) {
|
||||||
stsd.setPosition(Atom.FULL_HEADER_SIZE);
|
stsd.setPosition(Atom.FULL_HEADER_SIZE);
|
||||||
int numberOfEntries = stsd.readInt();
|
int numberOfEntries = stsd.readInt();
|
||||||
StsdDataHolder holder = new StsdDataHolder(numberOfEntries);
|
StsdData out = new StsdData(numberOfEntries);
|
||||||
for (int i = 0; i < numberOfEntries; i++) {
|
for (int i = 0; i < numberOfEntries; i++) {
|
||||||
int childStartPosition = stsd.getPosition();
|
int childStartPosition = stsd.getPosition();
|
||||||
int childAtomSize = stsd.readInt();
|
int childAtomSize = stsd.readInt();
|
||||||
@ -347,25 +369,26 @@ import java.util.List;
|
|||||||
|| childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v
|
|| childAtomType == Atom.TYPE_encv || childAtomType == Atom.TYPE_mp4v
|
||||||
|| childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1
|
|| childAtomType == Atom.TYPE_hvc1 || childAtomType == Atom.TYPE_hev1
|
||||||
|| childAtomType == Atom.TYPE_s263) {
|
|| childAtomType == Atom.TYPE_s263) {
|
||||||
parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, durationUs, holder, i);
|
parseVideoSampleEntry(stsd, childStartPosition, childAtomSize, durationUs, rotationDegrees,
|
||||||
|
out, i);
|
||||||
} else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca
|
} else if (childAtomType == Atom.TYPE_mp4a || childAtomType == Atom.TYPE_enca
|
||||||
|| childAtomType == Atom.TYPE_ac_3) {
|
|| childAtomType == Atom.TYPE_ac_3) {
|
||||||
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, durationUs,
|
parseAudioSampleEntry(stsd, childAtomType, childStartPosition, childAtomSize, durationUs,
|
||||||
holder, i);
|
out, i);
|
||||||
} else if (childAtomType == Atom.TYPE_TTML) {
|
} else if (childAtomType == Atom.TYPE_TTML) {
|
||||||
holder.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, language,
|
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TTML, language,
|
||||||
durationUs);
|
durationUs);
|
||||||
} else if (childAtomType == Atom.TYPE_tx3g) {
|
} else if (childAtomType == Atom.TYPE_tx3g) {
|
||||||
holder.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TX3G, language,
|
out.mediaFormat = MediaFormat.createTextFormat(MimeTypes.APPLICATION_TX3G, language,
|
||||||
durationUs);
|
durationUs);
|
||||||
}
|
}
|
||||||
stsd.setPosition(childStartPosition + childAtomSize);
|
stsd.setPosition(childStartPosition + childAtomSize);
|
||||||
}
|
}
|
||||||
return holder;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size,
|
private static void parseVideoSampleEntry(ParsableByteArray parent, int position, int size,
|
||||||
long durationUs, StsdDataHolder out, int entryIndex) {
|
long durationUs, int rotationDegrees, StsdData out, int entryIndex) {
|
||||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||||
|
|
||||||
parent.skipBytes(24);
|
parent.skipBytes(24);
|
||||||
@ -428,7 +451,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
|
|
||||||
out.mediaFormat = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, durationUs,
|
out.mediaFormat = MediaFormat.createVideoFormat(mimeType, MediaFormat.NO_VALUE, durationUs,
|
||||||
width, height, pixelWidthHeightRatio, initializationData);
|
width, height, rotationDegrees, pixelWidthHeightRatio, initializationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AvcCData parseAvcCFromParent(ParsableByteArray parent, int position) {
|
private static AvcCData parseAvcCFromParent(ParsableByteArray parent, int position) {
|
||||||
@ -556,7 +579,7 @@ import java.util.List;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
|
private static void parseAudioSampleEntry(ParsableByteArray parent, int atomType, int position,
|
||||||
int size, long durationUs, StsdDataHolder out, int entryIndex) {
|
int size, long durationUs, StsdData out, int entryIndex) {
|
||||||
parent.setPosition(position + Atom.HEADER_SIZE);
|
parent.setPosition(position + Atom.HEADER_SIZE);
|
||||||
parent.skipBytes(16);
|
parent.skipBytes(16);
|
||||||
int channelCount = parent.readUnsignedShort();
|
int channelCount = parent.readUnsignedShort();
|
||||||
@ -702,23 +725,43 @@ import java.util.List;
|
|||||||
// Prevent instantiation.
|
// Prevent instantiation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds data parsed from a tkhd atom.
|
||||||
|
*/
|
||||||
|
private static final class TkhdData {
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
private final long duration;
|
||||||
|
private final int rotationDegrees;
|
||||||
|
|
||||||
|
public TkhdData(int id, long duration, int rotationDegrees) {
|
||||||
|
this.id = id;
|
||||||
|
this.duration = duration;
|
||||||
|
this.rotationDegrees = rotationDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds data parsed from an stsd atom and its children.
|
* Holds data parsed from an stsd atom and its children.
|
||||||
*/
|
*/
|
||||||
private static final class StsdDataHolder {
|
private static final class StsdData {
|
||||||
|
|
||||||
public final TrackEncryptionBox[] trackEncryptionBoxes;
|
public final TrackEncryptionBox[] trackEncryptionBoxes;
|
||||||
|
|
||||||
public MediaFormat mediaFormat;
|
public MediaFormat mediaFormat;
|
||||||
public int nalUnitLengthFieldLength;
|
public int nalUnitLengthFieldLength;
|
||||||
|
|
||||||
public StsdDataHolder(int numberOfEntries) {
|
public StsdData(int numberOfEntries) {
|
||||||
trackEncryptionBoxes = new TrackEncryptionBox[numberOfEntries];
|
trackEncryptionBoxes = new TrackEncryptionBox[numberOfEntries];
|
||||||
nalUnitLengthFieldLength = -1;
|
nalUnitLengthFieldLength = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds data parsed from an AvcC atom.
|
||||||
|
*/
|
||||||
private static final class AvcCData {
|
private static final class AvcCData {
|
||||||
|
|
||||||
public final List<byte[]> initializationData;
|
public final List<byte[]> initializationData;
|
||||||
|
@ -211,7 +211,7 @@ import java.util.List;
|
|||||||
|
|
||||||
// Construct and output the format.
|
// Construct and output the format.
|
||||||
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
|
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE,
|
||||||
C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height,
|
C.UNKNOWN_TIME_US, parsedSpsData.width, parsedSpsData.height, 0,
|
||||||
parsedSpsData.pixelWidthAspectRatio, initializationData));
|
parsedSpsData.pixelWidthAspectRatio, initializationData));
|
||||||
hasOutputFormat = true;
|
hasOutputFormat = true;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ import java.util.Collections;
|
|||||||
}
|
}
|
||||||
|
|
||||||
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE,
|
output.format(MediaFormat.createVideoFormat(MimeTypes.VIDEO_H265, MediaFormat.NO_VALUE,
|
||||||
C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, pixelWidthHeightRatio,
|
C.UNKNOWN_TIME_US, picWidthInLumaSamples, picHeightInLumaSamples, 0, pixelWidthHeightRatio,
|
||||||
Collections.singletonList(csd)));
|
Collections.singletonList(csd)));
|
||||||
hasOutputFormat = true;
|
hasOutputFormat = true;
|
||||||
}
|
}
|
||||||
|
@ -1127,7 +1127,7 @@ public final class WebmExtractor implements Extractor {
|
|||||||
sampleRate, initializationData);
|
sampleRate, initializationData);
|
||||||
} else if (MimeTypes.isVideo(mimeType)) {
|
} else if (MimeTypes.isVideo(mimeType)) {
|
||||||
return MediaFormat.createVideoFormat(mimeType, maxInputSize, durationUs, pixelWidth,
|
return MediaFormat.createVideoFormat(mimeType, maxInputSize, durationUs, pixelWidth,
|
||||||
pixelHeight, initializationData);
|
pixelHeight, 0, initializationData);
|
||||||
} else {
|
} else {
|
||||||
throw new ParserException("Unexpected MIME type.");
|
throw new ParserException("Unexpected MIME type.");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user