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