1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.composer.remote;
23
24 import org.opencastproject.composer.api.ComposerService;
25 import org.opencastproject.composer.api.EncoderException;
26 import org.opencastproject.composer.api.EncodingProfile;
27 import org.opencastproject.composer.api.EncodingProfileBuilder;
28 import org.opencastproject.composer.api.EncodingProfileImpl;
29 import org.opencastproject.composer.api.EncodingProfileList;
30 import org.opencastproject.composer.api.LaidOutElement;
31 import org.opencastproject.composer.layout.Dimension;
32 import org.opencastproject.composer.layout.Serializer;
33 import org.opencastproject.job.api.Job;
34 import org.opencastproject.job.api.JobParser;
35 import org.opencastproject.mediapackage.Attachment;
36 import org.opencastproject.mediapackage.MediaPackageElementParser;
37 import org.opencastproject.mediapackage.MediaPackageException;
38 import org.opencastproject.mediapackage.Track;
39 import org.opencastproject.security.api.TrustedHttpClient;
40 import org.opencastproject.serviceregistry.api.RemoteBase;
41 import org.opencastproject.serviceregistry.api.ServiceRegistry;
42 import org.opencastproject.smil.entity.api.Smil;
43
44 import org.apache.commons.io.IOUtils;
45 import org.apache.commons.lang3.StringUtils;
46 import org.apache.http.HttpResponse;
47 import org.apache.http.HttpStatus;
48 import org.apache.http.client.entity.UrlEncodedFormEntity;
49 import org.apache.http.client.methods.HttpGet;
50 import org.apache.http.client.methods.HttpPost;
51 import org.apache.http.message.BasicNameValuePair;
52 import org.apache.http.util.EntityUtils;
53 import org.osgi.service.component.annotations.Component;
54 import org.osgi.service.component.annotations.Reference;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import java.io.IOException;
59 import java.nio.charset.Charset;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.List;
63 import java.util.Locale;
64 import java.util.Map;
65 import java.util.Map.Entry;
66 import java.util.Optional;
67 import java.util.stream.Collectors;
68
69
70
71
72 @Component(
73 property = {
74 "service.description=Composer (Encoder) Remote Service Proxy"
75 },
76 immediate = true,
77 service = { ComposerService.class }
78 )
79 public class ComposerServiceRemoteImpl extends RemoteBase implements ComposerService {
80
81
82 private static final Logger logger = LoggerFactory.getLogger(ComposerServiceRemoteImpl.class);
83
84 public ComposerServiceRemoteImpl() {
85 super(JOB_TYPE);
86 }
87
88
89
90
91
92
93 @Override
94 @Reference
95 public void setTrustedHttpClient(TrustedHttpClient client) {
96 this.client = client;
97 }
98
99
100
101
102
103
104 @Override
105 @Reference
106 public void setRemoteServiceManager(ServiceRegistry remoteServiceManager) {
107 this.remoteServiceManager = remoteServiceManager;
108 }
109
110
111
112
113
114
115
116 @Override
117 public Job encode(Track sourceTrack, String profileId) throws EncoderException {
118 HttpPost post = new HttpPost("/encode");
119 try {
120 List<BasicNameValuePair> params = new ArrayList<>();
121 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
122 params.add(new BasicNameValuePair("profileId", profileId));
123 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
124 } catch (Exception e) {
125 throw new EncoderException("Unable to assemble a remote composer request for track " + sourceTrack, e);
126 }
127 HttpResponse response = null;
128 try {
129 response = getResponse(post);
130 if (response != null) {
131 String content = EntityUtils.toString(response.getEntity());
132 Job r = JobParser.parseJob(content);
133 logger.info("Encoding job {} started on a remote composer", r.getId());
134 return r;
135 }
136 } catch (Exception e) {
137 throw new EncoderException("Unable to encode track " + sourceTrack + " using a remote composer service", e);
138 } finally {
139 closeConnection(response);
140 }
141 throw new EncoderException("Unable to encode track " + sourceTrack + " using a remote composer service");
142 }
143
144
145
146
147 @Override
148 public Job parallelEncode(Track sourceTrack, String profileId) throws EncoderException {
149 HttpPost post = new HttpPost("/parallelencode");
150 try {
151 List<BasicNameValuePair> params = new ArrayList<>();
152 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
153 params.add(new BasicNameValuePair("profileId", profileId));
154 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
155 } catch (Exception e) {
156 throw new EncoderException("Unable to assemble a remote composer request for track " + sourceTrack, e);
157 }
158 HttpResponse response = null;
159 try {
160 response = getResponse(post);
161 if (response != null) {
162 String content = EntityUtils.toString(response.getEntity());
163 Job r = JobParser.parseJob(content);
164 logger.info("Encoding job {} started on a remote composer", r.getId());
165 return r;
166 }
167 } catch (Exception e) {
168 throw new EncoderException("Unable to encode track " + sourceTrack + " using a remote composer service", e);
169 } finally {
170 closeConnection(response);
171 }
172 throw new EncoderException("Unable to encode track " + sourceTrack + " using a remote composer service");
173 }
174
175
176
177
178
179
180 @Override
181 public Job trim(Track sourceTrack, String profileId, long start, long duration) throws EncoderException {
182 HttpPost post = new HttpPost("/trim");
183 try {
184 List<BasicNameValuePair> params = new ArrayList<>();
185 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
186 params.add(new BasicNameValuePair("profileId", profileId));
187 params.add(new BasicNameValuePair("start", Long.toString(start)));
188 params.add(new BasicNameValuePair("duration", Long.toString(duration)));
189 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
190 } catch (Exception e) {
191 throw new EncoderException("Unable to assemble a remote composer request for track " + sourceTrack, e);
192 }
193 HttpResponse response = null;
194 try {
195 response = getResponse(post);
196 if (response != null) {
197 String content = EntityUtils.toString(response.getEntity());
198 Job r = JobParser.parseJob(content);
199 logger.info("Trimming job {} started on a remote composer", r.getId());
200 return r;
201 }
202 } catch (Exception e) {
203 throw new EncoderException("Unable to trim track " + sourceTrack + " using a remote composer service", e);
204 } finally {
205 closeConnection(response);
206 }
207 throw new EncoderException("Unable to trim track " + sourceTrack + " using a remote composer service");
208 }
209
210
211
212
213
214
215
216 @Override
217 public Job mux(Track sourceVideoTrack, Track sourceAudioTrack, String profileId) throws EncoderException {
218 HttpPost post = new HttpPost("/mux");
219 try {
220 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
221 params.add(new BasicNameValuePair("videoSourceTrack", MediaPackageElementParser.getAsXml(sourceVideoTrack)));
222 params.add(new BasicNameValuePair("audioSourceTrack", MediaPackageElementParser.getAsXml(sourceAudioTrack)));
223 params.add(new BasicNameValuePair("profileId", profileId));
224 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
225 } catch (Exception e) {
226 throw new EncoderException("Unable to assemble a remote composer request", e);
227 }
228 HttpResponse response = null;
229 try {
230 response = getResponse(post);
231 if (response != null) {
232 String content = EntityUtils.toString(response.getEntity());
233 Job r = JobParser.parseJob(content);
234 logger.info("Muxing job {} started on a remote composer", r.getId());
235 return r;
236 }
237 } catch (IOException e) {
238 throw new EncoderException(e);
239 } finally {
240 closeConnection(response);
241 }
242 throw new EncoderException("Unable to mux tracks " + sourceVideoTrack + " and " + sourceAudioTrack
243 + " using a remote composer");
244 }
245
246
247
248
249
250
251 @Override
252 public Job mux(Map<String, Track> sourceTracks, String profileId) throws EncoderException {
253 HttpPost post = new HttpPost("/mux");
254 try {
255 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
256 List<String> sourceTracksEntries = new ArrayList<>();
257 for (Entry<String, Track> sourceTrack : sourceTracks.entrySet()) {
258 String sourceTrackXml = MediaPackageElementParser.getAsXml(sourceTrack.getValue());
259 sourceTracksEntries.add(StringUtils.join(sourceTrack.getKey(), "#=#", sourceTrackXml));
260 }
261 params.add(new BasicNameValuePair("sourceTracks", StringUtils.join(sourceTracksEntries, "#|#")));
262 params.add(new BasicNameValuePair("profileId", profileId));
263 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
264 } catch (Exception e) {
265 throw new EncoderException("Unable to assemble a remote composer request", e);
266 }
267 HttpResponse response = null;
268 try {
269 response = getResponse(post);
270 if (response != null) {
271 String content = EntityUtils.toString(response.getEntity());
272 Job r = JobParser.parseJob(content);
273 logger.info("Muxing job {} started on a remote composer", r.getId());
274 return r;
275 }
276 } catch (IOException e) {
277 throw new EncoderException(e);
278 } finally {
279 closeConnection(response);
280 }
281 throw new EncoderException("Unable to mux tracks " + sourceTracks.entrySet().stream()
282 .map(entry -> String.format("%s: %s", entry.getKey(), entry.getValue().getIdentifier())).collect(
283 Collectors.joining(", ")) + " using a remote composer");
284 }
285
286
287
288
289
290
291 @Override
292 public EncodingProfile getProfile(String profileId) {
293 HttpGet get = new HttpGet("/profile/" + profileId + ".xml");
294 HttpResponse response = null;
295 try {
296 response = getResponse(get, HttpStatus.SC_OK, HttpStatus.SC_NOT_FOUND);
297 if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
298 return EncodingProfileBuilder.getInstance().parseProfile(response.getEntity().getContent());
299 } else {
300 return null;
301 }
302 } catch (Exception e) {
303 throw new RuntimeException(e);
304 } finally {
305 closeConnection(response);
306 }
307 }
308
309
310
311
312 @Override
313 public Job image(Track sourceTrack, String profileId, double... times) throws EncoderException {
314 HttpPost post = new HttpPost("/image");
315 try {
316 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
317 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
318 params.add(new BasicNameValuePair("profileId", profileId));
319 params.add(new BasicNameValuePair("time", buildTimeArray(times)));
320 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
321 } catch (Exception e) {
322 throw new EncoderException(e);
323 }
324 HttpResponse response = null;
325 try {
326 response = getResponse(post);
327 if (response != null) {
328 Job r = JobParser.parseJob(response.getEntity().getContent());
329 logger.info("Image extraction job {} started on a remote composer", r.getId());
330 return r;
331 }
332 } catch (Exception e) {
333 throw new EncoderException(e);
334 } finally {
335 closeConnection(response);
336 }
337 throw new EncoderException("Unable to compose an image from track " + sourceTrack
338 + " using the remote composer service proxy");
339 }
340
341 @Override
342 public List<Attachment> imageSync(Track sourceTrack, String profileId, double... times)
343 throws EncoderException, MediaPackageException {
344 HttpPost post = new HttpPost("/imagesync");
345 try {
346 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
347 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
348 params.add(new BasicNameValuePair("profileId", profileId));
349 params.add(new BasicNameValuePair("time", buildTimeArray(times)));
350 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
351 } catch (Exception e) {
352 throw new EncoderException(e);
353 }
354 HttpResponse response = null;
355 try {
356 response = getResponse(post);
357 if (response != null) {
358 final String xml = IOUtils.toString(response.getEntity().getContent(), Charset.forName("utf-8"));
359 return MediaPackageElementParser.getArrayFromXml(xml)
360 .stream().map(e -> (Attachment)e)
361 .collect(Collectors.toList());
362 }
363 } catch (Exception e) {
364 throw new EncoderException(e);
365 } finally {
366 closeConnection(response);
367 }
368 throw new EncoderException("Unable to compose an image from track " + sourceTrack
369 + " using the remote composer service proxy");
370 }
371
372
373
374
375
376
377 @Override
378 public Job image(Track sourceTrack, String profileId, Map<String, String> properties) throws EncoderException,
379 MediaPackageException {
380 HttpPost post = new HttpPost("/image");
381 try {
382 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
383 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
384 params.add(new BasicNameValuePair("profileId", profileId));
385 if (properties != null) {
386 params.add(new BasicNameValuePair("properties", mapToString(properties)));
387 }
388 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
389 } catch (Exception e) {
390 throw new EncoderException(e);
391 }
392 HttpResponse response = null;
393 try {
394 response = getResponse(post);
395 if (response != null) {
396 Job r = JobParser.parseJob(response.getEntity().getContent());
397 logger.info("Image extraction job {} started on a remote composer", r.getId());
398 return r;
399 }
400 } catch (Exception e) {
401 throw new EncoderException(e);
402 } finally {
403 closeConnection(response);
404 }
405 throw new EncoderException("Unable to compose an image from track " + sourceTrack
406 + " using the remote composer service proxy");
407 }
408
409
410
411
412
413
414
415 @Override
416 public Job convertImage(Attachment image, String... profileIds) throws EncoderException, MediaPackageException {
417 HttpPost post = new HttpPost("/convertimage");
418 try {
419 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
420 params.add(new BasicNameValuePair("sourceImage", MediaPackageElementParser.getAsXml(image)));
421 params.add(new BasicNameValuePair("profileId", StringUtils.join(profileIds, ',')));
422 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
423 } catch (Exception e) {
424 throw new EncoderException(e);
425 }
426 HttpResponse response = null;
427 try {
428 response = getResponse(post);
429 if (response != null) {
430 Job r = JobParser.parseJob(response.getEntity().getContent());
431 logger.info("Image conversion job {} started on a remote composer", r.getId());
432 return r;
433 }
434 } catch (Exception e) {
435 throw new EncoderException(e);
436 } finally {
437 closeConnection(response);
438 }
439 throw new EncoderException("Unable to convert image at " + image + " using the remote composer service proxy");
440 }
441
442
443
444
445
446
447
448 @Override
449 public List<Attachment> convertImageSync(Attachment image, String... profileIds)
450 throws EncoderException, MediaPackageException {
451 HttpPost post = new HttpPost("/convertimagesync");
452 try {
453 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
454 params.add(new BasicNameValuePair("sourceImage", MediaPackageElementParser.getAsXml(image)));
455 params.add(new BasicNameValuePair("profileIds", StringUtils.join(profileIds, ',')));
456 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
457 } catch (Exception e) {
458 throw new EncoderException(e);
459 }
460 HttpResponse response = null;
461 try {
462 response = getResponse(post);
463 if (response != null) {
464 final String xml = IOUtils.toString(response.getEntity().getContent(), Charset.forName("utf-8"));
465 return MediaPackageElementParser.getArrayFromXml(xml).stream()
466 .map(a -> (Attachment) a)
467 .collect(Collectors.toList());
468 }
469 } catch (Exception e) {
470 throw new EncoderException(e);
471 } finally {
472 closeConnection(response);
473 }
474 throw new EncoderException("Unable to convert image at " + image + " using the remote composer service proxy");
475 }
476
477
478
479
480
481
482 @Override
483 public EncodingProfile[] listProfiles() {
484 HttpGet get = new HttpGet("/profiles.xml");
485 HttpResponse response = null;
486 try {
487 response = getResponse(get);
488 if (response != null) {
489 EncodingProfileList profileList = EncodingProfileBuilder.getInstance().parseProfileList(
490 response.getEntity().getContent());
491 List<EncodingProfileImpl> list = profileList.getProfiles();
492 return list.toArray(new EncodingProfile[list.size()]);
493 }
494 } catch (Exception e) {
495 throw new RuntimeException(
496 "Unable to list the encoding profiles registered with the remote composer service proxy", e);
497 } finally {
498 closeConnection(response);
499 }
500 throw new RuntimeException("Unable to list the encoding profiles registered with the remote composer service "
501 + "proxy");
502 }
503
504
505
506
507
508
509
510
511 protected String buildTimeArray(double[] times) {
512 if (times.length == 0) {
513 return "";
514 }
515
516 StringBuilder builder = new StringBuilder();
517 builder.append(Double.toString(times[0]));
518 for (int i = 1; i < times.length; i++) {
519 builder.append(";" + Double.toString(times[i]));
520 }
521 return builder.toString();
522 }
523
524 @Override
525 public Job composite(Dimension compositeTrackSize, Optional<LaidOutElement<Track>> upperTrack,
526 LaidOutElement<Track> lowerTrack, Optional<LaidOutElement<Attachment>> watermark, String profileId,
527 String background, String sourceAudioName) throws EncoderException, MediaPackageException {
528 HttpPost post = new HttpPost("/composite");
529 try {
530 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
531 params.add(new BasicNameValuePair("compositeSize", Serializer.json(compositeTrackSize).toJson()));
532 params.add(new BasicNameValuePair("lowerTrack", MediaPackageElementParser.getAsXml(lowerTrack.getElement())));
533 params.add(new BasicNameValuePair("lowerLayout", Serializer.json(lowerTrack.getLayout()).toJson()));
534 if (upperTrack.isPresent()) {
535 params.add(new BasicNameValuePair("upperTrack", MediaPackageElementParser.getAsXml(upperTrack.get()
536 .getElement())));
537 params.add(new BasicNameValuePair("upperLayout", Serializer.json(upperTrack.get().getLayout()).toJson()));
538 }
539
540 if (watermark.isPresent()) {
541 params.add(new BasicNameValuePair("watermarkAttachment", MediaPackageElementParser.getAsXml(watermark.get()
542 .getElement())));
543 params.add(new BasicNameValuePair("watermarkLayout", Serializer.json(watermark.get().getLayout()).toJson()));
544 }
545 params.add(new BasicNameValuePair("profileId", profileId));
546 params.add(new BasicNameValuePair("background", background));
547 params.add(new BasicNameValuePair("sourceAudioName", sourceAudioName));
548 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
549 } catch (Exception e) {
550 throw new EncoderException(e);
551 }
552 HttpResponse response = null;
553 try {
554 response = getResponse(post);
555 if (response != null) {
556 Job r = JobParser.parseJob(response.getEntity().getContent());
557 logger.info("Composite video job {} started on a remote composer", r.getId());
558 return r;
559 }
560 } catch (Exception e) {
561 throw new EncoderException(e);
562 } finally {
563 closeConnection(response);
564 }
565 if (upperTrack.isPresent()) {
566 throw new EncoderException("Unable to composite video from track " + lowerTrack.getElement() + " and "
567 + upperTrack.get().getElement() + " using the remote composer service proxy");
568 } else {
569 throw new EncoderException("Unable to composite video from track " + lowerTrack.getElement()
570 + " using the remote composer service proxy");
571 }
572 }
573
574 @Override
575 public Job concat(String profileId, Dimension outputDimension, boolean sameCodec, Track... tracks)
576 throws EncoderException, MediaPackageException {
577 return concat(profileId, outputDimension, -1.0f, sameCodec, tracks);
578 }
579
580 @Override
581 public Job concat(String profileId, Dimension outputDimension, float outputFrameRate, boolean sameCodec,
582 Track... tracks)
583 throws EncoderException, MediaPackageException {
584 HttpPost post = new HttpPost("/concat");
585 try {
586 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
587 params.add(new BasicNameValuePair("profileId", profileId));
588 if (outputDimension != null) {
589 params.add(new BasicNameValuePair("outputDimension", Serializer.json(outputDimension).toJson()));
590 }
591 params.add(new BasicNameValuePair("outputFrameRate", String.format(Locale.US, "%f", outputFrameRate)));
592 params.add(new BasicNameValuePair("sourceTracks", MediaPackageElementParser.getArrayAsXml(
593 Arrays.asList(tracks))));
594 if (sameCodec) {
595 params.add(new BasicNameValuePair("sameCodec", "true"));
596 }
597 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
598 } catch (Exception e) {
599 throw new EncoderException(e);
600 }
601 HttpResponse response = null;
602 try {
603 response = getResponse(post);
604 if (response != null) {
605 Job r = JobParser.parseJob(response.getEntity().getContent());
606 logger.info("Concat video job {} started on a remote composer", r.getId());
607 return r;
608 }
609 } catch (Exception e) {
610 throw new EncoderException(e);
611 } finally {
612 closeConnection(response);
613 }
614 throw new EncoderException("Unable to concat videos from tracks " + tracks
615 + " using the remote composer service proxy");
616 }
617
618 @Override
619 public Job imageToVideo(Attachment sourceImageAttachment, String profileId, double time) throws EncoderException,
620 MediaPackageException {
621 HttpPost post = new HttpPost("/imagetovideo");
622 try {
623 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
624 params.add(new BasicNameValuePair("sourceAttachment", MediaPackageElementParser.getAsXml(sourceImageAttachment)));
625 params.add(new BasicNameValuePair("profileId", profileId));
626 params.add(new BasicNameValuePair("time", Double.toString(time)));
627 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
628 } catch (Exception e) {
629 throw new EncoderException(e);
630 }
631 HttpResponse response = null;
632 try {
633 response = getResponse(post);
634 if (response != null) {
635 Job r = JobParser.parseJob(response.getEntity().getContent());
636 logger.info("Image to video converting job {} started on a remote composer", r.getId());
637 return r;
638 }
639 } catch (Exception e) {
640 throw new EncoderException(e);
641 } finally {
642 closeConnection(response);
643 }
644 throw new EncoderException("Unable to convert an image to a video from attachment " + sourceImageAttachment
645 + " using the remote composer service proxy");
646 }
647
648 @Override
649 public Job demux(Track sourceTrack, String profileId) throws EncoderException, MediaPackageException {
650 HttpPost post = new HttpPost("/demux");
651 try {
652 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
653 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
654 params.add(new BasicNameValuePair("profileId", profileId));
655 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
656 } catch (Exception e) {
657 throw new EncoderException("Unable to assemble a remote demux request for track " + sourceTrack, e);
658 }
659 HttpResponse response = null;
660 try {
661 response = getResponse(post);
662 if (response != null) {
663 String content = EntityUtils.toString(response.getEntity());
664 Job r = JobParser.parseJob(content);
665 logger.info("Demuxing job {} started on a remote service ", r.getId());
666 return r;
667 }
668 } catch (Exception e) {
669 throw new EncoderException("Unable to demux track " + sourceTrack + " using a remote composer service", e);
670 } finally {
671 closeConnection(response);
672 }
673 throw new EncoderException("Unable to demux track " + sourceTrack + " using a remote composer service");
674 }
675
676 @Override
677 public Job processSmil(Smil smil, String trackParamGroupId, String mediaType, List<String> profileIds)
678 throws EncoderException, MediaPackageException {
679 HttpPost post = new HttpPost("/processsmil");
680 try {
681 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
682 params.add(new BasicNameValuePair("smilAsXml", smil.toXML()));
683 params.add(new BasicNameValuePair("trackId", trackParamGroupId));
684 params.add(new BasicNameValuePair("mediaType", mediaType));
685 params.add(new BasicNameValuePair("profileIds", StringUtils.join(profileIds, ",")));
686 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
687 } catch (Exception e) {
688 throw new EncoderException(e);
689 }
690 HttpResponse response = null;
691 try {
692 response = getResponse(post);
693 if (response != null) {
694 Job r = JobParser.parseJob(response.getEntity().getContent());
695 logger.info("Concat video job {} started on a remote composer", r.getId());
696 return r;
697 }
698 } catch (Exception e) {
699 throw new EncoderException(e);
700 } finally {
701 closeConnection(response);
702 }
703 throw new EncoderException("Unable to edit video group(" + trackParamGroupId + ") from smil " + smil
704 + " using the remote composer service proxy");
705 }
706
707 @Override
708 public Job multiEncode(Track sourceTrack, List<String> profileIds) throws EncoderException, MediaPackageException {
709 HttpPost post = new HttpPost("/multiencode");
710 try {
711 List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
712 params.add(new BasicNameValuePair("sourceTrack", MediaPackageElementParser.getAsXml(sourceTrack)));
713 params.add(new BasicNameValuePair("profileIds", StringUtils.join(profileIds, ",")));
714 post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
715 } catch (Exception e) {
716 throw new EncoderException("Unable to assemble a remote demux request for track " + sourceTrack, e);
717 }
718 HttpResponse response = null;
719 try {
720 response = getResponse(post);
721 if (response != null) {
722 String content = EntityUtils.toString(response.getEntity());
723 Job job = JobParser.parseJob(content);
724 logger.info("Encoding job {} started on a remote multiencode", job.getId());
725 return job;
726 }
727 } catch (Exception e) {
728 throw new EncoderException("Unable to multiencode track " + sourceTrack + " using a remote composer service", e);
729 } finally {
730 closeConnection(response);
731 }
732 throw new EncoderException("Unable to multiencode track " + sourceTrack + " using a remote composer service");
733 }
734
735
736
737
738
739
740
741
742
743 private String mapToString(Map<String, String> props) {
744 StringBuilder sb = new StringBuilder();
745 for (Entry<String, String> entry : props.entrySet()) {
746 sb.append(entry.getKey());
747 sb.append("=");
748 sb.append(entry.getValue());
749 sb.append("\n");
750 }
751 return sb.toString();
752 }
753
754 }