/src/theora/lib/encinfo.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include <stdlib.h> |
2 | | #include <string.h> |
3 | | #include "state.h" |
4 | | #include "enquant.h" |
5 | | #include "huffenc.h" |
6 | | |
7 | | |
8 | | |
9 | | /*Packs a series of octets from a given byte array into the pack buffer. |
10 | | _opb: The pack buffer to store the octets in. |
11 | | _buf: The byte array containing the bytes to pack. |
12 | | _len: The number of octets to pack.*/ |
13 | 13.7k | static void oc_pack_octets(oggpack_buffer *_opb,const char *_buf,int _len){ |
14 | 13.7k | int i; |
15 | 255k | for(i=0;i<_len;i++)oggpackB_write(_opb,_buf[i],8); |
16 | 13.7k | } |
17 | | |
18 | | |
19 | | |
20 | | int oc_state_flushheader(oc_theora_state *_state,int *_packet_state, |
21 | | oggpack_buffer *_opb,const th_quant_info *_qinfo, |
22 | | const th_huff_code _codes[TH_NHUFFMAN_TABLES][TH_NDCT_TOKENS], |
23 | 13.7k | const char *_vendor,th_comment *_tc,ogg_packet *_op){ |
24 | 13.7k | unsigned char *packet; |
25 | 13.7k | int b_o_s; |
26 | 13.7k | if(_op==NULL)return TH_EFAULT; |
27 | 13.7k | switch(*_packet_state){ |
28 | | /*Codec info header.*/ |
29 | 3.44k | case OC_PACKET_INFO_HDR:{ |
30 | 3.44k | if(_state==NULL)return TH_EFAULT; |
31 | 3.44k | oggpackB_reset(_opb); |
32 | | /*Mark this packet as the info header.*/ |
33 | 3.44k | oggpackB_write(_opb,0x80,8); |
34 | | /*Write the codec string.*/ |
35 | 3.44k | oc_pack_octets(_opb,"theora",6); |
36 | | /*Write the codec bitstream version.*/ |
37 | 3.44k | oggpackB_write(_opb,TH_VERSION_MAJOR,8); |
38 | 3.44k | oggpackB_write(_opb,TH_VERSION_MINOR,8); |
39 | 3.44k | oggpackB_write(_opb,TH_VERSION_SUB,8); |
40 | | /*Describe the encoded frame.*/ |
41 | 3.44k | oggpackB_write(_opb,_state->info.frame_width>>4,16); |
42 | 3.44k | oggpackB_write(_opb,_state->info.frame_height>>4,16); |
43 | 3.44k | oggpackB_write(_opb,_state->info.pic_width,24); |
44 | 3.44k | oggpackB_write(_opb,_state->info.pic_height,24); |
45 | 3.44k | oggpackB_write(_opb,_state->info.pic_x,8); |
46 | 3.44k | oggpackB_write(_opb,_state->info.pic_y,8); |
47 | 3.44k | oggpackB_write(_opb,_state->info.fps_numerator,32); |
48 | 3.44k | oggpackB_write(_opb,_state->info.fps_denominator,32); |
49 | 3.44k | oggpackB_write(_opb,_state->info.aspect_numerator,24); |
50 | 3.44k | oggpackB_write(_opb,_state->info.aspect_denominator,24); |
51 | 3.44k | oggpackB_write(_opb,_state->info.colorspace,8); |
52 | 3.44k | oggpackB_write(_opb,_state->info.target_bitrate,24); |
53 | 3.44k | oggpackB_write(_opb,_state->info.quality,6); |
54 | 3.44k | oggpackB_write(_opb,_state->info.keyframe_granule_shift,5); |
55 | 3.44k | oggpackB_write(_opb,_state->info.pixel_fmt,2); |
56 | | /*Spare configuration bits.*/ |
57 | 3.44k | oggpackB_write(_opb,0,3); |
58 | 3.44k | b_o_s=1; |
59 | 3.44k | }break; |
60 | | /*Comment header.*/ |
61 | 3.44k | case OC_PACKET_COMMENT_HDR:{ |
62 | 3.44k | int vendor_len; |
63 | 3.44k | int i; |
64 | 3.44k | if(_tc==NULL)return TH_EFAULT; |
65 | 3.44k | vendor_len=strlen(_vendor); |
66 | 3.44k | oggpackB_reset(_opb); |
67 | | /*Mark this packet as the comment header.*/ |
68 | 3.44k | oggpackB_write(_opb,0x81,8); |
69 | | /*Write the codec string.*/ |
70 | 3.44k | oc_pack_octets(_opb,"theora",6); |
71 | | /*Write the vendor string.*/ |
72 | 3.44k | oggpack_write(_opb,vendor_len,32); |
73 | 3.44k | oc_pack_octets(_opb,_vendor,vendor_len); |
74 | 3.44k | oggpack_write(_opb,_tc->comments,32); |
75 | 3.44k | for(i=0;i<_tc->comments;i++){ |
76 | 0 | if(_tc->user_comments[i]!=NULL){ |
77 | 0 | oggpack_write(_opb,_tc->comment_lengths[i],32); |
78 | 0 | oc_pack_octets(_opb,_tc->user_comments[i],_tc->comment_lengths[i]); |
79 | 0 | } |
80 | 0 | else oggpack_write(_opb,0,32); |
81 | 0 | } |
82 | 3.44k | b_o_s=0; |
83 | 3.44k | }break; |
84 | | /*Codec setup header.*/ |
85 | 3.44k | case OC_PACKET_SETUP_HDR:{ |
86 | 3.44k | int ret; |
87 | 3.44k | oggpackB_reset(_opb); |
88 | | /*Mark this packet as the setup header.*/ |
89 | 3.44k | oggpackB_write(_opb,0x82,8); |
90 | | /*Write the codec string.*/ |
91 | 3.44k | oc_pack_octets(_opb,"theora",6); |
92 | | /*Write the quantizer tables.*/ |
93 | 3.44k | oc_quant_params_pack(_opb,_qinfo); |
94 | | /*Write the huffman codes.*/ |
95 | 3.44k | ret=oc_huff_codes_pack(_opb,_codes); |
96 | | /*This should never happen, because we validate the tables when they |
97 | | are set. |
98 | | If you see, it's a good chance memory is being corrupted.*/ |
99 | 3.44k | if(ret<0)return ret; |
100 | 3.44k | b_o_s=0; |
101 | 3.44k | }break; |
102 | | /*No more headers to emit.*/ |
103 | 3.44k | default:return 0; |
104 | 13.7k | } |
105 | | /*This is kind of fugly: we hand the user a buffer which they do not own. |
106 | | We will overwrite it when the next packet is output, so the user better be |
107 | | done with it by then. |
108 | | Vorbis is little better: it hands back buffers that it will free the next |
109 | | time the headers are requested, or when the encoder is cleared. |
110 | | Hopefully libogg2 will make this much cleaner.*/ |
111 | 10.3k | packet=oggpackB_get_buffer(_opb); |
112 | | /*If there's no packet, malloc failed while writing.*/ |
113 | 10.3k | if(packet==NULL)return TH_EFAULT; |
114 | 10.3k | _op->packet=packet; |
115 | 10.3k | _op->bytes=oggpackB_bytes(_opb); |
116 | 10.3k | _op->b_o_s=b_o_s; |
117 | 10.3k | _op->e_o_s=0; |
118 | 10.3k | _op->granulepos=0; |
119 | 10.3k | _op->packetno=*_packet_state+3; |
120 | 10.3k | return ++(*_packet_state)+3; |
121 | 10.3k | } |