-
Notifications
You must be signed in to change notification settings - Fork 156
/
BufferHelper.java
388 lines (357 loc) · 11 KB
/
BufferHelper.java
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
package com.serenegiant.utils;
/*
* libcommon
* utility/helper classes for myself
*
* Copyright (c) 2014-2024 saki t_saki@serenegiant.com
*
* 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.
*/
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
/**
* Buffer/配列用のヘルパークラス
*/
public class BufferHelper {
private BufferHelper() {
// インスタンス化をエラーにするためにデフォルトコンストラクタをprivateに
}
private static final char[] HEX = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f'};
private static final int BUF_LEN = 256;
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param buffer
* @param offset
* @param size
*/
public static final void dump(@NonNull final String tag,
final ByteBuffer buffer, final int offset, final int size) {
dump(tag, null, buffer, offset, size, false);
}
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param prefix
* @param buffer
* @param offset
* @param size
*/
public static final void dump(
@NonNull final String tag, final String prefix,
final ByteBuffer buffer, final int offset, final int size) {
dump(tag, prefix, buffer, offset, size, false);
}
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param buffer
* @param offset
* @param size
* @param findAnnexB
*/
public static final void dump(@NonNull final String tag,
final ByteBuffer buffer, final int offset, final int size, final boolean findAnnexB) {
dump(tag, null, buffer, offset, size, findAnnexB);
}
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param _prefix
* @param _buffer
* @param offset
* @param _size
* @param findAnnexB
*/
public static final void dump(
@NonNull final String tag, @Nullable final String _prefix,
final ByteBuffer _buffer, final int offset, final int _size, final boolean findAnnexB) {
@NonNull
final String prefix = _prefix != null ? _prefix : "dump:";
final byte[] dump = new byte[BUF_LEN];
// if (DEBUG) Log.i(TAG, "dump:" + buffer);
if (_buffer == null) return;
final ByteBuffer buffer = _buffer.asReadOnlyBuffer();
final int n = buffer.limit();
final int pos = buffer.position();
// final int cap = buffer.capacity();
// if (DEBUG) Log.i(TAG, "dump:limit=" + n + ",capacity=" + cap + ",position=" + buffer.position());
int size = _size;
if (size > n) size = n;
buffer.position(offset);
final StringBuilder sb = new StringBuilder();
int sz;
for (int i = offset; i < size; i += BUF_LEN) {
sz = i + BUF_LEN < size ? BUF_LEN : size - i;
buffer.get(dump, 0, sz);
for (int j = 0; j < sz; j++) {
sb.append(String.format("%02x", dump[j]));
}
if (findAnnexB) {
int index = -1;
do {
index = byteComp(dump, index+1, ANNEXB_START_MARK, ANNEXB_START_MARK.length);
if (index >= 0) {
Log.i(tag, prefix + " found ANNEXB: start index=" + index);
}
} while (index >= 0);
}
}
Log.i(tag, prefix + sb);
}
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param buffer
* @param offset
* @param size
* @param findAnnexB
*/
public static final void dump(final String tag,
final byte[] buffer, final int offset, final int size, final boolean findAnnexB) {
dump(tag, null, buffer, offset, size, findAnnexB);
}
/**
* ByteBufferの中身をlogCatへ出力する
* @param tag
* @param _prefix
* @param buffer
* @param offset
* @param _size
* @param findAnnexB
*/
public static final void dump(
@NonNull final String tag, @Nullable final String _prefix,
final byte[] buffer, final int offset, final int _size, final boolean findAnnexB) {
@NonNull
final String prefix = _prefix != null ? _prefix : "dump:";
final int n = buffer != null ? buffer.length : 0;
if (n == 0) return;
int size = _size;
if (size > n) size = n;
final StringBuilder sb = new StringBuilder();
int sz;
for (int i = offset; i < size; i ++) {
sb.append(String.format("%02x", buffer[i]));
}
if (findAnnexB) {
int index = -1;
do {
index = byteComp(buffer, index+1, ANNEXB_START_MARK, ANNEXB_START_MARK.length);
if (index >= 0) {
Log.i(tag, prefix + " found ANNEXB: start index=" + index);
}
} while (index >= 0);
}
Log.i(tag, prefix + sb);
}
/**
* codec specific dataのスタートマーカー
* AnnexBのスタートマーカーと同じ
* N[00] 00 00 01 (N ≧ 0)
*/
public static final byte[] ANNEXB_START_MARK = { 0, 0, 0, 1, };
/**
* byte[]を検索して一致する先頭インデックスを返す
* @param array 検索されるbyte[]
* @param search 検索するbyte[]
* @param len 検索するバイト数
* @return 一致した先頭位置、一致しなければ-1
*/
public static final int byteComp(@NonNull final byte[] array, final int offset, @NonNull final byte[] search, final int len) {
int index = -1;
final int n0 = array.length;
final int ns = search.length;
if ((n0 >= offset + len) && (ns >= len)) {
for (int i = offset; i < n0 - len; i++) {
int j = len - 1;
while (j >= 0) {
if (array[i + j] != search[j]) break;
j--;
}
if (j < 0) {
index = i;
break;
}
}
}
return index;
}
/**
* AnnexBのスタートマーカー(N[00] 00 00 01 (N ≧ 0))を探して先頭インデックスを返す
* 返り値が0以上の場合は、返り値+3がpayloadの先頭位置(nalu headerのはず)
* @param data
* @param offset
* @return 見つからなければ負
*/
public static final int findAnnexB(final byte[] data, final int offset) {
if (data != null) {
final int len5 = data.length - 5; // 本当はlength-3までだけどpayloadが無いのは無効とみなしてlength-4までとする
for (int i = offset; i < len5; i++) {
// 最低3つは連続して0x00
if ((data[i] != 0x00) || (data[i+1] != 0x00) || (data[i+2] != 0x00)) {
continue;
}
// 4つ目が0x01ならOK
if (data[i+3] == 0x01) {
return i;
}
}
final int len4 = data.length - 4; // 本当はlength-3までだけどpayloadが無いのは無効とみなしてlength-4までとする
for (int i = offset; i < len4; i++) {
// 最低2つは連続して0x00でないとだめ
if ((data[i] != 0x00) || (data[i+1] != 0x00)) {
continue;
}
// 3つ目が0x01ならOK
if (data[i+2] == 0x01) {
return i;
}
}
}
return -1;
}
/**
* float1つのサイズ[バイト]
*/
public static final int SIZEOF_FLOAT_BYTES = Float.SIZE / 8;
/**
* 引数のfloat配列と同じ長さのFloatBufferを生成して引数の値をセットする
* @param coords
* @return
*/
public static FloatBuffer createFloatBuffer(@NonNull final float[] coords) {
// Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it.
final FloatBuffer result
= ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
result.put(coords).flip();
return result;
}
/**
* 16進文字列をパースしてByteBufferとして返す
* @param hexString
* @return
* @throws NumberFormatException
*/
public static ByteBuffer from(final String hexString) throws NumberFormatException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final int n = !TextUtils.isEmpty(hexString) ? hexString.length() : 0;
for (int i = 0; i < n; i += 2) {
final int b = Integer.parseInt(hexString.substring(i, i + 2), 16);
out.write(b);
}
return ByteBuffer.wrap(out.toByteArray());
}
/**
* byte配列を16進文字列に変換する
* @param bytes
* @return
*/
public static String toHexString(@NonNull final byte[] bytes) {
return toHexString(bytes, 0, bytes.length);
}
/**
* byte配列を16進文字列に変換する
* @param bytes
* @param offset
* @param len 出力する最大バイト数
* @return
*/
public static String toHexString(final byte[] bytes,
final int offset, final int len) {
final int n = (bytes != null) ? bytes.length : 0;
final int m = Math.min(n, offset + len);
final StringBuilder sb = new StringBuilder(n * 2 + 2);
for (int i = offset; i < m; i++) {
final byte b = bytes[i];
sb.append(HEX[(0xf0 & b) >>> 4]);
sb.append(HEX[0x0f & b]);
}
return sb.toString();
}
/**
* ByteBufferを16進文字列に変換する
* @param buffer
* @return
*/
public static String toHexString(final ByteBuffer buffer) {
if (buffer == null) return null;
final ByteBuffer _buffer = buffer.duplicate();
final int n = _buffer.remaining();
final StringBuilder sb = new StringBuilder(n * 2 + 2);
for (int i = 0; i < n; i++) {
final byte b = _buffer.get();
sb.append(HEX[(0xf0 & b) >>> 4]);
sb.append(HEX[0x0f & b]);
}
return sb.toString();
}
/**
* 指定したbyte配列が指定したサイズ以上になるようにする
* 引数のbyte配列がnullまたは指定したサイズよりも小さい場合には新しいbyte配列を生成して返す
* @param buffer
* @param newSize
* @return
*/
@NonNull
public static byte[] resize(@Nullable final byte[] buffer, final int newSize) {
byte[] result = buffer;
if ((result == null) || (result.length < newSize)) {
result = new byte[newSize];
}
return result;
}
/**
* 指定したByteBufferが指定したサイズ以上になるようにする
* 引数のByteBufferがnullまたは指定したサイズよりも小さい場合には新しいByteBufferを生成して返す
* @param buffer
* @param newSize
* @return
*/
@NonNull
public static ByteBuffer resize(@Nullable final ByteBuffer buffer, final int newSize) {
ByteBuffer result = buffer;
if ((result == null) || (result.capacity() < newSize)) {
result = ByteBuffer.allocate(newSize);
}
result.clear();
return result;
}
/**
* 指定したByteBufferが指定したサイズ以上になるようにする
* 引数のByteBufferがnullまたは指定したサイズよりも小さい場合には新しいダイレクトByteBufferを生成して返す
* @param buffer
* @param newSize
* @return
*/
@NonNull
public static ByteBuffer resizeDirect(@Nullable final ByteBuffer buffer, final int newSize) {
ByteBuffer result = buffer;
if ((result == null) || (result.capacity() < newSize)) {
result = ByteBuffer.allocateDirect(newSize).order(ByteOrder.nativeOrder());
}
result.clear();
return result;
}
}