# 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 = _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 = self._info.frame_width / self._width self._scaleY = self._info.frame_height / self._height self._aspect = ( self._info.frame_width / \ self._info.frame_height ) * \ ( self._info.aspect_numerator / \ 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 = 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 = _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