blob: 049296b9be9e8241f117790b2d8b8a68e075d89c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
/*
* Copyright (C) 2015 Yuya Tanaka
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.ypresto.androidtranscoder.utils;
import android.media.MediaFormat;
import net.ypresto.androidtranscoder.format.MediaFormatExtraConstants;
import java.nio.ByteBuffer;
import java.util.Arrays;
public class AvcCsdUtils {
// Refer: https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright/MediaCodec.cpp#2198
// Refer: http://stackoverflow.com/a/2861340
private static final byte[] AVC_START_CODE_3 = {0x00, 0x00, 0x01};
private static final byte[] AVC_START_CODE_4 = {0x00, 0x00, 0x00, 0x01};
// Refer: http://www.cardinalpeak.com/blog/the-h-264-sequence-parameter-set/
private static final byte AVC_SPS_NAL = 103; // 0<<7 + 3<<5 + 7<<0
// https://tools.ietf.org/html/rfc6184
private static final byte AVC_SPS_NAL_2 = 39; // 0<<7 + 1<<5 + 7<<0
private static final byte AVC_SPS_NAL_3 = 71; // 0<<7 + 2<<5 + 7<<0
/**
* @return ByteBuffer contains SPS without NAL header.
*/
public static ByteBuffer getSpsBuffer(MediaFormat format) {
ByteBuffer sourceBuffer = format.getByteBuffer(MediaFormatExtraConstants.KEY_AVC_SPS).asReadOnlyBuffer(); // might be direct buffer
ByteBuffer prefixedSpsBuffer = ByteBuffer.allocate(sourceBuffer.limit()).order(sourceBuffer.order());
prefixedSpsBuffer.put(sourceBuffer);
prefixedSpsBuffer.flip();
skipStartCode(prefixedSpsBuffer);
byte spsNalData = prefixedSpsBuffer.get();
if (spsNalData != AVC_SPS_NAL && spsNalData != AVC_SPS_NAL_2 && spsNalData != AVC_SPS_NAL_3) {
throw new IllegalStateException("Got non SPS NAL data.");
}
return prefixedSpsBuffer.slice();
}
private static void skipStartCode(ByteBuffer prefixedSpsBuffer) {
byte[] prefix3 = new byte[3];
prefixedSpsBuffer.get(prefix3);
if (Arrays.equals(prefix3, AVC_START_CODE_3)) return;
byte[] prefix4 = Arrays.copyOf(prefix3, 4);
prefix4[3] = prefixedSpsBuffer.get();
if (Arrays.equals(prefix4, AVC_START_CODE_4)) return;
throw new IllegalStateException("AVC NAL start code does not found in csd.");
}
private AvcCsdUtils() {
throw new RuntimeException();
}
}
|