1 /******************************************************************************
2 * recordMyDesktop *
3 *******************************************************************************
4 * *
5 * Copyright (C) 2006,2007,2008 John Varouhakis *
6 * *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
21 * *
22 * *
23 * *
24 * For further information contact me at johnvarouhakis@gmail.com *
25 ******************************************************************************/
26
27 #include "config.h"
28 #include "rmd_init_encoder.h"
29
30 #include "rmd_types.h"
31
32 #include "skeleton.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38
39
40
41
42
m_add_fishead_packet(ogg_stream_state * m_ogg_state)43 static void m_add_fishead_packet(ogg_stream_state *m_ogg_state) {
44
45 fishead_packet skel_fp;
46
47 skel_fp.ptime_n=skel_fp.btime_n=0;
48 skel_fp.ptime_d=skel_fp.btime_d=1000;
49
50 add_fishead_to_stream(m_ogg_state,&skel_fp);
51
52
53 }
54
55
IncrementalNaming(char ** name)56 static int IncrementalNaming(char **name) {
57 struct stat buff;
58 char *base_name__;
59 int i=0,
60 fname_length=strlen(*name)-4;
61
62 base_name__=malloc(fname_length+1);
63 strncpy(base_name__,*name,fname_length);
64 base_name__[fname_length]='\0';
65
66
67 //this will go on an endless loop if you have 65536?
68 //files with the same name
69 //or it will crash and die.anyone interested in trying ?
70 while (stat(*name,&buff)==0){
71 //create new name
72 char *tname=malloc(strlen(*name)+10);
73 char numbuf[8];
74
75 strcpy(tname,base_name__);
76 strcat(tname,"-");
77 i++;
78 snprintf( numbuf, 8, "%d", i );
79 strcat(tname,numbuf);
80 strcat(tname,".ogv");
81 //save new name
82
83 free(*name);
84 *name=malloc(strlen(tname)+1);
85 strcpy(*name,tname);
86 free(tname);
87 }
88
89 free(base_name__);
90 return 0;
91 }
92
InitEncoder(ProgData * pdata,EncData * enc_data_t,int buffer_ready)93 void InitEncoder(ProgData *pdata,EncData *enc_data_t,int buffer_ready){
94
95 int y0,
96 y1,
97 y2,
98 fname_length;
99 ogg_stream_state m_ogg_skel;
100 ogg_page skel_og_pg;
101 fisbone_packet skel_fbv, //video fisbone packet
102 skel_fba ; //audio fisbone packet
103
104 (pdata)->enc_data=enc_data_t;
105
106 fname_length=strlen(pdata->args.filename);
107 if(!(fname_length>4 &&
108 pdata->args.filename[fname_length-4] == '.' &&
109 (pdata->args.filename[fname_length-3] == 'o' ||
110 pdata->args.filename[fname_length-3] == 'O') &&
111 (pdata->args.filename[fname_length-2] == 'g' ||
112 pdata->args.filename[fname_length-2] == 'G') &&
113 (pdata->args.filename[fname_length-1] == 'v' ||
114 pdata->args.filename[fname_length-1] == 'V'))){
115
116 char *new_name=malloc(fname_length+5);
117 strcpy(new_name,pdata->args.filename);
118 strcat(new_name,".ogv");
119
120 free(pdata->args.filename);
121 pdata->args.filename=new_name;
122
123
124 }
125
126 if (!pdata->args.overwrite) {
127 IncrementalNaming(&(pdata)->args.filename);
128 fprintf(stderr, "Output file: %s\n", pdata->args.filename);
129 }
130
131 enc_data_t->fp=fopen((pdata)->args.filename,"w");
132 if(enc_data_t->fp==NULL){
133 fprintf(stderr,"Cannot open file %s for writting!\n",
134 (pdata)->args.filename);
135 exit(13);
136 }
137
138 //each stream must have a unique
139 srand(time(NULL));
140 y0=rand()+1;
141 y1=rand()+1;
142 y2=rand()+1;
143 y2+=(y1==y2);
144 y0=(((y0==y1)||(y0==y2))?(y1+y2):y0);
145
146 //init ogg streams
147 //skeleton first
148 ogg_stream_init(&m_ogg_skel,y0);
149 m_add_fishead_packet(&m_ogg_skel);
150 if(ogg_stream_pageout(&m_ogg_skel,&skel_og_pg)!= 1){
151 fprintf (stderr, "Internal Ogg library error.\n");
152 exit (2);
153 }
154 fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
155 fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
156
157
158
159 ogg_stream_init(&enc_data_t->m_ogg_ts,y1);
160 if(!pdata->args.nosound)
161 ogg_stream_init(&enc_data_t->m_ogg_vs,y2);
162
163
164 theora_info_init(&enc_data_t->m_th_inf);
165 enc_data_t->m_th_inf.frame_width = pdata->brwin.rrect.width;
166 enc_data_t->m_th_inf.frame_height = pdata->brwin.rrect.height;
167 enc_data_t->m_th_inf.width = ((enc_data_t->m_th_inf.frame_width + 15) >> 4) << 4;
168 enc_data_t->m_th_inf.height = ((enc_data_t->m_th_inf.frame_height + 15) >> 4) << 4;
169 enc_data_t->m_th_inf.offset_x = 0;
170 enc_data_t->m_th_inf.offset_y = 0;
171
172 enc_data_t->m_th_inf.fps_numerator = pdata->args.fps * 100.0;
173 enc_data_t->m_th_inf.fps_denominator = 100;
174 enc_data_t->m_th_inf.aspect_numerator = 1;
175 enc_data_t->m_th_inf.aspect_denominator = 1;
176
177 enc_data_t->m_th_inf.colorspace = OC_CS_UNSPECIFIED;
178 enc_data_t->m_th_inf.pixelformat = OC_PF_420;
179
180 enc_data_t->m_th_inf.target_bitrate = pdata->args.v_bitrate;
181 enc_data_t->m_th_inf.quality = pdata->args.v_quality;
182 enc_data_t->m_th_inf.dropframes_p = 0;
183 enc_data_t->m_th_inf.quick_p = 1;
184 enc_data_t->m_th_inf.keyframe_auto_p = 1;
185 enc_data_t->m_th_inf.keyframe_frequency = 64;
186 enc_data_t->m_th_inf.keyframe_frequency_force = 64;
187 enc_data_t->m_th_inf.keyframe_data_target_bitrate = enc_data_t->m_th_inf.quality * 1.5;
188 enc_data_t->m_th_inf.keyframe_auto_threshold = 80;
189 enc_data_t->m_th_inf.keyframe_mindistance = 8;
190 enc_data_t->m_th_inf.noise_sensitivity = 1;
191 enc_data_t->m_th_inf.sharpness = 2;
192
193 theora_encode_init(&enc_data_t->m_th_st,&enc_data_t->m_th_inf);
194
195
196 if(!pdata->args.nosound){
197 int ret;
198 vorbis_info_init(&enc_data_t->m_vo_inf);
199 ret = vorbis_encode_init_vbr(&enc_data_t->m_vo_inf,
200 pdata->args.channels,
201 pdata->args.frequency,
202 (float)pdata->args.s_quality*0.1);
203 if(ret){
204 fprintf(stderr,"Error while setting up vorbis stream quality!\n");
205 exit(2);
206 }
207 vorbis_comment_init(&enc_data_t->m_vo_cmmnt);
208 vorbis_analysis_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_inf);
209 vorbis_block_init(&enc_data_t->m_vo_dsp,&enc_data_t->m_vo_block);
210 }
211
212
213 theora_encode_header(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1);
214 ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);
215 if(ogg_stream_pageout(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pg)!=1){
216 fprintf(stderr,"Internal Ogg library error.\n");
217 exit(2);
218 }
219 fwrite(enc_data_t->m_ogg_pg.header,1,
220 enc_data_t->m_ogg_pg.header_len,
221 enc_data_t->fp);
222 fwrite(enc_data_t->m_ogg_pg.body,1,
223 enc_data_t->m_ogg_pg.body_len,
224 enc_data_t->fp);
225
226 theora_comment_init(&enc_data_t->m_th_cmmnt);
227 theora_comment_add_tag(&enc_data_t->m_th_cmmnt,"recordMyDesktop",VERSION);
228 theora_encode_comment(&enc_data_t->m_th_cmmnt,&enc_data_t->m_ogg_pckt1);
229 ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);
230 theora_encode_tables(&enc_data_t->m_th_st,&enc_data_t->m_ogg_pckt1);
231 ogg_stream_packetin(&enc_data_t->m_ogg_ts,&enc_data_t->m_ogg_pckt1);
232
233
234 if(!pdata->args.nosound){
235 ogg_packet header;
236 ogg_packet header_comm;
237 ogg_packet header_code;
238
239 vorbis_analysis_headerout(&enc_data_t->m_vo_dsp,
240 &enc_data_t->m_vo_cmmnt,
241 &header,&header_comm,
242 &header_code);
243 ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header);
244 if(ogg_stream_pageout(&enc_data_t->m_ogg_vs,&enc_data_t->m_ogg_pg)!=1){
245 fprintf(stderr,"Internal Ogg library error.\n");
246 exit(2);
247 }
248 fwrite(enc_data_t->m_ogg_pg.header,1,
249 enc_data_t->m_ogg_pg.header_len,
250 enc_data_t->fp);
251 fwrite(enc_data_t->m_ogg_pg.body,1,
252 enc_data_t->m_ogg_pg.body_len,
253 enc_data_t->fp);
254
255 ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_comm);
256 ogg_stream_packetin(&enc_data_t->m_ogg_vs,&header_code);
257 }
258
259 //fishbone packets go here
260 memset(&skel_fbv,0,sizeof(skel_fbv));
261 skel_fbv.serial_no=enc_data_t->m_ogg_ts.serialno;
262 skel_fbv.nr_header_packet=3;
263 skel_fbv.granule_rate_n=enc_data_t->m_th_inf.fps_numerator;
264 skel_fbv.granule_rate_d=enc_data_t->m_th_inf.fps_denominator;
265 skel_fbv.start_granule=0;
266 skel_fbv.preroll=0;
267 skel_fbv.granule_shift=theora_granule_shift(&enc_data_t->m_th_inf);
268 add_message_header_field(&skel_fbv,
269 "Content-Type",
270 "video/theora");
271
272 add_fisbone_to_stream(&m_ogg_skel,&skel_fbv);
273
274 if(!pdata->args.nosound){
275
276 memset(&skel_fba,0,sizeof(skel_fba));
277 skel_fba.serial_no=enc_data_t->m_ogg_vs.serialno;
278 skel_fba.nr_header_packet=3;
279 skel_fba.granule_rate_n=pdata->args.frequency;
280 skel_fba.granule_rate_d=(ogg_int64_t)1;
281 skel_fba.start_granule=0;
282 skel_fba.preroll=2;
283 skel_fba.granule_shift=0;
284 add_message_header_field(&skel_fba,
285 "Content-Type",
286 "audio/vorbis");
287
288 add_fisbone_to_stream(&m_ogg_skel,&skel_fba);
289
290 }
291
292 while(1){
293 int result = ogg_stream_flush(&m_ogg_skel, &skel_og_pg);
294 if(result<0){
295 fprintf (stderr, "Internal Ogg library error.\n");
296 exit(2);
297 }
298 if(result==0)
299 break;
300 fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
301 fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
302 }
303
304
305
306 while(1){
307 int result = ogg_stream_flush(&enc_data_t->m_ogg_ts,
308 &enc_data_t->m_ogg_pg);
309 if(result<0){
310 fprintf(stderr,"Internal Ogg library error.\n");
311 exit(2);
312 }
313 if(result==0)break;
314 fwrite(enc_data_t->m_ogg_pg.header,1,
315 enc_data_t->m_ogg_pg.header_len,
316 enc_data_t->fp);
317 fwrite(enc_data_t->m_ogg_pg.body,1,
318 enc_data_t->m_ogg_pg.body_len,
319 enc_data_t->fp);
320 }
321
322 if(!pdata->args.nosound){
323 while(1){
324 int result=ogg_stream_flush(&enc_data_t->m_ogg_vs,
325 &enc_data_t->m_ogg_pg);
326 if(result<0){
327 fprintf(stderr,"Internal Ogg library error.\n");
328 exit(2);
329 }
330 if(result==0)break;
331 fwrite(enc_data_t->m_ogg_pg.header,1,
332 enc_data_t->m_ogg_pg.header_len,
333 enc_data_t->fp);
334 fwrite(enc_data_t->m_ogg_pg.body,1,
335 enc_data_t->m_ogg_pg.body_len,
336 enc_data_t->fp);
337 }
338 }
339
340 //skeleton eos
341 add_eos_packet_to_stream(&m_ogg_skel);
342 if(ogg_stream_flush(&m_ogg_skel,&skel_og_pg)<0){
343 fprintf(stderr,"Internal Ogg library error.\n");
344 exit(2);
345 }
346 fwrite(skel_og_pg.header,1,skel_og_pg.header_len,enc_data_t->fp);
347 fwrite(skel_og_pg.body,1,skel_og_pg.body_len,enc_data_t->fp);
348
349
350 //theora buffer allocation, if any
351 if(!buffer_ready){
352 enc_data_t->yuv.y=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
353 enc_data_t->m_th_inf.width);
354 enc_data_t->yuv.u=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
355 enc_data_t->m_th_inf.width/4);
356 enc_data_t->yuv.v=(unsigned char *)malloc(enc_data_t->m_th_inf.height*
357 enc_data_t->m_th_inf.width/4);
358 enc_data_t->yuv.y_width=enc_data_t->m_th_inf.width;
359 enc_data_t->yuv.y_height=enc_data_t->m_th_inf.height;
360 enc_data_t->yuv.y_stride=enc_data_t->m_th_inf.width;
361
362 enc_data_t->yuv.uv_width=enc_data_t->m_th_inf.width/2;
363 enc_data_t->yuv.uv_height=enc_data_t->m_th_inf.height/2;
364 enc_data_t->yuv.uv_stride=enc_data_t->m_th_inf.width/2;
365 enc_data_t->x_offset=enc_data_t->m_th_inf.offset_x;
366 enc_data_t->y_offset=enc_data_t->m_th_inf.offset_y;
367 }
368 theora_info_clear(&enc_data_t->m_th_inf);
369
370 }
371
372
373
374
375