Don't overwrite MP4 container fps using capture fps

The capture frame rate is currently available both via Format.metadata
and decoded in Format.frameRate. As the container Format.frameRate may
be useful to apps, only store the capture frame rate in metadata (apps
will need to decode it but can now access the container frame rate too).

PiperOrigin-RevId: 284165711
This commit is contained in:
andrewlewis 2019-12-06 13:21:46 +00:00 committed by Oliver Woodman
parent 781e15ae3e
commit 4ad6d9d85c
8 changed files with 253 additions and 11 deletions

View file

@ -21,6 +21,8 @@
speed ([#5978](https://github.com/google/ExoPlayer/issues/5978)).
* Allow `AdtsExtractor` to encounter EoF when calculating average frame size
([#6700](https://github.com/google/ExoPlayer/issues/6700)).
* In MP4 streams, store the Android capture frame rate only in
`Format.metadata`. `Format.frameRate` now stores the calculated frame rate.
* Make media session connector dispatch ACTION_SET_CAPTIONING_ENABLED.
* Add support for position and overlapping start/end times in SSA/ASS subtitles
([#6320](https://github.com/google/ExoPlayer/issues/6320)).

View file

@ -27,7 +27,6 @@ import com.google.android.exoplayer2.metadata.id3.InternalFrame;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.nio.ByteBuffer;
/** Utilities for handling metadata in MP4. */
/* package */ final class MetadataUtil {
@ -108,7 +107,6 @@ import java.nio.ByteBuffer;
private static final int TYPE_TOP_BYTE_REPLACEMENT = 0xFD; // Truncated value of \uFFFD.
private static final String MDTA_KEY_ANDROID_CAPTURE_FPS = "com.android.capture.fps";
private static final int MDTA_TYPE_INDICATOR_FLOAT = 23;
private MetadataUtil() {}
@ -138,15 +136,8 @@ import java.nio.ByteBuffer;
Metadata.Entry entry = mdtaMetadata.get(i);
if (entry instanceof MdtaMetadataEntry) {
MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry;
if (MDTA_KEY_ANDROID_CAPTURE_FPS.equals(mdtaMetadataEntry.key)
&& mdtaMetadataEntry.typeIndicator == MDTA_TYPE_INDICATOR_FLOAT) {
try {
float fps = ByteBuffer.wrap(mdtaMetadataEntry.value).asFloatBuffer().get();
format = format.copyWithFrameRate(fps);
format = format.copyWithMetadata(new Metadata(mdtaMetadataEntry));
} catch (NumberFormatException e) {
Log.w(TAG, "Ignoring invalid framerate");
}
if (MDTA_KEY_ANDROID_CAPTURE_FPS.equals(mdtaMetadataEntry.key)) {
format = format.copyWithMetadata(new Metadata(mdtaMetadataEntry));
}
}
}

View file

@ -0,0 +1,61 @@
seekMap:
isSeekable = true
duration = 526000
getPosition(0) = [[timeUs=0, position=1161]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = 1
containerMimeType = null
sampleMimeType = video/avc
maxInputSize = 34686
width = 1280
height = 720
frameRate = 13.307984
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = -1
sampleRate = -1
pcmEncoding = -1
encoderDelay = 0
encoderPadding = 0
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[mdta: key=com.android.capture.fps]
initializationData:
data = length 22, hash 4CF81805
data = length 9, hash FBAFBA1C
total output bytes = 42320
sample count = 7
sample 0:
time = 0
flags = 1
data = length 34656, hash D92B66FF
sample 1:
time = 325344
flags = 0
data = length 768, hash D0C3B229
sample 2:
time = 358677
flags = 0
data = length 1184, hash C598EFC0
sample 3:
time = 392011
flags = 0
data = length 576, hash 667AEC2C
sample 4:
time = 425344
flags = 0
data = length 1456, hash 430D1498
sample 5:
time = 458677
flags = 0
data = length 1280, hash 12267E0E
sample 6:
time = 492011
flags = 536870912
data = length 2400, hash FBCB42C
tracksEnded = true

View file

@ -0,0 +1,61 @@
seekMap:
isSeekable = true
duration = 526000
getPosition(0) = [[timeUs=0, position=1161]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = 1
containerMimeType = null
sampleMimeType = video/avc
maxInputSize = 34686
width = 1280
height = 720
frameRate = 13.307984
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = -1
sampleRate = -1
pcmEncoding = -1
encoderDelay = 0
encoderPadding = 0
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[mdta: key=com.android.capture.fps]
initializationData:
data = length 22, hash 4CF81805
data = length 9, hash FBAFBA1C
total output bytes = 42320
sample count = 7
sample 0:
time = 0
flags = 1
data = length 34656, hash D92B66FF
sample 1:
time = 325344
flags = 0
data = length 768, hash D0C3B229
sample 2:
time = 358677
flags = 0
data = length 1184, hash C598EFC0
sample 3:
time = 392011
flags = 0
data = length 576, hash 667AEC2C
sample 4:
time = 425344
flags = 0
data = length 1456, hash 430D1498
sample 5:
time = 458677
flags = 0
data = length 1280, hash 12267E0E
sample 6:
time = 492011
flags = 536870912
data = length 2400, hash FBCB42C
tracksEnded = true

View file

@ -0,0 +1,61 @@
seekMap:
isSeekable = true
duration = 526000
getPosition(0) = [[timeUs=0, position=1161]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = 1
containerMimeType = null
sampleMimeType = video/avc
maxInputSize = 34686
width = 1280
height = 720
frameRate = 13.307984
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = -1
sampleRate = -1
pcmEncoding = -1
encoderDelay = 0
encoderPadding = 0
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[mdta: key=com.android.capture.fps]
initializationData:
data = length 22, hash 4CF81805
data = length 9, hash FBAFBA1C
total output bytes = 42320
sample count = 7
sample 0:
time = 0
flags = 1
data = length 34656, hash D92B66FF
sample 1:
time = 325344
flags = 0
data = length 768, hash D0C3B229
sample 2:
time = 358677
flags = 0
data = length 1184, hash C598EFC0
sample 3:
time = 392011
flags = 0
data = length 576, hash 667AEC2C
sample 4:
time = 425344
flags = 0
data = length 1456, hash 430D1498
sample 5:
time = 458677
flags = 0
data = length 1280, hash 12267E0E
sample 6:
time = 492011
flags = 536870912
data = length 2400, hash FBCB42C
tracksEnded = true

View file

@ -0,0 +1,61 @@
seekMap:
isSeekable = true
duration = 526000
getPosition(0) = [[timeUs=0, position=1161]]
numberOfTracks = 1
track 0:
format:
bitrate = -1
id = 1
containerMimeType = null
sampleMimeType = video/avc
maxInputSize = 34686
width = 1280
height = 720
frameRate = 13.307984
rotationDegrees = 0
pixelWidthHeightRatio = 1.0
channelCount = -1
sampleRate = -1
pcmEncoding = -1
encoderDelay = 0
encoderPadding = 0
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
metadata = entries=[mdta: key=com.android.capture.fps]
initializationData:
data = length 22, hash 4CF81805
data = length 9, hash FBAFBA1C
total output bytes = 42320
sample count = 7
sample 0:
time = 0
flags = 1
data = length 34656, hash D92B66FF
sample 1:
time = 325344
flags = 0
data = length 768, hash D0C3B229
sample 2:
time = 358677
flags = 0
data = length 1184, hash C598EFC0
sample 3:
time = 392011
flags = 0
data = length 576, hash 667AEC2C
sample 4:
time = 425344
flags = 0
data = length 1456, hash 430D1498
sample 5:
time = 458677
flags = 0
data = length 1280, hash 12267E0E
sample 6:
time = 492011
flags = 536870912
data = length 2400, hash FBCB42C
tracksEnded = true

View file

@ -28,4 +28,9 @@ public final class Mp4ExtractorTest {
public void testMp4Sample() throws Exception {
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample.mp4");
}
@Test
public void testMp4SampleWithSlowMotionMetadata() throws Exception {
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample_android_slow_motion.mp4");
}
}