1

我正在尝试使用 gst-python 构建视频缩略图,它看起来像这样。

from __future__ import division

import sys
import logging
import pdb

_log = logging.getLogger(__name__)
logging.basicConfig()
_log.setLevel(logging.DEBUG)

try:
    import gobject
    gobject.threads_init()
except:
    raise Exception('gobject could not be found')

try:
    import pygst
    pygst.require('0.10')
    import gst
    from gst import pbutils
    from gst.extend import discoverer
except:
    raise Exception('gst/pygst 0.10 could not be found')

class VideoThumbnailer:
    '''
        Creates a video thumbnail

     - Sets up discoverer & transcoding pipeline.
       Discoverer finds out information about the media file
     - Launches gobject.MainLoop, this triggers the discoverer to start running
     - Once the discoverer is done, it calls the __discovered callback function
     - The __discovered callback function launches the transcoding process
     - The _on_message callback is called from the transcoding process until it
       gets a message of type gst.MESSAGE_EOS, then it calls __stop which shuts
       down the gobject.MainLoop
    '''

    def __init__(self, src, dst, **kwargs):
        _log.info('Initializing VideoThumbnailer...')

        # Set instance variables
        self.loop = gobject.MainLoop()
        self.source_path = src
        self.destination_path = dst
        self.destination_dimensions = kwargs.get('dimensions') or (180, 180)

        if not type(self.destination_dimensions) == tuple:
            raise Exception('dimensions must be tuple: (width, height)')

        # Run setup
        self._setup()
        # Run.
        self._run()

    def _setup(self):
        self._setup_pipeline()
        self._setup_discover()

    def _run(self):
        _log.info('Discovering...')
        self.discoverer.discover()
        _log.info('Done')

        _log.debug('Initializing MainLoop()')
        self.loop.run()

    def _setup_discover(self):
        self.discoverer = discoverer.Discoverer(self.source_path)

        # Connect self.__discovered to the 'discovered' event
        self.discoverer.connect('discovered', self.__discovered)

    def __discovered(self, data, is_media):
        '''
        Callback for media discoverer.
        '''
        if not is_media:
            self.__stop()
            raise Exception('Could not discover {0}'.format(self.source_path))

        _log.debug('__discovered, data: {0}'.format(data))

        self.data = data

        # Run any tasks that depend on the info from the discovery
        self._on_discovered()

        # Tell the transcoding pipeline to start running
        #self.pipeline.set_state(gst.STATE_PLAYING)
        _log.info('Transcoding...')

    def _on_discovered(self):
        self.__setup_capsfilter()

    def _setup_pipeline(self):
        # Create a new pipeline
        self.pipeline = gst.Pipeline('VideoThumbnailerPipeline')

        # Create the elements in the pipeline
        self.filesrc = gst.element_factory_make('filesrc', 'filesrc')
        self.filesrc.set_property('location', self.source_path)
        self.pipeline.add(self.filesrc)

        self.decoder = gst.element_factory_make('decodebin2', 'decoder')
        self.decoder.connect('new-decoded-pad', self._on_dynamic_pad)
        self.pipeline.add(self.decoder)

        self.ffmpegcolorspace = gst.element_factory_make(
            'ffmpegcolorspace', 'ffmpegcolorspace')
        self.pipeline.add(self.ffmpegcolorspace)

        self.videoscale = gst.element_factory_make('videoscale', 'videoscale')
        self.videoscale.set_property('method', 'bilinear')
        self.pipeline.add(self.videoscale)

        self.capsfilter = gst.element_factory_make('capsfilter', 'capsfilter')
        self.pipeline.add(self.capsfilter)

        self.jpegenc = gst.element_factory_make('jpegenc', 'jpegenc')
        self.pipeline.add(self.jpegenc)

        self.filesink = gst.element_factory_make('filesink', 'filesink')
        self.filesink.set_property('location', self.destination_path)
        self.pipeline.add(self.filesink)

        # Link all the elements together
        self.filesrc.link(self.decoder)
        self.ffmpegcolorspace.link(self.videoscale)
        self.videoscale.link(self.capsfilter)
        self.capsfilter.link(self.jpegenc)
        self.jpegenc.link(self.filesink)

        self._setup_bus()

    def _on_dynamic_pad(self, dbin, pad, islast):
        '''
        Callback called when ``decodebin2`` has a pad that we can connect to
        '''
        # Intersect the capabilities of the video sink and the pad src
        # Then check if they have common capabilities.
        if not self.ffmpegcolorspace.get_pad_template('sink')\
                .get_caps().intersect(pad.get_caps()).is_empty():
            # It IS a video src pad.
            pad.link(self.ffmpegcolorspace.get_pad('sink'))

    def _setup_bus(self):
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect('message', self._on_message)

    def __setup_capsfilter(self):
        caps = ['video/x-raw-rgb']

        if self.data.videoheight > self.data.videowidth:
            # Whoa! We have ourselves a portrait video!
            caps.append('height={0}'.format(
                    self.destination_dimensions[1]))
        else:
            # It's a landscape, phew, how normal.
            caps.append('width={0}'.format(
                    self.destination_dimensions[0]))

        self.capsfilter.set_property(
            'caps',
            gst.caps_from_string(
                ', '.join(caps)))

    def _on_message(self, bus, message):
        _log.debug((bus, message))

        t = message.type

        if t == gst.MESSAGE_EOS:
            self.__stop()
            _log.info('Done')
        elif t == gst.MESSAGE_ERROR:
            _log.error((bus, message))
            self.__stop()

    def __stop(self):
        _log.debug(self.loop)

        self.pipeline.set_state(gst.STATE_NULL)

        gobject.idle_add(self.loop.quit)

它能做什么

  1. filesrc 加载视频文件
  2. decodebin2 解复用视频文件,将视频 src pad 连接到 ffmpegcolorspace sink
  3. ffmpegcolorspace 对视频流的颜色空间做任何事情
  4. videoscale 缩放视频
  5. capsfilter 告诉 videoscale 使视频适合 180x180 框
  6. jpegenc 捕获单个帧
  7. filesink 保存 jpeg 文件

我想让它做什么

  1. filesrc 加载视频文件
  2. decodebin2 解复用视频文件,将视频 src pad 连接到 ffmpegcolorspace sink
  3. ffmpegcolorspace 对视频流的颜色空间做任何事情
  4. videoscale 缩放视频
  5. capsfilter 告诉 videoscale 使视频适合 180x180 框
  6. jpegenc 在30% 的视频中捕获单个帧
  7. filesink 保存 jpeg 文件

我试过了

    self.decoder.seek_simple(
        gst.FORMAT_PERCENT,
        gst.SEEK_FLAG_FLUSH,
        self.WADSWORTH_CONSTANT) # int(30)

放置在_on_dynamic_pad,pad链接后,唉,无济于事。

4

1 回答 1

0

这现在在https://github.com/jwandborg/mediagoblin/blob/video_gstreamer-only/mediagoblin/media_types/video/transcoders.py#L53的 VideoThumbnailer 类中实现。

于 2011-11-14T09:32:39.723 回答