Example #1
0
    def _loop(self):
        executable = self.get_executable()
        args = self.get_parameters()
        self._start_logging(executable, args)

        args.insert(0, executable)

        logging.debug("Conversion: (%s)", " ".join(args))

        kwargs = {"bufsize": 1,
                  "stdout": subprocess.PIPE,
                  "stderr": subprocess.STDOUT,
                  "stdin": subprocess.PIPE,
                  "startupinfo": util.no_console_startupinfo()}
        if os.name != "nt":
            kwargs["close_fds"] = True

        try:
            self.process_handle = subprocess.Popen(args, **kwargs)
            self.process_output(line_reader(self.process_handle.stdout))
            self.process_handle.wait()

        except OSError, ose:
            if ose.errno == errno.ENOENT:
                self.error = _("%(program)s does not exist.",
                               {"program": self.get_executable()})
            else:
                logging.exception("Exception in conversion loop: %s %s",
                                  args, kwargs)
Example #2
0
    def run_movie_data_program(self, command_line, env):
        start_time = time.time()
        # create tempfiles to catch output for the movie data program.  Using
        # a pipe fails if the movie data program outputs enough to fill up the
        # buffers (see #17059)
        movie_data_stdout = tempfile.TemporaryFile()
        movie_data_stderr = tempfile.TemporaryFile()
        pipe = subprocess.Popen(command_line, stdout=movie_data_stdout,
                stdin=subprocess.PIPE, stderr=movie_data_stderr, env=env,
                startupinfo=util.no_console_startupinfo())
        # close stdin since we won't write to it.
        pipe.stdin.close()
        while pipe.poll() is None and not self.in_shutdown:
            time.sleep(SLEEP_DELAY)
            if time.time() - start_time > MOVIE_DATA_UTIL_TIMEOUT:
                logging.warning("Movie data process hung, killing it")
                self.kill_process(pipe)
                raise ProcessHung

        if self.in_shutdown:
            if pipe.poll() is None:
                logging.warning("Movie data process running after shutdown, "
                                "killing it")
                self.kill_process(pipe)
            raise Shutdown
        # FIXME: should we do anything with stderr?
        movie_data_stdout.seek(0)
        return movie_data_stdout.read()
Example #3
0
    def run_movie_data_program(self, command_line, env):
        start_time = time.time()
        # create tempfiles to catch output for the movie data program.  Using
        # a pipe fails if the movie data program outputs enough to fill up the
        # buffers (see #17059)
        movie_data_stdout = tempfile.TemporaryFile()
        movie_data_stderr = tempfile.TemporaryFile()
        pipe = subprocess.Popen(command_line, stdout=movie_data_stdout,
                stdin=subprocess.PIPE, stderr=movie_data_stderr, env=env,
                startupinfo=util.no_console_startupinfo())
        # close stdin since we won't write to it.
        pipe.stdin.close()
        while pipe.poll() is None and not self.in_shutdown:
            time.sleep(SLEEP_DELAY)
            if time.time() - start_time > MOVIE_DATA_UTIL_TIMEOUT:
                logging.warning("Movie data process hung, killing it")
                self.kill_process(pipe)
                raise ProcessHung

        if self.in_shutdown:
            if pipe.poll() is None:
                logging.warning("Movie data process running after shutdown, "
                                "killing it")
                self.kill_process(pipe)
            raise Shutdown
        # FIXME: should we do anything with stderr?
        movie_data_stdout.seek(0)
        return movie_data_stdout.read()
Example #4
0
 def _start_subprocess(self):
     cmd_line, env = miro_helper_program_info()
     kwargs = {
               "stdout": subprocess.PIPE,
               "stdin": subprocess.PIPE,
               "startupinfo": util.no_console_startupinfo(),
               "env": env,
     }
     if _on_windows():
         # normally we just clone stderr for the subprocess, but on windows
         # this doesn't work.  So we use a pipe that we immediately close
         kwargs["stderr"] = subprocess.PIPE
     else:
         kwargs["stderr"] = None
         kwargs["close_fds"] = True
     process = subprocess.Popen(cmd_line, **kwargs)
     if _on_windows():
         process.stderr.close()
     return process
