001    /**
002     * Copyright (c) 2000-present 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                    if ((originalBitRate == 0) || (originalBitRate > AUDIO_BIT_RATE_MAX)) {
421                            originalBitRate = AUDIO_BIT_RATE_DEFAULT;
422                    }
423    
424                    ICodec.ID iCodecID = outputICodec.getID();
425    
426                    if (iCodecID.equals(ICodec.ID.CODEC_ID_VORBIS)) {
427                            if (originalBitRate < 64000) {
428                                    originalBitRate = 64000;
429                            }
430                    }
431    
432                    return originalBitRate;
433            }
434    
435            protected int getAudioEncodingChannels(
436                    IContainer outputIContainer, int channels) {
437    
438                    IContainerFormat iContainerFormat =
439                            outputIContainer.getContainerFormat();
440    
441                    String outputFormat = iContainerFormat.getOutputFormatShortName();
442    
443                    if (outputFormat.equals("ogg")) {
444                            return 2;
445                    }
446    
447                    if ((channels == 0) || (channels > 2)) {
448                            channels = 2;
449                    }
450    
451                    return channels;
452            }
453    
454            protected ICodec getAudioEncodingICodec(IContainer outputIContainer) {
455                    IContainerFormat iContainerFormat =
456                            outputIContainer.getContainerFormat();
457    
458                    String outputFormat = iContainerFormat.getOutputFormatShortName();
459    
460                    if (outputFormat.equals("ogg")) {
461                            return ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_VORBIS);
462                    }
463    
464                    return null;
465            }
466    
467            protected Format getAudioSampleFormat(
468                    ICodec outputICodec, Format originalSampleFormat) {
469    
470                    Format sampleFormat = null;
471    
472                    List<Format> supportedSampleFormats =
473                            outputICodec.getSupportedAudioSampleFormats();
474    
475                    for (Format supportedSampleFormat : supportedSampleFormats) {
476                            sampleFormat = supportedSampleFormat;
477    
478                            if (supportedSampleFormat == originalSampleFormat) {
479                                    break;
480                            }
481                    }
482    
483                    return sampleFormat;
484            }
485    
486            protected int getAudioSampleRate() {
487                    return AUDIO_SAMPLE_RATE_DEFAULT;
488            }
489    
490            protected abstract IContainer getInputIContainer();
491    
492            protected int getProperty(
493                    int originalValue, int defaultValue, int maxValue) {
494    
495                    if (originalValue <= 0) {
496                            originalValue = defaultValue;
497                    }
498                    else if (originalValue > maxValue) {
499                            originalValue = maxValue;
500                    }
501    
502                    return originalValue;
503            }
504    
505            protected int getProperty(
506                    Properties properties, String propertyName, String prettyPropertyName,
507                    String container, int defaultValue, int maxValue) {
508    
509                    int property = GetterUtil.getInteger(
510                            properties.getProperty(propertyName + "[" + container + "]"),
511                            defaultValue);
512    
513                    if (property > maxValue) {
514                            property = maxValue;
515                    }
516    
517                    if (_log.isInfoEnabled()) {
518                            _log.info(
519                                    "Default " + prettyPropertyName + " for " + container +
520                                            " configured to " + property);
521                    }
522    
523                    return property;
524            }
525    
526            protected long getSeekTimeStamp(int percentage) throws Exception {
527                    IContainer inputIContainer = getInputIContainer();
528    
529                    long seekTimeStamp = -1;
530    
531                    long videoSeconds = inputIContainer.getDuration() / 1000000L;
532    
533                    long seekSeconds = ((videoSeconds * percentage) / 100L);
534    
535                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
536                            IStream inputIStream = inputIContainer.getStream(i);
537    
538                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
539    
540                            if (inputIStreamCoder.getCodecType() !=
541                                            ICodec.Type.CODEC_TYPE_VIDEO) {
542    
543                                    continue;
544                            }
545    
546                            IRational iRational = inputIStream.getTimeBase();
547    
548                            long timeStampOffset =
549                                    iRational.getDenominator() / iRational.getNumerator() *
550                                            seekSeconds;
551    
552                            seekTimeStamp = inputIContainer.getStartTime() + timeStampOffset;
553    
554                            break;
555                    }
556    
557                    return seekTimeStamp;
558            }
559    
560            protected long getStreamTimeStampOffset(IStream iStream) {
561                    long timeStampOffset = 0;
562    
563                    if ((iStream.getStartTime() != Global.NO_PTS) &&
564                            (iStream.getStartTime() > 0) && (iStream.getTimeBase() != null)) {
565    
566                            IRational iRational = IRational.make(
567                                    1, (int)Global.DEFAULT_PTS_PER_SECOND);
568    
569                            timeStampOffset = iRational.rescale(
570                                    iStream.getStartTime(), iStream.getTimeBase());
571                    }
572    
573                    return timeStampOffset;
574            }
575    
576            protected boolean isKeyPacketFound(
577                    IPacket inputIPacket, boolean keyPacketFound) {
578    
579                    if (inputIPacket.isKey() && !keyPacketFound) {
580                            return true;
581                    }
582    
583                    return keyPacketFound;
584            }
585    
586            protected boolean isStartDecoding(
587                    IPacket inputIPacket, IStreamCoder inputIStreamCoder,
588                    boolean keyPacketFound, int nonKeyAfterKeyCount,
589                    boolean onlyDecodeKeyPackets) {
590    
591                    if (onlyDecodeKeyPackets && !inputIPacket.isKey()) {
592                            return false;
593                    }
594    
595                    ICodec.ID iCodecID = inputIStreamCoder.getCodecID();
596    
597                    if (iCodecID.equals(ICodec.ID.CODEC_ID_MJPEG)) {
598                            return true;
599                    }
600                    else if (iCodecID.equals(ICodec.ID.CODEC_ID_MPEG2VIDEO) ||
601                                     iCodecID.equals(ICodec.ID.CODEC_ID_THEORA)) {
602    
603                            if (nonKeyAfterKeyCount != 1) {
604                                    return true;
605                            }
606    
607                            return false;
608                    }
609    
610                    return keyPacketFound;
611            }
612    
613            protected void openContainer(
614                            IContainer iContainer, String url, boolean writeContainer)
615                    throws Exception {
616    
617                    int value = 0;
618    
619                    if (writeContainer) {
620                            value = iContainer.open(url, IContainer.Type.WRITE, null);
621                    }
622                    else {
623                            value = iContainer.open(url, IContainer.Type.READ, null);
624                    }
625    
626                    if (value < 0) {
627                            if (writeContainer) {
628                                    throw new RuntimeException("Unable to open output URL");
629                            }
630                            else {
631                                    throw new RuntimeException("Unable to open input URL");
632                            }
633                    }
634            }
635    
636            protected void openStreamCoder(IStreamCoder iStreamCoder) throws Exception {
637                    if ((iStreamCoder != null) &&
638                            (iStreamCoder.getCodecType() != ICodec.Type.CODEC_TYPE_UNKNOWN)) {
639    
640                            int result = iStreamCoder.setStandardsCompliance(
641                                    IStreamCoder.CodecStandardsCompliance.COMPLIANCE_EXPERIMENTAL);
642    
643                            if (result < 0) {
644                                    throw new RuntimeException(
645                                            "Unable to set compliance mode to experimental");
646                            }
647    
648                            if (iStreamCoder.open(null, null) < 0) {
649                                    throw new RuntimeException("Unable to open coder");
650                            }
651                    }
652            }
653    
654            protected void prepareAudio(
655                            IAudioResampler[] iAudioResamplers,
656                            IAudioSamples[] inputIAudioSamples,
657                            IAudioSamples[] outputIAudioSamples, IStreamCoder inputIStreamCoder,
658                            IStreamCoder[] outputIStreamCoders, IContainer outputIContainer,
659                            IStream[] outputIStreams, ICodec.Type inputICodecType,
660                            String outputURL, int index)
661                    throws Exception {
662    
663                    ICodec iCodec = getAudioEncodingICodec(outputIContainer);
664    
665                    if (iCodec == null) {
666                            iCodec = ICodec.guessEncodingCodec(
667                                    null, null, outputURL, null, inputICodecType);
668                    }
669    
670                    if (iCodec == null) {
671                            throw new RuntimeException(
672                                    "Unable to determine " + inputICodecType + " encoder for " +
673                                            outputURL);
674                    }
675    
676                    IStream outputIStream = outputIContainer.addNewStream(iCodec);
677    
678                    outputIStreams[index] = outputIStream;
679    
680                    IStreamCoder outputIStreamCoder = outputIStream.getStreamCoder();
681    
682                    outputIStreamCoders[index] = outputIStreamCoder;
683    
684                    int bitRate = inputIStreamCoder.getBitRate();
685    
686                    if (_log.isInfoEnabled()) {
687                            _log.info("Original audio bitrate " + bitRate);
688                    }
689    
690                    bitRate = getAudioBitRate(iCodec, bitRate);
691    
692                    if (_log.isInfoEnabled()) {
693                            _log.info("Modified audio bitrate " + bitRate);
694                    }
695    
696                    outputIStreamCoder.setBitRate(bitRate);
697    
698                    int channels = getAudioEncodingChannels(
699                            outputIContainer, inputIStreamCoder.getChannels());
700    
701                    outputIStreamCoder.setChannels(channels);
702    
703                    outputIStreamCoder.setGlobalQuality(0);
704    
705                    Format sampleFormat = inputIStreamCoder.getSampleFormat();
706    
707                    if (_log.isInfoEnabled()) {
708                            _log.info(
709                                    "Original audio sample format " + sampleFormat.toString());
710                    }
711    
712                    sampleFormat = getAudioSampleFormat(iCodec, sampleFormat);
713    
714                    if (_log.isInfoEnabled()) {
715                            _log.info(
716                                    "Modified audio sample format " + sampleFormat.toString());
717                    }
718    
719                    outputIStreamCoder.setSampleFormat(sampleFormat);
720    
721                    outputIStreamCoder.setSampleRate(getAudioSampleRate());
722    
723                    iAudioResamplers[index] = createIAudioResampler(
724                            inputIStreamCoder, outputIStreamCoder);
725    
726                    inputIAudioSamples[index] = IAudioSamples.make(
727                            1024, inputIStreamCoder.getChannels(),
728                            inputIStreamCoder.getSampleFormat());
729                    outputIAudioSamples[index] = IAudioSamples.make(
730                            1024, outputIStreamCoder.getChannels(),
731                            outputIStreamCoder.getSampleFormat());
732            }
733    
734            protected IAudioSamples resampleAudio(
735                            IAudioResampler iAudioResampler, IAudioSamples inputIAudioSample,
736                            IAudioSamples resampledIAudioSample)
737                    throws Exception {
738    
739                    if ((iAudioResampler == null) ||
740                            (inputIAudioSample.getNumSamples() <= 0)) {
741    
742                            return inputIAudioSample;
743                    }
744    
745                    iAudioResampler.resample(
746                            resampledIAudioSample, inputIAudioSample,
747                            inputIAudioSample.getNumSamples());
748    
749                    return resampledIAudioSample;
750            }
751    
752            protected IVideoPicture resampleVideo(
753                            IVideoResampler iVideoResampler, IVideoPicture inputIVideoPicture,
754                            IVideoPicture resampledIVideoPicture)
755                    throws Exception {
756    
757                    if (iVideoResampler == null) {
758                            return inputIVideoPicture;
759                    }
760    
761                    if (iVideoResampler.resample(
762                                    resampledIVideoPicture, inputIVideoPicture) < 0) {
763    
764                            throw new RuntimeException("Unable to resample video");
765                    }
766    
767                    return resampledIVideoPicture;
768            }
769    
770            protected void rewind() throws Exception {
771                    IContainer inputIContainer = getInputIContainer();
772    
773                    if (inputIContainer == null) {
774                            return;
775                    }
776    
777                    int value = 0;
778    
779                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
780                            IStream inputIStream = inputIContainer.getStream(i);
781    
782                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
783    
784                            if (inputIStreamCoder.getCodecType() !=
785                                            ICodec.Type.CODEC_TYPE_VIDEO) {
786    
787                                    continue;
788                            }
789    
790                            value = rewind(i);
791    
792                            if (value < 0) {
793                                    throw new RuntimeException("Error while seeking file");
794                            }
795    
796                            break;
797                    }
798            }
799    
800            protected int rewind(int index) throws Exception {
801                    IContainer inputIContainer = getInputIContainer();
802    
803                    if (inputIContainer == null) {
804                            return -1;
805                    }
806    
807                    int value = inputIContainer.seekKeyFrame(index, -1, 0);
808    
809                    if (value < 0) {
810                            throw new RuntimeException("Error while seeking file");
811                    }
812    
813                    return value;
814            }
815    
816            protected int seek(int index, long timeStamp) throws Exception {
817                    IContainer inputIContainer = getInputIContainer();
818    
819                    if (inputIContainer == null) {
820                            return -1;
821                    }
822    
823                    int value = inputIContainer.seekKeyFrame(index, timeStamp, 0);
824    
825                    if (value < 0) {
826                            throw new RuntimeException("Error while seeking file");
827                    }
828    
829                    return value;
830            }
831    
832            protected long seek(long timeStamp) throws Exception {
833                    IContainer inputIContainer = getInputIContainer();
834    
835                    if (inputIContainer == null) {
836                            return -1;
837                    }
838    
839                    int value = 0;
840    
841                    for (int i = 0; i < inputIContainer.getNumStreams(); i++) {
842                            IStream inputIStream = inputIContainer.getStream(i);
843    
844                            IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
845    
846                            if (inputIStreamCoder.getCodecType() !=
847                                            ICodec.Type.CODEC_TYPE_VIDEO) {
848    
849                                    continue;
850                            }
851    
852                            value = seek(i, timeStamp);
853    
854                            if (value < 0) {
855                                    throw new RuntimeException("Error while seeking file");
856                            }
857    
858                            break;
859                    }
860    
861                    return value;
862            }
863    
864            protected void updateAudioTimeStamp(
865                    IAudioSamples inputAudioSample, long timeStampOffset) {
866    
867                    if (inputAudioSample.getTimeStamp() != Global.NO_PTS) {
868                            inputAudioSample.setTimeStamp(
869                                    inputAudioSample.getTimeStamp() - timeStampOffset);
870                    }
871            }
872    
873            protected void updateVideoTimeStamp(
874                    IVideoPicture inputIVideoPicture, long timeStampOffset) {
875    
876                    if (inputIVideoPicture.getTimeStamp() != Global.NO_PTS) {
877                            inputIVideoPicture.setTimeStamp(
878                                    inputIVideoPicture.getTimeStamp() - timeStampOffset);
879                    }
880            }
881    
882            protected static final int AUDIO_BIT_RATE_DEFAULT = 64000;
883    
884            protected static final int AUDIO_BIT_RATE_MAX = 500000;
885    
886            protected static final int AUDIO_SAMPLE_RATE_DEFAULT = 44100;
887    
888            protected static final int AUDIO_SAMPLE_RATE_MAX = 192000;
889    
890            protected static final int DECODE_VIDEO_THUMBNAIL = 2;
891    
892            private static Log _log = LogFactoryUtil.getLog(LiferayConverter.class);
893    
894            private ConverterFactory.Type _converterFactoryType;
895            private IConverter _videoIConverter;
896    
897    }