All pastes #1287964 Raw Edit

Something

public text v1 · immutable
#1287964 ·published 2008-12-17 19:19 UTC
rendered paste body
# PySoy's textures.Video class
#
# Copyright (C) 2006,2007,2008 PySoy Group
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU Affero General Public License as published
#  by the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Affero General Public License for more details.
#
#  You should have received a copy of the GNU Affero General Public License
#  along with this program; if not, see http://www.gnu.org/licenses
#
# $Id: Video.pym 1265 2008-05-18 17:14:51Z ArcRiley $


cdef class Video (Texture) :
  '''PySoy textures.Video Class

    Renders an Ogg Theora stream to a texture
  '''

  ############################################################################
  #
  # C functions
  #
  
  cdef int _load(self, void* _data, int _size) nogil :
    cdef int _x, _y, _tx, _ty, _yl, _yc
    cdef int _py, _pu, _pv, _pr, _pg, _pb
    cdef ogg.ogg_page*   _page
    cdef ogg.yuv_buffer  _yuv
    cdef ogg.ogg_packet  _packet
    cdef double          _start  # for benchmarking
    cdef gl.GLubyte*     _rgbx
    if _data == NULL :
      stdio.printf('done decoding.\n')
      if self._stage > 0 :
        ogg.ogg_stream_clear(&self._stream)
        ogg.theora_info_clear(&self._info)
        ogg.theora_comment_clear(&self._comment)
        ogg.theora_clear(&self._decode)
      return 0
    _page = <ogg.ogg_page*> _data
    #
    # For Chaining/Looping
    if ogg.ogg_page_bos(_page) :
      if self._stage > 0 :
        ogg.ogg_stream_clear(&self._stream)
        ogg.theora_info_clear(&self._info)
        ogg.theora_comment_clear(&self._comment)
        ogg.theora_clear(&self._decode)
        self._startTime = self._startTime + self._frameTime
        self._frameTime = 0
      else :
        self._startTime = _time()
      self._stage = 0
    #
    # Read Page 0
    if self._stage == 0 :
      ogg.ogg_stream_init(&self._stream, ogg.ogg_page_serialno(_page))
      ogg.theora_info_init(&self._info)
      ogg.theora_comment_init(&self._comment)
      self._stage = 1
    # Read in the page if not -1
    if self._stage > 0 :
      ogg.ogg_stream_pagein(&self._stream, _page)
    # Read pre-data pages (if any)
    if self._stage == 1 :
      if ogg.ogg_page_granulepos(_page) == 0 :
        while ogg.ogg_stream_packetout(&self._stream, &_packet) :
          if ogg.theora_decode_header(&self._info, &self._comment,&_packet)<0 :
            # Error in header, clear what we've setup and bail
            ogg.ogg_stream_clear(&self._stream)
            ogg.theora_info_clear(&self._info)
            ogg.theora_comment_clear(&self._comment)
            self._stage = -1
            return 0
        if ogg.ogg_page_pageno(_page) == 0 :
          self._resize(1, 3, self._squareup(self._info.frame_width),
                          self._squareup(self._info.frame_height), 1)
          self._scaleX = <float> self._info.frame_width  / <float> self._width
          self._scaleY = <float> self._info.frame_height / <float> self._height
          self._aspect = ( <float> self._info.frame_width / \
                           <float> self._info.frame_height ) * \
                         ( <float> self._info.aspect_numerator / \
                           <float> self._info.aspect_denominator )
      else :
        ogg.theora_decode_init(&self._decode, &self._info)
        self._stage = 2
    if self._stage == 2 :
      # Theora frames are 1:1 with Ogg packets, but packets != pages
      while ogg.ogg_stream_packetout(&self._stream, &_packet) :
        ogg.theora_decode_packetin(&self._decode, &_packet)
        self._frameTime = ogg.theora_granule_time(&self._decode, 
                                              ogg.ogg_page_granulepos(_page))
        ogg.theora_decode_YUVout(&self._decode, &_yuv)
        #
        # tx/ty = texels x/y offset
        # yl/yc = yuv l/c offsets
        #
        # This can and should be optimized further
        #_start = _time()
        _rgbx = <gl.GLubyte*> py.PyMem_Malloc(self._width * 4)
        for _y from 0 <= _y < self._info.frame_height :
          _ty = (self._info.frame_height - _y) * self._width
          _yl = _y * _yuv.y_stride
          _yc = (_y/2) * _yuv.uv_stride
          oil.oil_yuv2rgbx_sub2_u8(
            _rgbx,
            _yuv.y + _yl,
            _yuv.u + _yc,
            _yuv.v + _yc,
            self._info.frame_width)
          #
          # copy rgbx to rgb, this needs to be optimized
          for _x from 0 <= _x < self._width :
            _tx = (_ty + _x) * 3
            self._texels[_tx    ] = _rgbx[(_x*4)    ]
            self._texels[_tx + 1] = _rgbx[(_x*4) + 1]
            self._texels[_tx + 2] = _rgbx[(_x*4) + 2]
          #  _py = _yuv.y[_yl + x]
          #  _pu = _yuv.u[_yc + (x/2)]
          #  _pv = _yuv.v[_yc + (x/2)]
          #  _pr = _py + _tableRV[_pv]
          #  _pg = _py - _tableGV[_pv] - _tableGU[_pu]
          #  _pb = _py + _tableBU[_pu]
          #  if _pr < 0 : 
          #    _pr = 0
          #  if _pg < 0 : 
          #    _pg = 0
          #  if _pb < 0 : 
          #    _pb = 0
          #  if _pr > 255 : 
          #    _pr = 255
          #  if _pg > 255 : 
          #    _pg = 255
          #  if _pb > 255 : 
          #    _pb = 255
          #  self._texels[_tx  ] = _pr
          #  self._texels[_tx+1] = _pg
          #  self._texels[_tx+2] = _pb
        py.PyMem_Free(_rgbx)
        self._update = 1
    return 1


  cdef int _save(self, void *_data, int _size) nogil :
    cdef ogg.ogg_page   *_page
    _page = <ogg.ogg_page*> _data
    return 1


  cdef int _ready(self) nogil :
    cdef double  _now
    _now = _time()
    if self._startTime + self._frameTime < _now :
      return 1
    return 0


  ############################################################################
  #
  # Properties
  #
  
  property offset :
    def __get__(self) :
      return self._frameTime