|
|
@ -619,56 +619,53 @@ public class SrsFlvMuxer {
|
|
|
|
return allocation;
|
|
|
|
return allocation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private SrsAnnexbSearch searchAnnexb(ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
private SrsAnnexbSearch searchStartcode(ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
annexb.match = false;
|
|
|
|
annexb.match = false;
|
|
|
|
annexb.nb_start_code = 0;
|
|
|
|
annexb.nb_start_code = 0;
|
|
|
|
|
|
|
|
if (bi.size - 4 > 0) {
|
|
|
|
|
|
|
|
if (bb.get(0) == 0x00 && bb.get(1) == 0x00 && bb.get(2) == 0x00 && bb.get(3) == 0x01) {
|
|
|
|
|
|
|
|
// match N[00] 00 00 00 01, where N>=0
|
|
|
|
|
|
|
|
annexb.match = true;
|
|
|
|
|
|
|
|
annexb.nb_start_code = 4;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return annexb;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private SrsAnnexbSearch searchAnnexb(ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
|
|
|
|
annexb.match = false;
|
|
|
|
|
|
|
|
annexb.nb_start_code = 0;
|
|
|
|
for (int i = bb.position(); i < bi.size - 3; i++) {
|
|
|
|
for (int i = bb.position(); i < bi.size - 3; i++) {
|
|
|
|
// not match.
|
|
|
|
// not match.
|
|
|
|
if (bb.get(i) != 0x00 || bb.get(i + 1) != 0x00) {
|
|
|
|
if (bb.get(i) != 0x00 || bb.get(i + 1) != 0x00 || bb.get(i + 2) != 0x00) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// match N[00] 00 00 01, where N>=0
|
|
|
|
// match N[00] 00 00 01, where N>=0
|
|
|
|
if (bb.get(i + 2) == 0x01) {
|
|
|
|
if (bb.get(i + 3) == 0x01) {
|
|
|
|
annexb.match = true;
|
|
|
|
annexb.match = true;
|
|
|
|
annexb.nb_start_code = i + 3 - bb.position();
|
|
|
|
annexb.nb_start_code = i + 4 - bb.position();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return annexb;
|
|
|
|
return annexb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public SrsFlvFrameBytes demuxAnnexb(ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
public SrsFlvFrameBytes demuxAnnexb(ByteBuffer bb, MediaCodec.BufferInfo bi, boolean isOnlyChkHeader) {
|
|
|
|
// each frame must prefixed by annexb format.
|
|
|
|
|
|
|
|
// about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
|
|
|
|
|
|
|
SrsAnnexbSearch tbbsc = searchAnnexb(bb, bi);
|
|
|
|
|
|
|
|
// the start codes.
|
|
|
|
|
|
|
|
for (int i = 0; i < tbbsc.nb_start_code; i++) {
|
|
|
|
|
|
|
|
bb.get();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// find out the frame size.
|
|
|
|
|
|
|
|
SrsFlvFrameBytes tbb = new SrsFlvFrameBytes();
|
|
|
|
SrsFlvFrameBytes tbb = new SrsFlvFrameBytes();
|
|
|
|
tbb.data = bb.slice();
|
|
|
|
if (bb.position() < bi.size) {
|
|
|
|
|
|
|
|
// each frame must prefixed by annexb format.
|
|
|
|
|
|
|
|
// about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211.
|
|
|
|
|
|
|
|
SrsAnnexbSearch tbbsc = isOnlyChkHeader ? searchStartcode(bb, bi) : searchAnnexb(bb, bi);
|
|
|
|
|
|
|
|
// tbbsc.nb_start_code always 4 , after 00 00 00 01
|
|
|
|
|
|
|
|
if (!tbbsc.match || tbbsc.nb_start_code < 3) {
|
|
|
|
|
|
|
|
Log.e(TAG, "annexb not match.");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Assume there always be single slice for each video frame when sps and pps are found.
|
|
|
|
// find out the frame size.
|
|
|
|
// That would promote efficiency on some low-end devices.
|
|
|
|
tbb.data = bb.slice();
|
|
|
|
if (sps_pps_found) {
|
|
|
|
|
|
|
|
tbb.size = bi.size - bb.position();
|
|
|
|
tbb.size = bi.size - bb.position();
|
|
|
|
bb.position(bb.limit());
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
int pos = bb.position();
|
|
|
|
|
|
|
|
while (bb.position() < bi.size) {
|
|
|
|
|
|
|
|
SrsAnnexbSearch bsc = searchAnnexb(bb, bi);
|
|
|
|
|
|
|
|
if (bsc.match) {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bb.get();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tbb.size = bi.size - pos;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tbb;
|
|
|
|
return tbb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -854,62 +851,41 @@ public class SrsFlvMuxer {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
public void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) {
|
|
|
|
|
|
|
|
if (bi.size < 4) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int pts = (int) (bi.presentationTimeUs / 1000);
|
|
|
|
int pts = (int) (bi.presentationTimeUs / 1000);
|
|
|
|
int dts = pts;
|
|
|
|
int dts = pts;
|
|
|
|
|
|
|
|
|
|
|
|
int type = SrsCodecVideoAVCFrame.InterFrame;
|
|
|
|
int type = SrsCodecVideoAVCFrame.InterFrame;
|
|
|
|
|
|
|
|
SrsFlvFrameBytes frame = avc.demuxAnnexb(bb, bi, true);
|
|
|
|
// send each frame.
|
|
|
|
int nal_unit_type = frame.data.get(0) & 0x1f;
|
|
|
|
while (bb.position() < bi.size) {
|
|
|
|
|
|
|
|
SrsFlvFrameBytes frame = avc.demuxAnnexb(bb, bi);
|
|
|
|
if (nal_unit_type == SrsAvcNaluType.IDR) {
|
|
|
|
|
|
|
|
type = SrsCodecVideoAVCFrame.KeyFrame;
|
|
|
|
// 5bits, 7.3.1 NAL unit syntax,
|
|
|
|
} else if (nal_unit_type == SrsAvcNaluType.SPS || nal_unit_type == SrsAvcNaluType.PPS) {
|
|
|
|
// H.264-AVC-ISO_IEC_14496-10.pdf, page 44.
|
|
|
|
if (!frame.data.equals(h264_sps)) {
|
|
|
|
// 7: SPS, 8: PPS, 5: I Frame, 1: P Frame
|
|
|
|
byte[] sps = new byte[frame.size];
|
|
|
|
int nal_unit_type = frame.data.get(0) & 0x1f;
|
|
|
|
frame.data.get(sps);
|
|
|
|
if (nal_unit_type == SrsAvcNaluType.SPS || nal_unit_type == SrsAvcNaluType.PPS) {
|
|
|
|
h264_sps_changed = true;
|
|
|
|
Log.i(TAG, String.format("annexb demux %dB, pts=%d, frame=%dB, nalu=%d",
|
|
|
|
h264_sps = ByteBuffer.wrap(sps);
|
|
|
|
bi.size, pts, frame.size, nal_unit_type));
|
|
|
|
writeH264SpsPps(dts, pts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
frame = avc.demuxAnnexb(bb, bi, false);
|
|
|
|
// for IDR frame, the frame is keyframe.
|
|
|
|
if (!frame.data.equals(h264_pps)) {
|
|
|
|
if (nal_unit_type == SrsAvcNaluType.IDR) {
|
|
|
|
byte[] pps = new byte[frame.size];
|
|
|
|
type = SrsCodecVideoAVCFrame.KeyFrame;
|
|
|
|
frame.data.get(pps);
|
|
|
|
}
|
|
|
|
h264_pps_changed = true;
|
|
|
|
|
|
|
|
h264_pps = ByteBuffer.wrap(pps);
|
|
|
|
// ignore the nalu type aud(9)
|
|
|
|
writeH264SpsPps(dts, pts);
|
|
|
|
if (nal_unit_type == SrsAvcNaluType.AccessUnitDelimiter) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
// for sps
|
|
|
|
} else if (nal_unit_type != SrsAvcNaluType.NonIDR) {
|
|
|
|
if (avc.isSps(frame)) {
|
|
|
|
return;
|
|
|
|
if (!frame.data.equals(h264_sps)) {
|
|
|
|
|
|
|
|
byte[] sps = new byte[frame.size];
|
|
|
|
|
|
|
|
frame.data.get(sps);
|
|
|
|
|
|
|
|
h264_sps_changed = true;
|
|
|
|
|
|
|
|
h264_sps = ByteBuffer.wrap(sps);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// for pps
|
|
|
|
|
|
|
|
if (avc.isPps(frame)) {
|
|
|
|
|
|
|
|
if (!frame.data.equals(h264_pps)) {
|
|
|
|
|
|
|
|
byte[] pps = new byte[frame.size];
|
|
|
|
|
|
|
|
frame.data.get(pps);
|
|
|
|
|
|
|
|
h264_pps_changed = true;
|
|
|
|
|
|
|
|
h264_pps = ByteBuffer.wrap(pps);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// IPB frame.
|
|
|
|
|
|
|
|
ipbs.add(avc.muxNaluHeader(frame));
|
|
|
|
|
|
|
|
ipbs.add(frame);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
writeH264SpsPps(dts, pts);
|
|
|
|
ipbs.add(avc.muxNaluHeader(frame));
|
|
|
|
|
|
|
|
ipbs.add(frame);
|
|
|
|
writeH264IpbFrame(ipbs, type, dts, pts);
|
|
|
|
writeH264IpbFrame(ipbs, type, dts, pts);
|
|
|
|
ipbs.clear();
|
|
|
|
ipbs.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|