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
43cfc4a6
authored
Oct 05, 2021
by
olly
Committed by
Dustin
Feb 01, 2022
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Revert Demo and remove BitmapFactoryVideoRenderer classes
parent
e9fcc967
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
3 additions
and
697 deletions
demos/main/src/main/assets/media.exolist.json
demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java
library/core/build.gradle
library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java
library/core/src/main/java/com/google/android/exoplayer2/video/BitmapFactoryVideoRenderer.java
library/core/src/test/java/com/google/android/exoplayer2/video/BitmapFactoryVideoRendererTest.java
library/core/src/test/java/com/google/android/exoplayer2/video/FakeEventListener.java
library/core/src/test/java/com/google/android/exoplayer2/video/ShadowSurfaceExtended.java
testdata/src/test/assets/media/jpeg/image-320-240.jpg
demos/main/src/main/assets/media.exolist.json
View file @
43cfc4a6
...
...
@@ -543,10 +543,6 @@
"name"
:
"Misc"
,
"samples"
:
[
{
"name"
:
"User File"
,
"uri"
:
"content://user"
},
{
"name"
:
"Dizzy (MP4)"
,
"uri"
:
"https://html5demos.com/assets/dizzy.mp4"
},
...
...
demos/main/src/main/java/com/google/android/exoplayer2/demo/SampleChooserActivity.java
View file @
43cfc4a6
...
...
@@ -19,7 +19,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
android.content.ContentResolver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.SharedPreferences
;
...
...
@@ -41,8 +40,6 @@ import android.widget.ExpandableListView.OnChildClickListener;
import
android.widget.ImageButton
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
androidx.activity.result.ActivityResultLauncher
;
import
androidx.activity.result.contract.ActivityResultContracts
;
import
androidx.annotation.Nullable
;
import
androidx.appcompat.app.AppCompatActivity
;
import
com.google.android.exoplayer2.MediaItem
;
...
...
@@ -76,7 +73,6 @@ public class SampleChooserActivity extends AppCompatActivity
private
static
final
String
TAG
=
"SampleChooserActivity"
;
private
static
final
String
GROUP_POSITION_PREFERENCE_KEY
=
"sample_chooser_group_position"
;
private
static
final
String
CHILD_POSITION_PREFERENCE_KEY
=
"sample_chooser_child_position"
;
private
static
final
Uri
USER_CONTENT
=
new
Uri
.
Builder
().
scheme
(
ContentResolver
.
SCHEME_CONTENT
).
authority
(
"user"
).
build
();
private
String
[]
uris
;
private
boolean
useExtensionRenderers
;
...
...
@@ -84,13 +80,6 @@ public class SampleChooserActivity extends AppCompatActivity
private
SampleAdapter
sampleAdapter
;
private
MenuItem
preferExtensionDecodersMenuItem
;
private
ExpandableListView
sampleListView
;
private
final
ActivityResultLauncher
<
String
[]>
openDocumentLauncher
=
registerForActivityResult
(
new
ActivityResultContracts
.
OpenDocument
(),
uri
->
{
if
(
uri
!=
null
)
{
final
MediaItem
mediaItem
=
new
MediaItem
.
Builder
().
setUri
(
uri
).
build
();
startPlayer
(
Collections
.
singletonList
(
mediaItem
));
}
});
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
...
...
@@ -234,25 +223,13 @@ public class SampleChooserActivity extends AppCompatActivity
prefEditor
.
apply
();
PlaylistHolder
playlistHolder
=
(
PlaylistHolder
)
view
.
getTag
();
final
List
<
MediaItem
>
mediaItems
=
playlistHolder
.
mediaItems
;
if
(!
mediaItems
.
isEmpty
())
{
final
MediaItem
mediaItem
=
mediaItems
.
get
(
0
);
if
(
mediaItem
.
localConfiguration
!=
null
&&
USER_CONTENT
.
equals
(
mediaItem
.
localConfiguration
.
uri
))
{
openDocumentLauncher
.
launch
(
new
String
[]{
"video/*"
,
"audio/*"
});
return
true
;
}
}
startPlayer
(
playlistHolder
.
mediaItems
);
return
true
;
}
private
void
startPlayer
(
final
List
<
MediaItem
>
mediaItems
)
{
Intent
intent
=
new
Intent
(
this
,
PlayerActivity
.
class
);
intent
.
putExtra
(
IntentUtil
.
PREFER_EXTENSION_DECODERS_EXTRA
,
isNonNullAndChecked
(
preferExtensionDecodersMenuItem
));
IntentUtil
.
addToIntent
(
mediaItems
,
intent
);
IntentUtil
.
addToIntent
(
playlistHolder
.
mediaItems
,
intent
);
startActivity
(
intent
);
return
true
;
}
private
void
onSampleDownloadButtonClicked
(
PlaylistHolder
playlistHolder
)
{
...
...
library/core/build.gradle
View file @
43cfc4a6
...
...
@@ -21,11 +21,7 @@ android {
testInstrumentationRunnerArguments
clearPackageData:
'true'
multiDexEnabled
true
}
testOptions
{
unitTests
.
all
{
jvmArgs
'-noverify'
}
}
buildTypes
{
debug
{
testCoverageEnabled
=
true
...
...
library/core/src/main/java/com/google/android/exoplayer2/DefaultRenderersFactory.java
View file @
43cfc4a6
...
...
@@ -27,7 +27,6 @@ import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import
com.google.android.exoplayer2.audio.AudioSink
;
import
com.google.android.exoplayer2.audio.DefaultAudioSink
;
import
com.google.android.exoplayer2.audio.MediaCodecAudioRenderer
;
import
com.google.android.exoplayer2.video.BitmapFactoryVideoRenderer
;
import
com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
...
...
@@ -396,7 +395,6 @@ public class DefaultRenderersFactory implements RenderersFactory {
eventListener
,
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY
);
out
.
add
(
videoRenderer
);
out
.
add
(
new
BitmapFactoryVideoRenderer
(
eventHandler
,
eventListener
));
if
(
extensionRendererMode
==
EXTENSION_RENDERER_MODE_OFF
)
{
return
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/BitmapFactoryVideoRenderer.java
deleted
100644 → 0
View file @
e9fcc967
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.graphics.Canvas
;
import
android.graphics.Rect
;
import
android.os.Handler
;
import
android.os.SystemClock
;
import
android.view.Surface
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.VisibleForTesting
;
import
androidx.annotation.WorkerThread
;
import
androidx.arch.core.util.Function
;
import
com.google.android.exoplayer2.BaseRenderer
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlaybackException
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.source.SampleStream
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
java.nio.ByteBuffer
;
public
class
BitmapFactoryVideoRenderer
extends
BaseRenderer
{
static
final
String
TAG
=
"BitmapFactoryRenderer"
;
//Sleep Reasons
static
final
String
STREAM_END
=
"Stream End"
;
static
final
String
STREAM_EMPTY
=
"Stream Empty"
;
static
final
String
RENDER_WAIT
=
"Render Wait"
;
private
static
int
threadId
;
private
final
Rect
rect
=
new
Rect
();
private
final
RenderRunnable
renderRunnable
=
new
RenderRunnable
();
final
VideoRendererEventListener
.
EventDispatcher
eventDispatcher
;
final
Thread
thread
=
new
Thread
(
renderRunnable
,
getClass
().
getSimpleName
()
+
threadId
++);
@Nullable
volatile
Surface
surface
;
private
VideoSize
lastVideoSize
=
VideoSize
.
UNKNOWN
;
private
long
currentTimeUs
;
private
long
frameUs
;
private
boolean
firstFrameRendered
;
@Nullable
private
DecoderCounters
decoderCounters
;
public
BitmapFactoryVideoRenderer
(
@Nullable
Handler
eventHandler
,
@Nullable
VideoRendererEventListener
eventListener
)
{
super
(
C
.
TRACK_TYPE_VIDEO
);
eventDispatcher
=
new
VideoRendererEventListener
.
EventDispatcher
(
eventHandler
,
eventListener
);
}
@NonNull
@Override
public
String
getName
()
{
return
TAG
;
}
@Override
protected
void
onEnabled
(
boolean
joining
,
boolean
mayRenderStartOfStream
)
throws
ExoPlaybackException
{
decoderCounters
=
new
DecoderCounters
();
eventDispatcher
.
enabled
(
decoderCounters
);
if
(
mayRenderStartOfStream
)
{
thread
.
start
();
}
}
@Override
protected
void
onStarted
()
throws
ExoPlaybackException
{
if
(
thread
.
getState
()
==
Thread
.
State
.
NEW
)
{
thread
.
start
();
}
}
@Override
protected
void
onDisabled
()
{
renderRunnable
.
stop
();
@Nullable
final
DecoderCounters
decoderCounters
=
this
.
decoderCounters
;
if
(
decoderCounters
!=
null
)
{
eventDispatcher
.
disabled
(
decoderCounters
);
}
}
@Override
public
void
render
(
long
positionUs
,
long
elapsedRealtimeUs
)
throws
ExoPlaybackException
{
//Log.d(TAG, "Render: us=" + positionUs);
synchronized
(
renderRunnable
)
{
currentTimeUs
=
positionUs
;
renderRunnable
.
notify
();
}
}
@Override
protected
void
onPositionReset
(
long
positionUs
,
boolean
joining
)
throws
ExoPlaybackException
{
thread
.
interrupt
();
}
@Override
public
void
handleMessage
(
int
messageType
,
@Nullable
Object
message
)
throws
ExoPlaybackException
{
if
(
messageType
==
MSG_SET_VIDEO_OUTPUT
)
{
if
(
message
instanceof
Surface
)
{
surface
=
(
Surface
)
message
;
}
else
{
surface
=
null
;
}
}
super
.
handleMessage
(
messageType
,
message
);
}
@Override
public
boolean
isReady
()
{
return
surface
!=
null
;
}
@Override
public
boolean
isEnded
()
{
return
renderRunnable
.
isEnded
();
}
@Override
public
int
supportsFormat
(
Format
format
)
throws
ExoPlaybackException
{
//Technically could support any format BitmapFactory supports
if
(
MimeTypes
.
VIDEO_MJPEG
.
equals
(
format
.
sampleMimeType
))
{
return
RendererCapabilities
.
create
(
C
.
FORMAT_HANDLED
);
}
return
RendererCapabilities
.
create
(
C
.
FORMAT_UNSUPPORTED_TYPE
);
}
@WorkerThread
private
void
onFormatChanged
(
@NonNull
FormatHolder
formatHolder
)
{
@Nullable
final
Format
format
=
formatHolder
.
format
;
if
(
format
!=
null
)
{
frameUs
=
(
long
)(
1_000_000L
/
format
.
frameRate
);
eventDispatcher
.
inputFormatChanged
(
format
,
null
);
}
}
@WorkerThread
void
renderBitmap
(
@NonNull
final
Bitmap
bitmap
)
{
@Nullable
final
Surface
surface
=
this
.
surface
;
if
(
surface
==
null
)
{
return
;
}
//Log.d(TAG, "Drawing: " + bitmap.getWidth() + "x" + bitmap.getHeight());
final
Canvas
canvas
=
surface
.
lockCanvas
(
null
);
renderBitmap
(
bitmap
,
canvas
);
surface
.
unlockCanvasAndPost
(
canvas
);
@Nullable
final
DecoderCounters
decoderCounters
=
BitmapFactoryVideoRenderer
.
this
.
decoderCounters
;
if
(
decoderCounters
!=
null
)
{
decoderCounters
.
renderedOutputBufferCount
++;
}
if
(!
firstFrameRendered
)
{
firstFrameRendered
=
true
;
eventDispatcher
.
renderedFirstFrame
(
surface
);
}
}
@WorkerThread
@VisibleForTesting
void
renderBitmap
(
Bitmap
bitmap
,
Canvas
canvas
)
{
final
VideoSize
videoSize
=
new
VideoSize
(
bitmap
.
getWidth
(),
bitmap
.
getHeight
());
if
(!
videoSize
.
equals
(
lastVideoSize
))
{
lastVideoSize
=
videoSize
;
eventDispatcher
.
videoSizeChanged
(
videoSize
);
}
rect
.
set
(
0
,
0
,
canvas
.
getWidth
(),
canvas
.
getHeight
());
canvas
.
drawBitmap
(
bitmap
,
null
,
rect
,
null
);
}
class
RenderRunnable
implements
Runnable
,
Function
<
String
,
Boolean
>
{
final
DecoderInputBuffer
decoderInputBuffer
=
new
DecoderInputBuffer
(
DecoderInputBuffer
.
BUFFER_REPLACEMENT_MODE_NORMAL
);
private
volatile
boolean
running
=
true
;
@VisibleForTesting
Function
<
String
,
Boolean
>
sleepFunction
=
this
;
void
stop
()
{
running
=
false
;
thread
.
interrupt
();
}
boolean
isEnded
()
{
return
!
running
||
decoderInputBuffer
.
isEndOfStream
();
}
@Nullable
private
Bitmap
decodeInputBuffer
(
final
DecoderInputBuffer
decoderInputBuffer
)
{
@Nullable
final
ByteBuffer
byteBuffer
=
decoderInputBuffer
.
data
;
if
(
byteBuffer
!=
null
)
{
final
Bitmap
bitmap
;
try
{
bitmap
=
BitmapFactory
.
decodeByteArray
(
byteBuffer
.
array
(),
byteBuffer
.
arrayOffset
(),
byteBuffer
.
arrayOffset
()
+
byteBuffer
.
position
());
if
(
bitmap
==
null
)
{
throw
new
NullPointerException
(
"Decode bytes failed"
);
}
else
{
return
bitmap
;
}
}
catch
(
Exception
e
)
{
eventDispatcher
.
videoCodecError
(
e
);
}
}
return
null
;
}
/**
*
* @return true if interrupted
*/
public
synchronized
Boolean
apply
(
String
why
)
{
try
{
wait
();
return
false
;
}
catch
(
InterruptedException
e
)
{
//If we are interrupted, treat as a cancel
return
true
;
}
}
private
boolean
sleep
(
String
why
)
{
return
sleepFunction
.
apply
(
why
);
}
@WorkerThread
public
void
run
()
{
final
FormatHolder
formatHolder
=
getFormatHolder
();
long
start
=
SystemClock
.
uptimeMillis
();
main:
while
(
running
)
{
decoderInputBuffer
.
clear
();
final
int
result
=
readSource
(
formatHolder
,
decoderInputBuffer
,
formatHolder
.
format
==
null
?
SampleStream
.
FLAG_REQUIRE_FORMAT
:
0
);
switch
(
result
)
{
case
C
.
RESULT_BUFFER_READ
:
{
if
(
decoderInputBuffer
.
isEndOfStream
())
{
//Wait for shutdown or stream to be changed
sleep
(
STREAM_END
);
continue
;
}
final
long
leadUs
=
decoderInputBuffer
.
timeUs
-
currentTimeUs
;
//If we are more than 1/2 a frame behind, skip the next frame
if
(
leadUs
<
-
frameUs
/
2
)
{
eventDispatcher
.
droppedFrames
(
1
,
SystemClock
.
uptimeMillis
()
-
start
);
start
=
SystemClock
.
uptimeMillis
();
continue
;
}
start
=
SystemClock
.
uptimeMillis
();
@Nullable
final
Bitmap
bitmap
=
decodeInputBuffer
(
decoderInputBuffer
);
if
(
bitmap
==
null
)
{
continue
;
}
while
(
currentTimeUs
<
decoderInputBuffer
.
timeUs
)
{
//Log.d(TAG, "Sleep: us=" + currentTimeUs);
if
(
sleep
(
RENDER_WAIT
))
{
//Sleep was interrupted, discard Bitmap
continue
main
;
}
}
if
(
running
)
{
renderBitmap
(
bitmap
);
}
}
break
;
case
C
.
RESULT_FORMAT_READ
:
onFormatChanged
(
formatHolder
);
break
;
case
C
.
RESULT_NOTHING_READ
:
sleep
(
STREAM_EMPTY
);
break
;
}
}
}
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
Rect
getRect
()
{
return
rect
;
}
@Nullable
@VisibleForTesting
DecoderCounters
getDecoderCounters
()
{
return
decoderCounters
;
}
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
Thread
getThread
()
{
return
thread
;
}
@Nullable
@VisibleForTesting
(
otherwise
=
VisibleForTesting
.
NONE
)
Surface
getSurface
()
{
return
surface
;
}
RenderRunnable
getRenderRunnable
()
{
return
renderRunnable
;
}
}
library/core/src/test/java/com/google/android/exoplayer2/video/BitmapFactoryVideoRendererTest.java
deleted
100644 → 0
View file @
e9fcc967
This diff is collapsed.
Click to expand it.
library/core/src/test/java/com/google/android/exoplayer2/video/FakeEventListener.java
deleted
100644 → 0
View file @
e9fcc967
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
public
class
FakeEventListener
implements
VideoRendererEventListener
{
@Nullable
VideoSize
videoSize
;
@Nullable
DecoderCounters
decoderCounters
;
private
long
firstFrameRenderMs
=
Long
.
MIN_VALUE
;
private
int
droppedFrames
;
private
Exception
videoCodecError
;
@Override
public
void
onVideoSizeChanged
(
VideoSize
videoSize
)
{
this
.
videoSize
=
videoSize
;
}
public
boolean
isVideoEnabled
()
{
return
decoderCounters
!=
null
;
}
@Override
public
void
onVideoEnabled
(
DecoderCounters
counters
)
{
decoderCounters
=
counters
;
}
@Override
public
void
onVideoDisabled
(
DecoderCounters
counters
)
{
decoderCounters
=
null
;
}
public
long
getFirstFrameRenderMs
()
{
return
firstFrameRenderMs
;
}
@Override
public
void
onRenderedFirstFrame
(
Object
output
,
long
renderTimeMs
)
{
firstFrameRenderMs
=
renderTimeMs
;
}
public
int
getDroppedFrames
()
{
return
droppedFrames
;
}
@Override
public
void
onDroppedFrames
(
int
count
,
long
elapsedMs
)
{
droppedFrames
+=
count
;
}
public
Exception
getVideoCodecError
()
{
return
videoCodecError
;
}
@Override
public
void
onVideoCodecError
(
Exception
videoCodecError
)
{
this
.
videoCodecError
=
videoCodecError
;
}
}
library/core/src/test/java/com/google/android/exoplayer2/video/ShadowSurfaceExtended.java
deleted
100644 → 0
View file @
e9fcc967
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
android.graphics.Bitmap
;
import
android.graphics.Canvas
;
import
android.graphics.Rect
;
import
android.view.Surface
;
import
java.util.concurrent.Semaphore
;
import
java.util.concurrent.TimeUnit
;
import
org.robolectric.annotation.Implements
;
import
org.robolectric.shadow.api.Shadow
;
import
org.robolectric.shadows.ShadowSurface
;
@Implements
(
Surface
.
class
)
public
class
ShadowSurfaceExtended
extends
ShadowSurface
{
private
final
Semaphore
postSemaphore
=
new
Semaphore
(
0
);
private
int
width
;
private
int
height
;
public
static
Surface
newInstance
()
{
return
Shadow
.
newInstanceOf
(
Surface
.
class
);
}
public
void
setSize
(
final
int
width
,
final
int
height
)
{
this
.
width
=
width
;
this
.
height
=
height
;
}
public
Canvas
lockCanvas
(
Rect
canvas
)
{
return
new
Canvas
(
Bitmap
.
createBitmap
(
width
,
height
,
Bitmap
.
Config
.
ARGB_8888
));
}
public
void
unlockCanvasAndPost
(
Canvas
canvas
)
{
postSemaphore
.
release
();
}
public
boolean
waitForPost
(
long
millis
)
{
try
{
return
postSemaphore
.
tryAcquire
(
millis
,
TimeUnit
.
MILLISECONDS
);
}
catch
(
InterruptedException
e
)
{
return
false
;
}
}
}
testdata/src/test/assets/media/jpeg/image-320-240.jpg
deleted
100644 → 0
View file @
e9fcc967
35.2 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