Skip to content

Commit 2791286

Browse files
committed
Fix DataSource.seek implementation, fix thumbnails upside down
1 parent fa07f92 commit 2791286

4 files changed

Lines changed: 44 additions & 13 deletions

File tree

lib/src/main/java/com/otaliastudios/transcoder/internal/thumbnails/DefaultThumbnailsEngine.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ internal class DefaultThumbnailsEngine(
9797
Seeker(source, positions) { it == stubs.firstOrNull()?.localizedUs } +
9898
Reader(source, type) +
9999
Decoder(source.getTrackFormat(type)!!, continuous = false) +
100-
VideoRenderer(source.orientation, rotation, outputFormat) +
100+
VideoRenderer(source.orientation, rotation, outputFormat, flipY = true) +
101101
VideoSnapshots(outputFormat, positions, 50 * 1000) { pos, bitmap ->
102102
val stub = stubs.removeFirst()
103103
stub.actualLocalizedUs = pos

lib/src/main/java/com/otaliastudios/transcoder/internal/video/FrameDrawer.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class FrameDrawer {
4040
private float mScaleX = 1F;
4141
private float mScaleY = 1F;
4242
private int mRotation = 0;
43+
private boolean mFlipY = false;
4344

4445
@GuardedBy("mFrameAvailableLock")
4546
private boolean mFrameAvailable;
@@ -95,6 +96,10 @@ public void setRotation(int rotation) {
9596
mRotation = rotation;
9697
}
9798

99+
public void setFlipY(boolean flipY) {
100+
mFlipY = flipY;
101+
}
102+
98103
/**
99104
* Returns a Surface to draw onto.
100105
* @return the output surface
@@ -169,10 +174,14 @@ private void drawNewFrame() {
169174
Matrix.translateM(mProgram.getTextureTransform(), 0, glTranslX, glTranslY, 0);
170175
// Scale.
171176
Matrix.scaleM(mProgram.getTextureTransform(), 0, glScaleX, glScaleY, 1);
172-
// Apply rotation.
177+
// Apply rotation and flip.
173178
Matrix.translateM(mProgram.getTextureTransform(), 0, 0.5F, 0.5F, 0);
174179
Matrix.rotateM(mProgram.getTextureTransform(), 0, mRotation, 0, 0, 1);
180+
if (mFlipY) {
181+
Matrix.scaleM(mProgram.getTextureTransform(), 0, 1F, -1F, 1F);
182+
}
175183
Matrix.translateM(mProgram.getTextureTransform(), 0, -0.5F, -0.5F, 0);
184+
176185
// Draw.
177186
mProgram.draw(mDrawable);
178187
}

lib/src/main/java/com/otaliastudios/transcoder/internal/video/VideoRenderer.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@ internal class VideoRenderer(
1616
private val sourceRotation: Int, // intrinsic source rotation
1717
private val extraRotation: Int, // any extra rotation in TranscoderOptions
1818
private val targetFormat: MediaFormat,
19+
flipY: Boolean = false
1920
): Step<DecoderData, DecoderChannel, Long, Channel>, DecoderChannel {
2021

2122
private val log = Logger("VideoRenderer")
2223

2324
override val channel = this
2425

2526
// frame drawer needs EGL context which is not created by us, so let's use by lazy.
26-
private val frameDrawer by lazy { FrameDrawer() }
27+
private val frameDrawer by lazy {
28+
val drawer = FrameDrawer()
29+
drawer.setFlipY(flipY)
30+
drawer
31+
}
2732

2833
private lateinit var frameDropper: FrameDropper
2934

lib/src/main/java/com/otaliastudios/transcoder/source/DefaultDataSource.java

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public abstract class DefaultDataSource implements DataSource {
4343

4444
@Override
4545
public void initialize() {
46+
LOG.i("initialize(): initializing...");
4647
mExtractor = new MediaExtractor();
4748
try {
4849
initializeExtractor(mExtractor);
@@ -67,13 +68,27 @@ public void initialize() {
6768
// This is very important to have a timebase e.g. for seeks that happen before any read.
6869
for (int i = 0; i < mExtractor.getTrackCount(); i++) mExtractor.selectTrack(i);
6970
mOriginUs = mExtractor.getSampleTime();
71+
LOG.v("initialize(): found origin=" + mOriginUs);
7072
for (int i = 0; i < mExtractor.getTrackCount(); i++) mExtractor.unselectTrack(i);
7173
mInitialized = true;
74+
75+
// Debugging mOriginUs issues.
76+
/* LOG.v("initialize(): origin after unselect is" + mExtractor.getSampleTime());
77+
if (getTrackFormat(TrackType.VIDEO) != null) {
78+
mExtractor.selectTrack(mIndex.getVideo());
79+
LOG.v("initialize(): video only origin is" + mExtractor.getSampleTime());
80+
mExtractor.unselectTrack(mIndex.getVideo());
81+
}
82+
if (getTrackFormat(TrackType.AUDIO) != null) {
83+
mExtractor.selectTrack(mIndex.getAudio());
84+
LOG.v("initialize(): audio only origin is" + mExtractor.getSampleTime());
85+
mExtractor.unselectTrack(mIndex.getAudio());
86+
} */
7287
}
7388

7489
@Override
7590
public void deinitialize() {
76-
LOG.i("deinitialize(): releasing...");
91+
LOG.i("deinitialize(): deinitializing...");
7792
try {
7893
mExtractor.release();
7994
} catch (Exception e) {
@@ -124,6 +139,7 @@ public long seekTo(long desiredPositionUs) {
124139
boolean hasAudio = mSelectedTracks.contains(TrackType.AUDIO);
125140
LOG.i("seekTo(): seeking to " + (mOriginUs + desiredPositionUs)
126141
+ " originUs=" + mOriginUs
142+
+ " extractorUs=" + mExtractor.getSampleTime()
127143
+ " externalUs=" + desiredPositionUs
128144
+ " hasVideo=" + hasVideo
129145
+ " hasAudio=" + hasAudio);
@@ -140,17 +156,18 @@ public long seekTo(long desiredPositionUs) {
140156
}
141157
mDontRenderRangeStart = mExtractor.getSampleTime();
142158
mDontRenderRangeEnd = mOriginUs + desiredPositionUs;
143-
144159
if (mDontRenderRangeStart > mDontRenderRangeEnd) {
145-
throw new IllegalStateException("The dontRenderRange has unexpected values! " +
146-
"start=" + mDontRenderRangeStart + ", " +
147-
"end=" + mDontRenderRangeEnd);
148-
} else {
149-
LOG.i("seekTo(): dontRenderRange=" +
150-
mDontRenderRangeStart + ".." +
151-
mDontRenderRangeEnd + " (" +
152-
(mDontRenderRangeEnd - mDontRenderRangeStart) + "us)");
160+
// Extractor jumped beyond the requested point!
161+
// This can happen in edge cases because we compute mOriginUs with both tracks selected,
162+
// while source can later be used with a single track. E.g. audio track starts at 0,
163+
// video track starts at 20000, mOriginUs is 0. A seekTo(0) will give range=20000..0.
164+
// In this case, range should just be empty.
165+
mDontRenderRangeStart = mDontRenderRangeEnd; // 0..0
153166
}
167+
LOG.i("seekTo(): dontRenderRange=" +
168+
mDontRenderRangeStart + ".." +
169+
mDontRenderRangeEnd + " (" +
170+
(mDontRenderRangeEnd - mDontRenderRangeStart) + "us)");
154171
return mExtractor.getSampleTime() - mOriginUs;
155172
}
156173

0 commit comments

Comments
 (0)