001
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
020 import com.xuggle.xuggler.ICodec;
021 import com.xuggle.xuggler.IContainer;
022 import com.xuggle.xuggler.IPacket;
023 import com.xuggle.xuggler.IStream;
024 import com.xuggle.xuggler.IStreamCoder;
025 import com.xuggle.xuggler.IVideoPicture;
026
027 import java.io.File;
028
029
034 public class LiferayVideoThumbnailConverter extends LiferayConverter {
035
036 public LiferayVideoThumbnailConverter(
037 String inputURL, File outputFile, String extension, int height,
038 int width, int percentage) {
039
040 _inputURL = inputURL;
041 _outputFile = outputFile;
042 _extension = extension;
043 _height = height;
044 _width = width;
045 _percentage = percentage;
046 }
047
048 @Override
049 public void convert() throws Exception {
050 try {
051 doConvert();
052 }
053 finally {
054 if (_inputIContainer.isOpened()) {
055 _inputIContainer.close();
056 }
057 }
058 }
059
060 protected void doConvert() throws Exception {
061 _inputIContainer = IContainer.make();
062
063 openContainer(_inputIContainer, _inputURL, false);
064
065 long seekTimeStamp = -1;
066
067 if ((_percentage > 0) && (_percentage <= 100)) {
068 seekTimeStamp = getSeekTimeStamp(_percentage);
069 }
070
071 int inputStreamsCount = _inputIContainer.getNumStreams();
072
073 if (inputStreamsCount < 0) {
074 throw new RuntimeException("Input URL does not have any streams");
075 }
076
077 IVideoPicture[] inputIVideoPictures =
078 new IVideoPicture[inputStreamsCount];
079
080 IStreamCoder[] inputIStreamCoders = new IStreamCoder[inputStreamsCount];
081
082 for (int i = 0; i < inputStreamsCount; i++) {
083 IStream inputIStream = _inputIContainer.getStream(i);
084
085 IStreamCoder inputIStreamCoder = inputIStream.getStreamCoder();
086
087 inputIStreamCoders[i] = inputIStreamCoder;
088
089 if (inputIStreamCoder.getCodecType() ==
090 ICodec.Type.CODEC_TYPE_VIDEO) {
091
092 inputIVideoPictures[i] = IVideoPicture.make(
093 inputIStreamCoder.getPixelType(),
094 inputIStreamCoder.getWidth(),
095 inputIStreamCoder.getHeight());
096 }
097
098 openStreamCoder(inputIStreamCoder);
099 }
100
101 boolean thumbnailGenerated = false;
102
103 try {
104 if (seekTimeStamp != -1) {
105 rewind();
106
107 seek(seekTimeStamp);
108 }
109
110 thumbnailGenerated = generateThumbnail(
111 inputIStreamCoders, inputIVideoPictures);
112 }
113 catch (Exception e) {
114 }
115
116 if (!thumbnailGenerated) {
117 if (_log.isWarnEnabled()) {
118 _log.warn(
119 "Unable to create thumbnail from specified frame. Will " +
120 "generate thumbnail from the beginning.");
121 }
122
123 rewind();
124
125 generateThumbnail(inputIStreamCoders, inputIVideoPictures);
126 }
127
128 cleanUp(inputIVideoPictures, null);
129 cleanUp(inputIStreamCoders, null);
130 }
131
132 protected boolean generateThumbnail(
133 IStreamCoder[] inputIStreamCoders,
134 IVideoPicture[] inputIVideoPictures)
135 throws Exception {
136
137 boolean keyPacketFound = false;
138 int nonKeyAfterKeyCount = 0;
139 boolean onlyDecodeKeyPackets = false;
140
141 IPacket inputIPacket = IPacket.make();
142
143 while (_inputIContainer.readNextPacket(inputIPacket) == 0) {
144 if (_log.isDebugEnabled()) {
145 _log.debug("Current packet size " + inputIPacket.getSize());
146 }
147
148 int streamIndex = inputIPacket.getStreamIndex();
149
150 IStreamCoder inputIStreamCoder = inputIStreamCoders[streamIndex];
151
152 if (inputIStreamCoder.getCodecType() !=
153 ICodec.Type.CODEC_TYPE_VIDEO) {
154
155 continue;
156 }
157
158 keyPacketFound = isKeyPacketFound(inputIPacket, keyPacketFound);
159
160 nonKeyAfterKeyCount = countNonKeyAfterKey(
161 inputIPacket, keyPacketFound, nonKeyAfterKeyCount);
162
163 if (isStartDecoding(
164 inputIPacket, inputIStreamCoder, keyPacketFound,
165 nonKeyAfterKeyCount, onlyDecodeKeyPackets)) {
166
167 IStream iStream = _inputIContainer.getStream(streamIndex);
168
169 long timeStampOffset = getStreamTimeStampOffset(iStream);
170
171 int value = decodeVideo(
172 null, inputIVideoPictures[streamIndex], null, inputIPacket,
173 null, inputIStreamCoder, null, null, _outputFile,
174 _extension, _height, _width, timeStampOffset);
175
176 if (value <= 0) {
177 if (inputIPacket.isKey()) {
178 throw new RuntimeException(
179 "Unable to decode video stream " + streamIndex);
180 }
181
182 onlyDecodeKeyPackets = true;
183
184 continue;
185 }
186 else if (value == DECODE_VIDEO_THUMBNAIL) {
187 cleanUp(inputIPacket, null);
188
189 return true;
190 }
191 }
192 else {
193 if (_log.isDebugEnabled()) {
194 _log.debug("Do not decode video stream " + streamIndex);
195 }
196 }
197 }
198
199 cleanUp(inputIPacket, null);
200
201 return false;
202 }
203
204 @Override
205 protected IContainer getInputIContainer() {
206 return _inputIContainer;
207 }
208
209 private static Log _log = LogFactoryUtil.getLog(
210 LiferayVideoThumbnailConverter.class);
211
212 private String _extension;
213 private int _height = 240;
214 private IContainer _inputIContainer;
215 private String _inputURL;
216 private File _outputFile;
217 private int _percentage;
218 private int _width = 320;
219
220 }