Path: blob/master/thirdparty/libtheora/encapiwrapper.c
9898 views
#include <stdlib.h>1#include <string.h>2#include <limits.h>3#include "apiwrapper.h"4#include "encint.h"5#include "theora/theoraenc.h"6789static void th_enc_api_clear(th_api_wrapper *_api){10if(_api->encode)th_encode_free(_api->encode);11memset(_api,0,sizeof(*_api));12}1314static void theora_encode_clear(theora_state *_te){15if(_te->i!=NULL)theora_info_clear(_te->i);16memset(_te,0,sizeof(*_te));17}1819static int theora_encode_control(theora_state *_te,int _req,20void *_buf,size_t _buf_sz){21return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,22_req,_buf,_buf_sz);23}2425static ogg_int64_t theora_encode_granule_frame(theora_state *_te,26ogg_int64_t _gp){27return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);28}2930static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){31return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);32}3334static const oc_state_dispatch_vtable OC_ENC_DISPATCH_VTBL={35(oc_state_clear_func)theora_encode_clear,36(oc_state_control_func)theora_encode_control,37(oc_state_granule_frame_func)theora_encode_granule_frame,38(oc_state_granule_time_func)theora_encode_granule_time,39};4041int theora_encode_init(theora_state *_te,theora_info *_ci){42th_api_info *apiinfo;43th_info info;44ogg_uint32_t keyframe_frequency_force;45/*Allocate our own combined API wrapper/theora_info struct.46We put them both in one malloc'd block so that when the API wrapper is47freed, the info struct goes with it.48This avoids having to figure out whether or not we need to free the info49struct in either theora_info_clear() or theora_clear().*/50apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));51if(apiinfo==NULL)return TH_EFAULT;52/*Make our own copy of the info struct, since its lifetime should be53independent of the one we were passed in.*/54*&apiinfo->info=*_ci;55oc_theora_info2th_info(&info,_ci);56apiinfo->api.encode=th_encode_alloc(&info);57if(apiinfo->api.encode==NULL){58_ogg_free(apiinfo);59return OC_EINVAL;60}61apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;62/*Provide entry points for ABI compatibility with old decoder shared libs.*/63_te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;64_te->internal_decode=NULL;65_te->granulepos=0;66_te->i=&apiinfo->info;67_te->i->codec_setup=&apiinfo->api;68/*Set the precise requested keyframe frequency.*/69keyframe_frequency_force=_ci->keyframe_auto_p?70_ci->keyframe_frequency_force:_ci->keyframe_frequency;71th_encode_ctl(apiinfo->api.encode,72TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,73&keyframe_frequency_force,sizeof(keyframe_frequency_force));74/*TODO: Additional codec setup using the extra fields in theora_info.*/75return 0;76}7778int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){79th_api_wrapper *api;80th_ycbcr_buffer buf;81int ret;82api=(th_api_wrapper *)_te->i->codec_setup;83buf[0].width=_yuv->y_width;84buf[0].height=_yuv->y_height;85buf[0].stride=_yuv->y_stride;86buf[0].data=_yuv->y;87buf[1].width=_yuv->uv_width;88buf[1].height=_yuv->uv_height;89buf[1].stride=_yuv->uv_stride;90buf[1].data=_yuv->u;91buf[2].width=_yuv->uv_width;92buf[2].height=_yuv->uv_height;93buf[2].stride=_yuv->uv_stride;94buf[2].data=_yuv->v;95ret=th_encode_ycbcr_in(api->encode,buf);96if(ret<0)return ret;97_te->granulepos=api->encode->state.granpos;98return ret;99}100101int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){102th_api_wrapper *api;103api=(th_api_wrapper *)_te->i->codec_setup;104return th_encode_packetout(api->encode,_last_p,_op);105}106107int theora_encode_header(theora_state *_te,ogg_packet *_op){108oc_enc_ctx *enc;109th_api_wrapper *api;110int ret;111api=(th_api_wrapper *)_te->i->codec_setup;112enc=api->encode;113/*If we've already started encoding, fail.*/114if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){115return TH_EINVAL;116}117/*Reset the state to make sure we output an info packet.*/118enc->packet_state=OC_PACKET_INFO_HDR;119ret=th_encode_flushheader(api->encode,NULL,_op);120return ret>=0?0:ret;121}122123int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){124oggpack_buffer opb;125void *buf;126int packet_state;127int ret;128packet_state=OC_PACKET_COMMENT_HDR;129oggpackB_writeinit(&opb);130ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,131th_version_string(),(th_comment *)_tc,_op);132if(ret>=0){133/*The oggpack_buffer's lifetime ends with this function, so we have to134copy out the packet contents.135Presumably the application knows it is supposed to free this.136This part works nothing like the Vorbis API, and the documentation on it137has been wrong for some time, claiming libtheora owned the memory.*/138buf=_ogg_malloc(_op->bytes);139if(buf==NULL){140_op->packet=NULL;141ret=TH_EFAULT;142}143else{144memcpy(buf,_op->packet,_op->bytes);145_op->packet=buf;146ret=0;147}148}149oggpack_writeclear(&opb);150return ret;151}152153int theora_encode_tables(theora_state *_te,ogg_packet *_op){154oc_enc_ctx *enc;155th_api_wrapper *api;156int ret;157api=(th_api_wrapper *)_te->i->codec_setup;158enc=api->encode;159/*If we've already started encoding, fail.*/160if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){161return TH_EINVAL;162}163/*Reset the state to make sure we output a setup packet.*/164enc->packet_state=OC_PACKET_SETUP_HDR;165ret=th_encode_flushheader(api->encode,NULL,_op);166return ret>=0?0:ret;167}168169170