Example #5
0
    def run_movie_data_program(self, command_line, env):
        start_time = time.time()
        pipe = subprocess.Popen(command_line, stdout=subprocess.PIPE,
                stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
                startupinfo=util.no_console_startupinfo())
        while pipe.poll() is None and not self.in_shutdown:
            time.sleep(SLEEP_DELAY)
            if time.time() - start_time > MOVIE_DATA_UTIL_TIMEOUT:
                logging.info("Movie data process hung, killing it")
                self.kill_process(pipe.pid)
                return ''

        if self.in_shutdown:
            if pipe.poll() is None:
                logging.info("Movie data process running after shutdown, "
                             "killing it")
                self.kill_process(pipe.pid)
            return ''
        return pipe.stdout.read()
Example #6
0
 def _start_subprocess(self):
     cmd_line, env = miro_helper_program_info()
     kwargs = {
         "stdout": subprocess.PIPE,
         "stdin": subprocess.PIPE,
         "startupinfo": util.no_console_startupinfo(),
         "env": env,
     }
     if _on_windows():
         # normally we just clone stderr for the subprocess, but on windows
         # this doesn't work.  So we use a pipe that we immediately close
         kwargs["stderr"] = subprocess.PIPE
     else:
         kwargs["stderr"] = None
         kwargs["close_fds"] = True
     process = subprocess.Popen(cmd_line, **kwargs)
     if _on_windows():
         process.stderr.close()
     return process
Example #7
0
    def transcode(self):
        rc = True
        try:
            ffmpeg_exe = get_ffmpeg_executable_path()
            kwargs = {
                "stdin": open(os.devnull, 'rb'),
                "stdout": subprocess.PIPE,
                "stderr": open(os.devnull, 'wb'),
                "startupinfo": util.no_console_startupinfo()
            }
            if os.name != "nt":
                kwargs["close_fds"] = True
            args = [ffmpeg_exe, "-i", self.media_file]
            if self.time_offset:
                logging.debug('transcode: start job @ %d' % self.time_offset)
                args += TranscodeObject.time_offset_args + [
                    str(self.time_offset)
                ]
            video_needs_trancode = False
            if self.has_video:
                logging.debug('Video codec: %s', self.video_codec)
                logging.debug('Video size: %s', self.video_size)
                if video_can_copy(self.video_codec, self.video_size):
                    args += get_transcode_video_copy_options()
                else:
                    args += get_transcode_video_options()
                    video_needs_transcode = True
            if self.has_audio:
                logging.debug('Audio codec: %s', self.audio_codec)
                logging.debug('Audio sample rate: %s', self.audio_sample_rate)
                if (valid_av_combo(self.video_codec, self.audio_codec)
                        and audio_can_copy(self.audio_codec,
                                           self.audio_sample_rate)):
                    args += get_transcode_audio_copy_options()
                else:
                    args += get_transcode_audio_options()
            else:
                raise ValueError('no video or audio stream present')

            args += TranscodeObject.output_args
            logging.debug('Running command %s' % ' '.join(args))
            self.ffmpeg_handle = subprocess.Popen(args, **kwargs)

            segmenter_exe = get_segmenter_executable_path()
            args = [segmenter_exe]
            address, port = self.sink.server_address
            args += TranscodeObject.segmenter_args + [str(port)]
            kwargs = {
                "stdout": open(os.devnull, 'rb'),
                "stdin": self.ffmpeg_handle.stdout,
                "stderr": open(os.devnull, 'wb'),
                "startupinfo": util.no_console_startupinfo()
            }
            # XXX Can't use this - need to pass on the child fds
            #if os.name != "nt":
            #    kwargs["close_fds"] = True

            logging.debug('Running command %s' % ' '.join(args))
            self.segmenter_handle = subprocess.Popen(args, **kwargs)

            self.sink_thread = threading.Thread(target=thread_body,
                                                args=[self.segmenter_consumer],
                                                name="Segmenter Consumer")
            self.sink_thread.daemon = True
            self.sink_thread.start()

        except StandardError:
            (typ, value, tb) = sys.exc_info()
            logging.error('ERROR: %s %s' % (str(typ), str(value)))
            rc = False
        self.transcode_gate.set()
        return rc
