Index: Makefile =================================================================== RCS file: /cvsroot/mplayer/main/Makefile,v retrieving revision 1.322 diff -u -r1.322 Makefile --- Makefile 7 May 2005 14:50:14 -0000 1.322 +++ Makefile 14 May 2005 00:58:49 -0000 @@ -35,7 +35,7 @@ CODEC_LIBS = $(AV_LIB) $(FAME_LIB) $(MAD_LIB) $(VORBIS_LIB) $(THEORA_LIB) $(FAAD_LIB) $(LIBLZO_LIB) $(DECORE_LIB) $(XVID_LIB) $(DTS_LIB) $(PNG_LIB) $(Z_LIB) $(JPEG_LIB) $(ALSA_LIB) $(XMMS_LIB) $(X264_LIB) COMMON_LIBS = libmpcodecs/libmpcodecs.a $(W32_LIB) $(DS_LIB) libaf/libaf.a libmpdemux/libmpdemux.a input/libinput.a postproc/libswscale.a osdep/libosdep.a $(DVDREAD_LIB) $(CODEC_LIBS) $(FREETYPE_LIB) $(TERMCAP_LIB) $(CDPARANOIA_LIB) $(MPLAYER_NETWORK_LIB) $(WIN32_LIB) $(GIF_LIB) $(MACOSX_FRAMEWORKS) $(SMBSUPPORT_LIB) $(FRIBIDI_LIB) $(FONTCONFIG_LIB) $(ENCA_LIB) -CFLAGS = $(OPTFLAGS) -I. $(FREETYPE_INC) $(EXTRA_INC) $(CDPARANOIA_INC) $(SDL_INC) $(X11_INC) $(FRIBIDI_INC) $(DVB_INC) $(XVID_INC) $(FONTCONFIG_INC) $(CACA_INC) # -Wall +CFLAGS = $(OPTFLAGS) -I. $(FREETYPE_INC) $(EXTRA_INC) $(CDPARANOIA_INC) $(SDL_INC) $(X11_INC) $(FRIBIDI_INC) $(DVB_INC) $(XVID_INC) $(FONTCONFIG_INC) $(CACA_INC) $(THEORA_INC) # -Wall ifeq ($(TOOLAME),yes) CFLAGS += $(TOOLAME_EXTRAFLAGS) CODEC_LIBS += $(TOOLAME_LIB) Index: configure =================================================================== RCS file: /cvsroot/mplayer/main/configure,v retrieving revision 1.1002 diff -u -r1.1002 configure --- configure 11 May 2005 16:00:07 -0000 1.1002 +++ configure 14 May 2005 00:58:54 -0000 @@ -218,6 +218,7 @@ --enable-external-tremor build with external tremor [disabled] --disable-vorbis disable OggVorbis support entirely [autodetect] --enable-theora build with OggTheora support [autodetect] + --enable-theora-exp build with experimental OggTheora support [autodetect] --disable-internal-matroska disable internal Matroska support [enabled] --enable-external-faad build with external FAAD2 (AAC) support [autodetect] --disable-internal-faad disable internal FAAD2 (AAC) support [autodetect] @@ -1339,6 +1340,7 @@ _tremor_low=no _vorbis=auto _theora=auto +_theoraexp=auto _mp3lib=yes _liba52=yes _libdts=auto @@ -1535,6 +1537,8 @@ --disable-external-tremor) _tremor=no ;; --enable-theora) _theora=yes ;; --disable-theora) _theora=no ;; + --enable-theora-exp) _theoraexp=yes ;; + --disable-theora-exp) _theoraexp=no ;; --enable-mp3lib) _mp3lib=yes ;; --disable-mp3lib) _mp3lib=no ;; --enable-liba52) _liba52=yes ;; @@ -5301,54 +5305,35 @@ echores "$_vorbis" fi -echocheck "OggTheora support (only the CVS version!)" +echocheck "OggTheora support" if test "$_theora" = auto ; then _theora=no - cat > $TMPC << EOF -#include -#include -int main(void) -{ - /* theora is in flux, make sure that all interface routines and - * datatypes exist and work the way we expect it, so we don't break - * mplayer */ - ogg_packet op; - theora_comment tc; - theora_info inf; - theora_state st; - yuv_buffer yuv; - int r; - double t; - - theora_info_init (&inf); - theora_comment_init (&tc); - - return 0; - - /* we don't want to execute this kind of nonsense; just for making sure - * that compilation works... */ - memset(&op, 0, sizeof(op)); - r = theora_decode_header (&inf, &tc, &op); - r = theora_decode_init (&st, &inf); - t = theora_granule_time (&st, op.granulepos); - r = theora_decode_packetin (&st, &op); - r = theora_decode_YUVout (&st, &yuv); - theora_clear (&st); - - return 0; -} -EOF - cc_check -ltheora -logg $_ld_lm && _theora=yes + pkg-config --exists 'theora' && _theora=yes fi -if test "$_theora" = yes ; then +if test "$_theoraexp" = auto ; then + _theoraexp=no + pkg-config --exists 'theoradec' && _theoraexp=yes +fi +if test "$_theoraexp" = yes ; then + _theora=yes + _def_theora='#define HAVE_OGGTHEORA_EXP 1' + _codecmodules="libtheoradec $_codecmodules" + _ld_theora=`pkg-config --libs theoradec` + _inc_theora=`pkg-config --cflags theoradec` + _theora_version=" (theora-exp)" +elif test "$_theora" = yes ; then _def_theora='#define HAVE_OGGTHEORA 1' _codecmodules="libtheora $_codecmodules" - _ld_theora="-ltheora -logg" + _ld_theora=`pkg-config --libs theora` + _inc_theora=`pkg-config --cflags theora` + _theora_version=`pkg-config --modversion theora` + _theora_version="(Version $_theora_version)" else _def_theora='#undef HAVE_OGGTHEORA' _nocodecmodules="libtheora $_nocodecmodules" fi -echores "$_theora" + +echores "$_theora $_theora_version" echocheck "mp3lib support" if test "$_mp3lib" = yes ; then @@ -6955,6 +6940,7 @@ LIBLZO_LIB= $_ld_liblzo MAD_LIB = $_ld_mad VORBIS_LIB = $_ld_vorbis $_ld_libdv +THEORA_INC = $_inc_theora THEORA_LIB = $_ld_theora FAAD_LIB = $_ld_faad INTERNAL_FAAD = $_faad_internal Index: etc/codecs.conf =================================================================== RCS file: /cvsroot/mplayer/main/etc/codecs.conf,v retrieving revision 1.411 diff -u -r1.411 codecs.conf --- etc/codecs.conf 4 May 2005 20:35:21 -0000 1.411 +++ etc/codecs.conf 14 May 2005 00:58:55 -0000 @@ -220,6 +220,14 @@ dll libtheora out YV12 +videocodec theoraexp + info "Theora (experimental version)" + status working + fourcc theo,Thra + driver theoraexp + dll libtheoradec + out YV12,422P,444P + ; prefer native codecs over win32? ; the win32 codecs probably are (better) optimized and support direct ; rendering, so this may be not the best idea... Index: libmpcodecs/Makefile =================================================================== RCS file: /cvsroot/mplayer/main/libmpcodecs/Makefile,v retrieving revision 1.141 diff -u -r1.141 Makefile --- libmpcodecs/Makefile 7 May 2005 14:49:18 -0000 1.141 +++ libmpcodecs/Makefile 14 May 2005 00:58:56 -0000 @@ -11,7 +11,7 @@ VIDEO_SRCS_LIB=vd_libmpeg2.c vd_nuv.c vd_lzo.c VIDEO_SRCS_NAT=vd_null.c vd_raw.c vd_hmblck.c vd_mpegpes.c vd_mtga.c vd_sgi.c -VIDEO_SRCS_OPT=vd_realvid.c vd_ffmpeg.c vd_dshow.c vd_dmo.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_zrmjpeg.c vd_xanim.c vd_xvid.c vd_xvid4.c vd_libdv.c vd_qtvideo.c vd_theora.c +VIDEO_SRCS_OPT=vd_realvid.c vd_ffmpeg.c vd_dshow.c vd_dmo.c vd_vfw.c vd_vfwex.c vd_odivx.c vd_divx4.c vd_zrmjpeg.c vd_xanim.c vd_xvid.c vd_xvid4.c vd_libdv.c vd_qtvideo.c vd_theora.c vd_theora-exp.c VIDEO_SRCS=dec_video.c vd.c $(VIDEO_SRCS_NAT) $(VIDEO_SRCS_LIB) $(VIDEO_SRCS_OPT) VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c vf_scale.c vf_format.c vf_noformat.c vf_yuy2.c vf_flip.c vf_rgb2bgr.c vf_rotate.c vf_mirror.c vf_palette.c vf_lavc.c vf_dvbscale.c vf_cropdetect.c vf_test.c vf_noise.c vf_yvu9.c vf_rectangle.c vf_lavcdeint.c vf_eq.c vf_eq2.c vf_halfpack.c vf_dint.c vf_1bpp.c vf_bmovl.c vf_2xsai.c vf_unsharp.c vf_swapuv.c vf_il.c vf_boxblur.c vf_sab.c vf_smartblur.c vf_perspective.c vf_down3dright.c vf_field.c vf_denoise3d.c vf_hqdn3d.c vf_detc.c vf_telecine.c vf_tfields.c vf_ivtc.c vf_ilpack.c vf_dsize.c vf_decimate.c vf_softpulldown.c vf_tinterlace.c vf_pullup.c pullup.c vf_framestep.c vf_tile.c vf_delogo.c vf_fil.c vf_hue.c vf_spp.c vf_yuvcsp.c vf_filmdint.c vf_kerndeint.c vf_rgbtest.c vf_qp.c vf_phase.c vf_divtc.c vf_harddup.c vf_softskip.c Index: libmpcodecs/vd.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpcodecs/vd.c,v retrieving revision 1.83 diff -u -r1.83 vd.c --- libmpcodecs/vd.c 18 Apr 2005 15:52:37 -0000 1.83 +++ libmpcodecs/vd.c 14 May 2005 00:58:56 -0000 @@ -30,6 +30,7 @@ extern vd_functions_t mpcodecs_vd_null; extern vd_functions_t mpcodecs_vd_ffmpeg; extern vd_functions_t mpcodecs_vd_theora; +extern vd_functions_t mpcodecs_vd_theoraexp; extern vd_functions_t mpcodecs_vd_dshow; extern vd_functions_t mpcodecs_vd_dmo; extern vd_functions_t mpcodecs_vd_vfw; @@ -58,6 +59,9 @@ #ifdef USE_LIBAVCODEC &mpcodecs_vd_ffmpeg, #endif +#ifdef HAVE_OGGTHEORA_EXP + &mpcodecs_vd_theoraexp, +#endif #ifdef HAVE_OGGTHEORA &mpcodecs_vd_theora, #endif Index: libmpcodecs/vd_theora-exp.c =================================================================== RCS file: libmpcodecs/vd_theora-exp.c diff -N libmpcodecs/vd_theora-exp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ libmpcodecs/vd_theora-exp.c 14 May 2005 00:58:56 -0000 @@ -0,0 +1,398 @@ + +#include +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#ifdef HAVE_OGGTHEORA_EXP + +#include "vd_internal.h" + +static vd_info_t info = { + "Theora/VP3", + "theoraexp", + "David Kuehling", + "www.theora.org", + "Theora (experimental version)" +}; + +LIBVD_EXTERN(theoraexp) + +#include + +/**\name Chroma decimation flags. + These flags tell us in which dimensions chroma is subsampled. + Chroma is decimated in a given direction if its flag is _unset_. + If Theora's reserved pixel_fmt code is ever assigned, these flags may no + longer work like this, but currently we will (correctly) refuse to decode + such a file anyway.*/ +/*@{*/ +#define THEORA_CHROMA_HFULL (1) +#define THEORA_CHROMA_VFULL (2) +/*@}*/ + +typedef struct theora_struct_st { + theora_dec_ctx *td; + theora_comment cc; + theora_info inf; + int pic_width; + int pic_height; + int pic_x; + int pic_y; +} theora_struct_t; + +/**To set/get/query special features/parameters.*/ +static int control(sh_video_t *sh,int cmd,void* arg,...){ + theora_struct_t *context; + context=sh->context; + switch(cmd) { + case VDCTRL_QUERY_MAX_PP_LEVEL: + { + int pp_level_max; + if(theora_decode_ctl(context->td,OC_DECCTL_GET_PPLEVEL_MAX, + &pp_level_max,sizeof(pp_level_max))!=0) + return CONTROL_UNKNOWN; + return pp_level_max; + } + case VDCTRL_SET_PP_LEVEL: + if(theora_decode_ctl(context->td,OC_DECCTL_SET_PPLEVEL,arg, + sizeof(int))!=0) + return CONTROL_ERROR; + return CONTROL_OK; + case VDCTRL_QUERY_FORMAT: + switch(context->inf.pixel_fmt) { + case OC_PF_420: + if ((*((int*)arg)) == IMGFMT_YV12) + return CONTROL_TRUE; + break; + case OC_PF_422: + if ((*((int*)arg)) == IMGFMT_422P) + return CONTROL_TRUE; + break; + case OC_PF_444: + if ((*((int*)arg)) == IMGFMT_444P) + return CONTROL_TRUE; + break; + } + return CONTROL_FALSE; + } + + return CONTROL_UNKNOWN; +} + +/** + * Init driver. + */ +static int init(sh_video_t *sh){ + unsigned int *header_lens = NULL; + theora_struct_t *context = NULL; + theora_setup_info *ts = NULL; + int failed = 1; + int errorCode = 0; + ogg_packet op; + int imgfmt; + int i; + + /* this is not a loop, just a context, from which we can break on error */ + do + { + unsigned char *ed; + unsigned char *ed_end; + int nheaders; + context = (theora_struct_t *)calloc (sizeof (theora_struct_t), 1); + sh->context = context; + if (!context) + break; + + theora_info_init(&context->inf); + theora_comment_init(&context->cc); + + /* Read all header packets, pass them to theora_decode_header. */ + ed = (unsigned char *)(sh->bih+1); + ed_end = ((unsigned char *)sh->bih)+sh->bih->biSize; + if (ed >= ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data counting Theora headers.\n"); + break; + } + nheaders = *ed+++1; + if (nheaders < 3) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient Theora headers: %i found, at least 3 required.\n", nheaders); + break; + } + header_lens = calloc(nheaders,sizeof(header_lens[0])); + for (i = 0; i < nheaders-1 ; i++) + { + while (ed=ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data reading Theora header lengths.\n"); + break; + } + header_lens[i] = ed_end-ed-header_lens[i]; + + for (i = 0; i < nheaders ; i++) + { + if (ed+header_lens[i] > ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data reading Theora header %d (wanted %d bytes, only %d bytes remaining).\n",i,header_lens[i],ed_end-ed); + break; + } + op.packet = ed; + op.bytes = header_lens[i]; + op.b_o_s = i==0; + if ( (errorCode = theora_decode_headerin (&context->inf, &context->cc, &ts, &op))<0 ) + { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Broken Theora header; errorCode=%i!\n", errorCode); + break; + } + ed += header_lens[i]; + } + if (i < nheaders) + break; + + context->td = theora_decode_alloc (&context->inf,ts); + if (context->td == NULL) + { + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode init failed: %i \n", + errorCode); + break; + } + + imgfmt=0; + switch(context->inf.pixel_fmt){ + case OC_PF_420:imgfmt=IMGFMT_YV12;break; + case OC_PF_422:imgfmt=IMGFMT_422P;break; + case OC_PF_444:imgfmt=IMGFMT_444P;break; + default: + { + mp_msg(MSGT_DECVIDEO,MSGL_ERR, + "Unknown Theora pixel format: %i \n", + context->inf.pixel_fmt); + } + } + if(imgfmt==0)break; + + failed = 0; + } while (0); + + free(header_lens); + /*We're done with the setup info, so we can free it now.*/ + theora_setup_free(ts); + + if (failed) + { + if (context) + { + theora_info_clear(&context->inf); + theora_comment_clear(&context->cc); + theora_decode_free(context->td); + free (context); + sh->context = NULL; + } + return 0; + } + + /*Now handle non-multiple-of-16 frame sizes.*/ + /*For pixel formats with decimated chroma planes, we don't particularly + want to deal with half chroma pixels, so we pad frames out to an even + luma pixel boundary.*/ + context->pic_width=context->inf.pic_width; + context->pic_height=context->inf.pic_height; + context->pic_x=context->inf.pic_x; + context->pic_y=context->inf.pic_y; + if(!(context->inf.pixel_fmt&THEORA_CHROMA_HFULL)) + { + context->pic_width+=context->pic_x&1; + context->pic_x&=~1; + context->pic_width+=context->pic_width&1; + } + if(!(context->inf.pixel_fmt&THEORA_CHROMA_VFULL)) + { + context->pic_height+=context->pic_y&1; + context->pic_y&=~1; + context->pic_height+=context->pic_height&1; + } + + if(sh->aspect==0.0 && context->inf.aspect_numerator!=0 && + context->inf.aspect_denominator!=0) + { + /*Note that because of the adjustments above, the frame aspect ratio + reported by mplayer might be slightly off. + However, this is the correct interpretation of the aspect ratio stored + in the file, which is a pixel aspect ratio.*/ + sh->aspect = (float)(context->inf.aspect_numerator * context->pic_width)/ + (context->inf.aspect_denominator * context->pic_height); + } + + mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Theora video init ok!\n"); + + return mpcodecs_config_vo (sh,context->inf.pic_width,context->inf.pic_height,imgfmt); +} + +/** + * Uninit driver. + */ +static void uninit(sh_video_t *sh) +{ + theora_struct_t *context = (theora_struct_t *)sh->context; + + if (context) + { + theora_info_clear(&context->inf); + theora_comment_clear(&context->cc); + theora_decode_free(context->td); + free (context); + } +} + +/**libtheoradec's striped decode callback. + Not that decoding proceeds from bottom to top, so \a _yfrag0 will steadily + decrease with each call until it reaches 0, at which point the full frame is + decoded. + \param _ctx The #sh_video_t instance for the decoder. + \param _buf The buffer pointing to the newly decoded stripe. + \param _yfrag0 The top-most fragment position of the decoded stripe. + \param _yfrag_end The fragment position immediately following the decode + stripe.*/ +static void stripe_decoded(void *_ctx,theora_ycbcr_buffer _buf, + int _yfrag0,int _yfrag_end) +{ + unsigned char *src[3]; + int stride[3]; + sh_video_t *sh; + theora_struct_t *context; + int pic_cx; + int pic_cy; + int pic_yend; + int y0; + int y_end; + + sh = (sh_video_t *)_ctx; + context = (theora_struct_t *)sh->context; + /*Clip the slice to the picture region.*/ + y0 = _yfrag0<<3; + y_end = _yfrag_end<<3; + if(context->pic_y>=y_end)return; + else if(context->pic_y>y0)y0=context->pic_y; + pic_yend=context->pic_y+context->pic_height; + if(y0>=pic_yend)return; + else if(pic_yendpic_x>>!(context->inf.pixel_fmt&THEORA_CHROMA_HFULL); + pic_cy=y0>>!(context->inf.pixel_fmt&THEORA_CHROMA_VFULL); + /*Fill in the buffer pointers.*/ + src[0]=_buf[0].data+y0*_buf[0].ystride+context->pic_x; + stride[0]=_buf[0].ystride; + src[1]=_buf[1].data+pic_cy*_buf[1].ystride+pic_cx; + stride[1]=_buf[1].ystride; + src[2]=_buf[2].data+pic_cy*_buf[2].ystride+pic_cx; + stride[2]=_buf[2].ystride; + mpcodecs_draw_slice(sh,src,stride,context->pic_width,y_end-y0, + 0,y0-context->pic_y); +} + +/** + * Decode frame. + */ +static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags) +{ + theora_stripe_callback cb; + theora_struct_t *context = (theora_struct_t *)sh->context; + int errorCode = 0; + ogg_packet op; + theora_ycbcr_buffer ycbcr; + mp_image_t* mpi; + int i; + ogg_int64_t granpos; + int pic_cx; + int pic_cy; + + /*Skip dropped frames entirely. + If we were using granpos for anything, we would still have to call + theora_decode_packetin() to keep it updated correctly, but since we're + not we can just bail early.*/ + if(len<=0)return NULL; + + /*If we're not dropping frames, get an image.*/ + if(!(flags&VDFLAGS_DROPFRAME)){ + int mpi_flags; + mpi_flags = MP_IMGFLAG_PRESERVE; + cb.ctx = sh; + cb.stripe_decoded = stripe_decoded; + if(theora_decode_ctl(context->td, OC_DECCTL_SET_STRIPE_CB, &cb, + sizeof(cb))==0){ + mpi_flags |= MP_IMGFLAG_DRAW_CALLBACK; + } + mpi = mpcodecs_get_image(sh, MP_IMGTYPE_EXPORT, mpi_flags, + context->pic_width, context->pic_height); + if(!mpi) return NULL; + } + if(!mpi||!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) + { + cb.ctx = NULL; + cb.stripe_decoded = NULL; + theora_decode_ctl(context->td, OC_DECCTL_SET_STRIPE_CB, &cb, + sizeof(cb)); + } + + memset (&op, 0, sizeof (op)); + op.bytes = len; + op.packet = data; + op.granulepos = -1; + + /*Hard frame dropping: we keep keyframes (because they are long term + predictors, but otherwise skip decoding altogether).*/ + if((flags&VDFLAGS_DROPFRAME)==2&&theora_packet_iskeyframe(&op)<1) + return NULL; + + errorCode = theora_decode_packetin (context->td, &op, &granpos); + if (errorCode) + { + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Theora decode packetin failed: %i \n", + errorCode); + return NULL; + } + if(!(flags&VDFLAGS_DROPFRAME)){ + errorCode = theora_decode_ycbcr_out(context->td,ycbcr); + if (errorCode) + { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Theora decode YUVout failed: %i \n", + errorCode); + return 0; + } + } + + /*Figure out the offset to the chroma plane origin.*/ + pic_cx=context->pic_x>>!(context->inf.pixel_fmt&THEORA_CHROMA_HFULL); + pic_cy=context->pic_y>>!(context->inf.pixel_fmt&THEORA_CHROMA_VFULL); + /*Technically we should now pad the luma plane to even pixel boundaries + (e.g., by copying the odd pixel that's in the picture region). + However, unless post-processing is enabled, we can't write to libtheora's + buffer, because it's being used as the reference frame! + So, since padding somewhere further down the vo pipeline seems difficult, + and an extra copy ridiculous, we just ignore the problem. + This could cause artifacts along the edge, because the encoder is allowed + to store complete garbage outside the picture region, but for now it + should be okay. + We _are_ guaranteed a buffer that's a multiple of 16, so there's no need + to worry about access violations.*/ + /*We're also not worrying about different color standards or chroma + sampling sites now, as I don't think mplayer has any way to determine + what the output device is using.*/ + mpi->planes[0]=ycbcr[0].data+context->pic_y*ycbcr[0].ystride+context->pic_x; + mpi->stride[0]=ycbcr[0].ystride; + mpi->planes[1]=ycbcr[1].data+pic_cy*ycbcr[1].ystride+pic_cx; + mpi->stride[1]=ycbcr[1].ystride; + mpi->planes[2]=ycbcr[2].data+pic_cy*ycbcr[2].ystride+pic_cx; + mpi->stride[2]=ycbcr[2].ystride; + + return mpi; +} + +#endif Index: libmpcodecs/vd_theora.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpcodecs/vd_theora.c,v retrieving revision 1.7 diff -u -r1.7 vd_theora.c --- libmpcodecs/vd_theora.c 23 Feb 2005 11:55:26 -0000 1.7 +++ libmpcodecs/vd_theora.c 14 May 2005 00:58:56 -0000 @@ -23,8 +23,6 @@ #include -#define THEORA_NUM_HEADER_PACKETS 3 - // to set/get/query special features/parameters static int control(sh_video_t *sh,int cmd,void* arg,...){ switch(cmd) { @@ -47,25 +45,19 @@ * init driver */ static int init(sh_video_t *sh){ + unsigned int *header_lens = NULL; theora_struct_t *context = NULL; int failed = 1; int errorCode = 0; ogg_packet op; int i; - /* check whether video output format is supported */ - switch(sh->codec->outfmt[sh->outfmtidx]) - { - case IMGFMT_YV12: /* well, this should work... */ break; - default: - mp_msg (MSGT_DECVIDEO,MSGL_ERR,"Unsupported out_fmt: 0x%X\n", - sh->codec->outfmt[sh->outfmtidx]); - return 0; - } - /* this is not a loop, just a context, from which we can break on error */ do { + unsigned char *ed; + unsigned char *ed_end; + int nheaders; context = (theora_struct_t *)calloc (sizeof (theora_struct_t), 1); sh->context = context; if (!context) @@ -75,17 +67,49 @@ theora_comment_init(&context->cc); /* Read all header packets, pass them to theora_decode_header. */ - for (i = 0; i < THEORA_NUM_HEADER_PACKETS; i++) + ed = (unsigned char *)(sh->bih+1); + ed_end = ((unsigned char *)sh->bih)+sh->bih->biSize; + if (ed >= ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data counting Theora headers.\n"); + break; + } + nheaders = *ed+++1; + if (nheaders < 3) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient Theora headers: %i found, at least 3 required.\n", nheaders); + break; + } + header_lens = calloc(nheaders,sizeof(header_lens[0])); + for (i = 0; i < nheaders-1 ; i++) { - op.bytes = ds_get_packet (sh->ds, &op.packet); - op.b_o_s = 1; + while (ed=ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data reading Theora header lengths.\n"); + break; + } + header_lens[i] = ed_end-ed-header_lens[i]; + + for (i = 0; i < nheaders ; i++) + { + if (ed+header_lens[i] > ed_end) { + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Insufficient codec extra data reading Theora header %d (wanted %u bytes, only %d bytes remaining).\n",i,header_lens[i],ed_end-ed); + break; + } + op.packet = ed; + op.bytes = header_lens[i]; + op.b_o_s = i==0; if ( (errorCode = theora_decode_header (&context->inf, &context->cc, &op)) ) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Broken Theora header; errorCode=%i!\n", errorCode); break; } + ed += header_lens[i]; } - if (errorCode) + if (i < nheaders) break; /* now init codec */ @@ -99,10 +123,14 @@ failed = 0; } while (0); + free(header_lens); + if (failed) { if (context) { + theora_info_clear(&context->inf); + theora_comment_clear(&context->cc); free (context); sh->context = NULL; } Index: libmpdemux/demux_ogg.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/demux_ogg.c,v retrieving revision 1.75 diff -u -r1.75 demux_ogg.c --- libmpdemux/demux_ogg.c 13 May 2005 00:00:54 -0000 1.75 +++ libmpdemux/demux_ogg.c 14 May 2005 00:58:58 -0000 @@ -26,6 +26,9 @@ #include #endif +#ifdef HAVE_OGGTHEORA_EXP +#include +#endif #ifdef HAVE_OGGTHEORA #include #endif @@ -50,6 +53,17 @@ * without using theora_granule_time with the theora_state of the stream. * This is duplicated in `vd_theora.c'; put this in a common header? */ +#ifdef HAVE_OGGTHEORA_EXP +typedef struct theora_struct_st { + theora_dec_ctx *td; + theora_comment cc; + theora_info inf; + int pic_width; + int pic_height; + int pic_x; + int pic_y; +} theora_struct_t; +#endif #ifdef HAVE_OGGTHEORA typedef struct theora_struct_st { theora_state st; @@ -352,7 +366,7 @@ os->lastsize = blocksize; os->lastpos = pack->granulepos; } -# ifdef HAVE_OGGTHEORA +#if defined(HAVE_OGGTHEORA)||defined(HAVE_OGGTHEORA_EXP) } else if (os->theora) { /* we pass complete packets to theora, mustn't strip the header! */ data = pack->packet; @@ -363,8 +377,14 @@ decoder. */ if (context != NULL && !(*data&0x80)) { +#if defined(HAVE_OGGTHEORA) theora_info *thi = ((theora_struct_t*)context)->st.i; int keyframe_granule_shift=_ilog(thi->keyframe_frequency_force-1); +#endif +#if defined(HAVE_OGGTHEORA_EXP) + theora_info *thi = &(((theora_struct_t*)context)->inf); + int keyframe_granule_shift=thi->keyframe_granule_shift; +#endif int64_t iframemask = (1 << keyframe_granule_shift) - 1; if (pack->granulepos >= 0) @@ -380,7 +400,7 @@ pack->granulepos = os->lastpos; *pts = (double)os->lastpos / (double)os->samplerate; } -#endif /* HAVE_OGGTHEORA */ +#endif /* HAVE_OGGTHEORA||HAVE_OGGTHEORA_EXP */ # ifdef HAVE_FLAC } else if (os->flac) { /* we pass complete packets to flac, mustn't strip the header! */ @@ -817,6 +837,66 @@ free(buf[0]); } +static void fixup_theora_bih(sh_video_t *sh) +{ + int i; + int n; + int offset; + ogg_packet *op; + unsigned char *buf; + unsigned char *ptr; + unsigned int len; + + op = NULL; + for(n = 0;; n++) { + offset = ds_get_packet(sh->ds, &buf); + mp_msg(MSGT_DEMUX,MSGL_V, "fixup_theora_bih: i=%d, size=%u\n", n, offset); + if(offset < 0) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error!, fixup_theora_bih: bad packet n. %d\n", n); + } + if(offset <=0 || !(buf[0]&0x80)) { + ds_unget_packet(sh->ds, buf); + break; + } + op = realloc(op, sizeof(op[0])*(n+1)); + op[n].packet = malloc(offset); + memcpy(op[n].packet, buf, offset); + op[n].bytes = offset; + } + if(n < 3) { + mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error!, fixup_theora_bih: insufficient header packets: %i found, at least 3 required.\n", n); + } + else { + len = 0; + offset = 1; + for( i = 0; i < n-1; i++) { + len += op[i].bytes; + offset += op[i].bytes/255 + 1; + } + len += op[i].bytes; + len += offset; + sh->bih = (BITMAPINFOHEADER *)realloc(sh->bih, sizeof(BITMAPINFOHEADER) + len); + ptr = (unsigned char *)(sh->bih+1); + ptr[0] = n-1; + offset = 1; + for( i = 0; i < n-1; i++) { + offset += store_ughvlc(&ptr[offset], op[i].bytes); + mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after len %d = %u\n", i, offset); + } + for( i = 0; i < n; i++) { + mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, i=%d, bytes: %ld, offset: %u\n", i, op[i].bytes, offset); + memcpy(&ptr[offset], op[i].packet, op[i].bytes); + offset += op[i].bytes; + } + sh->bih->biSize = sizeof(BITMAPINFOHEADER)+offset; + mp_msg(MSGT_DEMUX,MSGL_V, "demux_ogg, extradata size: %d\n", sh->bih->biSize); + } + for (i = 0; i < n; i++) { + free(op[i].packet); + } + free(op); +} + /// Open an ogg physical stream int demux_ogg_open(demuxer_t* demuxer) { @@ -908,17 +988,27 @@ mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (Vorbis), -aid %d\n",ogg_d->num_sub,n_audio-1); // check for Theora -# ifdef HAVE_OGGTHEORA +# if defined(HAVE_OGGTHEORA)||defined(HAVE_OGGTHEORA_EXP) } else if (pack.bytes >= 7 && !strncmp (&pack.packet[1], "theora", 6)) { int errorCode = 0; theora_info inf; theora_comment cc; - +#if defined(HAVE_OGGTHEORA_EXP) + theora_setup_info *ts = NULL; + int pic_width; + int pic_height; +#endif + theora_info_init (&inf); theora_comment_init (&cc); - + +#if defined(HAVE_OGGTHEORA) errorCode = theora_decode_header (&inf, &cc, &pack); - if (errorCode) +#endif +#if defined(HAVE_OGGTHEORA_EXP) + errorCode = theora_decode_headerin (&inf, &cc, &ts, &pack); +#endif + if (errorCode<0) mp_msg(MSGT_DEMUX,MSGL_ERR,"Theora header parsing failed: %i \n", errorCode); else @@ -933,8 +1023,26 @@ (double)inf.fps_denominator; sh_v->frametime = ((double)inf.fps_denominator)/ (double)inf.fps_numerator; +#if defined(HAVE_OGGTHEORA_EXP) + pic_width = inf.pic_width; + pic_height = inf.pic_height; + if(!(inf.pixel_fmt&1)) + { + pic_width += inf.pic_x & 1; + pic_width += pic_width & 1; + } + if(!(inf.pixel_fmt&2)) + { + pic_height += inf.pic_y & 1; + pic_height += pic_height & 1; + } + sh_v->disp_w = sh_v->bih->biWidth = pic_width; + sh_v->disp_h = sh_v->bih->biHeight = pic_height; +#endif +#if defined(HAVE_OGGTHEORA) sh_v->disp_w = sh_v->bih->biWidth = inf.frame_width; sh_v->disp_h = sh_v->bih->biHeight = inf.frame_height; +#endif sh_v->bih->biBitCount = 24; sh_v->bih->biPlanes = 3; sh_v->bih->biSizeImage = ((sh_v->bih->biBitCount/8) * @@ -954,7 +1062,12 @@ n_video - 1); if(verbose>0) print_video_header(sh_v->bih); } -# endif /* HAVE_OGGTHEORA */ +#ifdef HAVE_OGGTHEORA_EXP + theora_setup_free(ts); +#endif + theora_info_clear(&inf); + theora_comment_clear(&cc); +# endif /* HAVE_OGGTHEORA||HAVE_OGGTHEORA_EXP */ # ifdef HAVE_FLAC } else if (pack.bytes >= 4 && !strncmp (&pack.packet[0], "fLaC", 4)) { sh_a = new_sh_audio(demuxer,ogg_d->num_sub); @@ -1193,6 +1306,10 @@ if(sh_a) if(sh_a->format == FOURCC_VORBIS) fixup_vorbis_wf(sh_a); + sh_v = demuxer->video->sh; + if(sh_v) + if(sh_v->format == FOURCC_THEORA) + fixup_theora_bih(sh_v); return 1; Index: libmpdemux/demuxer.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.c,v retrieving revision 1.187 diff -u -r1.187 demuxer.c --- libmpdemux/demuxer.c 29 Apr 2005 21:57:05 -0000 1.187 +++ libmpdemux/demuxer.c 14 May 2005 00:58:59 -0000 @@ -548,6 +548,14 @@ } } +int ds_unget_packet(demux_stream_t *ds,unsigned char *start){ + if(startbuffer||start>&ds->buffer[ds->buffer_pos]){ + return -1; + } + ds->buffer_pos=start-ds->buffer; + return 0; +} + int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start){ while(1){ int len; Index: libmpdemux/demuxer.h =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.h,v retrieving revision 1.76 diff -u -r1.76 demuxer.h --- libmpdemux/demuxer.h 28 Apr 2005 14:43:19 -0000 1.76 +++ libmpdemux/demuxer.h 14 May 2005 00:58:59 -0000 @@ -241,6 +241,7 @@ void ds_free_packs(demux_stream_t *ds); int ds_get_packet(demux_stream_t *ds,unsigned char **start); +int ds_unget_packet(demux_stream_t *ds,unsigned char *start); int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start); float ds_get_next_pts(demux_stream_t *ds);