Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4e15420

Browse files
authored
Fix selectTrack order (deepmedia#128)
1 parent b784e6b commit 4e15420

File tree

5 files changed

+28
-11
lines changed

5 files changed

+28
-11
lines changed

‎lib/src/main/java/com/otaliastudios/transcoder/internal/codec/Encoder.kt

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ internal class Encoder(
100100
val flags = info.flags and BUFFER_FLAG_END_OF_STREAM.inv()
101101
val buffer = buffers.getOutputBuffer(result)
102102
val timeUs = info.presentationTimeUs
103+
buffer.clear()
104+
buffer.limit(info.offset + info.size)
105+
buffer.position(info.offset)
103106
val data = WriterData(buffer, timeUs, flags) {
104107
codec.releaseOutputBuffer(result, false)
105108
}

‎lib/src/main/java/com/otaliastudios/transcoder/internal/transcode/DefaultTranscodeEngine.kt

+6-3
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,12 @@ internal class DefaultTranscodeEngine(
102102
"videoUs=${timer.durationUs.videoOrNull()}"
103103
)
104104
while (true) {
105-
val advanced =
106-
(segments.next(TrackType.AUDIO)?.advance() ?: false) or
107-
(segments.next(TrackType.VIDEO)?.advance() ?: false)
105+
// Create both segments before reading. Creating the segment calls source.selectTrack,
106+
// and if source is the same, it's important that both tracks are selected before
107+
// reading (or even worse, seeking. DataSource.seek is broken if you add a track later on).
108+
val audio = segments.next(TrackType.AUDIO)
109+
val video = segments.next(TrackType.VIDEO)
110+
val advanced = (audio?.advance() ?: false) or (video?.advance() ?: false)
108111
val completed = !advanced && !segments.hasNext() // avoid calling hasNext if we advanced.
109112

110113
log.v("transcode(): executed step=$loop advanced=$advanced completed=$completed")

‎lib/src/main/java/com/otaliastudios/transcoder/internal/utils/eos.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@ internal fun DataSink.ignoringEos(ignore: () -> Boolean): DataSink
1313
= EosIgnoringDataSink(this, ignore)
1414

1515
private class EosIgnoringDataSink(
16-
private val source: DataSink,
16+
private val sink: DataSink,
1717
private val ignore: () -> Boolean,
18-
) : DataSink by source {
18+
) : DataSink by sink {
1919
private val info = MediaCodec.BufferInfo()
2020
override fun writeTrack(type: TrackType, byteBuffer: ByteBuffer, bufferInfo: MediaCodec.BufferInfo) {
2121
if (ignore()) {
2222
val flags = bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM.inv()
2323
info.set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs, flags)
24-
source.writeTrack(type, byteBuffer, info)
24+
sink.writeTrack(type, byteBuffer, info)
2525
} else {
26-
source.writeTrack(type, byteBuffer, bufferInfo)
26+
sink.writeTrack(type, byteBuffer, bufferInfo)
2727
}
2828
}
2929
}

‎lib/src/main/java/com/otaliastudios/transcoder/sink/DefaultDataSink.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ private QueuedSample(@NonNull TrackType type,
5252

5353
private final static Logger LOG = new Logger("DefaultDataSink");
5454

55-
// I have no idea whether this value is appropriate or not...
56-
private final static int BUFFER_SIZE = 64 * 1024;
55+
// We must be able to handle potentially big buffers (e.g. first keyframe) in the queue.
56+
// Got crashes with 152kb - let's use 256kb. TODO use a dynamic queue instead
57+
private final static int BUFFER_SIZE = 256 * 1024;
5758

5859
private boolean mMuxerStarted = false;
5960
private final MediaMuxer mMuxer;
@@ -117,10 +118,10 @@ public void setTrackFormat(@NonNull TrackType type, @NonNull MediaFormat format)
117118
mMuxerChecks.checkOutputFormat(type, format);
118119
}
119120
mLastFormat.set(type, format);
120-
startIfNeeded();
121+
maybeStart();
121122
}
122123

123-
private void startIfNeeded() {
124+
private void maybeStart() {
124125
if (mMuxerStarted) return;
125126
boolean isTranscodingVideo = mStatus.get(TrackType.VIDEO).isTranscoding();
126127
boolean isTranscodingAudio = mStatus.get(TrackType.AUDIO).isTranscoding();
@@ -170,6 +171,12 @@ private void enqueue(@NonNull TrackType type,
170171
if (mQueueBuffer == null) {
171172
mQueueBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE).order(ByteOrder.nativeOrder());
172173
}
174+
LOG.v("enqueue(" + type + "): offset=" + bufferInfo.offset
175+
+ "\trealOffset=" + buffer.position()
176+
+ "\tsize=" + bufferInfo.size
177+
+ "\trealSize=" + buffer.remaining()
178+
+ "\tavailable=" + mQueueBuffer.remaining()
179+
+ "\ttotal=" + BUFFER_SIZE);
173180
buffer.limit(bufferInfo.offset + bufferInfo.size);
174181
buffer.position(bufferInfo.offset);
175182
mQueueBuffer.put(buffer);

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

+4
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,13 @@ public long seekTo(long desiredPositionUs) {
148148
// sync frames. MediaExtractor is not smart enough to sync the two tracks at the
149149
// video sync frame, so we must take care of this with the following trick.
150150
mExtractor.unselectTrack(mIndex.getAudio());
151+
LOG.v("seekTo(): unselected AUDIO, seeking to " + (mOriginUs + desiredPositionUs) + " (extractorUs=" + mExtractor.getSampleTime() + ")");
151152
mExtractor.seekTo(mOriginUs + desiredPositionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
153+
LOG.v("seekTo(): unselected AUDIO and sought (extractorUs=" + mExtractor.getSampleTime() + ")");
152154
mExtractor.selectTrack(mIndex.getAudio()); // second seek might not be needed, but should not hurt.
155+
LOG.v("seekTo(): reselected AUDIO, seeking to extractorUs (extractorUs=" + mExtractor.getSampleTime() + ")");
153156
mExtractor.seekTo(mExtractor.getSampleTime(), MediaExtractor.SEEK_TO_CLOSEST_SYNC);
157+
LOG.v("seekTo(): seek workaround completed. (extractorUs=" + mExtractor.getSampleTime() + ")");
154158
} else {
155159
mExtractor.seekTo(mOriginUs + desiredPositionUs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
156160
}

0 commit comments

Comments
 (0)