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