skeleton.c 6.61 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * skeleton.c
 * author: Tahseen Mohammad
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <ogg/ogg.h>

#include "skeleton.h"

alex's avatar
alex committed
14 15 16 17
#ifdef WIN32                                                                   
#define snprintf _snprintf
#endif 

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
/* 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;
}