From 908362bdf352883497a58ff4c520f69497463070 Mon Sep 17 00:00:00 2001 From: Michael Goffioul Date: Thu, 27 Jul 2017 15:44:28 -0400 Subject: [PATCH] Fix H262 segmentation. Prepend sequence headers to the next frame, instead of appending them to the previous frame. Tested decoders like FFMPEG and Google's Android/MPEG2 expects to read the sequence headers before the first frame they apply to. When sequence headers are appended to the previous frame, these are ignored and this leads to incorrect decoding. --- .../exoplayer2/extractor/ts/H262Reader.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java index 7266f847c4..92c8e8d800 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/H262Reader.java @@ -51,7 +51,7 @@ public final class H262Reader implements ElementaryStreamReader { // State that should be reset on seek. private final boolean[] prefixFlags; private final CsdBuffer csdBuffer; - private boolean foundFirstFrameInGroup; + private boolean foundPicture; private long totalBytesWritten; // Per packet state that gets reset at the start of each packet. @@ -60,8 +60,8 @@ public final class H262Reader implements ElementaryStreamReader { // Per sample state that gets reset at the start of each frame. private boolean isKeyframe; - private long framePosition; - private long frameTimeUs; + private long samplePosition; + private long sampleTimeUs; public H262Reader() { prefixFlags = new boolean[4]; @@ -73,7 +73,8 @@ public final class H262Reader implements ElementaryStreamReader { NalUnitUtil.clearPrefixFlags(prefixFlags); csdBuffer.reset(); pesPtsUsAvailable = false; - foundFirstFrameInGroup = false; + foundPicture = false; + samplePosition = C.POSITION_UNSET; totalBytesWritten = 0; } @@ -136,25 +137,28 @@ public final class H262Reader implements ElementaryStreamReader { } } - if (hasOutputFormat && (startCodeValue == START_GROUP || startCodeValue == START_PICTURE)) { + if (hasOutputFormat && (startCodeValue == START_PICTURE || startCodeValue == START_SEQUENCE_HEADER)) { int bytesWrittenPastStartCode = limit - startCodeOffset; - if (foundFirstFrameInGroup) { + boolean resetSample = (samplePosition == C.POSITION_UNSET); + if (foundPicture) { @C.BufferFlags int flags = isKeyframe ? C.BUFFER_FLAG_KEY_FRAME : 0; - int size = (int) (totalBytesWritten - framePosition) - bytesWrittenPastStartCode; - output.sampleMetadata(frameTimeUs, flags, size, bytesWrittenPastStartCode, null); + int size = (int) (totalBytesWritten - samplePosition) - bytesWrittenPastStartCode; + output.sampleMetadata(sampleTimeUs, flags, size, bytesWrittenPastStartCode, null); isKeyframe = false; + resetSample = true; } - if (startCodeValue == START_GROUP) { - foundFirstFrameInGroup = false; - isKeyframe = true; - } else /* startCodeValue == START_PICTURE */ { - frameTimeUs = pesPtsUsAvailable ? pesTimeUs : (frameTimeUs + frameDurationUs); - framePosition = totalBytesWritten - bytesWrittenPastStartCode; + foundPicture = (startCodeValue == START_PICTURE); + if (resetSample) { + samplePosition = totalBytesWritten - bytesWrittenPastStartCode; + sampleTimeUs = (pesPtsUsAvailable ? pesTimeUs : sampleTimeUs + frameDurationUs); pesPtsUsAvailable = false; - foundFirstFrameInGroup = true; } } + if (hasOutputFormat && startCodeValue == START_GROUP) { + isKeyframe = true; + } + offset = startCodeOffset; searchOffset = offset + 3; }