예제 #1
0
    def _play_thread_run(self):
        process_frame = self.process_frame
        ff_opts = {'sync': 'video', 'an': True, 'sn': True, 'paused': True}

        ifmt, icodec = self.file_fmt, self.icodec
        use_dshow = self.use_dshow
        if ifmt:
            ff_opts['f'] = ifmt
        if use_dshow:
            ff_opts['f'] = 'dshow'
        if icodec:
            ff_opts['vcodec'] = icodec

        ipix_fmt, iw, ih, _ = self.metadata_play
        ff_opts['x'] = iw
        ff_opts['y'] = ih

        lib_opts = {}
        if use_dshow:
            rate = self.dshow_rate
            if self.dshow_opt:
                fmt, size, (rmin, rmax) = self.parse_dshow_opt(self.dshow_opt)
                lib_opts['pixel_format'] = fmt
                lib_opts['video_size'] = '{}x{}'.format(*size)
                if rate:
                    rate = min(max(rate, rmin), rmax)
                    lib_opts['framerate'] = '{}'.format(rate)
            elif rate:
                lib_opts['framerate'] = '{}'.format(rate)

        fname = self.play_filename
        if use_dshow:
            fname = 'video={}'.format(self.dshow_true_filename)

        ffplayer = MediaPlayer(fname,
                               callback=self.player_callback,
                               ff_opts=ff_opts,
                               lib_opts=lib_opts)

        # wait for media to init pixel fmt
        src_fmt = ''
        s = clock()
        while self.play_state == 'starting' and clock() - s < 5.:
            src_fmt = ffplayer.get_metadata().get('src_pix_fmt')
            if src_fmt:
                break
            time.sleep(0.01)

        if not src_fmt:
            raise ValueError("Player failed, couldn't get pixel type")

        if ipix_fmt:
            src_fmt = ipix_fmt
        fmt = {
            'gray': 'gray',
            'rgb24': 'rgb24',
            'bgr24': 'rgb24',
            'rgba': 'rgba',
            'bgra': 'rgba'
        }.get(src_fmt, 'yuv420p')
        ffplayer.set_output_pix_fmt(fmt)

        ffplayer.toggle_pause()
        Logger.info('FFmpeg Player: input, output formats are: {}, {}'.format(
            src_fmt, fmt))

        # wait for first frame
        img = None
        s = clock()
        ivl_start = None
        while self.play_state == 'starting' and clock() - s < 5.:
            img, val = ffplayer.get_frame()
            if val == 'eof':
                raise ValueError("Player failed, reached eof")

            if img:
                ivl_start = clock()
                break
            time.sleep(0.01)

        rate = ffplayer.get_metadata().get('frame_rate')
        if rate == (0, 0) or not rate or not rate[1]:
            raise ValueError("Player failed, couldn't read frame rate")

        if not img:
            raise ValueError("Player failed, couldn't read frame")

        # ready to start
        rate = rate[0] / float(rate[1])
        w, h = img[0].get_size()
        fmt = img[0].get_pixel_format()
        use_rt = self.use_real_time

        Clock.schedule_once(
            partial(eat_first,
                    self.update_metadata,
                    rate=rate,
                    w=w,
                    h=h,
                    fmt=fmt), 0)
        Clock.schedule_once(self.complete_start)

        # started
        process_frame(img[0], {'t': ivl_start if use_rt else img[1]})

        min_sleep = 1 / (rate * 8.)
        self.setattr_in_kivy_thread('ts_play', ivl_start)
        self.setattr_in_kivy_thread('frames_played', 1)
        count = 1

        while self.play_state != 'stopping':
            img, val = ffplayer.get_frame()
            ivl_end = clock()

            if ivl_end - ivl_start >= 1.:
                real_rate = count / (ivl_end - ivl_start)
                self.setattr_in_kivy_thread('real_rate', real_rate)
                count = 0
                ivl_start = ivl_end

            if val == 'paused':
                raise ValueError("Player {} got {}".format(self, val))
            if val == 'eof':
                break

            if not img:
                time.sleep(min(val, min_sleep) if val else min_sleep)
                continue
            elif val:
                ts = clock()
                leftover = val
                while leftover > min_sleep and \
                        self.play_state != 'stopping':
                    time.sleep(min_sleep)
                    leftover = max(val - (clock() - ts), 0)

            count += 1
            self.increment_in_kivy_thread('frames_played')
            process_frame(img[0], {'t': ivl_end if use_rt else img[1]})