/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.container.flv; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import com.ttProject.container.flv.type.AudioTag; import com.ttProject.container.flv.type.VideoTag; import com.ttProject.frame.AudioFrame; import com.ttProject.frame.IFrame; import com.ttProject.frame.VideoFrame; import com.ttProject.frame.aac.AacFrame; import com.ttProject.frame.aac.type.Frame; import com.ttProject.frame.h264.H264Frame; import com.ttProject.frame.h264.type.PictureParameterSet; import com.ttProject.frame.h264.type.SequenceParameterSet; import com.ttProject.frame.h264.type.Slice; import com.ttProject.frame.h264.type.SliceIDR; import com.ttProject.frame.h264.type.SupplementalEnhancementInformation; /** * make flvTag from frame. * @author taktod */ public class FrameToFlvTagConverter { /** logger */ @SuppressWarnings("unused") private Logger logger = Logger.getLogger(FrameToFlvTagConverter.class); private ByteBuffer aacPrivateData = null; private SequenceParameterSet sps = null; private PictureParameterSet pps = null; /** last audioTag */ private AudioTag audioTag = null; /** last videoTag */ private VideoTag videoTag = null; /** * get the tags from frame. * FlvTagリストを取得します。 * @return */ public List<FlvTag> getTags(IFrame frame) throws Exception { if(frame instanceof VideoFrame) { return getVideoTags((VideoFrame)frame); } else if(frame instanceof AudioFrame) { return getAudioTags((AudioFrame)frame); } throw new Exception("neither audio nor video frame?:" + frame.toString()); } /** * audioFrame. * @param frame * @return */ private List<FlvTag> getAudioTags(AudioFrame frame) throws Exception { List<FlvTag> result = new ArrayList<FlvTag>(); // for aac we need to check msh. if(frame instanceof AacFrame) { Frame aacFrame = (Frame) frame; ByteBuffer privateData = aacFrame.getPrivateData(); if(privateData.equals(aacPrivateData)) { aacPrivateData = privateData; AudioTag audioTag = new AudioTag(); audioTag.setAacMediaSequenceHeader(aacFrame, aacPrivateData.duplicate()); result.add(audioTag); } } // make audioTag. AudioTag audioTag = new AudioTag(); audioTag.addFrame(frame); result.add(audioTag); return result; } /** * videoframe. * @param frame * @return */ private List<FlvTag> getVideoTags(VideoFrame frame) throws Exception { // for h264, use other way. if(frame instanceof H264Frame) { return getH264Tags(frame); } List<FlvTag> result = new ArrayList<FlvTag>(); // make videoTag. videoTag = new VideoTag(); videoTag.addFrame(frame); result.add(videoTag); return result; } /** * h264Frame * @param frame * @return * @throws Exception */ private List<FlvTag> getH264Tags(VideoFrame frame) throws Exception { List<FlvTag> result = new ArrayList<FlvTag>(); if(frame instanceof SupplementalEnhancementInformation) { // sei will be the cause of nullpointerexception. return result; } // check msh. if(frame instanceof SliceIDR) { SliceIDR sliceIDR = (SliceIDR)frame; if(sps == null || pps == null || sps.getData().compareTo(sliceIDR.getSps().getData()) != 0 || pps.getData().compareTo(sliceIDR.getPps().getData()) != 0) { sps = sliceIDR.getSps(); pps = sliceIDR.getPps(); VideoTag videoTag = new VideoTag(); videoTag.setH264MediaSequenceHeader(sliceIDR, sps, pps); result.add(videoTag); } } if(sps == null || pps == null) { // neither sps nor pps exists, no more task. return result; } if(frame instanceof Slice) { Slice slice = (Slice)frame; if(slice.getFirstMbInSlice() == 0) { if(videoTag != null) { result.add(videoTag); } videoTag = new VideoTag(); } videoTag.addFrame(frame); } if(frame instanceof SliceIDR) { SliceIDR sliceIDR = (SliceIDR)frame; if(sliceIDR.getFirstMbInSlice() == 0) { if(videoTag != null) { result.add(videoTag); } videoTag = new VideoTag(); } videoTag.addFrame(frame); } return result; } public VideoTag getRemainVideoTag() { return videoTag; } public AudioTag getRemainAudioTag() { return audioTag; } }