Mercurial > mplayer.hg
comparison mencoder.c @ 2531:cf6a236b2d00
very alpha code - needs Makefile modifications to compile
author | arpi |
---|---|
date | Mon, 29 Oct 2001 01:11:18 +0000 |
parents | |
children | 13608ff3d1e6 |
comparison
equal
deleted
inserted
replaced
2530:6fe4d4a5a0ff | 2531:cf6a236b2d00 |
---|---|
1 | |
2 #define VCODEC_DIVX4 1 | |
3 | |
4 #include <stdio.h> | |
5 #include <stdlib.h> | |
6 #include <string.h> | |
7 #include <signal.h> | |
8 | |
9 #include "mp_msg.h" | |
10 #include "help_mp.h" | |
11 | |
12 #include "codec-cfg.h" | |
13 | |
14 #include "stream.h" | |
15 #include "demuxer.h" | |
16 #include "parse_es.h" | |
17 #include "stheader.h" | |
18 | |
19 #include "aviwrite.h" | |
20 | |
21 #include "libvo/video_out.h" | |
22 | |
23 #include <encore2.h> | |
24 | |
25 char *get_path(char *filename){ | |
26 char *homedir; | |
27 char *buff; | |
28 static char *config_dir = "/.mplayer"; | |
29 int len; | |
30 | |
31 if ((homedir = getenv("HOME")) == NULL) | |
32 return NULL; | |
33 len = strlen(homedir) + strlen(config_dir) + 1; | |
34 if (filename == NULL) { | |
35 if ((buff = (char *) malloc(len)) == NULL) | |
36 return NULL; | |
37 sprintf(buff, "%s%s", homedir, config_dir); | |
38 } else { | |
39 len += strlen(filename) + 1; | |
40 if ((buff = (char *) malloc(len)) == NULL) | |
41 return NULL; | |
42 sprintf(buff, "%s%s/%s", homedir, config_dir, filename); | |
43 } | |
44 return buff; | |
45 } | |
46 | |
47 #define ABS(x) (((x)>=0)?(x):(-(x))) | |
48 | |
49 //-------------------------- | |
50 | |
51 // cache2: | |
52 #ifdef USE_STREAM_CACHE | |
53 extern int cache_fill_status; | |
54 #else | |
55 #define cache_fill_status 0 | |
56 #endif | |
57 | |
58 // AVI demuxer params: | |
59 static float c_total=0; | |
60 int delay_corrected=1; | |
61 extern int index_mode; // -1=untouched 0=don't use index 1=use (geneate) index | |
62 extern int force_ni; | |
63 extern int pts_from_bps; | |
64 | |
65 char *audio_codec=NULL; // override audio codec | |
66 char *video_codec=NULL; // override video codec | |
67 int audio_family=-1; // override audio codec family | |
68 int video_family=-1; // override video codec family | |
69 | |
70 // audio stream skip/resync functions requires only for seeking. | |
71 // (they should be implemented in the audio codec layer) | |
72 //void skip_audio_frame(sh_audio_t *sh_audio){} | |
73 //void resync_audio_stream(sh_audio_t *sh_audio){} | |
74 | |
75 int verbose=5; // must be global! | |
76 | |
77 double video_time_usage=0; | |
78 double vout_time_usage=0; | |
79 static double audio_time_usage=0; | |
80 static int total_time_usage_start=0; | |
81 static int benchmark=0; | |
82 | |
83 int divx_quality=0; | |
84 int force_fps=0; | |
85 | |
86 #include "libmpeg2/mpeg2.h" | |
87 #include "libmpeg2/mpeg2_internal.h" | |
88 | |
89 extern picture_t *picture; // exported from libmpeg2/decode.c | |
90 | |
91 int frameratecode2framerate[16] = { | |
92 0, | |
93 // Official mpeg1/2 framerates: | |
94 24000*10000/1001, 24*10000,25*10000, 30000*10000/1001, 30*10000,50*10000,60000*10000/1001, 60*10000, | |
95 // libmpeg3's "Unofficial economy rates": | |
96 1*10000,5*10000,10*10000,12*10000,15*10000,0,0 | |
97 }; | |
98 | |
99 static unsigned char* vo_image=NULL; | |
100 static unsigned char* vo_image_ptr=NULL; | |
101 static int vo_w,vo_h; | |
102 | |
103 static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h, int x0,int y0){ | |
104 int y; | |
105 // printf("draw_slice %dx%d %d;%d\n",w,h,x,y); | |
106 | |
107 // copy Y: | |
108 for(y=0;y<h;y++){ | |
109 unsigned char* s=src[0]+stride[0]*(y0+y)+x0; | |
110 unsigned char* d=vo_image+vo_w*(y0+y)+x0; | |
111 memcpy(d,s,w); | |
112 } | |
113 x0>>=1;y0>>=1; | |
114 w>>=1;h>>=1; | |
115 // copy U: | |
116 for(y=0;y<h;y++){ | |
117 unsigned char* s=src[1]+stride[1]*(y0+y)+x0; | |
118 unsigned char* d=vo_image+vo_w*vo_h+(vo_w>>1)*(y0+y)+x0; | |
119 memcpy(d,s,w); | |
120 } | |
121 // copy V: | |
122 for(y=0;y<h;y++){ | |
123 unsigned char* s=src[1]+stride[1]*(y0+y)+x0; | |
124 unsigned char* d=vo_image+vo_w*vo_h+vo_w*vo_h/4+(vo_w>>1)*(y0+y)+x0; | |
125 memcpy(d,s,w); | |
126 } | |
127 | |
128 } | |
129 | |
130 static uint32_t draw_frame(uint8_t *src[]){ | |
131 // printf("This function shouldn't be called - report bug!\n"); | |
132 // later: add YUY2->YV12 conversion here! | |
133 vo_image_ptr=src[0]; | |
134 } | |
135 | |
136 vo_functions_t video_out; | |
137 | |
138 //--------------- | |
139 | |
140 extern stream_t* open_stream(char* filename,int vcd_track,int* file_format); | |
141 | |
142 extern int video_read_properties(sh_video_t *sh_video); | |
143 extern int init_video(sh_video_t *sh_video); | |
144 extern int decode_video(vo_functions_t *video_out,sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame); | |
145 | |
146 static int eof=0; | |
147 | |
148 static void exit_sighandler(int x){ | |
149 eof=1; | |
150 } | |
151 | |
152 int main(int argc,char* argv[]){ | |
153 | |
154 stream_t* stream=NULL; | |
155 demuxer_t* demuxer=NULL; | |
156 demux_stream_t *d_audio=NULL; | |
157 demux_stream_t *d_video=NULL; | |
158 demux_stream_t *d_dvdsub=NULL; | |
159 sh_audio_t *sh_audio=NULL; | |
160 sh_video_t *sh_video=NULL; | |
161 int file_format=DEMUXER_TYPE_UNKNOWN; | |
162 int i; | |
163 unsigned int out_fmt; | |
164 | |
165 aviwrite_t* muxer=NULL; | |
166 aviwrite_stream_t* mux_a=NULL; | |
167 aviwrite_stream_t* mux_v=NULL; | |
168 FILE* muxer_f=NULL; | |
169 | |
170 ENC_PARAM enc_param; | |
171 ENC_FRAME enc_frame; | |
172 ENC_RESULT enc_result; | |
173 void* enc_handle=NULL; | |
174 | |
175 //int out_buffer_size=0x200000; | |
176 //unsigned char* out_buffer=malloc(out_buffer_size); | |
177 | |
178 mp_msg_init(verbose+MSGL_STATUS); | |
179 | |
180 // check codec.conf | |
181 if(!parse_codec_cfg("etc/codecs.conf")){ | |
182 mp_msg(MSGT_CPLAYER,MSGL_HINT,MSGTR_CopyCodecsConf); | |
183 exit(0); // From unknown reason a hangup occurs here :(((((( | |
184 } | |
185 | |
186 if(argc>1) | |
187 stream=open_stream(argv[1],0,&file_format); | |
188 else | |
189 stream=open_stream("/3d/divx/405divx_sm_v2[1].avi",0,&file_format); | |
190 // stream=open_stream("/dev/cdrom",2,&file_format); // VCD track 2 | |
191 | |
192 if(!stream){ | |
193 printf("Cannot open file/device\n"); | |
194 exit(1); | |
195 } | |
196 | |
197 printf("success: format: %d data: 0x%X - 0x%X\n",file_format, (int)(stream->start_pos),(int)(stream->end_pos)); | |
198 | |
199 stream_enable_cache(stream,2048*1024); | |
200 | |
201 demuxer=demux_open(stream,file_format,-1,-1,-1); | |
202 if(!demuxer){ | |
203 printf("Cannot open demuxer\n"); | |
204 exit(1); | |
205 } | |
206 | |
207 d_audio=demuxer->audio; | |
208 d_video=demuxer->video; | |
209 d_dvdsub=demuxer->sub; | |
210 sh_audio=d_audio->sh; | |
211 sh_video=d_video->sh; | |
212 | |
213 if(!video_read_properties(sh_video)){ | |
214 printf("Couldn't read video properties\n"); | |
215 exit(1); | |
216 } | |
217 | |
218 mp_msg(MSGT_CPLAYER,MSGL_INFO,"[V] filefmt:%d fourcc:0x%X size:%dx%d fps:%5.2f ftime:=%6.4f\n", | |
219 demuxer->file_format,sh_video->format, sh_video->disp_w,sh_video->disp_h, | |
220 sh_video->fps,sh_video->frametime | |
221 ); | |
222 | |
223 | |
224 sh_video->codec=NULL; | |
225 if(video_family!=-1) mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_TryForceVideoFmt,video_family); | |
226 while(1){ | |
227 sh_video->codec=find_codec(sh_video->format, | |
228 sh_video->bih?((unsigned int*) &sh_video->bih->biCompression):NULL,sh_video->codec,0); | |
229 if(!sh_video->codec){ | |
230 if(video_family!=-1) { | |
231 sh_video->codec=NULL; /* re-search */ | |
232 mp_msg(MSGT_CPLAYER,MSGL_WARN,MSGTR_CantFindVfmtFallback); | |
233 video_family=-1; | |
234 continue; | |
235 } | |
236 mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CantFindVideoCodec,sh_video->format); | |
237 mp_msg(MSGT_CPLAYER,MSGL_HINT, MSGTR_TryUpgradeCodecsConfOrRTFM,get_path("codecs.conf")); | |
238 exit(1); | |
239 } | |
240 if(video_codec && strcmp(sh_video->codec->name,video_codec)) continue; | |
241 else if(video_family!=-1 && sh_video->codec->driver!=video_family) continue; | |
242 break; | |
243 } | |
244 | |
245 mp_msg(MSGT_CPLAYER,MSGL_INFO,"%s video codec: [%s] drv:%d (%s)\n",video_codec?"Forcing":"Detected",sh_video->codec->name,sh_video->codec->driver,sh_video->codec->info); | |
246 | |
247 for(i=0;i<CODECS_MAX_OUTFMT;i++){ | |
248 out_fmt=sh_video->codec->outfmt[i]; | |
249 if(out_fmt==0xFFFFFFFF) continue; | |
250 if(out_fmt==IMGFMT_YV12) break; | |
251 if(out_fmt==IMGFMT_I420) break; | |
252 if(out_fmt==IMGFMT_IYUV) break; | |
253 if(out_fmt==IMGFMT_YUY2) break; | |
254 } | |
255 if(i>=CODECS_MAX_OUTFMT){ | |
256 mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_VOincompCodec); | |
257 exit(1); // exit_player(MSGTR_Exit_error); | |
258 } | |
259 sh_video->outfmtidx=i; | |
260 | |
261 if(out_fmt==IMGFMT_YV12 || out_fmt==IMGFMT_I420 || out_fmt==IMGFMT_IYUV){ | |
262 vo_w=sh_video->disp_w; | |
263 vo_h=sh_video->disp_h; | |
264 vo_image=malloc(vo_w*vo_h*3/2); | |
265 vo_image_ptr=vo_image; | |
266 } | |
267 | |
268 if(!init_video(sh_video)){ | |
269 mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_CouldntInitVideoCodec); | |
270 exit(1); | |
271 } | |
272 | |
273 // set up video encoder: | |
274 video_out.draw_slice=draw_slice; | |
275 video_out.draw_frame=draw_frame; | |
276 | |
277 // set up output file: | |
278 muxer_f=fopen("test.avi","wb"); | |
279 muxer=aviwrite_new_muxer(); | |
280 mux_v=aviwrite_new_stream(muxer,AVIWRITE_TYPE_VIDEO); | |
281 | |
282 mux_v->buffer_size=0x200000; | |
283 mux_v->buffer=malloc(mux_v->buffer_size); | |
284 | |
285 mux_v->source=sh_video; | |
286 | |
287 mux_v->h.dwSampleSize=0; // VBR | |
288 mux_v->h.dwScale=10000; | |
289 mux_v->h.dwRate=mux_v->h.dwScale*sh_video->fps; | |
290 | |
291 switch(mux_v->codec){ | |
292 case 0: | |
293 mux_v->bih=sh_video->bih; | |
294 break; | |
295 case VCODEC_DIVX4: | |
296 mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); | |
297 mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); | |
298 mux_v->bih->biWidth=sh_video->disp_w; | |
299 mux_v->bih->biHeight=sh_video->disp_h; | |
300 mux_v->bih->biPlanes=0; | |
301 mux_v->bih->biBitCount=24; | |
302 mux_v->bih->biCompression=mmioFOURCC('d','i','v','x'); | |
303 mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); | |
304 break; | |
305 } | |
306 | |
307 aviwrite_write_header(muxer,muxer_f); | |
308 | |
309 switch(mux_v->codec){ | |
310 case 0: | |
311 break; | |
312 case VCODEC_DIVX4: | |
313 // init divx4linux: | |
314 enc_param.x_dim=sh_video->disp_w; | |
315 enc_param.y_dim=sh_video->disp_h; | |
316 enc_param.framerate=sh_video->fps; | |
317 enc_param.bitrate=800; | |
318 enc_param.rc_period=0; | |
319 enc_param.rc_reaction_period=0; | |
320 enc_param.rc_reaction_ratio=0; | |
321 enc_param.max_quantizer=0; | |
322 enc_param.min_quantizer=0; | |
323 enc_param.max_key_interval=0; | |
324 enc_param.use_bidirect=0; | |
325 enc_param.deinterlace=0; | |
326 enc_param.quality=5; // the quality of compression ( 1 - fastest, 5 - best ) | |
327 enc_param.obmc=0; | |
328 enc_param.handle=NULL; | |
329 encore(NULL,ENC_OPT_INIT,&enc_param,NULL); | |
330 enc_handle=enc_param.handle; | |
331 break; | |
332 } | |
333 | |
334 | |
335 signal(SIGINT,exit_sighandler); // Interrupt from keyboard | |
336 signal(SIGQUIT,exit_sighandler); // Quit from keyboard | |
337 signal(SIGTERM,exit_sighandler); // kill | |
338 | |
339 | |
340 while(!eof){ | |
341 | |
342 float frame_time=1; | |
343 float pts1=d_video->pts; | |
344 int blit_frame=0; | |
345 float a_pts=0; | |
346 float v_pts=0; | |
347 | |
348 // current_module="decode_video"; | |
349 | |
350 //-------------------- Decode a frame: ----------------------- | |
351 | |
352 if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS){ | |
353 int in_frame=0; | |
354 float newfps; | |
355 //videobuf_len=0; | |
356 while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){ | |
357 int i=sync_video_packet(d_video); | |
358 void* buffer=&videobuffer[videobuf_len+4]; | |
359 if(in_frame){ | |
360 if(i<0x101 || i>=0x1B0){ // not slice code -> end of frame | |
361 #if 1 | |
362 // send END OF FRAME code: | |
363 videobuffer[videobuf_len+0]=0; | |
364 videobuffer[videobuf_len+1]=0; | |
365 videobuffer[videobuf_len+2]=1; | |
366 videobuffer[videobuf_len+3]=0xFF; | |
367 videobuf_len+=4; | |
368 #endif | |
369 if(!i) eof=2; // EOF | |
370 break; | |
371 } | |
372 } else { | |
373 //if(i==0x100) in_frame=1; // picture startcode | |
374 if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode | |
375 else if(!i){ eof=3; break;} // EOF | |
376 } | |
377 if(!read_video_packet(d_video)){ eof=4; break;} // EOF | |
378 //printf("read packet 0x%X, len=%d\n",i,videobuf_len); | |
379 if(sh_video->codec->driver!=VFM_MPEG){ | |
380 // if not libmpeg2: | |
381 switch(i){ | |
382 case 0x1B3: header_process_sequence_header (picture, buffer);break; | |
383 case 0x1B5: header_process_extension (picture, buffer);break; | |
384 } | |
385 } | |
386 } | |
387 | |
388 //if(videobuf_len>max_framesize) max_framesize=videobuf_len; // debug | |
389 //printf("--- SEND %d bytes\n",videobuf_len); | |
390 | |
391 blit_frame=decode_video(&video_out,sh_video,videobuffer,videobuf_len,0); | |
392 | |
393 // get mpeg fps: | |
394 newfps=frameratecode2framerate[picture->frame_rate_code]*0.0001f; | |
395 if(ABS(sh_video->fps-newfps)>0.01f) { | |
396 mp_msg(MSGT_CPLAYER,MSGL_WARN,"Warning! FPS changed %5.3f -> %5.3f (%f) [%d] \n",sh_video->fps,newfps,sh_video->fps-newfps,picture->frame_rate_code); | |
397 sh_video->fps=newfps; | |
398 sh_video->frametime=10000.0f/(float)frameratecode2framerate[picture->frame_rate_code]; | |
399 } | |
400 | |
401 // fix mpeg2 frametime: | |
402 frame_time=(picture->display_time)*0.01f; | |
403 picture->display_time=100; | |
404 videobuf_len=0; | |
405 | |
406 } else { | |
407 // frame-based file formats: (AVI,ASF,MOV) | |
408 unsigned char* start=NULL; | |
409 int in_size=ds_get_packet(d_video,&start); | |
410 if(in_size<0){ eof=5;break;} | |
411 //if(in_size>max_framesize) max_framesize=in_size; | |
412 if(mux_v->codec){ | |
413 // convert | |
414 blit_frame=decode_video(&video_out,sh_video,start,in_size,0); | |
415 } else { | |
416 // copy | |
417 mux_v->buffer=start; | |
418 aviwrite_write_chunk(muxer,mux_v,muxer_f,in_size,(sh_video->ds->flags&1)?0x10:0); | |
419 } | |
420 } | |
421 if(eof) break; | |
422 | |
423 //------------------------ frame decoded. -------------------- | |
424 | |
425 // Increase video timers: | |
426 sh_video->num_frames+=frame_time; | |
427 ++sh_video->num_frames_decoded; | |
428 frame_time*=sh_video->frametime; | |
429 if(demuxer->file_format==DEMUXER_TYPE_ASF && !force_fps){ | |
430 // .ASF files has no fixed FPS - just frame durations! | |
431 float d=d_video->pts-pts1; | |
432 if(d>=0 && d<5) frame_time=d; | |
433 if(d>0){ | |
434 if(verbose) | |
435 if((int)sh_video->fps==1000) | |
436 mp_msg(MSGT_CPLAYER,MSGL_STATUS,"\rASF framerate: %d fps \n",(int)(1.0f/d)); | |
437 sh_video->frametime=d; // 1ms | |
438 sh_video->fps=1.0f/d; | |
439 } | |
440 } else | |
441 if(demuxer->file_format==DEMUXER_TYPE_MOV && !force_fps){ | |
442 // .MOV files has no fixed FPS - just frame durations! | |
443 float d=d_video->pts-pts1; | |
444 frame_time=d; | |
445 } | |
446 sh_video->timer+=frame_time; | |
447 | |
448 if(demuxer->file_format==DEMUXER_TYPE_MPEG_PS) d_video->pts+=frame_time; | |
449 | |
450 if(pts_from_bps){ | |
451 unsigned int samples=(sh_audio->audio.dwSampleSize)? | |
452 ((ds_tell(d_audio)-sh_audio->a_in_buffer_len)/sh_audio->audio.dwSampleSize) : | |
453 (d_audio->pack_no); // <- used for VBR audio | |
454 a_pts=samples*(float)sh_audio->audio.dwScale/(float)sh_audio->audio.dwRate; | |
455 delay_corrected=1; | |
456 } else { | |
457 // PTS = (last timestamp) + (bytes after last timestamp)/(bytes per sec) | |
458 a_pts=d_audio->pts; | |
459 if(!delay_corrected) if(a_pts) delay_corrected=1; | |
460 //printf("*** %5.3f ***\n",a_pts); | |
461 a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; | |
462 } | |
463 v_pts=d_video->pts; | |
464 | |
465 mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%6.1f V:%6.1f A-V:%7.3f ct:%7.3f %3d/%3d %2d%% %2d%% %4.1f%% %d%%\r", | |
466 a_pts,v_pts,a_pts-v_pts,c_total, | |
467 (int)sh_video->num_frames,(int)sh_video->num_frames_decoded, | |
468 (sh_video->timer>0.5)?(int)(100.0*video_time_usage/(double)sh_video->timer):0, | |
469 (sh_video->timer>0.5)?(int)(100.0*vout_time_usage/(double)sh_video->timer):0, | |
470 (sh_video->timer>0.5)?(100.0*audio_time_usage/(double)sh_video->timer):0 | |
471 ,cache_fill_status | |
472 ); | |
473 fflush(stdout); | |
474 | |
475 if(!blit_frame) continue; | |
476 | |
477 switch(mux_v->codec){ | |
478 case VCODEC_DIVX4: | |
479 enc_frame.image=vo_image_ptr; | |
480 enc_frame.bitstream=mux_v->buffer; | |
481 enc_frame.length=mux_v->buffer_size; | |
482 switch(out_fmt){ | |
483 case IMGFMT_YV12: enc_frame.colorspace=ENC_CSP_YV12; break; | |
484 case IMGFMT_IYUV: | |
485 case IMGFMT_I420: enc_frame.colorspace=ENC_CSP_I420; break; | |
486 case IMGFMT_YUY2: enc_frame.colorspace=ENC_CSP_YUY2; break; | |
487 case IMGFMT_UYVY: enc_frame.colorspace=ENC_CSP_UYVY; break; | |
488 case IMGFMT_RGB24: | |
489 case IMGFMT_BGR24: | |
490 enc_frame.colorspace=ENC_CSP_RGB24; break; | |
491 } | |
492 enc_frame.quant=0; | |
493 enc_frame.intra=0; | |
494 enc_frame.mvs=NULL; | |
495 | |
496 // printf("encoding...\n"); | |
497 encore(enc_handle,ENC_OPT_ENCODE,&enc_frame,&enc_result); | |
498 | |
499 // printf(" len=%d key:%d qualt:%d \n",enc_frame.length,enc_result.is_key_frame,enc_result.quantizer); | |
500 | |
501 aviwrite_write_chunk(muxer,mux_v,muxer_f,enc_frame.length,enc_result.is_key_frame?0x10:0); | |
502 break; | |
503 } | |
504 | |
505 | |
506 } // while(!eof) | |
507 | |
508 aviwrite_write_index(muxer,muxer_f); | |
509 fseek(muxer_f,0,SEEK_SET); | |
510 aviwrite_write_header(muxer,muxer_f); // update header | |
511 fclose(muxer_f); | |
512 | |
513 } |