private void generateStatusOfTranscodings() { // FIXME:FK fetch using one single SQL query availableTranscodings = new HashMap<>(); availableTranscodings.put(240, new HashSet<OLATResource>()); availableTranscodings.put(360, new HashSet<OLATResource>()); availableTranscodings.put(480, new HashSet<OLATResource>()); availableTranscodings.put(720, new HashSet<OLATResource>()); availableTranscodings.put(1080, new HashSet<OLATResource>()); availableTranscodings.put(2160, new HashSet<OLATResource>()); // determine resource type of interest List<String> types = new ArrayList<>(); types.add("FileResource.VIDEO"); // retrieve all resources of type video olatresources = olatresourceManager.findResourceByTypes(types); // go through all video resources for (OLATResource videoResource : olatresources) { // retrieve all transcodings for each video resource List<VideoTranscoding> transcodings = videoManager.getVideoTranscodings(videoResource); // map resource IDs to resolution for (VideoTranscoding videoTranscoding : transcodings) { if (videoTranscoding != null) { Set<OLATResource> oneResolution = availableTranscodings.get(videoTranscoding.getResolution()); if (oneResolution != null) { oneResolution.add(videoTranscoding.getVideoResource()); } } } } }
/** * Internal helper to fork a process with handbrake and read the values from the process * * @param videoTranscoding * @return true: all ok; false: an error happend along the way */ private boolean forkTranscodingProcess(VideoTranscoding videoTranscoding) { OLATResource video = videoTranscoding.getVideoResource(); VideoModule videoModule = CoreSpringFactory.getImpl(VideoModule.class); VideoManager videoManager = CoreSpringFactory.getImpl(VideoManager.class); File masterFile = videoManager.getVideoFile(video); File transcodingFolder = ((LocalFolderImpl) videoManager.getTranscodingContainer(video)).getBasefile(); File transcodedFile = new File( transcodingFolder, Integer.toString(videoTranscoding.getResolution()) + masterFile.getName()); // mark this as beeing transcoded by this local transcoder videoTranscoding.setTranscoder(VideoTranscoding.TRANSCODER_LOCAL); videoTranscoding = videoManager.updateVideoTranscoding(videoTranscoding); ArrayList<String> cmd = new ArrayList<>(); String tasksetConfig = videoModule.getTranscodingTasksetConfig(); if (tasksetConfig != null && !"Mac OS X".equals(System.getProperty("os.name"))) { cmd.add("taskset"); cmd.add("-c"); cmd.add(tasksetConfig); } cmd.add("HandBrakeCLI"); cmd.add("-i"); cmd.add(masterFile.getAbsolutePath()); cmd.add("-o"); cmd.add(transcodedFile.getAbsolutePath()); cmd.add("--optimize"); cmd.add("--preset"); cmd.add("Normal"); cmd.add("--height"); cmd.add(Integer.toString(videoTranscoding.getResolution())); cmd.add("--deinterlace"); cmd.add("--crop"); cmd.add("0:0:0:0"); Process process = null; try { if (log.isDebug()) { log.debug(cmd.toString()); } ProcessBuilder builder = new ProcessBuilder(cmd); process = builder.start(); return updateVideoTranscodingFromProcessOutput(process, videoTranscoding, transcodedFile); } catch (IOException e) { log.error("Could not spawn convert sub process", e); return false; } finally { if (process != null) { process.destroy(); process = null; } } }
// go through all and delete selection private void queueDeleteTranscoding(TranscodingRow source) { for (OLATResource videoResource : olatresources) { if (availableTranscodings.get(source.getResolution()).contains(videoResource)) { List<VideoTranscoding> videoTranscodings = videoManager.getVideoTranscodings(videoResource); for (VideoTranscoding videoTranscoding : videoTranscodings) { if (videoTranscoding.getResolution() == source.getResolution()) { videoManager.deleteVideoTranscoding(videoTranscoding); } } } } }
/** * Implementation of job execution * * @param context * @return * @throws JobExecutionException */ private boolean doExecute(JobExecutionContext context) throws JobExecutionException { VideoModule videoModule = CoreSpringFactory.getImpl(VideoModule.class); if (!videoModule.isTranscodingLocal()) { log.debug("Skipping execution of video transcoding job, local transcoding disabled"); return false; } // Find first one to work with VideoManager videoManager = CoreSpringFactory.getImpl(VideoManager.class); List<VideoTranscoding> videoTranscodings = videoManager.getVideoTranscodingsPendingAndInProgress(); VideoTranscoding videoTranscoding = null; for (VideoTranscoding videoTrans : videoTranscodings) { String transcoder = videoTrans.getTranscoder(); if (transcoder == null) { log.info( "Start transcoding video with resolution::" + videoTrans.getResolution() + " for video resource::" + videoTrans.getVideoResource().getResourceableId()); videoTrans.setTranscoder(VideoTranscoding.TRANSCODER_LOCAL); videoTranscoding = videoManager.updateVideoTranscoding(videoTrans); break; } else if (transcoder.equals(VideoTranscoding.TRANSCODER_LOCAL)) { log.info( "Continue with transcoding video with resolution::" + videoTrans.getResolution() + " for video resource::" + videoTrans.getVideoResource().getResourceableId()); videoTranscoding = videoTrans; break; } } if (videoTranscoding == null) { log.debug( "Skipping execution of video transcoding job, no pending video transcoding found in database"); return false; } // Ready transcode, forke process now boolean success = forkTranscodingProcess(videoTranscoding); // Transcoding done, call execution again until no more videos to be // processed. If an error happend, don't continue to not get into a loop if (success) { success = doExecute(context); } return success; }
/** * Internal helper to deal with the handbrake console output and update the transcoding metadata * * @param proc * @param videoTranscoding * @param transcodedFile * @return true: everything fine; false: an error happended somewhere */ private final boolean updateVideoTranscodingFromProcessOutput( Process proc, VideoTranscoding videoTranscoding, File transcodedFile) { VideoManager videoManager = CoreSpringFactory.getImpl(VideoManager.class); StringBuilder errors = new StringBuilder(); StringBuilder output = new StringBuilder(); String line; // Read from standard input and parse percentages of transcoding process InputStream stdout = proc.getInputStream(); InputStreamReader isr = new InputStreamReader(stdout); BufferedReader br = new BufferedReader(isr); line = null; try { while ((line = br.readLine()) != null) { output.append(line); // Parse the percentage. Logline looks like this: // Encoding: task 1 of 1, 85.90 % (307.59 fps, avg 330.35 fps, ETA 00h00m05s) int start = line.indexOf(","); if (start != -1) { line = line.substring(start); int end = line.indexOf("."); if (end != -1 && end < 5) { String percent = line.substring(2, end); log.debug("Output: " + percent); // update version file for UI try { videoTranscoding.setStatus(Integer.parseInt(percent)); videoTranscoding = videoManager.updateVideoTranscoding(videoTranscoding); DBFactory.getInstance().commitAndCloseSession(); } catch (ObjectDeletedException e) { // deleted by other process proc.destroy(); br.close(); return false; } } } } } catch (IOException e) { // } finally { try { stdout.close(); isr.close(); br.close(); } catch (Exception e2) { // ignore } } // Read and ignore errors, Handbrake outputs a lot info on startup. Only // display errors in debug level InputStream stderr = proc.getErrorStream(); InputStreamReader iserr = new InputStreamReader(stderr); BufferedReader berr = new BufferedReader(iserr); line = null; try { while ((line = berr.readLine()) != null) { errors.append(line); log.debug("Error: " + line); } } catch (IOException e) { // } finally { try { stderr.close(); iserr.close(); berr.close(); } catch (Exception e2) { // ignore } } try { // On finish, update metadata file int exitValue = proc.waitFor(); if (exitValue == 0) { MovieService movieService = CoreSpringFactory.getImpl(MovieService.class); Size videoSize = movieService.getSize(new LocalFileImpl(transcodedFile), VideoManagerImpl.FILETYPE_MP4); videoTranscoding.setWidth(videoSize.getWidth()); videoTranscoding.setHeight(videoSize.getHeight()); videoTranscoding.setSize(transcodedFile.length()); videoTranscoding.setStatus(VideoTranscoding.TRANSCODING_STATUS_DONE); videoTranscoding = videoManager.updateVideoTranscoding(videoTranscoding); DBFactory.getInstance().commitAndCloseSession(); return true; } return false; } catch (InterruptedException e) { return false; } }