001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.util;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.util.PropsKeys;
020    
021    import com.xuggle.xuggler.IAudioResampler;
022    import com.xuggle.xuggler.IAudioSamples;
023    import com.xuggle.xuggler.ICodec;
024    import com.xuggle.xuggler.IContainer;
025    import com.xuggle.xuggler.IPacket;
026    import com.xuggle.xuggler.IStream;
027    import com.xuggle.xuggler.IStreamCoder;
028    
029    import java.util.Properties;
030    
031    /**
032     * @author Juan Gonz??lez
033     * @author Sergio Gonz??lez
034     * @author Brian Wing Shun Chan
035     * @author Alexander Chow
036     */
037    public class LiferayAudioConverter extends LiferayConverter {
038    
039            public LiferayAudioConverter(
040                    String inputURL, String outputURL, String audioContainer,
041                    Properties audioProperties) {
042    
043                    _inputURL = inputURL;
044                    _outputURL = outputURL;
045                    _audioContainer = audioContainer;
046    
047                    initAudioBitRate(audioProperties);
048                    initAudioSampleRate(audioProperties);
049            }
050    
051            @Override
052            public void convert() throws Exception {
053                    try {
054                            doConvert();
055                    }
056                    finally {
057                            if (_inputIContainer.isOpened()) {
058                                    _inputIContainer.close();
059                            }
060    
061                            if (_outputIContainer.isOpened()) {
062                                    _outputIContainer.close();
063                            }
064                    }
065            }
066    
067            protected void doConvert() throws Exception {
068                    _inputIContainer = IContainer.make();
069                    _outputIContainer = IContainer.make();
070    
071                    openContainer(_inputIContainer, _inputURL, false);
072                    openContainer(_outputIContainer, _outputURL, true);
073    
074                    int inputStreamsCount = _inputIContainer.getNumStreams();
075    
076                    if (inputStreamsCount < 0) {
077                            throw new RuntimeException("Input URL does not have any streams");
078                    }
079    
080                    IAudioResampler[] iAudioResamplers =
081                            new IAudioResampler[inputStreamsCount];
082    
083                    IAudioSamples[] inputIAudioSamples =
084                            new IAudioSamples[inputStreamsCount];
085                    IAudioSamples[] outputIAudioSamples =
086                            new IAudioSamples[inputStreamsCount];
087    
088                    IStream[] outputIStreams = new IStream[inputStreamsCount];
089    
090                    IStreamCoder[] inputIStreamCoders = new IStreamCoder[inputStreamsCount];
091                    IStreamCoder[] outputIStreamCoders =
092                            new IStreamCoder[inputStreamsCount];
093    
094                    for (int i = 0; i < inputStreamsCount; i++) {
095                            IStream inputIStream = _inputIContainer.getStream(i);
096    
097                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
098    
099                            inputIStreamCoders[i] = inputIStreamCoder;
100    
101                            ICodec.Type inputICodecType = inputIStreamCoder.getCodecType();
102    
103                            if (inputICodecType == ICodec.Type.CODEC_TYPE_AUDIO) {
104                                    prepareAudio(
105                                            iAudioResamplers, inputIAudioSamples, outputIAudioSamples,
106                                            inputIStreamCoder, outputIStreamCoders, _outputIContainer,
107                                            outputIStreams, inputICodecType, _outputURL, i);
108                            }
109    
110                            openStreamCoder(inputIStreamCoders[i]);
111                            openStreamCoder(outputIStreamCoders[i]);
112                    }
113    
114                    if (_outputIContainer.writeHeader() < 0) {
115                            throw new RuntimeException("Unable to write container header");
116                    }
117    
118                    IPacket inputIPacket = IPacket.make();
119                    IPacket outputIPacket = IPacket.make();
120    
121                    int previousPacketSize = -1;
122    
123                    _inputIContainer.readNextPacket(inputIPacket);
124    
125                    while (_inputIContainer.readNextPacket(inputIPacket) == 0) {
126                            if (_log.isDebugEnabled()) {
127                                    _log.debug("Current packet size " + inputIPacket.getSize());
128                            }
129    
130                            int streamIndex = inputIPacket.getStreamIndex();
131    
132                            IStreamCoder inputIStreamCoder = inputIStreamCoders[streamIndex];
133                            IStreamCoder outputIStreamCoder = outputIStreamCoders[streamIndex];
134    
135                            if (outputIStreamCoder == null) {
136                                    continue;
137                            }
138    
139                            if (inputIStreamCoder.getCodecType() ==
140                                            ICodec.Type.CODEC_TYPE_AUDIO) {
141    
142                                    IStream iStream = _inputIContainer.getStream(streamIndex);
143    
144                                    long timeStampOffset = getStreamTimeStampOffset(iStream);
145    
146                                    decodeAudio(
147                                            iAudioResamplers[streamIndex],
148                                            inputIAudioSamples[streamIndex],
149                                            outputIAudioSamples[streamIndex], inputIPacket,
150                                            outputIPacket, inputIStreamCoder, outputIStreamCoder,
151                                            _outputIContainer, inputIPacket.getSize(),
152                                            previousPacketSize, streamIndex, timeStampOffset);
153                            }
154    
155                            previousPacketSize = inputIPacket.getSize();
156                    }
157    
158                    flush(outputIStreamCoders, _outputIContainer);
159    
160                    if (_outputIContainer.writeTrailer() < 0) {
161                            throw new RuntimeException(
162                                    "Unable to write trailer to output file");
163                    }
164    
165                    cleanUp(iAudioResamplers, null);
166                    cleanUp(inputIAudioSamples, outputIAudioSamples);
167                    cleanUp(inputIStreamCoders, outputIStreamCoders);
168                    cleanUp(inputIPacket, outputIPacket);
169            }
170    
171            @Override
172            protected int getAudioBitRate(ICodec outputICodec, int originalBitRate) {
173                    return getCodecBitRate(
174                            outputICodec,
175                            getProperty(originalBitRate, _audioBitRate, AUDIO_BIT_RATE_MAX));
176            }
177    
178            @Override
179            protected int getAudioSampleRate() {
180                    return _audioSampleRate;
181            }
182    
183            @Override
184            protected IContainer getInputIContainer() {
185                    return _inputIContainer;
186            }
187    
188            protected void initAudioBitRate(Properties audioProperties) {
189                    _audioBitRate = getProperty(
190                            audioProperties, PropsKeys.DL_FILE_ENTRY_PREVIEW_AUDIO_BIT_RATE,
191                            "audio bit rate", _audioContainer, AUDIO_BIT_RATE_DEFAULT,
192                            AUDIO_BIT_RATE_MAX);
193            }
194    
195            protected void initAudioSampleRate(Properties audioProperties) {
196                    _audioSampleRate = getProperty(
197                            audioProperties, PropsKeys.DL_FILE_ENTRY_PREVIEW_AUDIO_SAMPLE_RATE,
198                            "audio sample rate", _audioContainer, AUDIO_SAMPLE_RATE_DEFAULT,
199                            AUDIO_SAMPLE_RATE_MAX);
200            }
201    
202            private static Log _log = LogFactoryUtil.getLog(
203                    LiferayAudioConverter.class);
204    
205            private int _audioBitRate;
206            private String _audioContainer;
207            private int _audioSampleRate;
208            private IContainer _inputIContainer;
209            private String _inputURL;
210            private IContainer _outputIContainer;
211            private String _outputURL;
212    
213    }