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