Project

General

Profile

Download (15 KB) Statistics
| Branch: | Tag: | Revision:
1
package eu.etaxonomy.cdm.model.media;
2

    
3
import java.util.ArrayList;
4
import java.util.HashMap;
5
import java.util.LinkedHashMap;
6
import java.util.LinkedHashSet;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.NoSuchElementException;
10
import java.util.Set;
11
import java.util.SortedMap;
12
import java.util.TreeMap;
13
import java.util.regex.Pattern;
14

    
15
import org.apache.log4j.Logger;
16

    
17
import eu.etaxonomy.cdm.model.common.CdmBase;
18

    
19
public class MediaUtils {
20

    
21
    private static final Logger logger = Logger.getLogger(MediaUtils.class);
22

    
23
    /**
24
     * @param representationPartType TODO
25
     * @param size
26
     * @param height
27
     * @param widthOrDuration
28
     * @param mimeTypeRegexes
29
     * @return
30
     *
31
     *
32
     */
33
    public static MediaRepresentation findBestMatchingRepresentation(Media media,
34
            Class<? extends MediaRepresentationPart> representationPartType, Integer size, Integer height,
35
            Integer widthOrDuration, String[] mimeTypes){
36
        // find best matching representations of each media
37
        SortedMap<Integer, MediaRepresentation> prefRepresentations
38
                = filterAndOrderMediaRepresentations(media.getRepresentations(), null, mimeTypes,
39
                        size, widthOrDuration, height);
40
        try {
41
            // take first one and remove all other representations
42
            MediaRepresentation prefOne = prefRepresentations.get(prefRepresentations.firstKey());
43

    
44
            return prefOne;
45

    
46
        } catch (NoSuchElementException nse) {
47
            /* IGNORE */
48
        }
49
        return null;
50
    }
51

    
52
    /**
53
     * Return the first {@link MediaRepresentationPart} found for the given {@link Media}
54
     * or <code>null</code> otherwise.
55
     * @param media the media which is searched for the first part
56
     * @return the first part found or <code>null</code>
57
     */
58
    public static MediaRepresentationPart getFirstMediaRepresentationPart(Media media){
59
        if(media==null){
60
            return null;
61
        }
62
        MediaRepresentationPart mediaRepresentationPart = null;
63
        Set<MediaRepresentation> representations = media.getRepresentations();
64
        if(representations!=null && representations.size()>0){
65
            MediaRepresentation mediaRepresentation = representations.iterator().next();
66
            List<MediaRepresentationPart> parts = mediaRepresentation.getParts();
67
            if(parts!=null && parts.size()>0){
68
                mediaRepresentationPart = parts.iterator().next();
69
            }
70
        }
71
        return mediaRepresentationPart;
72
    }
73

    
74
    /**
75
     * Creates one single {@link MediaRepresentationPart} for the given {@link Media}
76
     * if it does not already exists. Otherwise the first part found is returned.<br>
77
     * @param media the media for which the representation part should be created
78
     * @return the first or newly created representation part
79
     */
80
    public static MediaRepresentationPart initFirstMediaRepresentationPart(Media media, boolean isImage) {
81
        MediaRepresentationPart mediaRepresentationPart = getFirstMediaRepresentationPart(media);
82
        if(mediaRepresentationPart==null){
83
            Set<MediaRepresentation> representations = media.getRepresentations();
84
            if(representations!=null && representations.size()>0){
85
                MediaRepresentation mediaRepresentation = representations.iterator().next();
86
                if(isImage){
87
                    mediaRepresentationPart = ImageFile.NewInstance(null, null);
88
                }
89
                else{
90
                    mediaRepresentationPart = MediaRepresentationPart.NewInstance(null, null);
91
                }
92
                mediaRepresentation.addRepresentationPart(mediaRepresentationPart);
93
            }
94
            else{
95
                if(isImage){
96
                    mediaRepresentationPart = ImageFile.NewInstance(null, null);
97
                }
98
                else{
99
                    mediaRepresentationPart = MediaRepresentationPart.NewInstance(null, null);
100
                }
101

    
102
                MediaRepresentation mediaRepresentation = MediaRepresentation.NewInstance();
103
                mediaRepresentation.addRepresentationPart(mediaRepresentationPart);
104
                media.addRepresentation(mediaRepresentation);
105
            }
106
        }
107
        return mediaRepresentationPart;
108
    }
109

    
110

    
111
    /**
112
     * Filters the given List of Media by the supplied filter parameters <code>representationPartType</code>,
113
     * <code>mimeTypes</code>, <code>sizeTokens</code>, <code>widthOrDuration</code>, <code>height</code>, <code>size</code>.
114
     * Only best matching MediaRepresentation remains attached to the Media entities.
115
     * A Media entity may be completely omitted in the resulting list if  {@link #filterAndOrderMediaRepresentations(Set, Class, String[], Integer, Integer, Integer)}
116
     * is not returning any matching representation. This can be the case if a <code>representationPartType</code> is supplied.
117
     * <p>
118
     * In order to prevent the media entities returned by this method from being persisted accidentally the resulting list contains cloned versions of the originally
119
     * supplied media entities, which have the same UUIDs as the original ones.
120
     *
121
     * @param mediaList
122
     * @param representationPartType any subclass of {@link MediaRepresentationPart}
123
     * @param mimeTypes
124
     * @param sizeTokens
125
     * @param widthOrDuration
126
     * @param height
127
     * @param size
128
     * @return
129
     */
130
    public static Map<Media, MediaRepresentation> findPreferredMedia(List<Media> mediaList,
131
            Class<? extends MediaRepresentationPart> representationPartType, String[] mimeTypes, String[] sizeTokens,
132
            Integer widthOrDuration, Integer height, Integer size) {
133

    
134
        if(mimeTypes != null) {
135
            for(int i=0; i<mimeTypes.length; i++){
136
                mimeTypes[i] = mimeTypes[i].replace(':', '/');
137
            }
138
        }
139

    
140
        if(sizeTokens != null) {
141
            if(sizeTokens.length > 0){
142
                try {
143
                    size = Integer.valueOf(sizeTokens[0]);
144
                } catch (NumberFormatException nfe) {
145
                    /* IGNORE */
146
                }
147
            }
148
            if(sizeTokens.length > 1){
149
                try {
150
                    widthOrDuration = Integer.valueOf(sizeTokens[1]);
151
                } catch (NumberFormatException nfe) {
152
                    /* IGNORE */
153
                }
154
            }
155
            if(sizeTokens.length > 2){
156
                try {
157
                    height = Integer.valueOf(sizeTokens[2]);
158
                } catch (NumberFormatException nfe) {
159
                    /* IGNORE */
160
                }
161
            }
162
        }
163

    
164
        Map<Media, MediaRepresentation> returnMediaList;
165
        if(mediaList != null){
166
            returnMediaList = new LinkedHashMap<>(mediaList.size());
167
            for(Media media : mediaList){
168

    
169
                Set<MediaRepresentation> candidateRepresentations = new LinkedHashSet<>();
170
                candidateRepresentations.addAll(media.getRepresentations());
171

    
172
                SortedMap<Integer, MediaRepresentation> prefRepresentations
173
                    = filterAndOrderMediaRepresentations(candidateRepresentations, representationPartType,
174
                            mimeTypes, size, widthOrDuration, height);
175
                try {
176
                    if(prefRepresentations.size() > 0){
177
                        // Media.representations is a set
178
                        // so it cannot retain the sorting which has been found by filterAndOrderMediaRepresentations()
179
                        // thus we take first one and remove all other representations
180
                        returnMediaList.put(media, prefRepresentations.get(prefRepresentations.firstKey()));
181
                    }
182
                } catch (NoSuchElementException nse) {
183
                    logger.debug(nse);
184
                    /* IGNORE */
185
                }
186
            }
187
        }
188
        else{
189
            returnMediaList = new HashMap<>();
190
        }
191
        return returnMediaList;
192
    }
193

    
194
    /**
195
     * @param media
196
     * @param mimeTypeRegexes
197
     * @param size
198
     * @param widthOrDuration
199
     * @param height
200
     * @return
201
     *
202
     * TODO move into a media utils class
203
     * TODO implement the quality filter
204

    
205
    public static SortedMap<String, MediaRepresentation> orderMediaRepresentations(Media media, String[] mimeTypeRegexes,
206
            Integer size, Integer widthOrDuration, Integer height) {
207
        SortedMap<String, MediaRepresentation> prefRepr = new TreeMap<String, MediaRepresentation>();
208
        for (String mimeTypeRegex : mimeTypeRegexes) {
209
            // getRepresentationByMimeType
210
            Pattern mimeTypePattern = Pattern.compile(mimeTypeRegex);
211
            int representationCnt = 0;
212
            for (MediaRepresentation representation : media.getRepresentations()) {
213
                int dwa = 0;
214
                if(representation.getMimeType() == null){
215
                    prefRepr.put((dwa + representationCnt++) + "_NA", representation);
216
                } else {
217
                    Matcher mather = mimeTypePattern.matcher(representation.getMimeType());
218
                    if (mather.matches()) {
219

    
220
                        /* TODO the quality filter part is being skipped
221
                         * // look for representation with the best matching parts
222
                        for (MediaRepresentationPart part : representation.getParts()) {
223
                            if (part instanceof ImageFile) {
224
                                ImageFile image = (ImageFile) part;
225
                                int dw = image.getWidth() * image.getHeight() - height * widthOrDuration;
226
                                if (dw < 0) {
227
                                    dw *= -1;
228
                                }
229
                                dwa += dw;
230
                            }
231
                            dwa = (representation.getParts().size() > 0 ? dwa / representation.getParts().size() : 0);
232
                        }
233
                        prefRepr.put((dwa + representationCnt++) + '_' + representation.getMimeType(), representation);
234

    
235
                        // preferred mime type found => end loop
236
                        break;
237
                    }
238
                }
239
            }
240
        }
241
        return prefRepr;
242
    }
243

    
244
    */
245
    /**
246
     * @param mimeTypeRegexes
247
     * @param size
248
     * @param widthOrDuration
249
     * @param height
250
     * @return
251
     *
252
     *
253
     */
254
    private static SortedMap<Integer, MediaRepresentation> filterAndOrderMediaRepresentations(
255
            Set<MediaRepresentation> mediaRepresentations,
256
            Class<? extends MediaRepresentationPart> representationPartType, String[] mimeTypeRegexes,
257
            Integer size, Integer widthOrDuration, Integer height) {
258

    
259
        SortedMap<Integer, MediaRepresentation> prefRepr = new TreeMap<>();
260

    
261

    
262
        size = (size == null ? new Integer(0) : size );
263
        widthOrDuration = (widthOrDuration == null ? new Integer(0) : widthOrDuration);
264
        height = (height == null ? new Integer(0) : height);
265
        mimeTypeRegexes = (mimeTypeRegexes == null ? new String[]{".*"} : mimeTypeRegexes);
266

    
267
        for (String mimeTypeRegex : mimeTypeRegexes) {
268
            // getRepresentationByMimeType
269
            Pattern mimeTypePattern = Pattern.compile(mimeTypeRegex);
270
            int representationCnt = 0;
271
            for (MediaRepresentation representation : mediaRepresentations) {
272

    
273
                List<MediaRepresentationPart> matchingParts = new ArrayList<>();
274

    
275

    
276
                // check MIME type
277
                boolean mimeTypeOK = representation.getMimeType() == null
278
                        || mimeTypePattern.matcher(representation.getMimeType()).matches();
279
                logger.debug("mimeTypeOK: " + Boolean.valueOf(mimeTypeOK).toString());
280

    
281
                int dwa = 0;
282

    
283

    
284
                //first the size is used for comparison
285
                for (MediaRepresentationPart part : representation.getParts()) {
286

    
287
                    // check representationPartType
288
                    boolean representationPartTypeOK = representationPartType == null
289
                            || part.getClass().isAssignableFrom(representationPartType);
290
                    logger.debug("representationPartTypeOK: " + Boolean.valueOf(representationPartTypeOK).toString());
291

    
292
                    if ( !(representationPartTypeOK && mimeTypeOK) ) {
293
                        continue;
294
                    }
295

    
296
                    logger.debug(part + " matches");
297
                    matchingParts.add(part);
298

    
299
                    if (part.getSize()!= null){
300
                        int sizeOfPart = part.getSize();
301
                        int distance = sizeOfPart - size;
302
                        if (distance < 0) {
303
                            distance *= -1;
304
                        }
305
                        dwa += distance;
306
                    }
307

    
308
                    //if height and width/duration is defined, add this information, too
309
                    if (height != 0 && widthOrDuration != 0){
310
                        int durationWidthWeight = 0;
311

    
312
                        if (part.isInstanceOf(ImageFile.class)) {
313
                            ImageFile image = CdmBase.deproxy(part, ImageFile.class);
314
                            if (image.getWidth() != null && image.getHeight() != null){
315
                                durationWidthWeight = image.getWidth() * image.getHeight() - height * widthOrDuration;
316
                            }
317
                        }
318
                        else if (part.isInstanceOf(MovieFile.class)){
319
                            MovieFile movie = CdmBase.deproxy(part, MovieFile.class);
320
                            durationWidthWeight = movie.getDuration() - widthOrDuration;
321
                        }else if (part.isInstanceOf(AudioFile.class)){
322
                            AudioFile audio = CdmBase.deproxy(part, AudioFile.class);
323
                            durationWidthWeight = audio.getDuration() - widthOrDuration;
324
                        }
325
                        if (durationWidthWeight < 0) {
326
                            durationWidthWeight *= -1;
327
                        }
328
                        dwa += durationWidthWeight;
329

    
330
                    }
331
                } // loop parts
332
                logger.debug("matchingParts.size():" + matchingParts.size());
333
                if(matchingParts.size() > 0 ){
334
                    dwa = dwa / matchingParts.size();
335

    
336
                    representation.getParts().clear();
337
                    representation.getParts().addAll(matchingParts);
338

    
339
                    //keyString =(dwa + representationCnt++) + '_' + representation.getMimeType();
340

    
341
                    prefRepr.put((dwa + representationCnt++), representation);
342
                }
343
            } // loop representations
344
        } // loop mime types
345
        logger.debug(prefRepr.size() + " preferred representations found");
346
        return prefRepr;
347
    }
348
}
(9-9/13)