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
aa250376
authored
Mar 23, 2021
by
kimvde
Committed by
marcbaechinger
Apr 09, 2021
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
JpegExtractor: support JFIF segment preceding Exif segment
#minor-release PiperOrigin-RevId: 364561115
parent
65ab0085
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
184 additions
and
9 deletions
RELEASENOTES.md
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/JpegExtractor.java
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/jpeg/JpegExtractorTest.java
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.0.dump
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.1.dump
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.2.dump
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.3.dump
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.unknown_length.dump
testdata/src/test/assets/media/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg
RELEASENOTES.md
View file @
aa250376
...
...
@@ -43,6 +43,8 @@
*
Extractors:
*
Add support for
`GContainer`
and
`GContainerItem`
XMP namespace prefixes
in JPEG motion photo parsing.
*
Allow JFIF APP0 marker segment preceding Exif APP1 segment in
`JpegExtractor`
.
*
Remove deprecated symbols:
*
Remove
`Player.DefaultEventListener`
. Use
`Player.EventListener`
instead.
...
...
@@ -77,9 +79,8 @@
media item and so that it is not triggered after a timeline change.
*
IMA extension:
*
Fix error caused by
`AdPlaybackState`
ad group times being cleared,
which can occur if the
`ImaAdsLoader`
is released while an ad is
pending loading
(
[
#8693
](
https://github.com/google/ExoPlayer/issues/8693
)
).
which can occur if the
`ImaAdsLoader`
is released while an ad is pending
loading (
[
#8693
](
https://github.com/google/ExoPlayer/issues/8693
)
).
*
Upgrade IMA SDK dependency to 3.22.3, fixing an issue with
`NullPointerExceptions`
within
`WebView`
callbacks
(
[
#8447
](
https://github.com/google/ExoPlayer/issues/8447
)
).
...
...
library/extractor/src/main/java/com/google/android/exoplayer2/extractor/jpeg/JpegExtractor.java
View file @
aa250376
...
...
@@ -60,10 +60,11 @@ public final class JpegExtractor implements Extractor {
private
static
final
int
STATE_READING_MOTION_PHOTO_VIDEO
=
5
;
private
static
final
int
STATE_ENDED
=
6
;
private
static
final
int
JPEG_EXIF_HEADER_LENGTH
=
12
;
private
static
final
int
EXIF_ID_CODE_LENGTH
=
6
;
private
static
final
long
EXIF_HEADER
=
0x45786966
;
// Exif
private
static
final
int
MARKER_SOI
=
0xFFD8
;
// Start of image marker
private
static
final
int
MARKER_SOS
=
0xFFDA
;
// Start of scan (image data) marker
private
static
final
int
MARKER_APP0
=
0xFFE0
;
// Application data 0 marker
private
static
final
int
MARKER_APP1
=
0xFFE1
;
// Application data 1 marker
private
static
final
String
HEADER_XMP_APP1
=
"http://ns.adobe.com/xap/1.0/"
;
...
...
@@ -85,21 +86,33 @@ public final class JpegExtractor implements Extractor {
@Nullable
private
MotionPhotoMetadata
motionPhotoMetadata
;
private
@MonotonicNonNull
ExtractorInput
lastExtractorInput
;
private
@MonotonicNonNull
StartOffsetExtractorInput
mp4ExtractorStartOffsetExtractorInput
;
private
@MonotonicNonNull
Mp4Extractor
mp4Extractor
;
@Nullable
private
Mp4Extractor
mp4Extractor
;
public
JpegExtractor
()
{
scratch
=
new
ParsableByteArray
(
JPEG_EXIF_HEADER
_LENGTH
);
scratch
=
new
ParsableByteArray
(
EXIF_ID_CODE
_LENGTH
);
mp4StartPosition
=
C
.
POSITION_UNSET
;
}
@Override
public
boolean
sniff
(
ExtractorInput
input
)
throws
IOException
{
// See ITU-T.81 (1992) subsection B.1.1.3 and Exif version 2.2 (2002) subsection 4.5.4.
input
.
peekFully
(
scratch
.
getData
(),
/* offset= */
0
,
JPEG_EXIF_HEADER_LENGTH
);
if
(
scratch
.
readUnsignedShort
()
!=
MARKER_SOI
||
scratch
.
readUnsignedShort
()
!=
MARKER_APP1
)
{
if
(
peekMarker
(
input
)
!=
MARKER_SOI
)
{
return
false
;
}
scratch
.
skipBytes
(
2
);
// Unused segment length
marker
=
peekMarker
(
input
);
// Even though JFIF and Exif standards are incompatible in theory, Exif files often contain a
// JFIF APP0 marker segment preceding the Exif APP1 marker segment. Skip the JFIF segment if
// present.
if
(
marker
==
MARKER_APP0
)
{
advancePeekPositionToNextSegment
(
input
);
marker
=
peekMarker
(
input
);
}
if
(
marker
!=
MARKER_APP1
)
{
return
false
;
}
input
.
advancePeekPosition
(
2
);
// Unused segment length
scratch
.
reset
(
/* limit= */
EXIF_ID_CODE_LENGTH
);
input
.
peekFully
(
scratch
.
getData
(),
/* offset= */
0
,
EXIF_ID_CODE_LENGTH
);
return
scratch
.
readUnsignedInt
()
==
EXIF_HEADER
&&
scratch
.
readUnsignedShort
()
==
0
;
// Exif\0\0
}
...
...
@@ -152,6 +165,7 @@ public final class JpegExtractor implements Extractor {
public
void
seek
(
long
position
,
long
timeUs
)
{
if
(
position
==
0
)
{
state
=
STATE_READING_MARKER
;
mp4Extractor
=
null
;
}
else
if
(
state
==
STATE_READING_MOTION_PHOTO_VIDEO
)
{
checkNotNull
(
mp4Extractor
).
seek
(
position
,
timeUs
);
}
...
...
@@ -164,6 +178,19 @@ public final class JpegExtractor implements Extractor {
}
}
private
int
peekMarker
(
ExtractorInput
input
)
throws
IOException
{
scratch
.
reset
(
/* limit= */
2
);
input
.
peekFully
(
scratch
.
getData
(),
/* offset= */
0
,
/* length= */
2
);
return
scratch
.
readUnsignedShort
();
}
private
void
advancePeekPositionToNextSegment
(
ExtractorInput
input
)
throws
IOException
{
scratch
.
reset
(
/* limit= */
2
);
input
.
peekFully
(
scratch
.
getData
(),
/* offset= */
0
,
/* length= */
2
);
int
segmentLength
=
scratch
.
readUnsignedShort
()
-
2
;
input
.
advancePeekPosition
(
segmentLength
);
}
private
void
readMarker
(
ExtractorInput
input
)
throws
IOException
{
scratch
.
reset
(
/* limit= */
2
);
input
.
readFully
(
scratch
.
getData
(),
/* offset= */
0
,
/* length= */
2
);
...
...
library/extractor/src/test/java/com/google/android/exoplayer2/extractor/jpeg/JpegExtractorTest.java
View file @
aa250376
...
...
@@ -46,6 +46,14 @@ public final class JpegExtractorTest {
}
@Test
public
void
samplePixelMotionPhotoJfifSegmentShortened
()
throws
Exception
{
ExtractorAsserts
.
assertBehavior
(
JpegExtractor:
:
new
,
"media/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg"
,
simulationConfig
);
}
@Test
public
void
samplePixelMotionPhotoVideoRemovedShortened
()
throws
Exception
{
ExtractorAsserts
.
assertBehavior
(
JpegExtractor:
:
new
,
...
...
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.0.dump
0 → 100644
View file @
aa250376
seekMap:
isSeekable = true
duration = 867000
getPosition(0) = [[timeUs=0, position=6425]]
getPosition(1) = [[timeUs=0, position=6425]]
getPosition(433500) = [[timeUs=0, position=6425]]
getPosition(867000) = [[timeUs=0, position=6425]]
numberOfTracks = 2
track 0:
total output bytes = 3865
sample count = 1
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64000A
maxInputSize = 3895
width = 180
height = 120
pixelWidthHeightRatio = 0.5
initializationData:
data = length 32, hash 1F3D6E87
data = length 10, hash 7A0D0F2B
sample 0:
time = 0
flags = 536870913
data = length 3865, hash 5B0DEEC7
track 1024:
total output bytes = 0
sample count = 0
format 0:
metadata = entries=[Motion photo metadata: photoStartPosition=0, photoSize=6377, photoPresentationTimestampUs=1232840, videoStartPosition=6377, videoSize=4686]
tracksEnded = true
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.1.dump
0 → 100644
View file @
aa250376
seekMap:
isSeekable = true
duration = 867000
getPosition(0) = [[timeUs=0, position=6425]]
getPosition(1) = [[timeUs=0, position=6425]]
getPosition(433500) = [[timeUs=0, position=6425]]
getPosition(867000) = [[timeUs=0, position=6425]]
numberOfTracks = 2
track 0:
total output bytes = 3865
sample count = 1
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64000A
maxInputSize = 3895
width = 180
height = 120
pixelWidthHeightRatio = 0.5
initializationData:
data = length 32, hash 1F3D6E87
data = length 10, hash 7A0D0F2B
sample 0:
time = 0
flags = 536870913
data = length 3865, hash 5B0DEEC7
track 1024:
total output bytes = 0
sample count = 0
format 0:
metadata = entries=[Motion photo metadata: photoStartPosition=0, photoSize=6377, photoPresentationTimestampUs=1232840, videoStartPosition=6377, videoSize=4686]
tracksEnded = true
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.2.dump
0 → 100644
View file @
aa250376
seekMap:
isSeekable = true
duration = 867000
getPosition(0) = [[timeUs=0, position=6425]]
getPosition(1) = [[timeUs=0, position=6425]]
getPosition(433500) = [[timeUs=0, position=6425]]
getPosition(867000) = [[timeUs=0, position=6425]]
numberOfTracks = 2
track 0:
total output bytes = 3865
sample count = 1
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64000A
maxInputSize = 3895
width = 180
height = 120
pixelWidthHeightRatio = 0.5
initializationData:
data = length 32, hash 1F3D6E87
data = length 10, hash 7A0D0F2B
sample 0:
time = 0
flags = 536870913
data = length 3865, hash 5B0DEEC7
track 1024:
total output bytes = 0
sample count = 0
format 0:
metadata = entries=[Motion photo metadata: photoStartPosition=0, photoSize=6377, photoPresentationTimestampUs=1232840, videoStartPosition=6377, videoSize=4686]
tracksEnded = true
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.3.dump
0 → 100644
View file @
aa250376
seekMap:
isSeekable = true
duration = 867000
getPosition(0) = [[timeUs=0, position=6425]]
getPosition(1) = [[timeUs=0, position=6425]]
getPosition(433500) = [[timeUs=0, position=6425]]
getPosition(867000) = [[timeUs=0, position=6425]]
numberOfTracks = 2
track 0:
total output bytes = 3865
sample count = 1
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64000A
maxInputSize = 3895
width = 180
height = 120
pixelWidthHeightRatio = 0.5
initializationData:
data = length 32, hash 1F3D6E87
data = length 10, hash 7A0D0F2B
sample 0:
time = 0
flags = 536870913
data = length 3865, hash 5B0DEEC7
track 1024:
total output bytes = 0
sample count = 0
format 0:
metadata = entries=[Motion photo metadata: photoStartPosition=0, photoSize=6377, photoPresentationTimestampUs=1232840, videoStartPosition=6377, videoSize=4686]
tracksEnded = true
testdata/src/test/assets/extractordumps/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg.unknown_length.dump
0 → 100644
View file @
aa250376
seekMap:
isSeekable = false
duration = UNSET TIME
getPosition(0) = [[timeUs=0, position=0]]
numberOfTracks = 1
track 1024:
total output bytes = 0
sample count = 0
format 0:
metadata = entries=[]
tracksEnded = true
testdata/src/test/assets/media/jpeg/pixel-motion-photo-jfif-segment-shortened.jpg
0 → 100644
View file @
aa250376
10.8 KB
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