Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
175b8eb6
authored
Oct 22, 2020
by
kimvde
Committed by
Oliver Woodman
Oct 22, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Read Google Photos motion photo metadata
PiperOrigin-RevId: 338436906
parent
9bde5d03
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
131 additions
and
36 deletions
RELEASENOTES.md
library/common/src/main/java/com/google/android/exoplayer2/C.java
library/common/src/main/java/com/google/android/exoplayer2/metadata/mp4/MotionPhoto.java
library/core/src/main/java/com/google/android/exoplayer2/MetadataRetriever.java
library/core/src/test/java/com/google/android/exoplayer2/MetadataRetrieverTest.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java
testdata/src/test/assets/media/mp4/sample_MP.heic
RELEASENOTES.md
View file @
175b8eb6
...
@@ -99,6 +99,8 @@
...
@@ -99,6 +99,8 @@
*
Upgrade IMA SDK dependency to 3.20.1. This brings in a fix for
*
Upgrade IMA SDK dependency to 3.20.1. This brings in a fix for
companion ads rendering when targeting API 29
companion ads rendering when targeting API 29
(
[
#6432
](
https://github.com/google/ExoPlayer/issues/6432
)
).
(
[
#6432
](
https://github.com/google/ExoPlayer/issues/6432
)
).
*
Metadata retriever:
*
Parse Google Photos HEIC motion photos metadata.
### 2.12.0 (2020-09-11) ###
### 2.12.0 (2020-09-11) ###
...
...
library/common/src/main/java/com/google/android/exoplayer2/C.java
View file @
175b8eb6
...
@@ -690,12 +690,14 @@ public final class C {
...
@@ -690,12 +690,14 @@ public final class C {
public
static
final
int
TRACK_TYPE_VIDEO
=
2
;
public
static
final
int
TRACK_TYPE_VIDEO
=
2
;
/** A type constant for text tracks. */
/** A type constant for text tracks. */
public
static
final
int
TRACK_TYPE_TEXT
=
3
;
public
static
final
int
TRACK_TYPE_TEXT
=
3
;
/** A type constant for image tracks. */
public
static
final
int
TRACK_TYPE_IMAGE
=
4
;
/** A type constant for metadata tracks. */
/** A type constant for metadata tracks. */
public
static
final
int
TRACK_TYPE_METADATA
=
4
;
public
static
final
int
TRACK_TYPE_METADATA
=
5
;
/** A type constant for camera motion tracks. */
/** A type constant for camera motion tracks. */
public
static
final
int
TRACK_TYPE_CAMERA_MOTION
=
5
;
public
static
final
int
TRACK_TYPE_CAMERA_MOTION
=
6
;
/** A type constant for a fake or empty track. */
/** A type constant for a fake or empty track. */
public
static
final
int
TRACK_TYPE_NONE
=
6
;
public
static
final
int
TRACK_TYPE_NONE
=
7
;
/**
/**
* Applications or extensions may define custom {@code TRACK_TYPE_*} constants greater than or
* Applications or extensions may define custom {@code TRACK_TYPE_*} constants greater than or
* equal to this value.
* equal to this value.
...
...
library/common/src/main/java/com/google/android/exoplayer2/metadata/mp4/MotionPhoto.java
View file @
175b8eb6
...
@@ -20,21 +20,23 @@ import android.os.Parcel;
...
@@ -20,21 +20,23 @@ import android.os.Parcel;
import
android.os.Parcelable
;
import
android.os.Parcelable
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.common.primitives.Longs
;
/** Metadata of a motion photo file. */
/** Metadata of a motion photo file. */
public
final
class
MotionPhoto
implements
Metadata
.
Entry
{
public
final
class
MotionPhoto
implements
Metadata
.
Entry
{
/** The start offset of the photo data, in bytes. */
/** The start offset of the photo data, in bytes. */
public
final
int
photoStartPosition
;
public
final
long
photoStartPosition
;
/** The size of the photo data, in bytes. */
/** The size of the photo data, in bytes. */
public
final
int
photoSize
;
public
final
long
photoSize
;
/** The start offset of the video data, in bytes. */
/** The start offset of the video data, in bytes. */
public
final
int
videoStartPosition
;
public
final
long
videoStartPosition
;
/** The size of the video data, in bytes. */
/** The size of the video data, in bytes. */
public
final
int
videoSize
;
public
final
long
videoSize
;
/** Creates an instance. */
/** Creates an instance. */
public
MotionPhoto
(
int
photoStartPosition
,
int
photoSize
,
int
videoStartPosition
,
int
videoSize
)
{
public
MotionPhoto
(
long
photoStartPosition
,
long
photoSize
,
long
videoStartPosition
,
long
videoSize
)
{
this
.
photoStartPosition
=
photoStartPosition
;
this
.
photoStartPosition
=
photoStartPosition
;
this
.
photoSize
=
photoSize
;
this
.
photoSize
=
photoSize
;
this
.
videoStartPosition
=
videoStartPosition
;
this
.
videoStartPosition
=
videoStartPosition
;
...
@@ -42,10 +44,10 @@ public final class MotionPhoto implements Metadata.Entry {
...
@@ -42,10 +44,10 @@ public final class MotionPhoto implements Metadata.Entry {
}
}
private
MotionPhoto
(
Parcel
in
)
{
private
MotionPhoto
(
Parcel
in
)
{
photoStartPosition
=
in
.
read
Int
();
photoStartPosition
=
in
.
read
Long
();
photoSize
=
in
.
read
Int
();
photoSize
=
in
.
read
Long
();
videoStartPosition
=
in
.
read
Int
();
videoStartPosition
=
in
.
read
Long
();
videoSize
=
in
.
read
Int
();
videoSize
=
in
.
read
Long
();
}
}
@Override
@Override
...
@@ -66,10 +68,10 @@ public final class MotionPhoto implements Metadata.Entry {
...
@@ -66,10 +68,10 @@ public final class MotionPhoto implements Metadata.Entry {
@Override
@Override
public
int
hashCode
()
{
public
int
hashCode
()
{
int
result
=
17
;
int
result
=
17
;
result
=
31
*
result
+
photoStartPosition
;
result
=
31
*
result
+
Longs
.
hashCode
(
photoStartPosition
)
;
result
=
31
*
result
+
photoSize
;
result
=
31
*
result
+
Longs
.
hashCode
(
photoSize
)
;
result
=
31
*
result
+
videoStartPosition
;
result
=
31
*
result
+
Longs
.
hashCode
(
videoStartPosition
)
;
result
=
31
*
result
+
videoSize
;
result
=
31
*
result
+
Longs
.
hashCode
(
videoSize
)
;
return
result
;
return
result
;
}
}
...
@@ -89,10 +91,10 @@ public final class MotionPhoto implements Metadata.Entry {
...
@@ -89,10 +91,10 @@ public final class MotionPhoto implements Metadata.Entry {
@Override
@Override
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
public
void
writeToParcel
(
Parcel
dest
,
int
flags
)
{
dest
.
write
Int
(
photoStartPosition
);
dest
.
write
Long
(
photoStartPosition
);
dest
.
write
Int
(
photoSize
);
dest
.
write
Long
(
photoSize
);
dest
.
write
Int
(
videoStartPosition
);
dest
.
write
Long
(
videoStartPosition
);
dest
.
write
Int
(
videoSize
);
dest
.
write
Long
(
videoSize
);
}
}
@Override
@Override
...
...
library/core/src/main/java/com/google/android/exoplayer2/MetadataRetriever.java
View file @
175b8eb6
...
@@ -22,6 +22,9 @@ import android.content.Context;
...
@@ -22,6 +22,9 @@ import android.content.Context;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.os.HandlerThread
;
import
android.os.HandlerThread
;
import
android.os.Message
;
import
android.os.Message
;
import
com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
;
import
com.google.android.exoplayer2.extractor.ExtractorsFactory
;
import
com.google.android.exoplayer2.extractor.mp4.Mp4Extractor
;
import
com.google.android.exoplayer2.source.DefaultMediaSourceFactory
;
import
com.google.android.exoplayer2.source.DefaultMediaSourceFactory
;
import
com.google.android.exoplayer2.source.MediaPeriod
;
import
com.google.android.exoplayer2.source.MediaPeriod
;
import
com.google.android.exoplayer2.source.MediaSource
;
import
com.google.android.exoplayer2.source.MediaSource
;
...
@@ -43,8 +46,9 @@ public final class MetadataRetriever {
...
@@ -43,8 +46,9 @@ public final class MetadataRetriever {
/**
/**
* Retrieves the {@link TrackGroupArray} corresponding to a {@link MediaItem}.
* Retrieves the {@link TrackGroupArray} corresponding to a {@link MediaItem}.
*
*
* <p>This is equivalent to using {@code retrieveMetadata(new DefaultMediaSourceFactory(context),
* <p>This is equivalent to using {@link #retrieveMetadata(MediaSourceFactory, MediaItem)} with a
* mediaItem)}.
* {@link DefaultMediaSourceFactory} and a {@link DefaultExtractorsFactory} with {@link
* Mp4Extractor#FLAG_READ_MOTION_PHOTO_METADATA} set.
*
*
* @param context The {@link Context}.
* @param context The {@link Context}.
* @param mediaItem The {@link MediaItem} whose metadata should be retrieved.
* @param mediaItem The {@link MediaItem} whose metadata should be retrieved.
...
@@ -52,7 +56,12 @@ public final class MetadataRetriever {
...
@@ -52,7 +56,12 @@ public final class MetadataRetriever {
*/
*/
public
static
ListenableFuture
<
TrackGroupArray
>
retrieveMetadata
(
public
static
ListenableFuture
<
TrackGroupArray
>
retrieveMetadata
(
Context
context
,
MediaItem
mediaItem
)
{
Context
context
,
MediaItem
mediaItem
)
{
return
retrieveMetadata
(
new
DefaultMediaSourceFactory
(
context
),
mediaItem
);
ExtractorsFactory
extractorsFactory
=
new
DefaultExtractorsFactory
()
.
setMp4ExtractorFlags
(
Mp4Extractor
.
FLAG_READ_MOTION_PHOTO_METADATA
);
MediaSourceFactory
mediaSourceFactory
=
new
DefaultMediaSourceFactory
(
context
,
extractorsFactory
);
return
retrieveMetadata
(
mediaSourceFactory
,
mediaItem
);
}
}
/**
/**
...
...
library/core/src/test/java/com/google/android/exoplayer2/MetadataRetrieverTest.java
View file @
175b8eb6
...
@@ -25,6 +25,7 @@ import android.net.Uri;
...
@@ -25,6 +25,7 @@ import android.net.Uri;
import
android.os.SystemClock
;
import
android.os.SystemClock
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.core.app.ApplicationProvider
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.metadata.mp4.MotionPhoto
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.source.TrackGroupArray
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.common.util.concurrent.ListenableFuture
;
import
com.google.common.util.concurrent.ListenableFuture
;
...
@@ -37,7 +38,7 @@ import org.junit.runner.RunWith;
...
@@ -37,7 +38,7 @@ import org.junit.runner.RunWith;
public
class
MetadataRetrieverTest
{
public
class
MetadataRetrieverTest
{
@Test
@Test
public
void
retrieveMetadata_singleMediaItem
()
throws
Exception
{
public
void
retrieveMetadata_singleMediaItem
_outputsExpectedMetadata
()
throws
Exception
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaItem
mediaItem
=
MediaItem
mediaItem
=
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/mp4/sample.mp4"
));
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/mp4/sample.mp4"
));
...
@@ -55,7 +56,7 @@ public class MetadataRetrieverTest {
...
@@ -55,7 +56,7 @@ public class MetadataRetrieverTest {
}
}
@Test
@Test
public
void
retrieveMetadata_multipleMediaItems
()
throws
Exception
{
public
void
retrieveMetadata_multipleMediaItems
_outputsExpectedMetadata
()
throws
Exception
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaItem
mediaItem1
=
MediaItem
mediaItem1
=
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/mp4/sample.mp4"
));
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/mp4/sample.mp4"
));
...
@@ -84,7 +85,28 @@ public class MetadataRetrieverTest {
...
@@ -84,7 +85,28 @@ public class MetadataRetrieverTest {
}
}
@Test
@Test
public
void
retrieveMetadata_throwsErrorIfCannotLoad
()
{
public
void
retrieveMetadata_motionPhoto_outputsExpectedMetadata
()
throws
Exception
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaItem
mediaItem
=
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/mp4/sample_MP.heic"
));
MotionPhoto
expectedMotionPhoto
=
new
MotionPhoto
(
/* photoStartPosition= */
0
,
/* photoSize= */
28_853
,
/* videoStartPosition= */
28_869
,
/* videoSize= */
28_803
);
ListenableFuture
<
TrackGroupArray
>
trackGroupsFuture
=
retrieveMetadata
(
context
,
mediaItem
);
TrackGroupArray
trackGroups
=
waitAndGetTrackGroups
(
trackGroupsFuture
);
assertThat
(
trackGroups
.
length
).
isEqualTo
(
1
);
assertThat
(
trackGroups
.
get
(
0
).
length
).
isEqualTo
(
1
);
assertThat
(
trackGroups
.
get
(
0
).
getFormat
(
0
).
metadata
.
length
()).
isEqualTo
(
1
);
assertThat
(
trackGroups
.
get
(
0
).
getFormat
(
0
).
metadata
.
get
(
0
)).
isEqualTo
(
expectedMotionPhoto
);
}
@Test
public
void
retrieveMetadata_invalidMediaItem_throwsError
()
{
Context
context
=
ApplicationProvider
.
getApplicationContext
();
Context
context
=
ApplicationProvider
.
getApplicationContext
();
MediaItem
mediaItem
=
MediaItem
mediaItem
=
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/does_not_exist"
));
MediaItem
.
fromUri
(
Uri
.
parse
(
"asset://android_asset/media/does_not_exist"
));
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Atom.java
View file @
175b8eb6
...
@@ -182,6 +182,9 @@ import java.util.List;
...
@@ -182,6 +182,9 @@ import java.util.List;
public
static
final
int
TYPE_moov
=
0x6d6f6f76
;
public
static
final
int
TYPE_moov
=
0x6d6f6f76
;
@SuppressWarnings
(
"ConstantCaseForConstants"
)
@SuppressWarnings
(
"ConstantCaseForConstants"
)
public
static
final
int
TYPE_mpvd
=
0x6d707664
;
@SuppressWarnings
(
"ConstantCaseForConstants"
)
public
static
final
int
TYPE_mvhd
=
0x6d766864
;
public
static
final
int
TYPE_mvhd
=
0x6d766864
;
@SuppressWarnings
(
"ConstantCaseForConstants"
)
@SuppressWarnings
(
"ConstantCaseForConstants"
)
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Mp4Extractor.java
View file @
175b8eb6
...
@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.extractor.SeekPoint;
...
@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.extractor.SeekPoint;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.TrackOutput
;
import
com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom
;
import
com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.mp4.MotionPhoto
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
import
com.google.android.exoplayer2.util.NalUnitUtil
;
...
@@ -61,19 +62,27 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -61,19 +62,27 @@ public final class Mp4Extractor implements Extractor, SeekMap {
public
static
final
ExtractorsFactory
FACTORY
=
()
->
new
Extractor
[]
{
new
Mp4Extractor
()};
public
static
final
ExtractorsFactory
FACTORY
=
()
->
new
Extractor
[]
{
new
Mp4Extractor
()};
/**
/**
* Flags controlling the behavior of the extractor. Possible flag value
is
{@link
* Flags controlling the behavior of the extractor. Possible flag value
s are
{@link
* #FLAG_WORKAROUND_IGNORE_EDIT_LISTS}.
* #FLAG_WORKAROUND_IGNORE_EDIT_LISTS}
and {@link #FLAG_READ_MOTION_PHOTO_METADATA}
.
*/
*/
@Documented
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
@IntDef
(
flag
=
true
,
flag
=
true
,
value
=
{
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
})
value
=
{
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
,
FLAG_READ_MOTION_PHOTO_METADATA
})
public
@interface
Flags
{}
public
@interface
Flags
{}
/**
/**
* Flag to ignore any edit lists in the stream.
* Flag to ignore any edit lists in the stream.
*/
*/
public
static
final
int
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
=
1
;
public
static
final
int
FLAG_WORKAROUND_IGNORE_EDIT_LISTS
=
1
;
/**
* Flag to extract {@link MotionPhoto} metadata from HEIC motion photos following the Google
* Photos Motion Photo File Format V1.1.
*
* <p>As playback is not supported for motion photos, this flag should only be used for metadata
* retrieval use cases.
*/
public
static
final
int
FLAG_READ_MOTION_PHOTO_METADATA
=
1
<<
1
;
/** Parser states. */
/** Parser states. */
@Documented
@Documented
...
@@ -154,7 +163,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -154,7 +163,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
@Override
@Override
public
boolean
sniff
(
ExtractorInput
input
)
throws
IOException
{
public
boolean
sniff
(
ExtractorInput
input
)
throws
IOException
{
return
Sniffer
.
sniffUnfragmented
(
input
);
return
Sniffer
.
sniffUnfragmented
(
input
,
/* acceptHeic= */
(
flags
&
FLAG_READ_MOTION_PHOTO_METADATA
)
!=
0
);
}
}
@Override
@Override
...
@@ -335,6 +345,14 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -335,6 +345,14 @@ public final class Mp4Extractor implements Extractor, SeekMap {
this
.
atomData
=
atomData
;
this
.
atomData
=
atomData
;
parserState
=
STATE_READING_ATOM_PAYLOAD
;
parserState
=
STATE_READING_ATOM_PAYLOAD
;
}
else
{
}
else
{
if
(
atomType
==
Atom
.
TYPE_mpvd
&&
(
flags
&
FLAG_READ_MOTION_PHOTO_METADATA
)
!=
0
)
{
// There is no need to parse the mpvd atom payload. All the necessary information is in the
// header.
processMpvdBox
(
/* atomStartPosition= */
input
.
getPosition
()
-
atomHeaderBytesRead
,
/* atomHeaderSize= */
atomHeaderBytesRead
,
atomSize
);
}
atomData
=
null
;
atomData
=
null
;
parserState
=
STATE_READING_ATOM_PAYLOAD
;
parserState
=
STATE_READING_ATOM_PAYLOAD
;
}
}
...
@@ -663,6 +681,26 @@ public final class Mp4Extractor implements Extractor, SeekMap {
...
@@ -663,6 +681,26 @@ public final class Mp4Extractor implements Extractor, SeekMap {
}
}
/**
/**
* Processes the Motion Photo Video Data of an HEIC motion photo following the Google Photos
* Motion Photo File Format V1.1. This consists in adding a track with the motion photo metadata
* and ending playback preparation.
*/
private
void
processMpvdBox
(
long
atomStartPosition
,
int
atomHeaderSize
,
long
atomSize
)
{
ExtractorOutput
extractorOutput
=
checkNotNull
(
this
.
extractorOutput
);
extractorOutput
.
seekMap
(
new
SeekMap
.
Unseekable
(
/* durationUs= */
C
.
TIME_UNSET
));
TrackOutput
trackOutput
=
extractorOutput
.
track
(
/* id= */
0
,
C
.
TRACK_TYPE_IMAGE
);
MotionPhoto
motionPhoto
=
new
MotionPhoto
(
/* photoStartPosition= */
0
,
/* photoSize= */
atomStartPosition
,
/* videoStartPosition= */
atomStartPosition
+
atomHeaderSize
,
/* videoSize= */
atomSize
-
atomHeaderSize
);
trackOutput
.
format
(
new
Format
.
Builder
().
setMetadata
(
new
Metadata
(
motionPhoto
)).
build
());
extractorOutput
.
endTracks
();
}
/**
* For each sample of each track, calculates accumulated size of all samples which need to be read
* For each sample of each track, calculates accumulated size of all samples which need to be read
* before this sample can be used.
* before this sample can be used.
*/
*/
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java
View file @
175b8eb6
...
@@ -70,7 +70,7 @@ import java.io.IOException;
...
@@ -70,7 +70,7 @@ import java.io.IOException;
* @throws IOException If an error occurs reading from the input.
* @throws IOException If an error occurs reading from the input.
*/
*/
public
static
boolean
sniffFragmented
(
ExtractorInput
input
)
throws
IOException
{
public
static
boolean
sniffFragmented
(
ExtractorInput
input
)
throws
IOException
{
return
sniffInternal
(
input
,
tru
e
);
return
sniffInternal
(
input
,
/* fragmented= */
true
,
/* acceptHeic= */
fals
e
);
}
}
/**
/**
...
@@ -82,10 +82,24 @@ import java.io.IOException;
...
@@ -82,10 +82,24 @@ import java.io.IOException;
* @throws IOException If an error occurs reading from the input.
* @throws IOException If an error occurs reading from the input.
*/
*/
public
static
boolean
sniffUnfragmented
(
ExtractorInput
input
)
throws
IOException
{
public
static
boolean
sniffUnfragmented
(
ExtractorInput
input
)
throws
IOException
{
return
sniffInternal
(
input
,
false
);
return
sniffInternal
(
input
,
/* fragmented= */
false
,
/* acceptHeic= */
false
);
}
}
private
static
boolean
sniffInternal
(
ExtractorInput
input
,
boolean
fragmented
)
/**
* Returns whether data peeked from the current position in {@code input} is consistent with the
* input being an unfragmented MP4 file.
*
* @param input The extractor input from which to peek data. The peek position will be modified.
* @param acceptHeic Whether {@code true} should be returned for HEIC photos.
* @return Whether the input appears to be in the unfragmented MP4 format.
* @throws IOException If an error occurs reading from the input.
*/
public
static
boolean
sniffUnfragmented
(
ExtractorInput
input
,
boolean
acceptHeic
)
throws
IOException
{
return
sniffInternal
(
input
,
/* fragmented= */
false
,
acceptHeic
);
}
private
static
boolean
sniffInternal
(
ExtractorInput
input
,
boolean
fragmented
,
boolean
acceptHeic
)
throws
IOException
{
throws
IOException
{
long
inputLength
=
input
.
getLength
();
long
inputLength
=
input
.
getLength
();
int
bytesToSearch
=
(
int
)
(
inputLength
==
C
.
LENGTH_UNSET
||
inputLength
>
SEARCH_LENGTH
int
bytesToSearch
=
(
int
)
(
inputLength
==
C
.
LENGTH_UNSET
||
inputLength
>
SEARCH_LENGTH
...
@@ -165,7 +179,7 @@ import java.io.IOException;
...
@@ -165,7 +179,7 @@ import java.io.IOException;
if
(
i
==
1
)
{
if
(
i
==
1
)
{
// This index refers to the minorVersion, not a brand, so skip it.
// This index refers to the minorVersion, not a brand, so skip it.
buffer
.
skipBytes
(
4
);
buffer
.
skipBytes
(
4
);
}
else
if
(
isCompatibleBrand
(
buffer
.
readInt
()))
{
}
else
if
(
isCompatibleBrand
(
buffer
.
readInt
()
,
acceptHeic
))
{
foundGoodFileType
=
true
;
foundGoodFileType
=
true
;
break
;
break
;
}
}
...
@@ -185,9 +199,12 @@ import java.io.IOException;
...
@@ -185,9 +199,12 @@ import java.io.IOException;
/**
/**
* Returns whether {@code brand} is an ftyp atom brand that is compatible with the MP4 extractors.
* Returns whether {@code brand} is an ftyp atom brand that is compatible with the MP4 extractors.
*/
*/
private
static
boolean
isCompatibleBrand
(
int
brand
)
{
private
static
boolean
isCompatibleBrand
(
int
brand
,
boolean
acceptHeic
)
{
// Accept all brands starting '3gp'.
if
(
brand
>>>
8
==
0x00336770
)
{
if
(
brand
>>>
8
==
0x00336770
)
{
// Brand starts with '3gp'.
return
true
;
}
else
if
(
brand
==
0x68656963
&&
acceptHeic
)
{
// Brand is `heic` and HEIC is supported by the extractor.
return
true
;
return
true
;
}
}
for
(
int
compatibleBrand
:
COMPATIBLE_BRANDS
)
{
for
(
int
compatibleBrand
:
COMPATIBLE_BRANDS
)
{
...
...
testdata/src/test/assets/media/mp4/sample_MP.heic
0 → 100644
View file @
175b8eb6
No preview for this file type
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment