Mercurial > mplayer.hg
view mencoder.c @ 4218:3931c41f740a
Added new syncengine thanks to a new previously undocumented feature of the em8300, this might fix playback on both slow and fast machines (more testing needed). This also requires users to get the em8300 driver from cvs until the next version is released (will probably happen this weekend)
Added lots of comments, should be pretty easy to understand most of the internals now
Added lots of brackets to if's for's while's etc, this is not a cosmetical thing but rather due to the fact I got some very odd bugs with else's since I didn't properly use brackets (and it's the K&R standard to have brackets everywhere)
Fixed some bugs that would occur when disabling libmp1e
Switched to default to the new naming scheme of device nodes, the driver will slowly switch over to this state, if it can't find devices under the new name it will try the old naming scheme
I stopped opening devices in non-blocking mode, it would break the new syncengine which tries to burst data to the device (alot of times meaning it will fill the fifo pretty fast which would previously result in jerkyness on fast machines)
The device now sets the initial state of the pts and speed (probably not needed, but assumption is the mother of all fuckups =)
Keep the control interface open during the entire duration of the libvo device, we might need this to flush video buffers on seeking (currently not implemented, therefore seeking is broken)
This is beta stuff to the driver, I will get some users to test it for me and do my best to fix seeking as soon as possible...
author | mswitch |
---|---|
date | Thu, 17 Jan 2002 10:33:47 +0000 |
parents | 1427d0f1f2d6 |
children | b0c8eed7473c |
line wrap: on
line source
#define VCODEC_COPY 0 #define VCODEC_FRAMENO 1 #define VCODEC_DIVX4 2 #define VCODEC_RAW 3 #define VCODEC_LIBAVCODEC 4 #define ACODEC_COPY 0 #define ACODEC_PCM 1 #define ACODEC_VBRMP3 2 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include "config.h" #include "mp_msg.h" #include "version.h" #include "help_mp.h" static char* banner_text= "\n\n" "MEncoder " VERSION "(C) 2000-2001 Arpad Gereoffy (see DOCS!)\n" "\n"; #include "cpudetect.h" #include "codec-cfg.h" #include "stream.h" #include "demuxer.h" #include "stheader.h" #include "playtree.h" #include "aviwrite.h" #ifdef USE_LIBVO2 #include "libvo2/libvo2.h" #else #include "libvo/video_out.h" #endif #include "dec_audio.h" #include "dec_video.h" #ifdef HAVE_DIVX4ENCORE #include <encore2.h> #include "divx4_vbr.h" #endif #ifdef HAVE_MP3LAME #include <lame/lame.h> #endif #ifdef USE_LIBAVCODEC #ifdef USE_LIBAVCODEC_SO #include <libffmpeg/avcodec.h> #else #include "libavcodec/avcodec.h" #endif static AVCodec *lavc_venc_codec=NULL; static AVCodecContext lavc_venc_context; static AVPicture lavc_venc_picture; extern int avcodec_inited; char *lavc_param_vcodec = NULL; int lavc_param_vbitrate = -1; int lavc_param_vhq = 0; /* default is realtime encoding */ int lavc_param_vme = 3; int lavc_param_keyint = -1; #endif #ifdef HAVE_LIBCSS #include "libmpdemux/dvdauth.h" #endif #include <inttypes.h> #include "../postproc/swscale.h" #include "fastmemcpy.h" //-------------------------- // cache2: static int stream_cache_size=0; #ifdef USE_STREAM_CACHE extern int cache_fill_status; #else #define cache_fill_status 0 #endif int vcd_track=0; int audio_id=-1; int video_id=-1; int dvdsub_id=-1; char *audio_codec=NULL; // override audio codec char *video_codec=NULL; // override video codec int audio_family=-1; // override audio codec family int video_family=-1; // override video codec family #ifdef HAVE_MP3LAME int out_audio_codec=ACODEC_VBRMP3; #else int out_audio_codec=ACODEC_PCM; #endif int out_video_codec=VCODEC_DIVX4; // audio stream skip/resync functions requires only for seeking. // (they should be implemented in the audio codec layer) //void skip_audio_frame(sh_audio_t *sh_audio){} //void resync_audio_stream(sh_audio_t *sh_audio){} int verbose=0; // must be global! double video_time_usage=0; double vout_time_usage=0; static double audio_time_usage=0; static int total_time_usage_start=0; static int benchmark=0; // A-V sync: int delay_corrected=1; static float default_max_pts_correction=-1;//0.01f; static float max_pts_correction=0;//default_max_pts_correction; static float c_total=0; float force_fps=0; float force_ofps=0; // set to 24 for inverse telecine int force_srate=0; char* out_filename="test.avi"; char* mp3_filename=NULL; char* ac3_filename=NULL; char *force_fourcc=NULL; #ifdef HAVE_DIVX4ENCORE static int pass=0; static char* passtmpfile="divx2pass.log"; int pass_working=0; #endif static int play_n_frames=-1; //char *out_audio_codec=NULL; // override audio codec //char *out_video_codec=NULL; // override video codec //#include "libmpeg2/mpeg2.h" //#include "libmpeg2/mpeg2_internal.h" #ifdef HAVE_DIVX4ENCORE ENC_PARAM divx4_param; int divx4_crispness=100; #endif #ifdef HAVE_MP3LAME int lame_param_quality=0; // best int lame_param_vbr=vbr_default; int lame_param_mode=-1; // unset int lame_param_padding=-1; // unset int lame_param_br=-1; // unset int lame_param_ratio=-1; // unset #endif static int scale_srcW=0; static int scale_srcH=0; static int vo_w=0, vo_h=0; //-------------------------- config stuff: #include "cfgparser.h" m_config_t* mconfig; static int cfg_inc_verbose(struct config *conf){ ++verbose; return 0;} static int cfg_include(struct config *conf, char *filename){ return m_config_parse_config_file(mconfig, filename); } static int parse_end_at(struct config *conf, const char* param); #include "get_path.c" #include "cfg-mplayer-def.h" #include "cfg-mencoder.h" #ifdef USE_DVDREAD #include "spudec.h" #endif //--------------------------------------------------------------------------- // mini dummy libvo: static unsigned char* vo_image=NULL; static unsigned char* vo_image_ptr=NULL; static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h, int x0,int y0){ int y; // printf("draw_slice %dx%d %d;%d\n",w,h,x0,y0); if(scale_srcW) { uint8_t* dstPtr[3]= { vo_image, vo_image + vo_w*vo_h*5/4, vo_image + vo_w*vo_h}; SwScale_YV12slice(src, stride, y0, h, dstPtr, vo_w, 12, scale_srcW, scale_srcH, vo_w, vo_h); } else { // copy Y: for(y=0;y<h;y++){ unsigned char* s=src[0]+stride[0]*y; unsigned char* d=vo_image+vo_w*(y0+y)+x0; memcpy(d,s,w); } x0>>=1;y0>>=1; w>>=1;h>>=1; // copy U: for(y=0;y<h;y++){ unsigned char* s=src[2]+stride[2]*y; unsigned char* d=vo_image+vo_w*vo_h+(vo_w>>1)*(y0+y)+x0; memcpy(d,s,w); } // copy V: for(y=0;y<h;y++){ unsigned char* s=src[1]+stride[1]*y; unsigned char* d=vo_image+vo_w*vo_h+vo_w*vo_h/4+(vo_w>>1)*(y0+y)+x0; memcpy(d,s,w); } } // !swscaler } static uint32_t draw_frame(uint8_t *src[]){ // printf("This function shouldn't be called - report bug!\n"); // later: add YUY2->YV12 conversion here! vo_image_ptr=src[0]; } vo_functions_t video_out; //--------------------------------------------------------------------------- void *vo_spudec=NULL; static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){ vo_draw_alpha_yv12(w,h,src,srca,stride,vo_image + vo_w * y0 + x0,vo_w); } static void draw_sub(void) { #ifdef USE_DVDREAD if (vo_spudec) spudec_draw_scaled(vo_spudec, vo_w, vo_h, draw_alpha); #endif } int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total){ int size=0; int eof=0; while(size<total && !eof){ int len=total-size; if(len>MAX_OUTBURST) len=MAX_OUTBURST; if(len>sh_audio->a_buffer_size) len=sh_audio->a_buffer_size; if(len>sh_audio->a_buffer_len){ int ret=decode_audio(sh_audio, &sh_audio->a_buffer[sh_audio->a_buffer_len], len-sh_audio->a_buffer_len, sh_audio->a_buffer_size-sh_audio->a_buffer_len); if(ret>0) sh_audio->a_buffer_len+=ret; else eof=1; } if(len>sh_audio->a_buffer_len) len=sh_audio->a_buffer_len; memcpy(buffer+size,sh_audio->a_buffer,len); sh_audio->a_buffer_len-=len; size+=len; if(sh_audio->a_buffer_len>0) memcpy(sh_audio->a_buffer,&sh_audio->a_buffer[len],sh_audio->a_buffer_len); } return size; } //--------------------------------------------------------------------------- static int eof=0; static int interrupted=0; enum end_at_type_t {END_AT_NONE, END_AT_TIME, END_AT_SIZE}; static enum end_at_type_t end_at_type = END_AT_NONE; static int end_at; static void exit_sighandler(int x){ eof=1; interrupted=1; } int main(int argc,char* argv[], char *envp[]){ stream_t* stream=NULL; demuxer_t* demuxer=NULL; demux_stream_t *d_audio=NULL; demux_stream_t *d_video=NULL; demux_stream_t *d_dvdsub=NULL; sh_audio_t *sh_audio=NULL; sh_video_t *sh_video=NULL; int file_format=DEMUXER_TYPE_UNKNOWN; int i; unsigned int out_fmt; aviwrite_t* muxer=NULL; aviwrite_stream_t* mux_a=NULL; aviwrite_stream_t* mux_v=NULL; FILE* muxer_f=NULL; #ifdef HAVE_DIVX4ENCORE ENC_FRAME enc_frame; ENC_RESULT enc_result; void* enc_handle=NULL; #endif #ifdef HAVE_MP3LAME lame_global_flags *lame; #endif float audio_preload=0.5; double v_pts_corr=0; double v_timer_corr=0; play_tree_t* playtree; play_tree_iter_t* playtree_iter; char* filename=NULL; int decoded_frameno=0; //int out_buffer_size=0x200000; //unsigned char* out_buffer=malloc(out_buffer_size); mp_msg_init(MSGL_STATUS); mp_msg(MSGT_CPLAYER,MSGL_INFO,"%s",banner_text); // check codec.conf if(!parse_codec_cfg(get_path("codecs.conf"))){ if(!parse_codec_cfg(CONFDIR"/codecs.conf")){ mp_msg(MSGT_MENCODER,MSGL_HINT,MSGTR_CopyCodecsConf); exit(0); } } /* Test for cpu capabilities (and corresponding OS support) for optimizing */ #ifdef ARCH_X86 GetCpuCaps(&gCpuCaps); mp_msg(MSGT_CPLAYER,MSGL_INFO,"CPUflags: Type: %d MMX: %d MMX2: %d 3DNow: %d 3DNow2: %d SSE: %d SSE2: %d\n", gCpuCaps.cpuType,gCpuCaps.hasMMX,gCpuCaps.hasMMX2, gCpuCaps.has3DNow, gCpuCaps.has3DNowExt, gCpuCaps.hasSSE, gCpuCaps.hasSSE2); #endif #ifdef HAVE_DIVX4ENCORE // set some defaults, before parsing configfile/commandline: divx4_param.min_quantizer = 2; divx4_param.max_quantizer = 31; divx4_param.rc_period = 2000; divx4_param.rc_reaction_period = 10; divx4_param.rc_reaction_ratio = 20; #endif playtree = play_tree_new(); mconfig = m_config_new(playtree); m_config_register_options(mconfig,mencoder_opts); if(m_config_parse_command_line(mconfig, argc, argv, envp) < 0) exit(1); // error parsing cmdline playtree = play_tree_cleanup(playtree); if(playtree) { playtree_iter = play_tree_iter_new(playtree,mconfig); if(playtree_iter) { if(play_tree_iter_step(playtree_iter,0,0) != PLAY_TREE_ITER_ENTRY) { play_tree_iter_free(playtree_iter); playtree_iter = NULL; } filename = play_tree_iter_get_file(playtree_iter,1); } } if(!filename && !vcd_track && !dvd_title && !tv_param_on){ printf("\nMissing filename!\n\n"); exit(1); } mp_msg_init(verbose+MSGL_STATUS); stream=open_stream(filename,vcd_track,&file_format); if(!stream){ printf("Cannot open file/device\n"); exit(1); } printf("success: format: %d data: 0x%X - 0x%X\n",file_format, (int)(stream->start_pos),(int)(stream->end_pos)); if(stream_cache_size) stream_enable_cache(stream,stream_cache_size*1024,0,0); #ifdef HAVE_LIBCSS // current_module="libcss"; if (dvdimportkey) { if (dvd_import_key(dvdimportkey)) { mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_ErrorDVDkey); exit(1); } mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_CmdlineDVDkey); } if (dvd_auth_device) { // if (dvd_auth(dvd_auth_device,f)) { if (dvd_auth(dvd_auth_device,filename)) { mp_msg(MSGT_CPLAYER,MSGL_FATAL,"Error in DVD auth...\n"); exit(1); } mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_DVDauthOk); } #endif //demuxer=demux_open(stream,file_format,video_id,audio_id,dvdsub_id); demuxer=demux_open(stream,file_format,audio_id,video_id,dvdsub_id); if(!demuxer){ printf("Cannot open demuxer\n"); exit(1); } d_audio=demuxer->audio; d_video=demuxer->video; d_dvdsub=demuxer->sub; sh_audio=d_audio->sh; sh_video=d_video->sh; if(!video_read_properties(sh_video)){ printf("Couldn't read video properties\n"); exit(1); } mp_msg(MSGT_MENCODER,MSGL_INFO,"[V] filefmt:%d fourcc:0x%X size:%dx%d fps:%5.2f ftime:=%6.4f\n", demuxer->file_format,sh_video->format, sh_video->disp_w,sh_video->disp_h, sh_video->fps,sh_video->frametime ); sh_video->codec=NULL; if(out_video_codec>1){ if(video_family!=-1) mp_msg(MSGT_MENCODER,MSGL_INFO,MSGTR_TryForceVideoFmt,video_family); { /* local vars */ short bestprio=-1; struct codecs_st *bestcodec=NULL; while(1){ sh_video->codec=find_codec(sh_video->format, sh_video->bih?((unsigned int*) &sh_video->bih->biCompression):NULL,sh_video->codec,0); if(!sh_video->codec){ if(video_family!=-1) { //sh_video->codec=NULL; /* re-search */ mp_msg(MSGT_MENCODER,MSGL_WARN,MSGTR_CantFindVfmtFallback); video_family=-1; continue; } if(bestprio==-1 || !video_codec) { mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantFindVideoCodec,sh_video->format); mp_msg(MSGT_MENCODER,MSGL_HINT, MSGTR_TryUpgradeCodecsConfOrRTFM,get_path("codecs.conf")); exit(1); } } else { if(video_codec && strcmp(sh_video->codec->name,video_codec)) continue; else if(video_family!=-1 && sh_video->codec->driver!=video_family) continue; else if(video_family==-1 && !video_codec && sh_video->codec->priority) { if(sh_video->codec->priority > bestprio) { //printf("\n\n!!! setting bestprio from %d to %d for %s!!!\n\n", bestprio, sh_video->codec->priority, sh_video->codec->name); bestprio=sh_video->codec->priority; bestcodec=sh_video->codec; } continue; } } /* sh_video->codec */ break; } if(bestprio!=-1) { //printf("chose codec %s by priority.\n", bestcodec->name); sh_video->codec=bestcodec; } } /* end local vars */ mp_msg(MSGT_MENCODER,MSGL_INFO,"%s video codec: [%s] drv:%d prio:%d (%s)\n",video_codec?"Forcing":"Detected",sh_video->codec->name,sh_video->codec->driver,sh_video->codec->priority!=-1?sh_video->codec->priority:0,sh_video->codec->info); for(i=0;i<CODECS_MAX_OUTFMT;i++){ out_fmt=sh_video->codec->outfmt[i]; if(out_fmt==0xFFFFFFFF) continue; if(IMGFMT_IS_RGB(out_fmt) || IMGFMT_IS_BGR(out_fmt)) break; if(out_fmt==IMGFMT_YV12) break; if(out_fmt==IMGFMT_I420) break; if(out_fmt==IMGFMT_IYUV) break; if(out_fmt==IMGFMT_YUY2) break; if(out_fmt==IMGFMT_UYVY) break; } if(i>=CODECS_MAX_OUTFMT){ mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_VOincompCodec); exit(1); // exit_player(MSGTR_Exit_error); } sh_video->outfmtidx=i; if(out_fmt==IMGFMT_YV12 && (vo_w!=0 || vo_h!=0)) { scale_srcW= sh_video->disp_w; scale_srcH= sh_video->disp_h; if(!vo_w) vo_w=sh_video->disp_w; if(!vo_h) vo_h=sh_video->disp_h; } else { vo_w=sh_video->disp_w; vo_h=sh_video->disp_h; } if(out_fmt==IMGFMT_YV12 || out_fmt==IMGFMT_I420 || out_fmt==IMGFMT_IYUV){ vo_image=malloc(vo_w*vo_h*3/2); vo_image_ptr=vo_image; } if (IMGFMT_IS_BGR(out_fmt)) vo_image_ptr = vo_image = malloc(vo_w*vo_h*IMGFMT_BGR_DEPTH(out_fmt)/8); if (IMGFMT_IS_RGB(out_fmt)) vo_image_ptr = vo_image = malloc(vo_w*vo_h*IMGFMT_RGB_DEPTH(out_fmt)/8); if(!init_video(sh_video)){ mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_CouldntInitVideoCodec); exit(1); } } // if(out_video_codec) if(sh_audio){ // Go through the codec.conf and find the best codec... sh_audio->codec=NULL; if(audio_family!=-1) mp_msg(MSGT_MENCODER,MSGL_INFO,MSGTR_TryForceAudioFmt,audio_family); while(1){ sh_audio->codec=find_codec(sh_audio->format,NULL,sh_audio->codec,1); if(!sh_audio->codec){ if(audio_family!=-1) { sh_audio->codec=NULL; /* re-search */ mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantFindAfmtFallback); audio_family=-1; continue; } mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CantFindAudioCodec,sh_audio->format); mp_msg(MSGT_MENCODER,MSGL_HINT, MSGTR_TryUpgradeCodecsConfOrRTFM,get_path("codecs.conf")); sh_audio=d_audio->sh=NULL; break; } if(audio_codec && strcmp(sh_audio->codec->name,audio_codec)) continue; else if(audio_family!=-1 && sh_audio->codec->driver!=audio_family) continue; mp_msg(MSGT_MENCODER,MSGL_INFO,"%s audio codec: [%s] drv:%d (%s)\n",audio_codec?"Forcing":"Detected",sh_audio->codec->name,sh_audio->codec->driver,sh_audio->codec->info); break; } } if(sh_audio){ mp_msg(MSGT_MENCODER,MSGL_V,"Initializing audio codec...\n"); if(!init_audio(sh_audio)){ mp_msg(MSGT_MENCODER,MSGL_ERR,MSGTR_CouldntInitAudioCodec); sh_audio=d_audio->sh=NULL; } else { mp_msg(MSGT_MENCODER,MSGL_INFO,"AUDIO: srate=%d chans=%d bps=%d sfmt=0x%X ratio: %d->%d\n",sh_audio->samplerate,sh_audio->channels,sh_audio->samplesize, sh_audio->sample_format,sh_audio->i_bps,sh_audio->o_bps); } } // set up video encoder: SwScale_Init(); video_out.draw_slice=draw_slice; video_out.draw_frame=draw_frame; #ifdef USE_DVDREAD vo_spudec=spudec_new_scaled(stream->priv?((dvd_priv_t *)(stream->priv))->cur_pgc->palette:NULL, sh_video->disp_w, sh_video->disp_h); #endif // set up output file: muxer_f=fopen(out_filename,"wb"); if(!muxer_f) { printf("Cannot open output file '%s'\n", out_filename); exit(1); } muxer=aviwrite_new_muxer(); // ============= VIDEO =============== mux_v=aviwrite_new_stream(muxer,AVIWRITE_TYPE_VIDEO); mux_v->buffer_size=0x200000; mux_v->buffer=malloc(mux_v->buffer_size); mux_v->source=sh_video; mux_v->h.dwSampleSize=0; // VBR mux_v->h.dwScale=10000; mux_v->h.dwRate=mux_v->h.dwScale*(force_ofps?force_ofps:sh_video->fps); mux_v->codec=out_video_codec; switch(mux_v->codec){ case VCODEC_COPY: printf("sh_video->bih: %x\n", sh_video->bih); if (sh_video->bih) mux_v->bih=sh_video->bih; else { mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); mux_v->bih->biWidth=sh_video->disp_w; mux_v->bih->biHeight=sh_video->disp_h; mux_v->bih->biCompression=sh_video->format; mux_v->bih->biPlanes=1; mux_v->bih->biBitCount=24; // FIXME!!! mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); } printf("videocodec: framecopy (%dx%d %dbpp fourcc=%x)\n", mux_v->bih->biWidth, mux_v->bih->biHeight, mux_v->bih->biBitCount, mux_v->bih->biCompression); break; case VCODEC_RAW: printf("sh_video->bih: %x\n", sh_video->bih); if (sh_video->bih) mux_v->bih=sh_video->bih; else { mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); mux_v->bih->biWidth=sh_video->disp_w; mux_v->bih->biHeight=sh_video->disp_h; mux_v->bih->biCompression=0; mux_v->bih->biPlanes=1; mux_v->bih->biBitCount=24; // FIXME!!! mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); } mux_v->bih->biCompression=0; printf("videocodec: raw (%dx%d %dbpp fourcc=%x)\n", mux_v->bih->biWidth, mux_v->bih->biHeight, mux_v->bih->biBitCount, mux_v->bih->biCompression); break; case VCODEC_FRAMENO: mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); mux_v->bih->biWidth=vo_w; mux_v->bih->biHeight=vo_h; mux_v->bih->biPlanes=1; mux_v->bih->biBitCount=24; mux_v->bih->biCompression=mmioFOURCC('F','r','N','o'); mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); break; case VCODEC_DIVX4: #ifndef HAVE_DIVX4ENCORE printf("No support for Divx4 encore compiled in\n"); return 0; /* FIXME */ #else mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); mux_v->bih->biWidth=vo_w; mux_v->bih->biHeight=vo_h; mux_v->bih->biPlanes=1; mux_v->bih->biBitCount=24; mux_v->bih->biCompression=mmioFOURCC('d','i','v','x'); mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); if (pass) printf("Divx: 2-pass logfile: %s\n", passtmpfile); break; #endif case VCODEC_LIBAVCODEC: #ifndef USE_LIBAVCODEC printf("No support for FFmpeg's libavcodec compiled in\n"); return 0; /* FIXME */ #else mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)); mux_v->bih->biSize=sizeof(BITMAPINFOHEADER); mux_v->bih->biWidth=vo_w; mux_v->bih->biHeight=vo_h; mux_v->bih->biPlanes=1; mux_v->bih->biBitCount=24; mux_v->bih->biCompression=mmioFOURCC(lavc_param_vcodec[0], lavc_param_vcodec[1], lavc_param_vcodec[2], lavc_param_vcodec[3]); /* FIXME!!! */ mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8); printf("videocodec: libavcodec (%dx%d fourcc=%x [%.4s])\n", mux_v->bih->biWidth, mux_v->bih->biHeight, mux_v->bih->biCompression, &mux_v->bih->biCompression); #endif } /* force output fourcc to .. */ if (force_fourcc != NULL) { mux_v->bih->biCompression = mmioFOURCC(force_fourcc[0], force_fourcc[1], force_fourcc[2], force_fourcc[3]); printf("Forcing output fourcc to %x [%.4s]\n", mux_v->bih->biCompression, &mux_v->bih->biCompression); } // ============= AUDIO =============== if(sh_audio){ mux_a=aviwrite_new_stream(muxer,AVIWRITE_TYPE_AUDIO); mux_a->buffer_size=0x100000; //16384; mux_a->buffer=malloc(mux_a->buffer_size); mux_a->source=sh_audio; mux_a->codec=out_audio_codec; switch(mux_a->codec){ case ACODEC_COPY: printf("sh_audio->wf: %x\n", sh_audio->wf); mux_a->h.dwSampleSize=sh_audio->audio.dwSampleSize; mux_a->h.dwScale=sh_audio->audio.dwScale; mux_a->h.dwRate=sh_audio->audio.dwRate; if (sh_audio->wf) mux_a->wf=sh_audio->wf; else { mux_a->wf = malloc(sizeof(WAVEFORMATEX)); mux_a->wf->nBlockAlign = mux_a->h.dwSampleSize; mux_a->wf->wFormatTag = sh_audio->sample_format; mux_a->wf->nChannels = sh_audio->channels; mux_a->wf->nSamplesPerSec = sh_audio->samplerate; mux_a->wf->nAvgBytesPerSec=mux_a->h.dwSampleSize*mux_a->wf->nSamplesPerSec; mux_a->wf->wBitsPerSample = 16; // FIXME mux_a->wf->cbSize=0; // FIXME for l3codeca.acm } printf("audiocodec: framecopy (format=%x chans=%d rate=%d bits=%d)\n", mux_a->wf->wFormatTag, mux_a->wf->nChannels, mux_a->wf->nSamplesPerSec, mux_a->wf->wBitsPerSample); break; case ACODEC_PCM: printf("CBR PCM audio selected\n"); mux_a->h.dwSampleSize=2*sh_audio->channels; mux_a->h.dwScale=1; mux_a->h.dwRate=sh_audio->samplerate; mux_a->wf=malloc(sizeof(WAVEFORMATEX)); mux_a->wf->nBlockAlign=mux_a->h.dwSampleSize; mux_a->wf->wFormatTag=0x1; // PCM mux_a->wf->nChannels=sh_audio->channels; mux_a->wf->nSamplesPerSec=sh_audio->samplerate; mux_a->wf->nAvgBytesPerSec=mux_a->h.dwSampleSize*mux_a->wf->nSamplesPerSec; mux_a->wf->wBitsPerSample=16; mux_a->wf->cbSize=0; // FIXME for l3codeca.acm break; case ACODEC_VBRMP3: printf("MP3 audio selected\n"); mux_a->h.dwSampleSize=0; // VBR mux_a->h.dwScale=1152; // samples/frame mux_a->h.dwRate=sh_audio->samplerate; if(sizeof(MPEGLAYER3WAVEFORMAT)!=30) mp_msg(MSGT_MENCODER,MSGL_WARN,"sizeof(MPEGLAYER3WAVEFORMAT)==%d!=30, maybe broken C compiler?\n",sizeof(MPEGLAYER3WAVEFORMAT)); mux_a->wf=malloc(sizeof(MPEGLAYER3WAVEFORMAT)); // should be 30 mux_a->wf->wFormatTag=0x55; // MP3 mux_a->wf->nChannels=sh_audio->channels; mux_a->wf->nSamplesPerSec=force_srate?force_srate:sh_audio->samplerate; mux_a->wf->nAvgBytesPerSec=192000/8; // FIXME! mux_a->wf->nBlockAlign=1152; // requires for l3codeca.acm + WMP 6.4 mux_a->wf->wBitsPerSample=0; //16; // from NaNdub: (requires for l3codeca.acm) mux_a->wf->cbSize=12; ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->wID=1; ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->fdwFlags=2; ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nBlockSize=1152; // ??? ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nFramesPerBlock=1; ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nCodecDelay=0; break; } } printf("Writing AVI header...\n"); aviwrite_write_header(muxer,muxer_f); switch(mux_v->codec){ case VCODEC_COPY: case VCODEC_RAW: break; case VCODEC_FRAMENO: decoded_frameno=0; break; case VCODEC_DIVX4: #ifndef HAVE_DIVX4ENCORE printf("No support for Divx4 encore compiled in\n"); return 0; /* FIXME */ #else // init divx4linux: divx4_param.x_dim=vo_w; divx4_param.y_dim=vo_h; divx4_param.framerate=(float)mux_v->h.dwRate/mux_v->h.dwScale; if(!divx4_param.bitrate) divx4_param.bitrate=800000; else if(divx4_param.bitrate<=16000) divx4_param.bitrate*=1000; if(!divx4_param.quality) divx4_param.quality=5; // the quality of compression ( 1 - fastest, 5 - best ) divx4_param.handle=NULL; encore(NULL,ENC_OPT_INIT,&divx4_param,NULL); enc_handle=divx4_param.handle; switch(out_fmt){ case IMGFMT_YV12: enc_frame.colorspace=ENC_CSP_YV12; break; case IMGFMT_IYUV: case IMGFMT_I420: enc_frame.colorspace=ENC_CSP_I420; break; case IMGFMT_YUY2: enc_frame.colorspace=ENC_CSP_YUY2; break; case IMGFMT_UYVY: enc_frame.colorspace=ENC_CSP_UYVY; break; case IMGFMT_RGB24: case IMGFMT_BGR24: enc_frame.colorspace=ENC_CSP_RGB24; break; default: mp_msg(MSGT_MENCODER,MSGL_ERR,"divx4: unsupported picture format (%s)!\n", vo_format_name(out_fmt)); } switch(pass){ case 1: if (VbrControl_init_2pass_vbr_analysis(passtmpfile, divx4_param.quality) == -1) { printf("2pass failed: filename=%s\n", passtmpfile); pass_working = 0; } else pass_working = 1; break; case 2: if (VbrControl_init_2pass_vbr_encoding(passtmpfile, divx4_param.bitrate, divx4_param.framerate, divx4_crispness, divx4_param.quality) == -1) { printf("2pass failed: filename=%s\n", passtmpfile); pass_working = 0; } else pass_working = 1; break; } break; #endif case VCODEC_LIBAVCODEC: #ifndef USE_LIBAVCODEC printf("No support for FFmpeg's libavcodec compiled in\n"); #else if (!avcodec_inited) { avcodec_init(); avcodec_register_all(); avcodec_inited=1; } #if 0 { extern AVCodec *first_avcodec; AVCodec *p = first_avcodec; lavc_venc_codec = NULL; while (p) { if (p->encode != NULL && strcmp(lavc_param_vcodec, p->name) == 0) break; p = p->next; } lavc_venc_codec = p; } #else /* XXX: implement this in avcodec (i will send a patch to ffmpeglist) -- alex */ lavc_venc_codec = (AVCodec *)avcodec_find_encoder_by_name(lavc_param_vcodec); #endif if (!lavc_venc_codec) { printf(MSGTR_MissingLAVCcodec, lavc_param_vcodec); return 0; /* FIXME */ } memset(&lavc_venc_context, 0, sizeof(lavc_venc_context)); // lavc_venc_context.width = mux_v->bih->biWidth; // lavc_venc_context.height = mux_v->bih->biHeight; /* scaling only for YV12 (and lavc supports only YV12 ;) */ lavc_venc_context.width = vo_w; lavc_venc_context.height = vo_h; if (lavc_param_vbitrate >= 0) /* != -1 */ lavc_venc_context.bit_rate = lavc_param_vbitrate; else lavc_venc_context.bit_rate = 800000; /* default */ lavc_venc_context.frame_rate = (float)(force_ofps?force_ofps:sh_video->fps) * FRAME_RATE_BASE; /* keyframe interval */ if (lavc_param_keyint >= 0) /* != -1 */ lavc_venc_context.gop_size = lavc_param_keyint; else lavc_venc_context.gop_size = 250; /* default */ /* ignored by libavcodec? */ if (lavc_param_vhq) { printf("High quality encoding selected (non real time)!\n"); lavc_venc_context.flags = CODEC_FLAG_HQ; } else lavc_venc_context.flags = 0; /* motion estimation (0 = none ... 3 = high quality but slow) */ /* this is just an extern from libavcodec but it should be in the encoder context - FIXME */ motion_estimation_method = lavc_param_vme; #if 0 /* fixed qscale :p */ lavc_venc_context.flags |= CODEC_FLAG_QSCALE; lavc_venc_context.quality = 1; #endif if (avcodec_open(&lavc_venc_context, lavc_venc_codec) != 0) { printf(MSGTR_CantOpenCodec); return 0; /* FIXME */ } if (lavc_venc_context.codec->encode == NULL) { printf("avcodec init failed (ctx->codec->encode == NULL)!\n"); return 0; } #if 1 if (out_fmt != IMGFMT_YV12 && out_fmt != IMGFMT_I420) { printf("Not supported image format! (%s)\n", vo_format_name(out_fmt)); return 0; /* FIXME */ } memset(&lavc_venc_picture, 0, sizeof(lavc_venc_picture)); { int size = lavc_venc_context.width * lavc_venc_context.height; /* Y */ lavc_venc_picture.data[0] = vo_image_ptr; if (out_fmt == IMGFMT_YV12) { /* U */ lavc_venc_picture.data[2] = lavc_venc_picture.data[0] + size; /* V */ lavc_venc_picture.data[1] = lavc_venc_picture.data[2] + size/4; } else /* IMGFMT_I420 */ { /* U */ lavc_venc_picture.data[1] = lavc_venc_picture.data[0] + size; /* V */ lavc_venc_picture.data[2] = lavc_venc_picture.data[1] + size/4; } lavc_venc_picture.linesize[0] = lavc_venc_context.width; lavc_venc_picture.linesize[1] = lavc_venc_context.width / 2; lavc_venc_picture.linesize[2] = lavc_venc_context.width / 2; } #else switch(out_fmt) { case IMGFMT_YV12: lavc_venc_context.pix_fmt = PIX_FMT_YUV420P; break; #if 0 /* it's faulting :( -- libavcodec's bug! -- alex */ case IMGFMT_YUY2: /* or UYVY */ lavc_venc_context.pix_fmt = PIX_FMT_YUV422; break; case IMGFMT_BGR24: lavc_venc_context.pix_fmt = PIX_FMT_BGR24; break; case IMGFMT_RGB24: lavc_venc_context.pix_fmt = PIX_FMT_RGB24; break; #endif default: printf("Not supported image format! (%s)\n", vo_format_name(out_fmt)); return 0; /* FIXME */ } printf("Using picture format: %s\n", vo_format_name(out_fmt)); memset(&lavc_venc_picture, 0, sizeof(lavc_venc_picture)); printf("ahh: avpict_getsize=%d, vo_image_ptr=%d\n", avpicture_get_size(lavc_venc_context.pix_fmt, lavc_venc_context.width, lavc_venc_context.height), vo_h*vo_w*3/2); avpicture_fill(&lavc_venc_picture, vo_image_ptr, lavc_venc_context.pix_fmt, lavc_venc_context.width, lavc_venc_context.height); { char buf[1024]; avcodec_string((char *)&buf[0], 1023, &lavc_venc_context, 1); printf("%s\n", buf); } #endif #endif } if(sh_audio) switch(mux_a->codec){ #ifdef HAVE_MP3LAME case ACODEC_VBRMP3: lame=lame_init(); lame_set_bWriteVbrTag(lame,0); lame_set_in_samplerate(lame,sh_audio->samplerate); lame_set_num_channels(lame,mux_a->wf->nChannels); lame_set_out_samplerate(lame,mux_a->wf->nSamplesPerSec); if(lame_param_vbr){ // VBR: lame_set_VBR(lame,lame_param_vbr); // vbr mode lame_set_VBR_q(lame,lame_param_quality+1); // 1 = best vbr q 6=~128k if(lame_param_br>0) lame_set_VBR_mean_bitrate_kbps(lame,lame_param_br); } else { // CBR: lame_set_quality(lame,lame_param_quality); // 0 = best q if(lame_param_br>0) lame_set_brate(lame,lame_param_br); } if(lame_param_mode>=0) lame_set_mode(lame,lame_param_mode); // j-st if(lame_param_ratio>0) lame_set_compression_ratio(lame,lame_param_ratio); lame_init_params(lame); if(verbose){ lame_print_config(lame); lame_print_internals(lame); } break; #endif } signal(SIGINT,exit_sighandler); // Interrupt from keyboard signal(SIGQUIT,exit_sighandler); // Quit from keyboard signal(SIGTERM,exit_sighandler); // kill while(!eof){ float frame_time=0; int blit_frame=0; float a_pts=0; float v_pts=0; unsigned char* start=NULL; int in_size; int skip_flag=0; // 1=skip -1=duplicate if((end_at_type == END_AT_SIZE && end_at <= ftell(muxer_f)) || (end_at_type == END_AT_TIME && end_at < sh_video->timer)) break; if(play_n_frames>=0){ --play_n_frames; if(play_n_frames<0) break; } if(sh_audio){ // get audio: while(mux_a->timer-audio_preload<mux_v->timer){ int len=0; if(mux_a->h.dwSampleSize){ // CBR - copy 0.5 sec of audio switch(mux_a->codec){ case ACODEC_COPY: // copy len=sh_audio->i_bps/2; len/=mux_a->h.dwSampleSize;if(len<1) len=1; len*=mux_a->h.dwSampleSize; len=demux_read_data(sh_audio->ds,mux_a->buffer,len); break; case ACODEC_PCM: len=mux_a->h.dwSampleSize*(mux_a->h.dwRate/2); len=dec_audio(sh_audio,mux_a->buffer,len); break; } } else { // VBR - encode/copy an audio frame switch(mux_a->codec){ case ACODEC_COPY: // copy printf("VBR audio framecopy not yet implemented!\n"); break; #ifdef HAVE_MP3LAME case ACODEC_VBRMP3: while(mux_a->buffer_len<4){ unsigned char tmp[2304]; int len=dec_audio(sh_audio,tmp,2304); if(len<=0) break; // eof len=lame_encode_buffer_interleaved(lame, tmp,len/4, mux_a->buffer+mux_a->buffer_len,mux_a->buffer_size-mux_a->buffer_len); if(len<0) break; // error mux_a->buffer_len+=len; } if(mux_a->buffer_len<4) break; len=mp_decode_mp3_header(mux_a->buffer); //printf("%d\n",len); if(len<=0) break; // bad frame! while(mux_a->buffer_len<len){ unsigned char tmp[2304]; int len=dec_audio(sh_audio,tmp,2304); if(len<=0) break; // eof len=lame_encode_buffer_interleaved(lame, tmp,len/4, mux_a->buffer+mux_a->buffer_len,mux_a->buffer_size-mux_a->buffer_len); if(len<0) break; // error mux_a->buffer_len+=len; } break; #endif } } if(len<=0) break; // EOF? aviwrite_write_chunk(muxer,mux_a,muxer_f,len,0); if(!mux_a->h.dwSampleSize && mux_a->timer>0) mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/mux_a->timer; // avg bps (VBR) if(mux_a->buffer_len>=len){ mux_a->buffer_len-=len; memcpy(mux_a->buffer,mux_a->buffer+len,mux_a->buffer_len); } } } // get video frame! in_size=video_read_frame(sh_video,&frame_time,&start,force_fps); if(in_size<0){ eof=1; break; } sh_video->timer+=frame_time; ++decoded_frameno; v_timer_corr-=frame_time-(float)mux_v->h.dwScale/mux_v->h.dwRate; // check frame duplicate/drop: if(v_timer_corr>=(float)mux_v->h.dwScale/mux_v->h.dwRate){ v_timer_corr-=(float)mux_v->h.dwScale/mux_v->h.dwRate; ++skip_flag; // skip } else while(v_timer_corr<=-(float)mux_v->h.dwScale/mux_v->h.dwRate){ v_timer_corr+=(float)mux_v->h.dwScale/mux_v->h.dwRate; --skip_flag; // dup } while( (v_pts_corr<=-(float)mux_v->h.dwScale/mux_v->h.dwRate && skip_flag>0) || (v_pts_corr<=-2*(float)mux_v->h.dwScale/mux_v->h.dwRate) ){ v_pts_corr+=(float)mux_v->h.dwScale/mux_v->h.dwRate; --skip_flag; // dup } if( (v_pts_corr>=(float)mux_v->h.dwScale/mux_v->h.dwRate && skip_flag<0) || (v_pts_corr>=2*(float)mux_v->h.dwScale/mux_v->h.dwRate) ) if(skip_flag<=0){ // we can't skip more than 1 frame now v_pts_corr-=(float)mux_v->h.dwScale/mux_v->h.dwRate; ++skip_flag; // skip } #ifdef USE_DVDREAD // DVD sub: if(vo_spudec){ unsigned char* packet=NULL; int len; while((len=ds_get_packet_sub(d_dvdsub,&packet))>0){ mp_msg(MSGT_MENCODER,MSGL_V,"\rDVD sub: len=%d v_pts=%5.3f s_pts=%5.3f \n",len,d_video->pts,d_dvdsub->pts); spudec_assemble(vo_spudec,packet,len,100*d_dvdsub->pts); } spudec_heartbeat(vo_spudec,100*d_video->pts); } #endif switch(mux_v->codec){ case VCODEC_COPY: mux_v->buffer=start; if(skip_flag<=0) aviwrite_write_chunk(muxer,mux_v,muxer_f,in_size,(sh_video->ds->flags&1)?0x10:0); break; case VCODEC_RAW: blit_frame=decode_video(&video_out,sh_video,start,in_size,0); if(skip_flag>0) break; if(!blit_frame){ // empty. aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0); break; } mux_v->buffer = vo_image_ptr; aviwrite_write_chunk(muxer,mux_v,muxer_f,mux_v->buffer_size,0x10); break; case VCODEC_FRAMENO: mux_v->buffer=&decoded_frameno; // tricky if(skip_flag<=0) aviwrite_write_chunk(muxer,mux_v,muxer_f,sizeof(int),0x10); break; case VCODEC_DIVX4: #ifndef HAVE_DIVX4ENCORE printf("No support for Divx4 encore compiled in\n"); return 0; /* FIXME */ #else blit_frame=decode_video(&video_out,sh_video,start,in_size,0); draw_sub(); if(skip_flag>0) break; if(!blit_frame){ // empty. aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0); break; } enc_frame.image=vo_image_ptr; enc_frame.bitstream=mux_v->buffer; enc_frame.length=mux_v->buffer_size; enc_frame.mvs=NULL; enc_frame.quant=0; enc_frame.intra=0; if(pass==2 && pass_working){ // handle 2-pass: enc_frame.quant = VbrControl_get_quant(); enc_frame.intra = VbrControl_get_intra(); encore(enc_handle,ENC_OPT_ENCODE_VBR,&enc_frame,&enc_result); VbrControl_update_2pass_vbr_encoding(enc_result.motion_bits, enc_result.texture_bits, enc_result.total_bits); } else { encore(enc_handle,ENC_OPT_ENCODE,&enc_frame,&enc_result); if(pass==1 && pass_working){ VbrControl_update_2pass_vbr_analysis(enc_result.is_key_frame, enc_result.motion_bits, enc_result.texture_bits, enc_result.total_bits, enc_result.quantizer); } } // printf("encoding...\n"); // printf(" len=%d key:%d qualt:%d \n",enc_frame.length,enc_result.is_key_frame,enc_result.quantizer); aviwrite_write_chunk(muxer,mux_v,muxer_f,enc_frame.length,enc_result.is_key_frame?0x10:0); break; #endif case VCODEC_LIBAVCODEC: { #ifndef USE_LIBAVCODEC printf("No support for FFmpeg's libavcodec compiled in\n"); #else int out_size; blit_frame=decode_video(&video_out,sh_video,start,in_size,0); if(skip_flag>0) break; if(!blit_frame){ // empty. aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0); break; } out_size = avcodec_encode_video(&lavc_venc_context, mux_v->buffer, mux_v->buffer_size, &lavc_venc_picture); // printf("out_size = %d\n", out_size); aviwrite_write_chunk(muxer,mux_v,muxer_f,out_size,lavc_venc_context.key_frame?0x10:0); #endif } } if(skip_flag<0){ // duplicate frame printf("\nduplicate %d frame(s)!!! \n",-skip_flag); while(skip_flag<0){ aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0); ++skip_flag; } } else if(skip_flag>0){ // skip frame printf("\nskip frame!!! \n"); --skip_flag; } if(sh_audio){ float AV_delay,x; // A-V sync! if(pts_from_bps){ unsigned int samples=(sh_audio->audio.dwSampleSize)? ((ds_tell(d_audio)-sh_audio->a_in_buffer_len)/sh_audio->audio.dwSampleSize) : (d_audio->pack_no); // <- used for VBR audio a_pts=samples*(float)sh_audio->audio.dwScale/(float)sh_audio->audio.dwRate; delay_corrected=1; } else { // PTS = (last timestamp) + (bytes after last timestamp)/(bytes per sec) a_pts=d_audio->pts; if(!delay_corrected) if(a_pts) delay_corrected=1; //printf("*** %5.3f ***\n",a_pts); a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps; } v_pts=d_video->pts; // av = compensated (with out buffering delay) A-V diff AV_delay=(a_pts-v_pts); AV_delay-=mux_a->timer-(mux_v->timer-(v_timer_corr+v_pts_corr)); // compensate input video timer by av: x=AV_delay*0.1f; if(x<-max_pts_correction) x=-max_pts_correction; else if(x> max_pts_correction) x= max_pts_correction; if(default_max_pts_correction>=0) max_pts_correction=default_max_pts_correction; else max_pts_correction=sh_video->frametime*0.10; // +-10% of time // sh_video->timer-=x; c_total+=x; v_pts_corr+=x; printf("A:%6.1f V:%6.1f A-V:%7.3f oAV:%7.3f diff:%7.3f ct:%7.3f vpc:%7.3f \r", a_pts,v_pts,a_pts-v_pts, (float)(mux_a->timer-mux_v->timer), AV_delay, c_total, v_pts_corr ); } #if 0 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", a_pts,v_pts,a_pts-v_pts,c_total, (int)sh_video->num_frames,(int)sh_video->num_frames_decoded, (sh_video->timer>0.5)?(int)(100.0*video_time_usage/(double)sh_video->timer):0, (sh_video->timer>0.5)?(int)(100.0*vout_time_usage/(double)sh_video->timer):0, (sh_video->timer>0.5)?(100.0*audio_time_usage/(double)sh_video->timer):0 ,cache_fill_status ); #endif fflush(stdout); } // while(!eof) #ifdef HAVE_MP3LAME // fixup CBR mp3 audio header: if(sh_audio && mux_a->codec==ACODEC_VBRMP3 && !lame_param_vbr){ mux_a->h.dwSampleSize=1; mux_a->h.dwRate=mux_a->wf->nAvgBytesPerSec; mux_a->h.dwScale=1; printf("\n\nCBR audio effective bitrate: %8.3f kbit/s (%d bytes/sec)\n", mux_a->h.dwRate*8.0f/1000.0f,mux_a->h.dwRate); } #endif #ifdef USE_LIBAVCODEC if (mux_v->codec == VCODEC_LIBAVCODEC) avcodec_close(&lavc_venc_context); #endif printf("\nWriting AVI index...\n"); aviwrite_write_index(muxer,muxer_f); printf("Fixup AVI header...\n"); fseek(muxer_f,0,SEEK_SET); aviwrite_write_header(muxer,muxer_f); // update header fclose(muxer_f); printf("\nVideo stream: %8.3f kbit/s (%d bps) size: %d bytes %5.3f secs\n", (float)(mux_v->size/mux_v->timer*8.0f/1000.0f), (int)(mux_v->size/mux_v->timer), mux_v->size, (float)mux_v->timer); if(sh_audio) printf("\nAudio stream: %8.3f kbit/s (%d bps) size: %d bytes %5.3f secs\n", (float)(mux_a->size/mux_a->timer*8.0f/1000.0f), (int)(mux_a->size/mux_a->timer), mux_a->size, (float)mux_a->timer); if(stream) free_stream(stream); // kill cache thread return interrupted; } static int parse_end_at(struct config *conf, const char* param) { int i; end_at_type = END_AT_NONE; /* End at size parsing */ { char unit[4]; end_at_type = END_AT_SIZE; if(sscanf(param, "%d%3s", &end_at, unit) == 2) { if(!strcasecmp(unit, "b")) ; else if(!strcasecmp(unit, "kb")) end_at *= 1024; else if(!strcasecmp(unit, "mb")) end_at *= 1024*1024; else end_at_type = END_AT_NONE; } else end_at_type = END_AT_NONE; } /* End at time parsing. This has to be last because of * sscanf("%f", ...) below */ if(end_at_type == END_AT_NONE) { int a,b; float d; end_at_type = END_AT_TIME; if (sscanf(param, "%d:%d:%f", &a, &b, &d) == 3) end_at = 3600*a + 60*b + d; else if (sscanf(param, "%d:%f", &a, &d) == 2) end_at = 60*a + d; else if (sscanf(param, "%f", &d) == 1) end_at = d; else end_at_type = END_AT_NONE; } if(end_at_type == END_AT_NONE) return ERR_FUNC_ERR; return 1; }