Put the channel count outside of the energy calculation. Increased the allowed
[opus.git] / tools / skeleton.c
1 /*
2  * skeleton.c
3  * author: Tahseen Mohammad
4  */
5
6 /* This file depends on WORDS_BIGENDIAN being defined to 1 if the host
7  * processor stores words with the most significant byte first (like Motorola
8  * and SPARC, unlike Intel and VAX). 
9  * On little endian systems, WORDS_BIGENDIAN should be undefined.
10  *
11  * When using GNU Autotools, the correct value will be written into config.h
12  * if the autoconf macro AC_C_BIGENDIAN is called in configure.ac.
13  */
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 #include <ogg/ogg.h>
23
24 #include "skeleton.h"
25
26 #ifdef WIN32                                                                   
27 #define snprintf _snprintf
28 #endif
29
30 static  unsigned short
31 _le_16 (unsigned short s)
32
33   unsigned short ret=s;
34 #ifdef WORDS_BIGENDIAN
35   ret = (s>>8) & 0x00ffU;
36   ret += (s<<8) & 0xff00U;
37 #endif
38   return ret;
39 }
40
41 static  ogg_uint32_t
42 _le_32 (ogg_uint32_t i)
43 {  
44    ogg_uint32_t ret=i;
45 #ifdef WORDS_BIGENDIAN
46    ret =  (i>>24);
47    ret += (i>>8) & 0x0000ff00;
48    ret += (i<<8) & 0x00ff0000;
49    ret += (i<<24);
50 #endif
51    return ret;
52 }
53
54 static  ogg_int64_t
55 _le_64 (ogg_int64_t l)
56
57   ogg_int64_t ret=l;
58   unsigned char *ucptr = (unsigned char *)&ret;
59 #ifdef WORDS_BIGENDIAN
60   unsigned char temp;
61
62   temp = ucptr [0] ;
63   ucptr [0] = ucptr [7] ;
64   ucptr [7] = temp ;
65
66   temp = ucptr [1] ;
67   ucptr [1] = ucptr [6] ;
68   ucptr [6] = temp ;
69
70   temp = ucptr [2] ;
71   ucptr [2] = ucptr [5] ;
72   ucptr [5] = temp ;
73
74   temp = ucptr [3] ;
75   ucptr [3] = ucptr [4] ;
76   ucptr [4] = temp ;
77
78 #endif
79   return (*(ogg_int64_t *)ucptr);
80 }
81
82 /* write an ogg_page to a file pointer */
83 int write_ogg_page_to_file(ogg_page *og, FILE *out) {
84    int written;
85    
86    written = fwrite(og->header,1, og->header_len, out);
87    written += fwrite(og->body,1, og->body_len, out);
88
89    return written;
90 }
91
92 int add_message_header_field(fisbone_packet *fp, 
93                                         char *header_key, 
94                                         char *header_value) {
95
96     /* size of both key and value + ': ' + CRLF */
97     int this_message_size = strlen(header_key) + strlen(header_value) + 4;
98     if (fp->message_header_fields == NULL) {
99         fp->message_header_fields = _ogg_calloc(this_message_size+1, sizeof(char));
100     } else {
101         int new_size = (fp->current_header_size + this_message_size+1) * sizeof(char);
102         fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
103     }
104     snprintf(fp->message_header_fields + fp->current_header_size, 
105                 this_message_size+1, 
106                 "%s: %s\r\n", 
107                 header_key, 
108                 header_value);
109     fp->current_header_size += this_message_size;
110
111     return 0;
112 }
113
114 /* create a ogg_packet from a fishead_packet structure */
115 ogg_packet ogg_from_fishead(fishead_packet *fp) {
116
117     ogg_packet op;
118
119     memset(&op, 0, sizeof(op));
120     op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
121     memset(op.packet, 0, FISHEAD_SIZE);
122
123     memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
124     *((ogg_uint16_t*)(op.packet+8)) = _le_16 (SKELETON_VERSION_MAJOR); /* version major */
125     *((ogg_uint16_t*)(op.packet+10)) = _le_16 (SKELETON_VERSION_MINOR); /* version minor */
126     *((ogg_int64_t*)(op.packet+12)) = _le_64 (fp->ptime_n); /* presentationtime numerator */
127     *((ogg_int64_t*)(op.packet+20)) = _le_64 (fp->ptime_d); /* presentationtime denominator */
128     *((ogg_int64_t*)(op.packet+28)) = _le_64 (fp->btime_n); /* basetime numerator */
129     *((ogg_int64_t*)(op.packet+36)) = _le_64 (fp->btime_d); /* basetime denominator */
130     /* TODO: UTC time, set to zero for now */
131
132     op.b_o_s = 1;   /* its the first packet of the stream */
133     op.e_o_s = 0;   /* its not the last packet of the stream */
134     op.bytes = FISHEAD_SIZE;  /* length of the packet in bytes */
135
136     return op;
137 }
138
139 /* create a ogg_packet from a fisbone_packet structure. 
140  * call this method after the fisbone_packet is filled and all message header fields are added
141  * by calling add_message_header_field method.
142  */
143 ogg_packet ogg_from_fisbone(fisbone_packet *fp) {
144     
145     ogg_packet op;
146     int packet_size = FISBONE_SIZE + fp->current_header_size;
147
148     memset (&op, 0, sizeof (op));       
149     op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
150     memset (op.packet, 0, packet_size);
151     memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
152     *((ogg_uint32_t*)(op.packet+8)) = _le_32 (FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
153     *((ogg_uint32_t*)(op.packet+12)) = _le_32 (fp->serial_no); /* serialno of the respective stream */
154     *((ogg_uint32_t*)(op.packet+16)) = _le_32 (fp->nr_header_packet); /* number of header packets */
155     *((ogg_int64_t*)(op.packet+20)) = _le_64 (fp->granule_rate_n); /* granulrate numerator */
156     *((ogg_int64_t*)(op.packet+28)) = _le_64 (fp->granule_rate_d); /* granulrate denominator */
157     *((ogg_int64_t*)(op.packet+36)) = _le_64 (fp->start_granule); /* start granule */
158     *((ogg_uint32_t*)(op.packet+44)) = _le_32 (fp->preroll); /* preroll, for theora its 0 */
159     *(op.packet+48) = fp->granule_shift; /* granule shift */
160     memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
161
162     op.b_o_s = 0;
163     op.e_o_s = 0;
164     op.bytes = packet_size; /* size of the packet in bytes */
165
166     return op;
167 }
168
169 /* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
170 fishead_packet fishead_from_ogg(ogg_packet *op) {
171         
172     fishead_packet fp;
173
174     if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8))
175         ; /* invalid packet what do we do? */
176
177     fp.version_major = _le_16 (*((ogg_uint16_t*)(op->packet+8))); /* version major */
178     fp.version_minor = _le_16 (*((ogg_uint16_t*)(op->packet+10))); /* version minor */
179     fp.ptime_n = _le_64 (*((ogg_int64_t*)(op->packet+12))); /* presentationtime numerator */
180     fp.ptime_d = _le_64 (*((ogg_int64_t*)(op->packet+20))); /* presentationtime denominator */
181     fp.btime_n = _le_64 (*((ogg_int64_t*)(op->packet+28))); /* basetime numerator */
182     fp.btime_d = _le_64 (*((ogg_int64_t*)(op->packet+36))); /* basetime denominator */
183     memcpy(fp.UTC, op->packet+44, 20);
184
185     return fp;
186 }
187
188 /* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
189 fisbone_packet fisbone_from_ogg(ogg_packet *op) {
190
191     fisbone_packet fp;
192     
193     if (memcmp(op->packet, FISBONE_IDENTIFIER, 8))
194         ; /* invalid value, what do we do? */
195     fp.serial_no = _le_32 (*((ogg_uint32_t*)(op->packet+12))); /* serialno of the stream represented by this fisbone packet */
196     fp.nr_header_packet = _le_32 (*((ogg_uint32_t*)(op->packet+16))); /* number of header packets */
197     fp.granule_rate_n = _le_64 (*((ogg_int64_t*)(op->packet+20))); /* granulrate numerator */
198     fp.granule_rate_d = _le_64 (*((ogg_int64_t*)(op->packet+28))); /* granulrate denominator */
199     fp.start_granule = _le_64 (*((ogg_int64_t*)(op->packet+36))); /* start granule */
200     fp.preroll = _le_32 (*((ogg_uint32_t*)(op->packet+44))); /* preroll, for theora its 0 */
201     fp.granule_shift = *(op->packet+48); /* granule shift */
202     fp.current_header_size = op->bytes - FISBONE_SIZE;
203     fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char));
204     memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size);
205
206     return fp;
207 }
208
209 int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
210
211     ogg_packet op;
212
213     op = ogg_from_fishead(fp);
214     ogg_stream_packetin(os, &op);
215     _ogg_free(op.packet);
216
217     return 0;
218 }
219
220 int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
221
222     ogg_packet op;
223
224     op = ogg_from_fisbone(fp);
225     ogg_stream_packetin(os, &op);
226     _ogg_free(op.packet);
227
228     return 0;
229 }
230
231 int add_eos_packet_to_stream(ogg_stream_state *os) {
232
233     ogg_packet op;
234
235     memset (&op, 0, sizeof(op));
236     op.e_o_s = 1;
237     ogg_stream_packetin(os, &op);
238
239     return 0;
240 }
241
242 int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
243
244     ogg_page og;
245     int result;
246
247     while((result = ogg_stream_flush(os, &og)))
248     {
249         if(!result) break;
250         result = write_ogg_page_to_file(&og, out);
251         if(result != og.header_len + og.body_len)
252             return 1;
253     }
254
255     return 0;
256 }