package com.laifeng.sopcastsdk.stream.packer; import android.media.MediaCodec; import com.laifeng.sopcastsdk.constant.SopCastConstant; import com.laifeng.sopcastsdk.utils.SopCastLog; import java.nio.ByteBuffer; import java.util.ArrayList; /** * @Title: AnnexbHelper * @Package com.laifeng.sopcastsdk.video * @Description: * @Author Jim * @Date 16/9/1 * @Time 下午2:20 * @Version */ public class AnnexbHelper { // Coded slice of a non-IDR picture slice_layer_without_partitioning_rbsp( ) public final static int NonIDR = 1; // Coded slice of an IDR picture slice_layer_without_partitioning_rbsp( ) public final static int IDR = 5; // Supplemental enhancement information (SEI) sei_rbsp( ) public final static int SEI = 6; // Sequence parameter set seq_parameter_set_rbsp( ) public final static int SPS = 7; // Picture parameter set pic_parameter_set_rbsp( ) public final static int PPS = 8; // Access unit delimiter access_unit_delimiter_rbsp( ) public final static int AccessUnitDelimiter = 9; private AnnexbNaluListener mListener; private byte[] mPps; private byte[] mSps; private boolean mUploadPpsSps = true; /** * the search result for annexb. */ class AnnexbSearch { public int startCode = 0; public boolean match = false; } public interface AnnexbNaluListener { void onSpsPps(byte[] sps, byte[] pps); void onVideo(byte[] data, boolean isKeyFrame); } public void setAnnexbNaluListener(AnnexbNaluListener listener) { mListener = listener; } public void stop() { mListener = null; mPps = null; mSps = null; mUploadPpsSps = true; } /** * 将硬编得到的视频数据进行处理生成每一帧视频数据,然后传给flv打包器 * @param bb 硬编后的数据buffer * @param bi 硬编的BufferInfo */ public void analyseVideoData(ByteBuffer bb, MediaCodec.BufferInfo bi) { bb.position(bi.offset); bb.limit(bi.offset + bi.size); ArrayList<byte[]> frames = new ArrayList<>(); boolean isKeyFrame = false; while(bb.position() < bi.offset + bi.size) { byte[] frame = annexbDemux(bb, bi); if(frame == null) { SopCastLog.e(SopCastConstant.TAG, "annexb not match."); break; } // ignore the nalu type aud(9) if (isAccessUnitDelimiter(frame)) { continue; } // for pps if(isPps(frame)) { mPps = frame; continue; } // for sps if(isSps(frame)) { mSps = frame; continue; } // for IDR frame if(isKeyFrame(frame)) { isKeyFrame = true; } else { isKeyFrame = false; } byte[] naluHeader = buildNaluHeader(frame.length); frames.add(naluHeader); frames.add(frame); } if (mPps != null && mSps != null && mListener != null && mUploadPpsSps) { if(mListener != null) { mListener.onSpsPps(mSps, mPps); } mUploadPpsSps = false; } if(frames.size() == 0 || mListener == null) { return; } int size = 0; for (int i = 0; i < frames.size(); i++) { byte[] frame = frames.get(i); size += frame.length; } byte[] data = new byte[size]; int currentSize = 0; for (int i = 0; i < frames.size(); i++) { byte[] frame = frames.get(i); System.arraycopy(frame, 0, data, currentSize, frame.length); currentSize += frame.length; } if(mListener != null) { mListener.onVideo(data, isKeyFrame); } } /** * 从硬编出来的数据取出一帧nal * @param bb * @param bi * @return */ private byte[] annexbDemux(ByteBuffer bb, MediaCodec.BufferInfo bi) { AnnexbSearch annexbSearch = new AnnexbSearch(); avcStartWithAnnexb(annexbSearch, bb, bi); if (!annexbSearch.match || annexbSearch.startCode < 3) { return null; } for (int i = 0; i < annexbSearch.startCode; i++) { bb.get(); } ByteBuffer frameBuffer = bb.slice(); int pos = bb.position(); while (bb.position() < bi.offset + bi.size) { avcStartWithAnnexb(annexbSearch, bb, bi); if (annexbSearch.match) { break; } bb.get(); } int size = bb.position() - pos; byte[] frameBytes = new byte[size]; frameBuffer.get(frameBytes); return frameBytes; } /** * 从硬编出来的byteBuffer中查找nal * @param as * @param bb * @param bi */ private void avcStartWithAnnexb(AnnexbSearch as, ByteBuffer bb, MediaCodec.BufferInfo bi) { as.match = false; as.startCode = 0; int pos = bb.position(); while (pos < bi.offset + bi.size - 3) { // not match. if (bb.get(pos) != 0x00 || bb.get(pos + 1) != 0x00) { break; } // match N[00] 00 00 01, where N>=0 if (bb.get(pos + 2) == 0x01) { as.match = true; as.startCode = pos + 3 - bb.position(); break; } pos++; } } private byte[] buildNaluHeader(int length) { ByteBuffer buffer = ByteBuffer.allocate(4); buffer.putInt(length); return buffer.array(); } private boolean isSps(byte[] frame) { if (frame.length < 1) { return false; } // 5bits, 7.3.1 NAL unit syntax, // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame int nal_unit_type = (frame[0] & 0x1f); return nal_unit_type == SPS; } private boolean isPps(byte[] frame) { if (frame.length < 1) { return false; } // 5bits, 7.3.1 NAL unit syntax, // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame int nal_unit_type = (frame[0] & 0x1f); return nal_unit_type == PPS; } private boolean isKeyFrame(byte[] frame) { if (frame.length < 1) { return false; } // 5bits, 7.3.1 NAL unit syntax, // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame int nal_unit_type = (frame[0] & 0x1f); return nal_unit_type == IDR; } private static boolean isAccessUnitDelimiter(byte[] frame) { if (frame.length < 1) { return false; } // 5bits, 7.3.1 NAL unit syntax, // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame int nal_unit_type = (frame[0] & 0x1f); return nal_unit_type == AccessUnitDelimiter; } }