/* * 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.io.FileOutputStream; import java.nio.channels.WritableByteChannel; import java.util.List; import org.apache.log4j.Logger; import com.ttProject.container.IContainer; import com.ttProject.container.IWriter; import com.ttProject.container.flv.type.AudioTag; import com.ttProject.container.flv.type.VideoTag; import com.ttProject.frame.CodecType; import com.ttProject.frame.IAudioFrame; import com.ttProject.frame.IFrame; import com.ttProject.frame.IVideoFrame; import com.ttProject.frame.extra.AudioMultiFrame; import com.ttProject.frame.extra.VideoMultiFrame; /** * flv Tag Writer * @author taktod */ public class FlvTagWriter implements IWriter { /** logger */ @SuppressWarnings("unused") private Logger logger = Logger.getLogger(FlvTagWriter.class); private final WritableByteChannel outputChannel; private FileOutputStream outputStream = null; /** convert frame to flvTag */ private FrameToFlvTagConverter frameConverter = new FrameToFlvTagConverter(); public FlvTagWriter(String fileName) throws Exception { outputStream = new FileOutputStream(fileName); this.outputChannel = outputStream.getChannel(); } public FlvTagWriter(FileOutputStream fileOutputStream) { this.outputChannel = fileOutputStream.getChannel(); } public FlvTagWriter(WritableByteChannel outputChannel) { this.outputChannel = outputChannel; } @Override public void addContainer(IContainer container) throws Exception { outputChannel.write(container.getData()); } @Override public void addFrame(int trackId, IFrame frame) throws Exception { if(frame == null) { return; } if(frame instanceof VideoMultiFrame) { VideoMultiFrame multiFrame = (VideoMultiFrame)frame; for(IVideoFrame vFrame : multiFrame.getFrameList()) { addFrame(trackId, vFrame); } return; } // nellymoser can have multiAudioFrame. // however, for mp3, we need to devide for each mp3 frame for audioTag. if(frame instanceof AudioMultiFrame) { AudioMultiFrame multiFrame = (AudioMultiFrame)frame; for(IAudioFrame aFrame : multiFrame.getFrameList()) { addFrame(trackId, aFrame); } return; } // TODO for h264, videoTag can have multiVideoFrame. List<FlvTag> tagList = frameConverter.getTags(frame); if(tagList != null) { for(FlvTag tag : tagList) { outputChannel.write(tag.getData()); } } } @Override public void prepareHeader(CodecType... codecs) throws Exception { if(codecs.length == 0) { return; } FlvHeaderTag headerTag = new FlvHeaderTag(); for(CodecType codec : codecs) { if(codec.isAudio()) { headerTag.setAudioFlag(true); } else if(codec.isVideo()) { headerTag.setVideoFlag(true); } } addContainer(headerTag); } @Override public void prepareTailer() throws Exception { AudioTag audioTag = frameConverter.getRemainAudioTag(); if(audioTag != null) { outputChannel.write(audioTag.getData()); } VideoTag videoTag = frameConverter.getRemainVideoTag(); if(videoTag != null) { outputChannel.write(videoTag.getData()); } // for h264, it is better to put h264 end videoTag. if(outputStream != null) { try { outputStream.close(); } catch(Exception e) { } outputStream = null; } } }