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
_le_16(unsigned short s)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
_le_32(ogg_uint32_t i)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
_le_64(ogg_int64_t l)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 */
write_ogg_page_to_file(ogg_page * og,FILE * out)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
add_message_header_field(fisbone_packet * fp,char * header_key,char * header_value)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 */
ogg_from_fishead(fishead_packet * fp)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 */
ogg_from_fisbone(fisbone_packet * fp)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
170
add_fishead_to_stream(ogg_stream_state * os,fishead_packet * fp)171 int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
172
173 ogg_packet op;
174
175 op = ogg_from_fishead(fp);
176 ogg_stream_packetin(os, &op);
177 _ogg_free(op.packet);
178
179 return 0;
180 }
181
add_fisbone_to_stream(ogg_stream_state * os,fisbone_packet * fp)182 int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
183
184 ogg_packet op;
185
186 op = ogg_from_fisbone(fp);
187 ogg_stream_packetin(os, &op);
188 _ogg_free(op.packet);
189
190 return 0;
191 }
192
add_eos_packet_to_stream(ogg_stream_state * os)193 int add_eos_packet_to_stream(ogg_stream_state *os) {
194
195 ogg_packet op;
196
197 memset (&op, 0, sizeof(op));
198 op.e_o_s = 1;
199 ogg_stream_packetin(os, &op);
200
201 return 0;
202 }
203
flush_ogg_stream_to_file(ogg_stream_state * os,FILE * out)204 int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
205
206 ogg_page og;
207 int result;
208
209 while((result = ogg_stream_flush(os, &og)))
210 {
211 if(!result) break;
212 result = write_ogg_page_to_file(&og, out);
213 if(result != og.header_len + og.body_len)
214 return 1;
215 }
216
217 return 0;
218 }
219