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.image.ImageToolImpl;
018    import com.liferay.portal.kernel.image.ImageTool;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    
023    import com.xuggle.ferry.RefCounted;
024    import com.xuggle.xuggler.Global;
025    import com.xuggle.xuggler.IAudioResampler;
026    import com.xuggle.xuggler.IAudioSamples;
027    import com.xuggle.xuggler.IAudioSamples.Format;
028    import com.xuggle.xuggler.ICodec;
029    import com.xuggle.xuggler.IContainer;
030    import com.xuggle.xuggler.IContainerFormat;
031    import com.xuggle.xuggler.IPacket;
032    import com.xuggle.xuggler.IPixelFormat;
033    import com.xuggle.xuggler.IRational;
034    import com.xuggle.xuggler.IStream;
035    import com.xuggle.xuggler.IStreamCoder;
036    import com.xuggle.xuggler.IVideoPicture;
037    import com.xuggle.xuggler.IVideoResampler;
038    import com.xuggle.xuggler.video.ConverterFactory;
039    import com.xuggle.xuggler.video.IConverter;
040    
041    import java.awt.image.BufferedImage;
042    import java.awt.image.RenderedImage;
043    
044    import java.io.File;
045    import java.io.FileOutputStream;
046    
047    import java.util.List;
048    import java.util.Properties;
049    
050    import javax.imageio.ImageIO;
051    
052    /**
053     * @author Juan Gonz??lez
054     * @author Sergio Gonz??lez
055     * @author Brian Wing Shun Chan
056     * @author Alexander Chow
057     */
058    public abstract class LiferayConverter {
059    
060            public abstract void convert() throws Exception;
061    
062            protected void cleanUp(IPacket inputIPacket, IPacket outputIPacket) {
063                    if (inputIPacket != null) {
064                            inputIPacket.delete();
065                    }
066    
067                    if (outputIPacket != null) {
068                            outputIPacket.delete();
069                    }
070            }
071    
072            protected void cleanUp(
073                    IStreamCoder[] inputIStreamCoders, IStreamCoder[] outputIStreamCoders) {
074    
075                    if (inputIStreamCoders != null) {
076                            for (IStreamCoder iStreamCoder : inputIStreamCoders) {
077                                    if (iStreamCoder != null) {
078                                            iStreamCoder.close();
079                                    }
080                            }
081                    }
082    
083                    if (outputIStreamCoders != null) {
084                            for (IStreamCoder iStreamCoder : outputIStreamCoders) {
085                                    if (iStreamCoder != null) {
086                                            iStreamCoder.close();
087                                    }
088                            }
089                    }
090            }
091    
092            protected void cleanUp(
093                    RefCounted[] inputRefCountedArray, RefCounted[] outputRefCountedArray) {
094    
095                    if (inputRefCountedArray != null) {
096                            for (RefCounted refCounted : inputRefCountedArray) {
097                                    if (refCounted != null) {
098                                            refCounted.delete();
099                                    }
100                            }
101                    }
102    
103                    if (outputRefCountedArray != null) {
104                            for (RefCounted refCounted : outputRefCountedArray) {
105                                    if (refCounted != null) {
106                                            refCounted.delete();
107                                    }
108                            }
109                    }
110            }
111    
112            protected int countNonKeyAfterKey(
113                    IPacket inputIPacket, Boolean keyPacketFound, int nonKeyAfterKeyCount) {
114    
115                    if (inputIPacket.isKey()) {
116                            nonKeyAfterKeyCount = 0;
117                    }
118                    else if (keyPacketFound) {
119                            nonKeyAfterKeyCount++;
120                    }
121    
122                    return nonKeyAfterKeyCount;
123            }
124    
125            protected IAudioResampler createIAudioResampler(
126                            IStreamCoder inputIStreamCoder, IStreamCoder outputIStreamCoder)
127                    throws Exception {
128    
129                    IAudioResampler iAudioResampler = null;
130    
131                    Format inputSampleFormat = inputIStreamCoder.getSampleFormat();
132                    Format outputSampleFormat = outputIStreamCoder.getSampleFormat();
133    
134                    if ((inputIStreamCoder.getChannels() ==
135                                    outputIStreamCoder.getChannels()) &&
136                            (inputIStreamCoder.getSampleRate() ==
137                                    outputIStreamCoder.getSampleRate()) &&
138                            inputSampleFormat.equals(outputSampleFormat)) {
139    
140                            return iAudioResampler;
141                    }
142    
143                    iAudioResampler = IAudioResampler.make(
144                            outputIStreamCoder.getChannels(), inputIStreamCoder.getChannels(),
145                            outputIStreamCoder.getSampleRate(),
146                            inputIStreamCoder.getSampleRate(),
147                            outputIStreamCoder.getSampleFormat(),
148                            inputIStreamCoder.getSampleFormat());
149    
150                    if (iAudioResampler == null) {
151                            throw new RuntimeException("Audio resampling is not supported");
152                    }
153    
154                    return iAudioResampler;
155            }
156    
157            protected IVideoResampler createIVideoResampler(
158                            IStreamCoder inputIStreamCoder, IStreamCoder outputIStreamCoder,
159                            int height, int width)
160                    throws Exception {
161    
162                    IVideoResampler iVideoResampler = null;
163    
164                    IPixelFormat.Type inputIPixelFormatType =
165                            inputIStreamCoder.getPixelType();
166                    IPixelFormat.Type outputIPixelFormatType =
167                            outputIStreamCoder.getPixelType();
168    
169                    if ((height == inputIStreamCoder.getHeight()) &&
170                            (width == inputIStreamCoder.getWidth()) &&
171                            inputIPixelFormatType.equals(outputIPixelFormatType)) {
172    
173                            return iVideoResampler;
174                    }
175    
176                    iVideoResampler = IVideoResampler.make(
177                            width, height, outputIStreamCoder.getPixelType(),
178                            inputIStreamCoder.getWidth(), inputIStreamCoder.getHeight(),
179                            inputIStreamCoder.getPixelType());
180    
181                    if (iVideoResampler == null) {
182                            throw new RuntimeException("Video resampling is not supported");
183                    }
184    
185                    return iVideoResampler;
186            }
187    
188            protected void decodeAudio(
189                            IAudioResampler iAudioResampler, IAudioSamples inputIAudioSample,
190                            IAudioSamples resampledIAudioSample, IPacket inputIPacket,
191                            IPacket outputIPacket, IStreamCoder inputIStreamCoder,
192                            IStreamCoder outputIStreamCoder, IContainer outputIContainer,
193                            int currentPacketSize, int previousPacketSize, int streamIndex,
194                            long timeStampOffset)
195                    throws Exception {
196    
197                    int offset = 0;
198    
199                    while (offset < inputIPacket.getSize()) {
200                            boolean stopDecoding = false;
201    
202                            int value = inputIStreamCoder.decodeAudio(
203                                    inputIAudioSample, inputIPacket, offset);
204    
205                            if (value <= 0) {
206                                    if ((previousPacketSize == currentPacketSize) &&
207                                            (previousPacketSize != -1)) {
208    
209                                            throw new RuntimeException(
210                                                    "Unable to decode audio stream " + streamIndex);
211                                    }
212                                    else {
213                                            stopDecoding = true;
214                                    }
215                            }
216    
217                            updateAudioTimeStamp(inputIAudioSample, timeStampOffset);
218    
219                            offset += value;
220    
221                            IAudioSamples outputIAudioSample = resampleAudio(
222                                    iAudioResampler, inputIAudioSample, resampledIAudioSample);
223    
224                            encodeAudio(
225                                    outputIStreamCoder, outputIPacket, outputIAudioSample,
226                                    outputIContainer);
227    
228                            if (stopDecoding) {
229                                    if (_log.isDebugEnabled()) {
230                                            _log.debug("Stop decoding audio stream " + streamIndex);
231                                    }
232    
233                                    break;
234                            }
235                    }
236            }
237    
238            protected int decodeVideo(
239                            IVideoResampler iVideoResampler, IVideoPicture inputIVideoPicture,
240                            IVideoPicture resampledIVideoPicture, IPacket inputIPacket,
241                            IPacket outputIPacket, IStreamCoder inputIStreamCoder,
242                            IStreamCoder outputIStreamCoder, IContainer outputIContainer,
243                            File thumbnailFile, String thumbnailExtension, int thumbnailHeight,
244                            int thumbnailWidth, long timeStampOffset)
245                    throws Exception {
246    
247                    int offset = 0;
248    
249                    boolean stopDecoding = false;
250    
251                    while (offset < inputIPacket.getSize()) {
252                            int value = inputIStreamCoder.decodeVideo(
253                                    inputIVideoPicture, inputIPacket, offset);
254    
255                            if (value <= 0) {
256                                    return value;
257                            }
258    
259                            updateVideoTimeStamp(inputIVideoPicture, timeStampOffset);
260    
261                            offset += value;
262    
263                            // Workaround for FFmpeg bug. See
264                            // http://comments.gmane.org/gmane.comp.video.ffmpeg.devel/135657
265    
266                            ICodec.ID iCodecID = inputIStreamCoder.getCodecID();
267    
268                            if (iCodecID.equals(ICodec.ID.CODEC_ID_MJPEG)) {
269                                    stopDecoding = true;
270                            }
271    
272                            if (!inputIVideoPicture.isComplete()) {
273                                    if (stopDecoding) {
274                                            return 1;
275                                    }
276    
277                                    continue;
278                            }
279    
280                            if (thumbnailFile != null) {
281                                    BufferedImage bufferedImage = null;
282    
283                                    if (_converterFactoryType == null) {
284                                            _converterFactoryType =
285                                                    ConverterFactory.findRegisteredConverter(
286                                                            ConverterFactory.XUGGLER_BGR_24);
287                                    }
288    
289                                    if (_converterFactoryType == null) {
290                                            throw new UnsupportedOperationException(
291                                                    "No converter found for " +
292                                                            ConverterFactory.XUGGLER_BGR_24);
293                                    }
294    
295                                    if (_videoIConverter == null) {
296                                            _videoIConverter = ConverterFactory.createConverter(
297                                                    _converterFactoryType.getDescriptor(),
298                                                    inputIVideoPicture);
299                                    }
300    
301                                    bufferedImage = _videoIConverter.toImage(inputIVideoPicture);
302    
303                                    thumbnailFile.createNewFile();
304    
305                                    ImageTool imageTool = ImageToolImpl.getInstance();
306    
307                                    RenderedImage renderedImage = imageTool.scale(
308                                            bufferedImage, thumbnailHeight, thumbnailWidth);
309    
310                                    ImageIO.write(
311                                            renderedImage, thumbnailExtension,
312                                            new FileOutputStream(thumbnailFile));
313    
314                                    return DECODE_VIDEO_THUMBNAIL;
315                            }
316    
317                            if ((outputIStreamCoder != null) && (outputIContainer != null)) {
318                                    IVideoPicture outputIVideoPicture = resampleVideo(
319                                            iVideoResampler, inputIVideoPicture,
320                                            resampledIVideoPicture);
321    
322                                    outputIVideoPicture.setQuality(0);
323    
324                                    encodeVideo(
325                                            outputIStreamCoder, outputIVideoPicture, outputIPacket,
326                                            outputIContainer);
327                            }
328    
329                            if (stopDecoding) {
330                                    break;
331                            }
332                    }
333    
334                    return 1;
335            }
336    
337            protected void encodeAudio(
338                            IStreamCoder outputIStreamCoder, IPacket outputIPacket,
339                            IAudioSamples outputIAudioSample, IContainer outputIContainer)
340                    throws Exception {
341    
342                    int consumedSamplesCount = 0;
343    
344                    while (consumedSamplesCount < outputIAudioSample.getNumSamples()) {
345                            int value = outputIStreamCoder.encodeAudio(
346                                    outputIPacket, outputIAudioSample, consumedSamplesCount);
347    
348                            if (value <= 0) {
349                                    throw new RuntimeException("Unable to encode audio");
350                            }
351    
352                            consumedSamplesCount += value;
353    
354                            if (outputIPacket.isComplete()) {
355                                    value = outputIContainer.writePacket(outputIPacket, true);
356    
357                                    if (value < 0) {
358                                            throw new RuntimeException("Unable to write audio packet");
359                                    }
360                            }
361                    }
362            }
363    
364            protected void encodeVideo(
365                            IStreamCoder outputIStreamCoder, IVideoPicture outputIVideoPicture,
366                            IPacket outputIPacket, IContainer outputIContainer)
367                    throws Exception {
368    
369                    int value = outputIStreamCoder.encodeVideo(
370                            outputIPacket, outputIVideoPicture, 0);
371    
372                    if (value < 0) {
373                            throw new RuntimeException("Unable to encode video");
374                    }
375    
376                    if (outputIPacket.isComplete()) {
377                            value = outputIContainer.writePacket(outputIPacket, true);
378    
379                            if (value < 0) {
380                                    throw new RuntimeException("Unable to write video packet");
381                            }
382                    }
383            }
384    
385            protected void flush(
386                    IStreamCoder outputIStreamCoder, IContainer outputIContainer,
387                    IPacket iPacket) {
388    
389                    if (outputIStreamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
390                            outputIStreamCoder.encodeAudio(iPacket, null, 0);
391                    }
392                    else {
393                            outputIStreamCoder.encodeVideo(iPacket, null, 0);
394                    }
395    
396                    if (iPacket.isComplete()) {
397                            outputIContainer.writePacket(iPacket, true);
398                    }
399            }
400    
401            protected void flush(
402                    IStreamCoder[] outputIStreamCoders, IContainer outputIContainer) {
403    
404                    for (IStreamCoder outputIStreamCoder : outputIStreamCoders) {
405                            if (outputIStreamCoder == null) {
406                                    continue;
407                            }
408    
409                            IPacket iPacket = IPacket.make();
410    
411                            flush(outputIStreamCoder, outputIContainer, iPacket);
412    
413                            while (iPacket.isComplete()) {
414                                    flush(outputIStreamCoder, outputIContainer, iPacket);
415                            }
416                    }
417            }
418    
419            protected int getAudioBitRate(ICodec outputICodec, int originalBitRate) {
420                    return getCodecBitRate(
421                            outputICodec,
422                            getProperty(
423                                    originalBitRate, AUDIO_BIT_RATE_DEFAULT, AUDIO_BIT_RATE_MAX));
424            }
425    
426            protected int getAudioEncodingChannels(
427                    IContainer outputIContainer, int channels) {
428    
429                    IContainerFormat iContainerFormat =
430                            outputIContainer.getContainerFormat();
431    
432                    String outputFormat = iContainerFormat.getOutputFormatShortName();
433    
434                    if (outputFormat.equals("ogg")) {
435                            return 2;
436                    }
437    
438                    if ((channels == 0) || (channels > 2)) {
439                            channels = 2;
440                    }
441    
442                    return channels;
443            }
444    
445            protected ICodec getAudioEncodingICodec(IContainer outputIContainer) {
446                    IContainerFormat iContainerFormat =
447                            outputIContainer.getContainerFormat();
448    
449                    String outputFormat = iContainerFormat.getOutputFormatShortName();
450    
451                    if (outputFormat.equals("ogg")) {
452                            return ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_VORBIS);
453                    }
454    
455                    return null;
456            }
457    
458            protected Format getAudioSampleFormat(
459                    ICodec outputICodec, Format originalSampleFormat) {
460    
461                    Format sampleFormat = null;
462    
463                    List<Format> supportedSampleFormats =
464                            outputICodec.getSupportedAudioSampleFormats();
465    
466                    for (Format supportedSampleFormat : supportedSampleFormats) {
467                            sampleFormat = supportedSampleFormat;
468    
469                            if (supportedSampleFormat == originalSampleFormat) {
470                                    break;
471                            }
472                    }
473    
474                    return sampleFormat;
475            }
476    
477            protected int getAudioSampleRate() {
478                    return AUDIO_SAMPLE_RATE_DEFAULT;
479            }
480    
481            protected int getCodecBitRate(ICodec outputICodec, int originalBitRate) {
482                    if ((originalBitRate == 0) || (originalBitRate > AUDIO_BIT_RATE_MAX)) {
483                            originalBitRate = AUDIO_BIT_RATE_DEFAULT;
484                    }
485    
486                    ICodec.ID iCodecID = outputICodec.getID();
487    
488                    if (iCodecID.equals(ICodec.ID.CODEC_ID_VORBIS)) {
489                            if (originalBitRate < 64000) {
490                                    return 64000;
491                            }
492                    }
493    
494                    return originalBitRate;
495            }
496    
497            protected abstract IContainer getInputIContainer();
498    
499            protected int getProperty(
500                    int originalValue, int defaultValue, int maxValue) {
501    
502                    if (originalValue <= 0) {
503                            return defaultValue;
504                    }
505                    else if (originalValue > maxValue) {
506                            return maxValue;
507                    }
508    
509                    return originalValue;
510            }
511    
512            protected int getProperty(
513                    Properties properties, String propertyName, String prettyPropertyName,
514                    String container, int defaultValue, int maxValue) {
515    
516                    int property = GetterUtil.getInteger(
517                            properties.getProperty(propertyName + "[" + container + "]"),
518                            defaultValue);
519    
520                    if (property > maxValue) {
521                            property = maxValue;
522                    }
523    
524                    if (_log.isInfoEnabled()) {
525                            _log.info(
526                                    "Default " + prettyPropertyName + " for " + container +
527                                            " configured to " + property);
528                    }
529    
530                    return property;
531            }
532    
533            protected long getSeekTimeStamp(int percentage) throws Exception {
534                    IContainer inputIContainer = getInputIContainer();
535    
536                    long seekTimeStamp = -1;
537    
538                    long videoSeconds = inputIContainer.getDuration() / 1000000L;
539    
540                    long seekSeconds = ((videoSeconds * percentage) / 100L);
541    
542                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
543                            IStream inputIStream = inputIContainer.getStream(i);
544    
545                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
546    
547                            if (inputIStreamCoder.getCodecType() !=
548                                            ICodec.Type.CODEC_TYPE_VIDEO) {
549    
550                                    continue;
551                            }
552    
553                            IRational iRational = inputIStream.getTimeBase();
554    
555                            long timeStampOffset =
556                                    iRational.getDenominator() / iRational.getNumerator() *
557                                            seekSeconds;
558    
559                            seekTimeStamp = inputIContainer.getStartTime() + timeStampOffset;
560    
561                            break;
562                    }
563    
564                    return seekTimeStamp;
565            }
566    
567            protected long getStreamTimeStampOffset(IStream iStream) {
568                    long timeStampOffset = 0;
569    
570                    if ((iStream.getStartTime() != Global.NO_PTS) &&
571                            (iStream.getStartTime() > 0) && (iStream.getTimeBase() != null)) {
572    
573                            IRational iRational = IRational.make(
574                                    1, (int)Global.DEFAULT_PTS_PER_SECOND);
575    
576                            timeStampOffset = iRational.rescale(
577                                    iStream.getStartTime(), iStream.getTimeBase());
578                    }
579    
580                    return timeStampOffset;
581            }
582    
583            protected boolean isKeyPacketFound(
584                    IPacket inputIPacket, boolean keyPacketFound) {
585    
586                    if (inputIPacket.isKey() && !keyPacketFound) {
587                            return true;
588                    }
589    
590                    return keyPacketFound;
591            }
592    
593            protected boolean isStartDecoding(
594                    IPacket inputIPacket, IStreamCoder inputIStreamCoder,
595                    boolean keyPacketFound, int nonKeyAfterKeyCount,
596                    boolean onlyDecodeKeyPackets) {
597    
598                    if (onlyDecodeKeyPackets && !inputIPacket.isKey()) {
599                            return false;
600                    }
601    
602                    ICodec.ID iCodecID = inputIStreamCoder.getCodecID();
603    
604                    if (iCodecID.equals(ICodec.ID.CODEC_ID_MJPEG)) {
605                            return true;
606                    }
607                    else if (iCodecID.equals(ICodec.ID.CODEC_ID_MPEG2VIDEO) ||
608                                     iCodecID.equals(ICodec.ID.CODEC_ID_THEORA)) {
609    
610                            if (nonKeyAfterKeyCount != 1) {
611                                    return true;
612                            }
613    
614                            return false;
615                    }
616    
617                    return keyPacketFound;
618            }
619    
620            protected void openContainer(
621                            IContainer iContainer, String url, boolean writeContainer)
622                    throws Exception {
623    
624                    int value = 0;
625    
626                    if (writeContainer) {
627                            value = iContainer.open(url, IContainer.Type.WRITE, null);
628                    }
629                    else {
630                            value = iContainer.open(url, IContainer.Type.READ, null);
631                    }
632    
633                    if (value < 0) {
634                            if (writeContainer) {
635                                    throw new RuntimeException("Unable to open output URL");
636                            }
637                            else {
638                                    throw new RuntimeException("Unable to open input URL");
639                            }
640                    }
641            }
642    
643            protected void openStreamCoder(IStreamCoder iStreamCoder) throws Exception {
644                    if ((iStreamCoder != null) &&
645                            (iStreamCoder.getCodecType() != ICodec.Type.CODEC_TYPE_UNKNOWN)) {
646    
647                            int result = iStreamCoder.setStandardsCompliance(
648                                    IStreamCoder.CodecStandardsCompliance.COMPLIANCE_EXPERIMENTAL);
649    
650                            if (result < 0) {
651                                    throw new RuntimeException(
652                                            "Unable to set compliance mode to experimental");
653                            }
654    
655                            if (iStreamCoder.open(null, null) < 0) {
656                                    throw new RuntimeException("Unable to open coder");
657                            }
658                    }
659            }
660    
661            protected void prepareAudio(
662                            IAudioResampler[] iAudioResamplers,
663                            IAudioSamples[] inputIAudioSamples,
664                            IAudioSamples[] outputIAudioSamples, IStreamCoder inputIStreamCoder,
665                            IStreamCoder[] outputIStreamCoders, IContainer outputIContainer,
666                            IStream[] outputIStreams, ICodec.Type inputICodecType,
667                            String outputURL, int index)
668                    throws Exception {
669    
670                    ICodec iCodec = getAudioEncodingICodec(outputIContainer);
671    
672                    if (iCodec == null) {
673                            iCodec = ICodec.guessEncodingCodec(
674                                    null, null, outputURL, null, inputICodecType);
675                    }
676    
677                    if (iCodec == null) {
678                            throw new RuntimeException(
679                                    "Unable to determine " + inputICodecType + " encoder for " +
680                                            outputURL);
681                    }
682    
683                    IStream outputIStream = outputIContainer.addNewStream(iCodec);
684    
685                    outputIStreams[index] = outputIStream;
686    
687                    IStreamCoder outputIStreamCoder = outputIStream.getStreamCoder();
688    
689                    outputIStreamCoders[index] = outputIStreamCoder;
690    
691                    int bitRate = inputIStreamCoder.getBitRate();
692    
693                    if (_log.isInfoEnabled()) {
694                            _log.info("Original audio bitrate " + bitRate);
695                    }
696    
697                    bitRate = getAudioBitRate(iCodec, bitRate);
698    
699                    if (_log.isInfoEnabled()) {
700                            _log.info("Modified audio bitrate " + bitRate);
701                    }
702    
703                    outputIStreamCoder.setBitRate(bitRate);
704    
705                    int channels = getAudioEncodingChannels(
706                            outputIContainer, inputIStreamCoder.getChannels());
707    
708                    outputIStreamCoder.setChannels(channels);
709    
710                    outputIStreamCoder.setGlobalQuality(0);
711    
712                    Format sampleFormat = inputIStreamCoder.getSampleFormat();
713    
714                    if (_log.isInfoEnabled()) {
715                            _log.info(
716                                    "Original audio sample format " + sampleFormat.toString());
717                    }
718    
719                    sampleFormat = getAudioSampleFormat(iCodec, sampleFormat);
720    
721                    if (_log.isInfoEnabled()) {
722                            _log.info(
723                                    "Modified audio sample format " + sampleFormat.toString());
724                    }
725    
726                    outputIStreamCoder.setSampleFormat(sampleFormat);
727    
728                    outputIStreamCoder.setSampleRate(getAudioSampleRate());
729    
730                    iAudioResamplers[index] = createIAudioResampler(
731                            inputIStreamCoder, outputIStreamCoder);
732    
733                    inputIAudioSamples[index] = IAudioSamples.make(
734                            1024, inputIStreamCoder.getChannels(),
735                            inputIStreamCoder.getSampleFormat());
736                    outputIAudioSamples[index] = IAudioSamples.make(
737                            1024, outputIStreamCoder.getChannels(),
738                            outputIStreamCoder.getSampleFormat());
739            }
740    
741            protected IAudioSamples resampleAudio(
742                            IAudioResampler iAudioResampler, IAudioSamples inputIAudioSample,
743                            IAudioSamples resampledIAudioSample)
744                    throws Exception {
745    
746                    if ((iAudioResampler == null) ||
747                            (inputIAudioSample.getNumSamples() <= 0)) {
748    
749                            return inputIAudioSample;
750                    }
751    
752                    iAudioResampler.resample(
753                            resampledIAudioSample, inputIAudioSample,
754                            inputIAudioSample.getNumSamples());
755    
756                    return resampledIAudioSample;
757            }
758    
759            protected IVideoPicture resampleVideo(
760                            IVideoResampler iVideoResampler, IVideoPicture inputIVideoPicture,
761                            IVideoPicture resampledIVideoPicture)
762                    throws Exception {
763    
764                    if (iVideoResampler == null) {
765                            return inputIVideoPicture;
766                    }
767    
768                    if (iVideoResampler.resample(
769                                    resampledIVideoPicture, inputIVideoPicture) < 0) {
770    
771                            throw new RuntimeException("Unable to resample video");
772                    }
773    
774                    return resampledIVideoPicture;
775            }
776    
777            protected void rewind() throws Exception {
778                    IContainer inputIContainer = getInputIContainer();
779    
780                    if (inputIContainer == null) {
781                            return;
782                    }
783    
784                    int value = 0;
785    
786                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
787                            IStream inputIStream = inputIContainer.getStream(i);
788    
789                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
790    
791                            if (inputIStreamCoder.getCodecType() !=
792                                            ICodec.Type.CODEC_TYPE_VIDEO) {
793    
794                                    continue;
795                            }
796    
797                            value = rewind(i);
798    
799                            if (value < 0) {
800                                    throw new RuntimeException("Error while seeking file");
801                            }
802    
803                            break;
804                    }
805            }
806    
807            protected int rewind(int index) throws Exception {
808                    IContainer inputIContainer = getInputIContainer();
809    
810                    if (inputIContainer == null) {
811                            return -1;
812                    }
813    
814                    int value = inputIContainer.seekKeyFrame(index, -1, 0);
815    
816                    if (value < 0) {
817                            throw new RuntimeException("Error while seeking file");
818                    }
819    
820                    return value;
821            }
822    
823            protected int seek(int index, long timeStamp) throws Exception {
824                    IContainer inputIContainer = getInputIContainer();
825    
826                    if (inputIContainer == null) {
827                            return -1;
828                    }
829    
830                    int value = inputIContainer.seekKeyFrame(index, timeStamp, 0);
831    
832                    if (value < 0) {
833                            throw new RuntimeException("Error while seeking file");
834                    }
835    
836                    return value;
837            }
838    
839            protected long seek(long timeStamp) throws Exception {
840                    IContainer inputIContainer = getInputIContainer();
841    
842                    if (inputIContainer == null) {
843                            return -1;
844                    }
845    
846                    int value = 0;
847    
848                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
849                            IStream inputIStream = inputIContainer.getStream(i);
850    
851                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
852    
853                            if (inputIStreamCoder.getCodecType() !=
854                                            ICodec.Type.CODEC_TYPE_VIDEO) {
855    
856                                    continue;
857                            }
858    
859                            value = seek(i, timeStamp);
860    
861                            if (value < 0) {
862                                    throw new RuntimeException("Error while seeking file");
863                            }
864    
865                            break;
866                    }
867    
868                    return value;
869            }
870    
871            protected void updateAudioTimeStamp(
872                    IAudioSamples inputAudioSample, long timeStampOffset) {
873    
874                    if (inputAudioSample.getTimeStamp() != Global.NO_PTS) {
875                            inputAudioSample.setTimeStamp(
876                                    inputAudioSample.getTimeStamp() - timeStampOffset);
877                    }
878            }
879    
880            protected void updateVideoTimeStamp(
881                    IVideoPicture inputIVideoPicture, long timeStampOffset) {
882    
883                    if (inputIVideoPicture.getTimeStamp() != Global.NO_PTS) {
884                            inputIVideoPicture.setTimeStamp(
885                                    inputIVideoPicture.getTimeStamp() - timeStampOffset);
886                    }
887            }
888    
889            protected static final int AUDIO_BIT_RATE_DEFAULT = 64000;
890    
891            protected static final int AUDIO_BIT_RATE_MAX = 500000;
892    
893            protected static final int AUDIO_SAMPLE_RATE_DEFAULT = 44100;
894    
895            protected static final int AUDIO_SAMPLE_RATE_MAX = 192000;
896    
897            protected static final int DECODE_VIDEO_THUMBNAIL = 2;
898    
899            private static Log _log = LogFactoryUtil.getLog(LiferayConverter.class);
900    
901            private ConverterFactory.Type _converterFactoryType;
902            private IConverter _videoIConverter;
903    
904    }