/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under GNU GENERAL PUBLIC LICENSE Version 3. */ package com.ttProject.xuggle.test; import org.apache.log4j.Logger; import com.ttProject.container.IContainer; import com.ttProject.container.flv.FlvTagReader; import com.ttProject.container.flv.FlvTagWriter; 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.extra.AudioMultiFrame; import com.ttProject.nio.channels.FileReadChannel; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.xuggle.frameutil.Depacketizer; import com.ttProject.xuggle.frameutil.Packetizer; import com.xuggle.xuggler.IAudioResampler; import com.xuggle.xuggler.IAudioSamples; import com.xuggle.xuggler.ICodec; import com.xuggle.xuggler.IPacket; import com.xuggle.xuggler.IStreamCoder; import com.xuggle.xuggler.ICodec.ID; import com.xuggle.xuggler.IStreamCoder.Direction; /** * try to decode * @author taktod */ public class DecodeTest { /** logger */ private Logger logger = Logger.getLogger(DecodeTest.class); /** encode information */ private int channels = 1; private int bitRate = 96000; private int sampleRate = 22050; private ICodec.ID codecId; /** encoder */ private IStreamCoder encoder = null; /** shared packet for encode. */ private IPacket packet = IPacket.make(); /** decoder */ private IStreamCoder decoder = null; /** shared packet for decode. */ private IPacket decodedPacket = IPacket.make(); /** frame -> packet */ private Packetizer packetizer = new Packetizer(); /** packet -> frame */ private Depacketizer depacketizer = new Depacketizer(); /** resampler */ private IAudioResampler resampler = null; private FlvTagWriter writer = null; /** * work test */ // @Test public void test() { try { IReadChannel source = FileReadChannel.openFileReadChannel( "xuggle_sound.error.flv" // timestampがおかしくてぷつぷついってうまく動作しなかった音声変換動作・・・原因はptsがおかしくなることだった // "xuggle_sound.error.flv" // timestampがおかしくてぷつぷついってうまく動作しなかった音声変換動作・・・原因はptsがおかしくなることだった ); FlvTagReader reader = new FlvTagReader(); writer = new FlvTagWriter("output4.flv"); writer.prepareHeader(CodecType.AAC); codecId = ID.CODEC_ID_MP3; // try mp3 openEncoder(); IContainer container = null; while((container = reader.read(source)) != null) { if(container instanceof VideoTag) { // logger.info(container); } else if(container instanceof AudioTag) { // logger.info(container); AudioTag aTag = (AudioTag) container; IAudioFrame aFrame = aTag.getFrame(); if(aFrame instanceof AudioMultiFrame) { AudioMultiFrame multiFrame = (AudioMultiFrame)aFrame; for(IAudioFrame af : multiFrame.getFrameList()) { decodeSound(af); } } } } } catch(Exception e) { e.printStackTrace(); } } /** * decode audioFrame * @param audioFrame */ private void decodeSound(IAudioFrame aFrame) throws Exception { if(aFrame instanceof AudioMultiFrame) { AudioMultiFrame multiFrame = (AudioMultiFrame)aFrame; for(IAudioFrame af : multiFrame.getFrameList()) { decodeSound(af); } return; } // need to check how many samples after decode. decoder = packetizer.getDecoder(aFrame, decoder); if(decoder == null) { logger.warn("decoder is null"); return; } if(!decoder.isOpen()) { logger.info("open decoder"); if(decoder.open(null, null) < 0) { throw new Exception("failed to open decoder"); } } IPacket pkt = packetizer.getPacket(aFrame, decodedPacket); if(pkt == null) { return; } decodedPacket = pkt; IAudioSamples samples = IAudioSamples.make(aFrame.getSampleNum(), decoder.getChannels()); int offset = 0; while(offset < decodedPacket.getSize()) { int bytesDecoded = decoder.decodeAudio(samples, decodedPacket, offset); if(bytesDecoded < 0) { throw new Exception("failed decode packet"); } offset += bytesDecoded; if(samples.isComplete()) { // sometime need resample. samples = getResampled(samples); encodeSound(samples); } } } /** * do resample to fit encoder. * @param samples * @return */ private IAudioSamples getResampled(IAudioSamples samples) throws Exception { if(samples.getSampleRate() != encoder.getSampleRate() || samples.getFormat() != encoder.getSampleFormat() || samples.getChannels() != encoder.getChannels()) { if(resampler == null || (samples.getSampleRate() != resampler.getInputRate() || samples.getFormat() != resampler.getInputFormat() || samples.getChannels() != resampler.getInputChannels())) { // in the case of no resampler, or format is not fit, make new resampler.(if we do this many times, miss the sample counter, a little.) // (audio will delay from video a little.) logger.info("open resampler"); logger.info(samples.getSampleRate()); logger.info(samples.getFormat()); logger.info(samples.getChannels()); resampler = IAudioResampler.make( encoder.getChannels(), samples.getChannels(), encoder.getSampleRate(), samples.getSampleRate(), encoder.getSampleFormat(), samples.getFormat()); } IAudioSamples spl = IAudioSamples.make(1024, encoder.getChannels()); int retval = resampler.resample(spl, samples, samples.getNumSamples()); if(retval <= 0) { throw new Exception("failed to resample audio."); } spl.setPts(samples.getPts()); spl.setTimeBase(samples.getTimeBase()); return spl; } else { return samples; } } /** * try encode */ private void encodeSound(IAudioSamples samples) throws Exception { int sampleConsumed = 0; while(sampleConsumed < samples.getNumSamples()) { int retval = encoder.encodeAudio(packet, samples, sampleConsumed); if(retval < 0) { throw new Exception("failed to encode."); } sampleConsumed += retval; if(packet.isComplete()) { IFrame frame = depacketizer.getFrame(encoder, packet); logger.info("made frame:" + frame); writer.addFrame(0x08, frame); } } } /** * open the encoder * @throws Exception */ private synchronized void openEncoder() throws Exception { if(encoder == null) { IStreamCoder coder = IStreamCoder.make(Direction.ENCODING, codecId); coder.setChannels(channels); coder.setSampleRate(sampleRate); coder.setBitRate(bitRate); encoder = coder; ICodec codec = encoder.getCodec(); IAudioSamples.Format findFormat = null; for(IAudioSamples.Format format : codec.getSupportedAudioSampleFormats()) { if(findFormat == null) { findFormat = format; } if(format == IAudioSamples.Format.FMT_S16) { findFormat = format; break; } } if(findFormat == null) { throw new Exception("supported audioFormat is undefined."); } encoder.setSampleFormat(findFormat); if(encoder.open(null, null) < 0) { throw new Exception("failed to open encoder.s"); } } } }