123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #include "apiwrapper.h"
- #include "encint.h"
- #include "theora/theoraenc.h"
- static void th_enc_api_clear(th_api_wrapper *_api){
- if(_api->encode)th_encode_free(_api->encode);
- memset(_api,0,sizeof(*_api));
- }
- static void theora_encode_clear(theora_state *_te){
- if(_te->i!=NULL)theora_info_clear(_te->i);
- memset(_te,0,sizeof(*_te));
- }
- static int theora_encode_control(theora_state *_te,int _req,
- void *_buf,size_t _buf_sz){
- return th_encode_ctl(((th_api_wrapper *)_te->i->codec_setup)->encode,
- _req,_buf,_buf_sz);
- }
- static ogg_int64_t theora_encode_granule_frame(theora_state *_te,
- ogg_int64_t _gp){
- return th_granule_frame(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
- }
- static double theora_encode_granule_time(theora_state *_te,ogg_int64_t _gp){
- return th_granule_time(((th_api_wrapper *)_te->i->codec_setup)->encode,_gp);
- }
- static const oc_state_dispatch_vtable OC_ENC_DISPATCH_VTBL={
- (oc_state_clear_func)theora_encode_clear,
- (oc_state_control_func)theora_encode_control,
- (oc_state_granule_frame_func)theora_encode_granule_frame,
- (oc_state_granule_time_func)theora_encode_granule_time,
- };
- int theora_encode_init(theora_state *_te,theora_info *_ci){
- th_api_info *apiinfo;
- th_info info;
- ogg_uint32_t keyframe_frequency_force;
- /*Allocate our own combined API wrapper/theora_info struct.
- We put them both in one malloc'd block so that when the API wrapper is
- freed, the info struct goes with it.
- This avoids having to figure out whether or not we need to free the info
- struct in either theora_info_clear() or theora_clear().*/
- apiinfo=(th_api_info *)_ogg_malloc(sizeof(*apiinfo));
- if(apiinfo==NULL)return TH_EFAULT;
- /*Make our own copy of the info struct, since its lifetime should be
- independent of the one we were passed in.*/
- *&apiinfo->info=*_ci;
- oc_theora_info2th_info(&info,_ci);
- apiinfo->api.encode=th_encode_alloc(&info);
- if(apiinfo->api.encode==NULL){
- _ogg_free(apiinfo);
- return OC_EINVAL;
- }
- apiinfo->api.clear=(oc_setup_clear_func)th_enc_api_clear;
- /*Provide entry points for ABI compatibility with old decoder shared libs.*/
- _te->internal_encode=(void *)&OC_ENC_DISPATCH_VTBL;
- _te->internal_decode=NULL;
- _te->granulepos=0;
- _te->i=&apiinfo->info;
- _te->i->codec_setup=&apiinfo->api;
- /*Set the precise requested keyframe frequency.*/
- keyframe_frequency_force=_ci->keyframe_auto_p?
- _ci->keyframe_frequency_force:_ci->keyframe_frequency;
- th_encode_ctl(apiinfo->api.encode,
- TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
- &keyframe_frequency_force,sizeof(keyframe_frequency_force));
- /*TODO: Additional codec setup using the extra fields in theora_info.*/
- return 0;
- }
- int theora_encode_YUVin(theora_state *_te,yuv_buffer *_yuv){
- th_api_wrapper *api;
- th_ycbcr_buffer buf;
- int ret;
- api=(th_api_wrapper *)_te->i->codec_setup;
- buf[0].width=_yuv->y_width;
- buf[0].height=_yuv->y_height;
- buf[0].stride=_yuv->y_stride;
- buf[0].data=_yuv->y;
- buf[1].width=_yuv->uv_width;
- buf[1].height=_yuv->uv_height;
- buf[1].stride=_yuv->uv_stride;
- buf[1].data=_yuv->u;
- buf[2].width=_yuv->uv_width;
- buf[2].height=_yuv->uv_height;
- buf[2].stride=_yuv->uv_stride;
- buf[2].data=_yuv->v;
- ret=th_encode_ycbcr_in(api->encode,buf);
- if(ret<0)return ret;
- _te->granulepos=api->encode->state.granpos;
- return ret;
- }
- int theora_encode_packetout(theora_state *_te,int _last_p,ogg_packet *_op){
- th_api_wrapper *api;
- api=(th_api_wrapper *)_te->i->codec_setup;
- return th_encode_packetout(api->encode,_last_p,_op);
- }
- int theora_encode_header(theora_state *_te,ogg_packet *_op){
- oc_enc_ctx *enc;
- th_api_wrapper *api;
- int ret;
- api=(th_api_wrapper *)_te->i->codec_setup;
- enc=api->encode;
- /*If we've already started encoding, fail.*/
- if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
- return TH_EINVAL;
- }
- /*Reset the state to make sure we output an info packet.*/
- enc->packet_state=OC_PACKET_INFO_HDR;
- ret=th_encode_flushheader(api->encode,NULL,_op);
- return ret>=0?0:ret;
- }
- int theora_encode_comment(theora_comment *_tc,ogg_packet *_op){
- oggpack_buffer opb;
- void *buf;
- int packet_state;
- int ret;
- packet_state=OC_PACKET_COMMENT_HDR;
- oggpackB_writeinit(&opb);
- ret=oc_state_flushheader(NULL,&packet_state,&opb,NULL,NULL,
- th_version_string(),(th_comment *)_tc,_op);
- if(ret>=0){
- /*The oggpack_buffer's lifetime ends with this function, so we have to
- copy out the packet contents.
- Presumably the application knows it is supposed to free this.
- This part works nothing like the Vorbis API, and the documentation on it
- has been wrong for some time, claiming libtheora owned the memory.*/
- buf=_ogg_malloc(_op->bytes);
- if(buf==NULL){
- _op->packet=NULL;
- ret=TH_EFAULT;
- }
- else{
- memcpy(buf,_op->packet,_op->bytes);
- _op->packet=buf;
- ret=0;
- }
- }
- oggpack_writeclear(&opb);
- return ret;
- }
- int theora_encode_tables(theora_state *_te,ogg_packet *_op){
- oc_enc_ctx *enc;
- th_api_wrapper *api;
- int ret;
- api=(th_api_wrapper *)_te->i->codec_setup;
- enc=api->encode;
- /*If we've already started encoding, fail.*/
- if(enc->packet_state>OC_PACKET_EMPTY||enc->state.granpos!=0){
- return TH_EINVAL;
- }
- /*Reset the state to make sure we output a setup packet.*/
- enc->packet_state=OC_PACKET_SETUP_HDR;
- ret=th_encode_flushheader(api->encode,NULL,_op);
- return ret>=0?0:ret;
- }
|