Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /******************************************************************** |
michael@0 | 2 | * * |
michael@0 | 3 | * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * |
michael@0 | 4 | * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * |
michael@0 | 5 | * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * |
michael@0 | 6 | * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * |
michael@0 | 7 | * * |
michael@0 | 8 | * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * |
michael@0 | 9 | * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * |
michael@0 | 10 | * * |
michael@0 | 11 | ******************************************************************** |
michael@0 | 12 | |
michael@0 | 13 | function: |
michael@0 | 14 | last mod: $Id: decapiwrapper.c 13596 2007-08-23 20:05:38Z tterribe $ |
michael@0 | 15 | |
michael@0 | 16 | ********************************************************************/ |
michael@0 | 17 | |
michael@0 | 18 | #include <stdlib.h> |
michael@0 | 19 | #include <string.h> |
michael@0 | 20 | #include <limits.h> |
michael@0 | 21 | #include "apiwrapper.h" |
michael@0 | 22 | #include "decint.h" |
michael@0 | 23 | #include "theora/theoradec.h" |
michael@0 | 24 | |
michael@0 | 25 | static void th_dec_api_clear(th_api_wrapper *_api){ |
michael@0 | 26 | if(_api->setup)th_setup_free(_api->setup); |
michael@0 | 27 | if(_api->decode)th_decode_free(_api->decode); |
michael@0 | 28 | memset(_api,0,sizeof(*_api)); |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | static void theora_decode_clear(theora_state *_td){ |
michael@0 | 32 | if(_td->i!=NULL)theora_info_clear(_td->i); |
michael@0 | 33 | memset(_td,0,sizeof(*_td)); |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | static int theora_decode_control(theora_state *_td,int _req, |
michael@0 | 37 | void *_buf,size_t _buf_sz){ |
michael@0 | 38 | return th_decode_ctl(((th_api_wrapper *)_td->i->codec_setup)->decode, |
michael@0 | 39 | _req,_buf,_buf_sz); |
michael@0 | 40 | } |
michael@0 | 41 | |
michael@0 | 42 | static ogg_int64_t theora_decode_granule_frame(theora_state *_td, |
michael@0 | 43 | ogg_int64_t _gp){ |
michael@0 | 44 | return th_granule_frame(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp); |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | static double theora_decode_granule_time(theora_state *_td,ogg_int64_t _gp){ |
michael@0 | 48 | return th_granule_time(((th_api_wrapper *)_td->i->codec_setup)->decode,_gp); |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | static const oc_state_dispatch_vtable OC_DEC_DISPATCH_VTBL={ |
michael@0 | 52 | (oc_state_clear_func)theora_decode_clear, |
michael@0 | 53 | (oc_state_control_func)theora_decode_control, |
michael@0 | 54 | (oc_state_granule_frame_func)theora_decode_granule_frame, |
michael@0 | 55 | (oc_state_granule_time_func)theora_decode_granule_time, |
michael@0 | 56 | }; |
michael@0 | 57 | |
michael@0 | 58 | static void th_info2theora_info(theora_info *_ci,const th_info *_info){ |
michael@0 | 59 | _ci->version_major=_info->version_major; |
michael@0 | 60 | _ci->version_minor=_info->version_minor; |
michael@0 | 61 | _ci->version_subminor=_info->version_subminor; |
michael@0 | 62 | _ci->width=_info->frame_width; |
michael@0 | 63 | _ci->height=_info->frame_height; |
michael@0 | 64 | _ci->frame_width=_info->pic_width; |
michael@0 | 65 | _ci->frame_height=_info->pic_height; |
michael@0 | 66 | _ci->offset_x=_info->pic_x; |
michael@0 | 67 | _ci->offset_y=_info->pic_y; |
michael@0 | 68 | _ci->fps_numerator=_info->fps_numerator; |
michael@0 | 69 | _ci->fps_denominator=_info->fps_denominator; |
michael@0 | 70 | _ci->aspect_numerator=_info->aspect_numerator; |
michael@0 | 71 | _ci->aspect_denominator=_info->aspect_denominator; |
michael@0 | 72 | switch(_info->colorspace){ |
michael@0 | 73 | case TH_CS_ITU_REC_470M:_ci->colorspace=OC_CS_ITU_REC_470M;break; |
michael@0 | 74 | case TH_CS_ITU_REC_470BG:_ci->colorspace=OC_CS_ITU_REC_470BG;break; |
michael@0 | 75 | default:_ci->colorspace=OC_CS_UNSPECIFIED;break; |
michael@0 | 76 | } |
michael@0 | 77 | switch(_info->pixel_fmt){ |
michael@0 | 78 | case TH_PF_420:_ci->pixelformat=OC_PF_420;break; |
michael@0 | 79 | case TH_PF_422:_ci->pixelformat=OC_PF_422;break; |
michael@0 | 80 | case TH_PF_444:_ci->pixelformat=OC_PF_444;break; |
michael@0 | 81 | default:_ci->pixelformat=OC_PF_RSVD; |
michael@0 | 82 | } |
michael@0 | 83 | _ci->target_bitrate=_info->target_bitrate; |
michael@0 | 84 | _ci->quality=_info->quality; |
michael@0 | 85 | _ci->keyframe_frequency_force=1<<_info->keyframe_granule_shift; |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | int theora_decode_init(theora_state *_td,theora_info *_ci){ |
michael@0 | 89 | th_api_info *apiinfo; |
michael@0 | 90 | th_api_wrapper *api; |
michael@0 | 91 | th_info info; |
michael@0 | 92 | api=(th_api_wrapper *)_ci->codec_setup; |
michael@0 | 93 | /*Allocate our own combined API wrapper/theora_info struct. |
michael@0 | 94 | We put them both in one malloc'd block so that when the API wrapper is |
michael@0 | 95 | freed, the info struct goes with it. |
michael@0 | 96 | This avoids having to figure out whether or not we need to free the info |
michael@0 | 97 | struct in either theora_info_clear() or theora_clear().*/ |
michael@0 | 98 | apiinfo=(th_api_info *)_ogg_calloc(1,sizeof(*apiinfo)); |
michael@0 | 99 | if(apiinfo==NULL)return OC_FAULT; |
michael@0 | 100 | /*Make our own copy of the info struct, since its lifetime should be |
michael@0 | 101 | independent of the one we were passed in.*/ |
michael@0 | 102 | *&apiinfo->info=*_ci; |
michael@0 | 103 | /*Convert the info struct now instead of saving the the one we decoded with |
michael@0 | 104 | theora_decode_header(), since the user might have modified values (i.e., |
michael@0 | 105 | color space, aspect ratio, etc. can be specified from a higher level). |
michael@0 | 106 | The user also might be doing something "clever" with the header packets if |
michael@0 | 107 | they are not using an Ogg encapsulation.*/ |
michael@0 | 108 | oc_theora_info2th_info(&info,_ci); |
michael@0 | 109 | /*Don't bother to copy the setup info; th_decode_alloc() makes its own copy |
michael@0 | 110 | of the stuff it needs.*/ |
michael@0 | 111 | apiinfo->api.decode=th_decode_alloc(&info,api->setup); |
michael@0 | 112 | if(apiinfo->api.decode==NULL){ |
michael@0 | 113 | _ogg_free(apiinfo); |
michael@0 | 114 | return OC_EINVAL; |
michael@0 | 115 | } |
michael@0 | 116 | apiinfo->api.clear=(oc_setup_clear_func)th_dec_api_clear; |
michael@0 | 117 | _td->internal_encode=NULL; |
michael@0 | 118 | /*Provide entry points for ABI compatibility with old decoder shared libs.*/ |
michael@0 | 119 | _td->internal_decode=(void *)&OC_DEC_DISPATCH_VTBL; |
michael@0 | 120 | _td->granulepos=0; |
michael@0 | 121 | _td->i=&apiinfo->info; |
michael@0 | 122 | _td->i->codec_setup=&apiinfo->api; |
michael@0 | 123 | return 0; |
michael@0 | 124 | } |
michael@0 | 125 | |
michael@0 | 126 | int theora_decode_header(theora_info *_ci,theora_comment *_cc,ogg_packet *_op){ |
michael@0 | 127 | th_api_wrapper *api; |
michael@0 | 128 | th_info info; |
michael@0 | 129 | int ret; |
michael@0 | 130 | api=(th_api_wrapper *)_ci->codec_setup; |
michael@0 | 131 | /*Allocate an API wrapper struct on demand, since it will not also include a |
michael@0 | 132 | theora_info struct like the ones that are used in a theora_state struct.*/ |
michael@0 | 133 | if(api==NULL){ |
michael@0 | 134 | _ci->codec_setup=_ogg_calloc(1,sizeof(*api)); |
michael@0 | 135 | if(_ci->codec_setup==NULL)return OC_FAULT; |
michael@0 | 136 | api=(th_api_wrapper *)_ci->codec_setup; |
michael@0 | 137 | api->clear=(oc_setup_clear_func)th_dec_api_clear; |
michael@0 | 138 | } |
michael@0 | 139 | /*Convert from the theora_info struct instead of saving our own th_info |
michael@0 | 140 | struct between calls. |
michael@0 | 141 | The user might be doing something "clever" with the header packets if they |
michael@0 | 142 | are not using an Ogg encapsulation, and we don't want to break this.*/ |
michael@0 | 143 | oc_theora_info2th_info(&info,_ci); |
michael@0 | 144 | /*We rely on the fact that theora_comment and th_comment structures are |
michael@0 | 145 | actually identical. |
michael@0 | 146 | Take care not to change this fact unless you change the code here as |
michael@0 | 147 | well!*/ |
michael@0 | 148 | ret=th_decode_headerin(&info,(th_comment *)_cc,&api->setup,_op); |
michael@0 | 149 | /*We also rely on the fact that the error return code values are the same, |
michael@0 | 150 | and that the implementations of these two functions return the same set of |
michael@0 | 151 | them. |
michael@0 | 152 | Note that theora_decode_header() really can return OC_NOTFORMAT, even |
michael@0 | 153 | though it is not currently documented to do so.*/ |
michael@0 | 154 | if(ret<0)return ret; |
michael@0 | 155 | th_info2theora_info(_ci,&info); |
michael@0 | 156 | return 0; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | int theora_decode_packetin(theora_state *_td,ogg_packet *_op){ |
michael@0 | 160 | th_api_wrapper *api; |
michael@0 | 161 | ogg_int64_t gp; |
michael@0 | 162 | int ret; |
michael@0 | 163 | if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT; |
michael@0 | 164 | api=(th_api_wrapper *)_td->i->codec_setup; |
michael@0 | 165 | ret=th_decode_packetin(api->decode,_op,&gp); |
michael@0 | 166 | if(ret<0)return OC_BADPACKET; |
michael@0 | 167 | _td->granulepos=gp; |
michael@0 | 168 | return 0; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | int theora_decode_YUVout(theora_state *_td,yuv_buffer *_yuv){ |
michael@0 | 172 | th_api_wrapper *api; |
michael@0 | 173 | th_dec_ctx *decode; |
michael@0 | 174 | th_ycbcr_buffer buf; |
michael@0 | 175 | int ret; |
michael@0 | 176 | if(!_td||!_td->i||!_td->i->codec_setup)return OC_FAULT; |
michael@0 | 177 | api=(th_api_wrapper *)_td->i->codec_setup; |
michael@0 | 178 | decode=(th_dec_ctx *)api->decode; |
michael@0 | 179 | if(!decode)return OC_FAULT; |
michael@0 | 180 | ret=th_decode_ycbcr_out(decode,buf); |
michael@0 | 181 | if(ret>=0){ |
michael@0 | 182 | _yuv->y_width=buf[0].width; |
michael@0 | 183 | _yuv->y_height=buf[0].height; |
michael@0 | 184 | _yuv->y_stride=buf[0].stride; |
michael@0 | 185 | _yuv->uv_width=buf[1].width; |
michael@0 | 186 | _yuv->uv_height=buf[1].height; |
michael@0 | 187 | _yuv->uv_stride=buf[1].stride; |
michael@0 | 188 | _yuv->y=buf[0].data; |
michael@0 | 189 | _yuv->u=buf[1].data; |
michael@0 | 190 | _yuv->v=buf[2].data; |
michael@0 | 191 | } |
michael@0 | 192 | return ret; |
michael@0 | 193 | } |