summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriovar <iovar@f606c939-3180-4ac9-a4b8-4b8779d57d0a>2008-01-20 02:22:36 +0000
committeriovar <iovar@f606c939-3180-4ac9-a4b8-4b8779d57d0a>2008-01-20 02:22:36 +0000
commite1085f168262672a20884fb161a3883e938435bc (patch)
tree12653e74fc351a91a438beb5f93f493f89bf8cbd
parent13489f20e056403796f722de7826dd6c745cdd31 (diff)
added include/skeleton.h src/skeleton.c.
implemented the skeleton bitsream recommendation git-svn-id: https://recordmydesktop.svn.sourceforge.net/svnroot/recordmydesktop/trunk@481 f606c939-3180-4ac9-a4b8-4b8779d57d0a
-rw-r--r--recordmydesktop/include/Makefile.am2
-rw-r--r--recordmydesktop/include/skeleton.h107
-rw-r--r--recordmydesktop/src/Makefile.am3
-rw-r--r--recordmydesktop/src/init_encoder.c115
-rw-r--r--recordmydesktop/src/skeleton.c216
5 files changed, 432 insertions, 11 deletions
diff --git a/recordmydesktop/include/Makefile.am b/recordmydesktop/include/Makefile.am
index fb8518c..1884a45 100644
--- a/recordmydesktop/include/Makefile.am
+++ b/recordmydesktop/include/Makefile.am
@@ -1 +1 @@
-noinst_HEADERS= recordmydesktop.h rmdfunc.h rmdtypes.h rmdmacro.h
+noinst_HEADERS= recordmydesktop.h rmdfunc.h rmdtypes.h rmdmacro.h skeleton.h
diff --git a/recordmydesktop/include/skeleton.h b/recordmydesktop/include/skeleton.h
new file mode 100644
index 0000000..a563c1f
--- /dev/null
+++ b/recordmydesktop/include/skeleton.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+* skeleton.h *
+* author: Tahseen Mohammad *
+*******************************************************************************
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions *
+* are met: *
+* *
+* - Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* - Redistributions in binary form must reproduce the above copyright *
+* notice, this list of conditions and the following disclaimer in the *
+* documentation and/or other materials provided with the distribution. *
+* *
+* - Neither the name of the Xiph.org Foundation nor the names of its *
+* contributors may be used to endorse or promote products derived from *
+* this software without specific prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
+* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR *
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
+******************************************************************************/
+
+
+
+#ifndef _SKELETON_H
+#define _SKELETON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+#include <ogg/ogg.h>
+
+#define SKELETON_VERSION_MAJOR 3
+#define SKELETON_VERSION_MINOR 0
+#define FISHEAD_IDENTIFIER "fishead\0"
+#define FISBONE_IDENTIFIER "fisbone\0"
+#define FISHEAD_SIZE 64
+#define FISBONE_SIZE 52
+#define FISBONE_MESSAGE_HEADER_OFFSET 44
+
+/* fishead_packet holds a fishead header packet. */
+typedef struct {
+ ogg_uint16_t version_major; /* skeleton version major */
+ ogg_uint16_t version_minor; /* skeleton version minor */
+ /* Start time of the presentation
+ * For a new stream presentationtime & basetime is same. */
+ ogg_int64_t ptime_n; /* presentation time numerator */
+ ogg_int64_t ptime_d; /* presentation time denominator */
+ ogg_int64_t btime_n; /* basetime numerator */
+ ogg_int64_t btime_d; /* basetime denominator */
+ /* will holds the time of origin of the stream, a 20 bit field. */
+ unsigned char UTC[20];
+} fishead_packet;
+
+/* fisbone_packet holds a fisbone header packet. */
+typedef struct {
+ ogg_uint32_t serial_no; /* serial no of the corresponding stream */
+ ogg_uint32_t nr_header_packet; /* number of header packets */
+ /* granule rate is the temporal resolution of the logical bitstream */
+ ogg_int64_t granule_rate_n; /* granule rate numerator */
+ ogg_int64_t granule_rate_d; /* granule rate denominator */
+ ogg_int64_t start_granule; /* start granule value */
+ ogg_uint32_t preroll; /* preroll */
+ unsigned char granule_shift; /* 1 byte value holding the granule shift */
+ char *message_header_fields; /* holds all the message header fields */
+ /* current total size of the message header fields, for realloc purpose, initially zero */
+ ogg_uint32_t current_header_size;
+} fisbone_packet;
+
+extern int write_ogg_page_to_file(ogg_page *og, FILE *out);
+extern int add_message_header_field(fisbone_packet *fp, char *header_key, char *header_value);
+/* remember to deallocate the returned ogg_packet properly */
+extern ogg_packet ogg_from_fishead(fishead_packet *fp);
+extern ogg_packet ogg_from_fisbone(fisbone_packet *fp);
+extern fishead_packet fishead_from_ogg(ogg_packet *op);
+extern fisbone_packet fisbone_from_ogg(ogg_packet *op);
+extern int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp);
+extern int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp);
+extern int add_eos_packet_to_stream(ogg_stream_state *os);
+extern int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SKELETON_H */
+
+
+
+
+
+
diff --git a/recordmydesktop/src/Makefile.am b/recordmydesktop/src/Makefile.am
index 09b77b0..c3046b5 100644
--- a/recordmydesktop/src/Makefile.am
+++ b/recordmydesktop/src/Makefile.am
@@ -35,7 +35,8 @@ recordmydesktop_SOURCES= recordmydesktop.c\
rmd_error.c\
rmd_frame.c\
rmd_timer.c\
- rmd_rescue.c
+ rmd_rescue.c\
+ skeleton.c
INCLUDES= $(all_includes) -I$(top_srcdir)/include
diff --git a/recordmydesktop/src/init_encoder.c b/recordmydesktop/src/init_encoder.c
index 055a83f..d646c59 100644
--- a/recordmydesktop/src/init_encoder.c
+++ b/recordmydesktop/src/init_encoder.c
@@ -27,6 +27,20 @@
#include <recordmydesktop.h>
#include <string.h>
+#include <skeleton.h>
+
+void m_add_fishead_packet(ogg_stream_state *m_ogg_state){
+
+ fishead_packet skel_fp;
+
+ skel_fp.ptime_n=skel_fp.btime_n=0;
+ skel_fp.ptime_d=skel_fp.btime_d=1000;
+
+ add_fishead_to_stream(m_ogg_state,&skel_fp);
+
+
+}
+
int IncrementalNaming(char **name){
struct stat buff;
@@ -66,20 +80,20 @@ int IncrementalNaming(char **name){
}
void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
- int y1,
+
+ int y0,
+ y1,
y2,
fname_length;
+ ogg_stream_state m_ogg_skel;
+ ogg_page skel_og_pg;
+ fisbone_packet skel_fbv, //video fisbone packet
+ skel_fba ; //audio fisbone packet
+
(pdata)->enc_data=enc_data_t;
- srand(time(NULL));
- y1=rand();
- y2=rand();
- y2+=(y1==y2);
- ogg_stream_init(&enc_data_t->m_ogg_ts,y1);
- if(!pdata->args.nosound)
- ogg_stream_init(&enc_data_t->m_ogg_vs,y2);
fname_length=strlen(pdata->args.filename);
- if(!(fname_length>4 &&
+ if(!(fname_length>4 &&
pdata->args.filename[fname_length-4] == '.' &&
(pdata->args.filename[fname_length-3] == 'o' ||
pdata->args.filename[fname_length-3] == 'O') &&
@@ -106,6 +120,34 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
(pdata)->args.filename);
exit(13);
}
+
+ //each stream must have a unique
+ srand(time(NULL));
+ y0=rand()+1;
+ y1=rand()+1;
+ y2=rand()+1;
+ y2+=(y1==y2);
+ y0=(((y0==y1)||(y0==y2))?(y1+y2):y0);
+
+ //init ogg streams
+ //skeleton first
+ ogg_stream_init(&m_ogg_skel,y0);
+ m_add_fishead_packet(&m_ogg_skel);
+ if(ogg_stream_pageout(&m_ogg_skel,&skel_og_pg)!= 1){
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit (2);
+ }
+ fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
+ fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
+
+
+
+ ogg_stream_init(&enc_data_t->m_ogg_ts,y1);
+ if(!pdata->args.nosound)
+ ogg_stream_init(&enc_data_t->m_ogg_vs,y2);
+
+
+
theora_info_init(&enc_data_t->m_th_inf);
enc_data_t->m_th_inf.frame_width=(pdata)->brwin.rgeom.width;
enc_data_t->m_th_inf.frame_height=(pdata)->brwin.rgeom.height;
@@ -203,6 +245,51 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_code);
}
+ //fishbone packets go here
+ memset(&skel_fbv,0,sizeof(skel_fbv));
+ skel_fbv.serial_no=enc_data_t->m_ogg_ts.serialno;
+ skel_fbv.nr_header_packet=2+(!pdata->args.nosound);
+ skel_fbv.granule_rate_n=enc_data_t->m_th_inf.fps_numerator;
+ skel_fbv.granule_rate_d=enc_data_t->m_th_inf.fps_denominator;
+ skel_fbv.start_granule=0;
+ skel_fbv.preroll=0;
+ skel_fbv.granule_shift=theora_granule_shift(&enc_data_t->m_th_inf);
+ add_message_header_field(&skel_fbv,
+ "Content-Type",
+ "video/x-theora");
+
+ add_fisbone_to_stream(&m_ogg_skel,&skel_fbv);
+
+ if(!pdata->args.nosound){
+
+ memset(&skel_fba,0,sizeof(skel_fba));
+ skel_fba.serial_no=enc_data_t->m_ogg_vs.serialno;
+ skel_fba.nr_header_packet=3;
+ skel_fba.granule_rate_n=pdata->args.frequency;
+ skel_fba.granule_rate_d=(ogg_int64_t)1;
+ skel_fba.start_granule=0;
+ skel_fba.preroll=2;
+ skel_fba.granule_shift=0;
+ add_message_header_field(&skel_fba,
+ "Content-Type",
+ "audio/x-vorbis");
+
+ add_fisbone_to_stream(&m_ogg_skel,&skel_fba);
+
+ }
+
+ while(1){
+ int result = ogg_stream_flush(&m_ogg_skel, &skel_og_pg);
+ if(result<0){
+ fprintf (stderr, "Internal Ogg library error.\n");
+ exit(2);
+ }
+ if(result==0)
+ break;
+ fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
+ fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
+ }
+
while(1){
@@ -238,8 +325,18 @@ void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
enc_data_t->fp);
}
}
+
+ //skeleton eos
+ add_eos_packet_to_stream(&m_ogg_skel);
+ if(ogg_stream_flush(&m_ogg_skel,&skel_og_pg)<0){
+ fprintf(stderr,"Internal Ogg library error.\n");
+ exit(2);
+ }
+ fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
+ fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
+ //theora buffer allocation, if any
if(!buffer_ready){
enc_data_t->yuv.y=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
enc_data_t->m_th_inf.width);
diff --git a/recordmydesktop/src/skeleton.c b/recordmydesktop/src/skeleton.c
new file mode 100644
index 0000000..02dd6bd
--- /dev/null
+++ b/recordmydesktop/src/skeleton.c
@@ -0,0 +1,216 @@
+/******************************************************************************
+* skeleton.c *
+* author: Tahseen Mohammad *
+*******************************************************************************
+* Redistribution and use in source and binary forms, with or without *
+* modification, are permitted provided that the following conditions *
+* are met: *
+* *
+* - Redistributions of source code must retain the above copyright *
+* notice, this list of conditions and the following disclaimer. *
+* *
+* - Redistributions in binary form must reproduce the above copyright *
+* notice, this list of conditions and the following disclaimer in the *
+* documentation and/or other materials provided with the distribution. *
+* *
+* - Neither the name of the Xiph.org Foundation nor the names of its *
+* contributors may be used to endorse or promote products derived from *
+* this software without specific prior written permission. *
+* *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
+* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR *
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
+******************************************************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <ogg/ogg.h>
+
+#include <skeleton.h>
+
+/* write an ogg_page to a file pointer */
+int write_ogg_page_to_file(ogg_page *og, FILE *out) {
+ int written;
+
+ written = fwrite(og->header,1, og->header_len, out);
+ written += fwrite(og->body,1, og->body_len, out);
+
+ return written;
+}
+
+int add_message_header_field(fisbone_packet *fp,
+ char *header_key,
+ char *header_value) {
+
+ /* size of both key and value + ': ' + CRLF */
+ int this_message_size = strlen(header_key) + strlen(header_value) + 4;
+ if (fp->message_header_fields == NULL) {
+ fp->message_header_fields = _ogg_calloc(this_message_size, sizeof(char));
+ } else {
+ int new_size = (fp->current_header_size + this_message_size) * sizeof(char);
+ fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
+ }
+ snprintf(fp->message_header_fields + fp->current_header_size,
+ this_message_size+1,
+ "%s: %s\r\n",
+ header_key,
+ header_value);
+ fp->current_header_size += this_message_size;
+
+ return 0;
+}
+
+/* create a ogg_packet from a fishead_packet structure */
+ogg_packet ogg_from_fishead(fishead_packet *fp) {
+
+ ogg_packet op;
+
+ memset(&op, 0, sizeof(op));
+ op.packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
+ memset(op.packet, 0, FISHEAD_SIZE);
+
+ memcpy (op.packet, FISHEAD_IDENTIFIER, 8); /* identifier */
+ *((ogg_uint16_t*)(op.packet+8)) = SKELETON_VERSION_MAJOR; /* version major */
+ *((ogg_uint16_t*)(op.packet+10)) = SKELETON_VERSION_MINOR; /* version minor */
+ *((ogg_int64_t*)(op.packet+12)) = (ogg_int64_t)fp->ptime_n; /* presentationtime numerator */
+ *((ogg_int64_t*)(op.packet+20)) = (ogg_int64_t)fp->ptime_d; /* presentationtime denominator */
+ *((ogg_int64_t*)(op.packet+28)) = (ogg_int64_t)fp->btime_n; /* basetime numerator */
+ *((ogg_int64_t*)(op.packet+36)) = (ogg_int64_t)fp->btime_d; /* basetime denominator */
+ /* TODO: UTC time, set to zero for now */
+
+ op.b_o_s = 1; /* its the first packet of the stream */
+ op.e_o_s = 0; /* its not the last packet of the stream */
+ op.bytes = FISHEAD_SIZE; /* length of the packet in bytes */
+
+ return op;
+}
+
+/* create a ogg_packet from a fisbone_packet structure.
+ * call this method after the fisbone_packet is filled and all message header fields are added
+ * by calling add_message_header_field method.
+ */
+ogg_packet ogg_from_fisbone(fisbone_packet *fp) {
+
+ ogg_packet op;
+ int packet_size = FISBONE_SIZE + fp->current_header_size;
+
+ memset (&op, 0, sizeof (op));
+ op.packet = _ogg_calloc (packet_size, sizeof(unsigned char));
+ memset (op.packet, 0, packet_size);
+ memcpy (op.packet, FISBONE_IDENTIFIER, 8); /* identifier */
+ *((ogg_uint32_t*)(op.packet+8)) = FISBONE_MESSAGE_HEADER_OFFSET; /* offset of the message header fields */
+ *((ogg_uint32_t*)(op.packet+12)) = fp->serial_no; /* serialno of the respective stream */
+ *((ogg_uint32_t*)(op.packet+16)) = fp->nr_header_packet; /* number of header packets */
+ *((ogg_int64_t*)(op.packet+20)) = fp->granule_rate_n; /* granulrate numerator */
+ *((ogg_int64_t*)(op.packet+28)) = fp->granule_rate_d; /* granulrate denominator */
+ *((ogg_int64_t*)(op.packet+36)) = fp->start_granule; /* start granule */
+ *((ogg_uint32_t*)(op.packet+44)) = fp->preroll; /* preroll, for theora its 0 */
+ *(op.packet+48) = fp->granule_shift; /* granule shift */
+ memcpy((op.packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
+
+ op.b_o_s = 0;
+ op.e_o_s = 0;
+ op.bytes = packet_size; /* size of the packet in bytes */
+
+ return op;
+}
+
+/* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
+fishead_packet fishead_from_ogg(ogg_packet *op) {
+
+ fishead_packet fp;
+
+ if (memcmp(op->packet, FISHEAD_IDENTIFIER, 8))
+ ; /* invalid packet what do we do? */
+
+ fp.version_major = *((ogg_uint16_t*)(op->packet+8)); /* version major */
+ fp.version_minor = *((ogg_uint16_t*)(op->packet+10)); /* version minor */
+ fp.ptime_n = *((ogg_int64_t*)(op->packet+12)); /* presentationtime numerator */
+ fp.ptime_d = *((ogg_int64_t*)(op->packet+20)); /* presentationtime denominator */
+ fp.btime_n = *((ogg_int64_t*)(op->packet+28)); /* basetime numerator */
+ fp.btime_d = *((ogg_int64_t*)(op->packet+36)); /* basetime denominator */
+ memcpy(fp.UTC, op->packet+44, 20);
+
+ return fp;
+}
+
+/* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
+fisbone_packet fisbone_from_ogg(ogg_packet *op) {
+
+ fisbone_packet fp;
+
+ if (memcmp(op->packet, FISBONE_IDENTIFIER, 8))
+ ; /* invalid value, what do we do? */
+ fp.serial_no = *((ogg_uint32_t*)(op->packet+12)); /* serialno of the stream represented by this fisbone packet */
+ fp.nr_header_packet = *((ogg_uint32_t*)(op->packet+16)); /* number of header packets */
+ fp.granule_rate_n = *((ogg_int64_t*)(op->packet+20)); /* granulrate numerator */
+ fp.granule_rate_d = *((ogg_int64_t*)(op->packet+28)); /* granulrate denominator */
+ fp.start_granule = *((ogg_int64_t*)(op->packet+36)); /* start granule */
+ fp.preroll = *((ogg_uint32_t*)(op->packet+44)); /* preroll, for theora its 0 */
+ fp.granule_shift = *(op->packet+48); /* granule shift */
+ fp.current_header_size = op->bytes - FISBONE_SIZE;
+ fp.message_header_fields = _ogg_calloc(fp.current_header_size+1, sizeof(char));
+ memcpy(fp.message_header_fields, op->packet+FISBONE_SIZE, fp.current_header_size);
+
+ return fp;
+}
+
+int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
+
+ ogg_packet op;
+
+ op = ogg_from_fishead(fp);
+ ogg_stream_packetin(os, &op);
+ _ogg_free(op.packet);
+
+ return 0;
+}
+
+int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
+
+ ogg_packet op;
+
+ op = ogg_from_fisbone(fp);
+ ogg_stream_packetin(os, &op);
+ _ogg_free(op.packet);
+
+ return 0;
+}
+
+int add_eos_packet_to_stream(ogg_stream_state *os) {
+
+ ogg_packet op;
+
+ memset (&op, 0, sizeof(op));
+ op.e_o_s = 1;
+ ogg_stream_packetin(os, &op);
+
+ return 0;
+}
+
+int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
+
+ ogg_page og;
+ int result;
+
+ while((result = ogg_stream_flush(os, &og)))
+ {
+ if(!result) break;
+ result = write_ogg_page_to_file(&og, out);
+ if(result != og.header_len + og.body_len)
+ return 1;
+ }
+
+ return 0;
+}
© All Rights Reserved