Example #8
0
def needs_transcode(media_file):
    """needs_transcode()

    Returns (False, None) if no need to transcode.
    Returns (True, info) if there is a need to transcode.

    where info is

    (duration, has_audio, has_video)

    The duration is transmitted for transcoding purposes because we need to
    build a m3u8 playlist and what we get out of the Miro database may be 
    unreliable (does not exist).

    May throw exception if ffmpeg not found.  Remember to catch."""
    ffmpeg_exe = get_ffmpeg_executable_path()
    kwargs = {
        "stdout": subprocess.PIPE,
        "stderr": subprocess.PIPE,
        "stdin": subprocess.PIPE,
        "startupinfo": util.no_console_startupinfo()
    }
    if os.name != "nt":
        kwargs["close_fds"] = True
    args = [ffmpeg_exe, "-i", media_file]
    handle = subprocess.Popen(args, **kwargs)
    # XXX unbounded read here but should be okay, ffmpeg output is finite.
    # note that we need to read from stderr, since that's what ffmpeg spits
    # out.
    text = handle.stderr.read()
    # Initial determination based on the file type - need to drill down
    # to see if the resolution, etc are within parameters.
    if container_regex.search(text):
        transcode = False
    else:
        transcode = True
    # "    Duration: XX:XX:XX.XX, ..."
    match = duration_regex.search(text)
    start, end = match.span()
    duration_start = text[end:]
    duration = duration_start[:duration_start.index(',')]
    # Convert to seconds.  We can't handle fractions of a second so
    # skip over those bits.
    hours, minutes, seconds = duration.split(':')
    # Strip the fractional seconds.  Always round up, then we won't miss
    # any data.
    seconds = int(float(seconds) + 0.5)
    seconds += int(minutes) * 60
    seconds += int(hours) * 3600
    has_audio = has_audio_regex.search(text)
    has_video = has_video_regex.search(text)
    vcodec = acodec = size = sample_rate = None
    vcopy = acopy = False
    if has_video:
        vcodec, size = get_video_parameters(has_video)
        vcopy = video_can_copy(vcodec, size)
        if not vcopy:
            transcode = False
    if has_audio:
        acodec, sample_rate = get_audio_parameters(has_audio)
        acopy = audio_can_copy(acodec, sample_rate)
        if not acopy:
            transcode = False
    return (transcode, (seconds, has_audio, acodec, sample_rate, has_video,
                        vcodec, size))
