Fixed the default int32 type which was wrong on amd64 (and added testcase).
[opus.git] / tools / skeleton.c
1 /*
2  * skeleton.c
3  * author: Tahseen Mohammad
4  */
5
6 #include <stdlib.h>
7 #include <string.h>
8 #include <stdio.h>
9
10 #include <ogg/ogg.h>
11
12 #include "skeleton.h"
13
14 /* write an ogg_page to a file pointer */
15 int write_ogg_page_to_file(ogg_page *og, FILE *out) {
16    int written;
17    
18    written = fwrite(og->header,1, og->header_len, out);
19    written += fwrite(og->body,1, og->body_len, out);
20
21    return written;
22 }
23
24 int add_message_header_field(fisbone_packet *fp, 
25                                         char *header_key, 
26                                         char *header_value) {
27
28     /* size of both key and value + ': ' + CRLF */
29     int this_message_size = strlen(header_key) + strlen(header_value) + 4;
30     if (fp->message_header_fields == NULL) {
31         fp->message_header_fields = _ogg_calloc(this_message_size, sizeof(char));
32     } else {
33         int new_size = (fp->current_header_size + this_message_size) * sizeof(char);
34         fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
35     }
36     snprintf(fp->message_header_fields + fp->current_header_size, 
37                 this_message_size+1, 
38                 "%s: %s\r\n", 
39                 header_key, 
40                 header_value);
41     fp->current_header_size += this_message_size;
42
43     return 0;
44 }
45
46 /* create a ogg_packet from a fishead_packet structure */
47 ogg_packet ogg_from_fishead(fishead_packet *fp) {
48
49     ogg_packet op;
50
51     memset(&op, 0, sizeof(op));
52     op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
53     memset(op.packet, 0, FISHEAD_SIZE);
54
55     memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
56     *((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */
57     *((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */
58     *((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)fp->ptime_n; /* presentationtime numerator */
59     *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)fp->ptime_d; /* presentationtime denominator */
60     *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)fp->btime_n; /* basetime numerator */
61     *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)fp->btime_d; /* basetime denominator */
62     /* TODO: UTC time, set to zero for now */
63
64     op.b_o_s = 1;   /* its the first packet of the stream */
65     op.e_o_s = 0;   /* its not the last packet of the stream */
66     op.bytes = FISHEAD_SIZE;  /* length of the packet in bytes */
67
68     return op;
69 }
70
71 /* create a ogg_packet from a fisbone_packet structure. 
72  * call this method after the fisbone_packet is filled and all message header fields are added
73  * by calling add_message_header_field method.
74  */
75 ogg_packet ogg_from_fisbone(fisbone_packet *fp) {
76     
77     ogg_packet op;
78     int packet_size = FISBONE_SIZE + fp->current_header_size;
79
80     memset (&op, 0, sizeof (op));       
81     op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
82     memset (op.packet, 0, packet_size);
83     memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
84     *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
85     *((ogg_uint32_t*)(op.packet+12)) = fp->serial_no; /* serialno of the respective stream */
86     *((ogg_uint32_t*)(op.packet+16)) = fp->nr_header_packet; /* number of header packets */
87     *((ogg_int64_t*)(op.packet+20)) = fp->granule_rate_n; /* granulrate numerator */
88     *((ogg_int64_t*)(op.packet+28)) = fp->granule_rate_d; /* granulrate denominator */
89     *((ogg_int64_t*)(op.packet+36)) = fp->start_granule; /* start granule */
90     *((ogg_uint32_t*)(op.packet+44)) = fp->preroll; /* preroll, for theora its 0 */
91     *(op.packet+48) = fp->granule_shift; /* granule shift */
92     memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
93
94     op.b_o_s = 0;
95     op.e_o_s = 0;
96     op.bytes = packet_size; /* size of the packet in bytes */
97
98     return op;
99 }
100
101 /* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
102 fishead_packet fishead_from_ogg(ogg_packet *op) {
103         
104     fishead_packet fp;
105
106     if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8))
107         ; /* invalid packet what do we do? */
108
109     fp.version_major = *((ogg_uint16_t*)(op->packet+8)); /* version major */
110     fp.version_minor = *((ogg_uint16_t*)(op->packet+10)); /* version minor */
111     fp.ptime_n = *((ogg_int64_t*)(op->packet+12)); /* presentationtime numerator */
112     fp.ptime_d = *((ogg_int64_t*)(op->packet+20)); /* presentationtime denominator */
113     fp.btime_n = *((ogg_int64_t*)(op->packet+28)); /* basetime numerator */
114     fp.btime_d = *((ogg_int64_t*)(op->packet+36)); /* basetime denominator */
115     memcpy(fp.UTC, op->packet+44, 20);
116
117     return fp;
118 }
119
120 /* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
121 fisbone_packet fisbone_from_ogg(ogg_packet *op) {
122
123     fisbone_packet fp;
124     
125     if (memcmp(op->packet, FISBONE_IDENTIFIER, 8))
126         ; /* invalid value, what do we do? */
127     fp.serial_no = *((ogg_uint32_t*)(op->packet+12)); /* serialno of the stream represented by this fisbone packet */
128     fp.nr_header_packet = *((ogg_uint32_t*)(op->packet+16)); /* number of header packets */
129     fp.granule_rate_n = *((ogg_int64_t*)(op->packet+20)); /* granulrate numerator */
130     fp.granule_rate_d = *((ogg_int64_t*)(op->packet+28)); /* granulrate denominator */
131     fp.start_granule = *((ogg_int64_t*)(op->packet+36)); /* start granule */
132     fp.preroll = *((ogg_uint32_t*)(op->packet+44)); /* preroll, for theora its 0 */
133     fp.granule_shift = *(op->packet+48); /* granule shift */
134     fp.current_header_size = op->bytes - FISBONE_SIZE;
135     fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char));
136     memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size);
137
138     return fp;
139 }
140
141 int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
142
143     ogg_packet op;
144
145     op = ogg_from_fishead(fp);
146     ogg_stream_packetin(os, &op);
147     _ogg_free(op.packet);
148
149     return 0;
150 }
151
152 int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
153
154     ogg_packet op;
155
156     op = ogg_from_fisbone(fp);
157     ogg_stream_packetin(os, &op);
158     _ogg_free(op.packet);
159
160     return 0;
161 }
162
163 int add_eos_packet_to_stream(ogg_stream_state *os) {
164
165     ogg_packet op;
166
167     memset (&op, 0, sizeof(op));
168     op.e_o_s = 1;
169     ogg_stream_packetin(os, &op);
170
171     return 0;
172 }
173
174 int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
175
176     ogg_page og;
177     int result;
178
179     while((result = ogg_stream_flush(os, &og)))
180     {
181         if(!result) break;
182         result = write_ogg_page_to_file(&og, out);
183         if(result != og.header_len + og.body_len)
184             return 1;
185     }
186
187     return 0;
188 }