Recognizes if input is ogg or not.
[xiph.git] / xiph-rtp / theorartp.c
blob29ba2c80e36801812809262c6e59b26a8ae2c2ae
1 /*
2 File: Vorbis RTP Server
3 Authors: Phil Kerr, Luca Barbato
4 Date: 05/01/2005
5 Platform: Linux
7 Copyright (c) 2006, Fluendo / Xiph.Org
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions are met:
12 * Redistributions of source code must retain the above copyright notice,
13 this list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 this list of conditions and the following disclaimer in the documentation
17 and/or other materials provided with the distribution.
19 * Neither the name of the Xiph.Org nor the names of its contributors may
20 be used to endorse or promote products derived from this software without
21 specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
27 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 THE POSSIBILITY OF SUCH DAMAGE.
35 */
37 /* System includes */
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <time.h>
45 /* Codec includes */
47 #include <theora/theora.h>
49 /* Network includes */
51 #include <arpa/inet.h>
52 #include <netinet/in.h>
53 #include <netdb.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
57 /* Common include */
59 #define HAVE_THEORA
61 #include "xiph_rtp.h"
63 #define BUFFER_SIZE 4096
64 unsigned int cfg_parse( xiph_rtp_t *xr )
66 oggpack_buffer opb;
68 oggpackB_readinit(&opb,xr->header[0].packet, xr->header[0].bytes);
70 oggpackB_read(&opb,8*7); // 0x80"theora"
71 oggpackB_read(&opb,8*3); // version
72 oggpackB_read(&opb,16); //w
73 oggpackB_read(&opb,16); //h
75 oggpackB_read(&opb,64);
77 oggpackB_read(&opb,32);
78 oggpackB_read(&opb,32);
80 oggpackB_read(&opb,24);
81 oggpackB_read(&opb,24);
83 oggpackB_read(&opb,38);
85 xr->gp_shift = oggpackB_read(&opb,5);
87 printf("gp_shift %d \n", xr->gp_shift);
89 return 0; //FIXME...
92 int main (int argc, char **argv)
94 xiph_rtp_t xr;
96 char *buffer;
97 int bytes;
99 char *filename;
100 FILE *file;
102 ogg_sync_init (&xr.oy);
104 int i = 0;
105 int opt;
107 char *ip = "227.0.0.1";
108 unsigned int port = 4044;
109 unsigned int ttl = 1;
110 long timestamp = 0;
112 fprintf (stderr, "Theora RTP Server (draft-barbato-avt-rtp-theora-00)\n");
113 memset (&xr,0,sizeof(xiph_rtp_t));
115 /* Command-line args processing */
117 if (argc < 2) {
118 fprintf (stderr, "\n\tNo Theora file specified.\n");
119 fprintf (stderr, "\tUsage: %s [-i ip address] [-p port] [-t ttl] filename\n\n",argv[0]);
120 exit (1);
123 while ((opt = getopt (argc, argv, "i:p:t:")) != -1) {
124 switch (opt)
127 /* Set IP address */
128 case 'i':
129 ip = optarg;
130 break;
132 /* Set port */
133 case 'p':
134 port = atoi (optarg);
135 break;
137 /* Set TTL value */
138 case 't':
139 ttl = atoi (optarg);
140 break;
142 /* Unknown option */
143 case '?':
144 fprintf (stderr, "\n Unknown option `-%c'.\n", optopt);
145 fprintf (stderr, "\tUsage: %s [-i ip address] [-p port] [-t ttl] filename\n\n",argv[0]);
146 return 1;
150 /* Init RTP socket */
152 if ( createsocket (&xr, ip, port, ttl)<0) return 1;
154 /* Print network details */
156 fprintf (stdout, "\n Network setup\n");
157 fprintf (stdout, " IP Address= %s\n", ip);
158 fprintf (stdout, " Port = %d\n", port);
159 fprintf (stdout, " TTL = %d\n", ttl);
160 fprintf (stdout, "\n");
162 /* Open Theora file */
164 filename = argv [argc - 1];
165 file = fopen (filename, "rb");
167 if (file == NULL) {
168 fprintf (stderr, " Could not open file %s\n", filename);
169 exit (1);
172 fprintf (stdout, " Theora setup\n");
173 fprintf (stdout, " Filename: %s\n", filename);
175 int eos = 0;
177 buffer = ogg_sync_buffer (&xr.oy, BUFFER_SIZE);
179 bytes = fread (buffer, 1, BUFFER_SIZE, file);
181 ogg_sync_wrote (&xr.oy, bytes);
183 if (ogg_sync_pageout (&xr.oy, &xr.og) != 1) {
184 if (bytes < BUFFER_SIZE) {
185 fprintf (stdout, " Done\n");
186 exit (0);
189 fprintf (stderr, "\n Input does not appear to be an Ogg bitstream.\n");
190 exit (1);
193 ogg_stream_init (&xr.os, ogg_page_serialno (&xr.og));
195 theora_info_init (&xr.ti);
196 theora_comment_init (&xr.tc);
198 if (ogg_stream_pagein (&xr.os, &xr.og) < 0) {
199 fprintf (stderr, " Error reading first page of Ogg bitstream data.\n");
200 exit (1);
203 if (ogg_stream_packetout (&xr.os, &xr.op) != 1) {
204 fprintf (stderr, " Error reading initial header packet.\n");
205 exit (1);
208 if (theora_decode_header (&xr.ti, &xr.tc, &xr.op) < 0) {
209 fprintf (stderr, " This Ogg bitstream does not contain Theora video data.\n");
210 exit (1);
213 ogg_copy_packet(&(xr.header[i]), &xr.op); //FIXME change it?
215 /*===========================================================================*/
216 /* Process comment and codebook headers */
217 /*===========================================================================*/
219 while (i < 2) {
220 while (i < 2) {
221 int result = ogg_sync_pageout (&xr.oy, &xr.og);
223 if (result == 0) break; /* Need more data */
225 if (result == 1) {
226 ogg_stream_pagein (&xr.os, &xr.og);
228 while(i < 2) {
229 result = ogg_stream_packetout (&xr.os, &xr.op);
231 if (result == 0) break;
233 if (result < 0) {
234 fprintf (stderr, " Corrupt secondary header. Exiting.\n");
235 exit (1);
238 theora_decode_header (&xr.ti, &xr.tc, &xr.op);
239 i++;
241 ogg_copy_packet(&(xr.header[i]), &xr.op);
246 buffer = ogg_sync_buffer (&xr.oy, BUFFER_SIZE);
247 bytes = fread (buffer, 1, BUFFER_SIZE, file);
249 if (bytes == 0 && i < 2) {
250 fprintf (stderr, "|| End of file before finding all Vorbis headers!\n");
251 exit (1);
254 ogg_sync_wrote (&xr.oy, bytes);
257 xr.bitfield.cbident = rand ();
259 theora_decode_init (&xr.td, &xr.ti);
261 /*===========================================================================*/
262 /* Print details */
263 /*===========================================================================*/
264 fprintf(stdout,"Theora %dx%d %.02f fps video\n"
265 "Encoded frame content is %dx%d with %dx%d offset\n",
266 xr.ti.width,xr.ti.height,
267 (double)xr.ti.fps_numerator/xr.ti.fps_denominator,
268 xr.ti.frame_width, xr.ti.frame_height,
269 xr.ti.offset_x, xr.ti.offset_y);
271 fprintf (stdout, "Decode setup ident is 0x%06x\n", xr.bitfield.cbident);
272 fprintf (stdout, "\n");
273 fprintf (stdout, "Processing\n");
275 /*===========================================================================*/
276 /* Send the three headers inline */
277 /*===========================================================================*/
279 int conf_bytes = xr.header[0].bytes + xr.header[2].bytes;
280 unsigned char *conf_packet = malloc(conf_bytes);
282 memcpy (conf_packet, xr.header[0].packet, xr.header[0].bytes);
283 memcpy (conf_packet + xr.header[0].bytes,
284 xr.header[2].packet,
285 xr.header[2].bytes);
286 creatertp(&xr, conf_packet, conf_bytes, 0, 0, 1, 0);
288 free(conf_packet);
291 cfg_parse(&xr);
293 /* Read raw data and send RTP packet */
295 while (!eos) {
296 while (!eos) {
297 int result = ogg_sync_pageout (&xr.oy, &xr.og);
299 if (result == 0) break; /* need more data */
301 if (result < 0) {
302 fprintf (stderr, "\n Corrupt or missing data in bitstream; continuing....\n ");
303 } else {
304 ogg_stream_pagein (&xr.os, &xr.og);
306 while (1) {
307 result = ogg_stream_packetout (&xr.os, &xr.op);
309 if (result == 0) break; /* need more data */
311 if (result < 0) {
312 /* no reason to complain; already complained above */
313 } else {
314 theora_decode_packetin(&xr.td,&xr.op);
315 if (xr.op.granulepos != -1)
316 timestamp = (xr.op.granulepos>>xr.gp_shift)+
317 (xr.op.granulepos & ((1<<xr.gp_shift)-1));
318 else
319 timestamp++ ;
320 #ifdef DEBUG
322 oggpack_buffer opb;
323 int type;
324 oggpackB_readinit(&opb,xr.op.packet,xr.op.bytes);
325 oggpack_read(&opb,1); //video marker
327 type = oggpackB_read(&opb,1);
328 printf(" type %d stamp %ld", type, timestamp);
330 printf(" bytes %ld bos %ld eos %ld gp %lld pno %lld\n", xr.op.bytes, xr.op.b_o_s, xr.op.e_o_s, xr.op.granulepos, xr.op.packetno);
331 #endif
332 //FIXME ugly as hell and probably wrong!!!!
333 creatertp ( &xr, xr.op.packet, xr.op.bytes,
334 timestamp*90000/((double)xr.ti.fps_numerator/xr.ti.fps_denominator), timestamp, 0, xr.op.e_o_s );
338 if (ogg_page_eos (&xr.og)) eos = 1;
342 if (!eos) {
343 buffer = ogg_sync_buffer (&xr.oy, BUFFER_SIZE);
344 bytes = fread (buffer, 1, BUFFER_SIZE, file);
346 ogg_sync_wrote (&xr.oy, bytes);
348 if (bytes == 0) eos = 1;
351 //FIXME make it a cleanup function!
352 ogg_packet_clear (&(xr.header[0]));
353 ogg_packet_clear (&(xr.header[1]));
354 ogg_packet_clear (&(xr.header[2]));
356 ogg_stream_clear (&xr.os);
358 theora_clear(&xr.td);
359 theora_comment_clear(&xr.tc);
360 theora_info_clear(&xr.ti);
362 ogg_sync_clear (&xr.oy);
363 fclose (file);
365 fprintf (stdout, "Done.\n");
366 return (0);