Example #9
0
    def transcode(self):
        rc = True
        try:
            ffmpeg_exe = get_ffmpeg_executable_path()
            kwargs = {
                "stdin": open(os.devnull, "rb"),
                "stdout": subprocess.PIPE,
                "stderr": open(os.devnull, "wb"),
                "startupinfo": util.no_console_startupinfo(),
            }
            if os.name != "nt":
                kwargs["close_fds"] = True
            args = [ffmpeg_exe, "-i", self.media_file]
            if self.time_offset:
                logging.debug("transcode: start job @ %d" % self.time_offset)
                args += TranscodeObject.time_offset_args + [str(self.time_offset)]
            video_needs_trancode = False
            if self.has_video:
                logging.debug("Video codec: %s", self.video_codec)
                logging.debug("Video size: %s", self.video_size)
                if video_can_copy(self.video_codec, self.video_size):
                    args += get_transcode_video_copy_options()
                else:
                    args += get_transcode_video_options()
                    video_needs_transcode = True
            if self.has_audio:
                logging.debug("Audio codec: %s", self.audio_codec)
                logging.debug("Audio sample rate: %s", self.audio_sample_rate)
                if valid_av_combo(self.video_codec, self.audio_codec) and audio_can_copy(
                    self.audio_codec, self.audio_sample_rate
                ):
                    args += get_transcode_audio_copy_options()
                else:
                    args += get_transcode_audio_options()
            else:
                raise ValueError("no video or audio stream present")

            args += TranscodeObject.output_args
            logging.debug("Running command %s" % " ".join(args))
            self.ffmpeg_handle = subprocess.Popen(args, **kwargs)

            segmenter_exe = get_segmenter_executable_path()
            args = [segmenter_exe]
            address, port = self.sink.server_address
            args += TranscodeObject.segmenter_args + [str(port)]
            kwargs = {
                "stdout": open(os.devnull, "rb"),
                "stdin": self.ffmpeg_handle.stdout,
                "stderr": open(os.devnull, "wb"),
                "startupinfo": util.no_console_startupinfo(),
            }
            # XXX Can't use this - need to pass on the child fds
            # if os.name != "nt":
            #    kwargs["close_fds"] = True

            logging.debug("Running command %s" % " ".join(args))
            self.segmenter_handle = subprocess.Popen(args, **kwargs)

            self.sink_thread = threading.Thread(
                target=thread_body, args=[self.segmenter_consumer], name="Segmenter Consumer"
            )
            self.sink_thread.daemon = True
            self.sink_thread.start()

        except StandardError:
            (typ, value, tb) = sys.exc_info()
            logging.error("ERROR: %s %s" % (str(typ), str(value)))
            rc = False
        self.transcode_gate.set()
        return rc
Example #10
0
def needs_transcode(media_file):
    """needs_transcode()

    Returns (False, None) if no need to transcode.
    Returns (True, info) if there is a need to transcode.

    where info is

    (duration, has_audio, has_video)

    The duration is transmitted for transcoding purposes because we need to
    build a m3u8 playlist and what we get out of the Miro database may be 
    unreliable (does not exist).

    May throw exception if ffmpeg not found.  Remember to catch."""
    ffmpeg_exe = get_ffmpeg_executable_path()
    kwargs = {
        "stdout": subprocess.PIPE,
        "stderr": subprocess.PIPE,
        "stdin": subprocess.PIPE,
        "startupinfo": util.no_console_startupinfo(),
    }
    if os.name != "nt":
        kwargs["close_fds"] = True
    args = [ffmpeg_exe, "-i", media_file]
    handle = subprocess.Popen(args, **kwargs)
    # XXX unbounded read here but should be okay, ffmpeg output is finite.
    # note that we need to read from stderr, since that's what ffmpeg spits
    # out.
    text = handle.stderr.read()
    # Initial determination based on the file type - need to drill down
    # to see if the resolution, etc are within parameters.
    if container_regex.search(text):
        transcode = False
    else:
        transcode = True
    # "    Duration: XX:XX:XX.XX, ..."
    match = duration_regex.search(text)
    start, end = match.span()
    duration_start = text[end:]
    duration = duration_start[: duration_start.index(",")]
    # Convert to seconds.  We can't handle fractions of a second so
    # skip over those bits.
    hours, minutes, seconds = duration.split(":")
    # Strip the fractional seconds.  Always round up, then we won't miss
    # any data.
    seconds = int(float(seconds) + 0.5)
    seconds += int(minutes) * 60
    seconds += int(hours) * 3600
    has_audio = has_audio_regex.search(text)
    has_video = has_video_regex.search(text)
    vcodec = acodec = size = sample_rate = None
    vcopy = acopy = False
    if has_video:
        vcodec, size = get_video_parameters(has_video)
        vcopy = video_can_copy(vcodec, size)
        if not vcopy:
            transcode = False
    if has_audio:
        acodec, sample_rate = get_audio_parameters(has_audio)
        acopy = audio_can_copy(acodec, sample_rate)
        if not acopy:
            transcode = False
    return (transcode, (seconds, has_audio, acodec, sample_rate, has_video, vcodec, size))