// read video frame #include "config.h" #include #ifdef HAVE_MALLOC_H #include #endif #include #include #include "mp_msg.h" #include "help_mp.h" #include "stream.h" #include "demuxer.h" #include "stheader.h" #include "parse_es.h" #include "mpeg_hdr.h" static mp_mpeg_header_t picture; int video_read_properties(sh_video_t *sh_video){ demux_stream_t *d_video=sh_video->ds; // Determine image properties: switch(d_video->demuxer->file_format){ case DEMUXER_TYPE_AVI: case DEMUXER_TYPE_ASF: { // display info: sh_video->format=sh_video->bih->biCompression; sh_video->disp_w=sh_video->bih->biWidth; sh_video->disp_h=abs(sh_video->bih->biHeight); break; } case DEMUXER_TYPE_MPEG_ES: case DEMUXER_TYPE_MPEG_PS: { // Find sequence_header first: videobuf_len=0; videobuf_code_len=0; mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence header... ");fflush(stdout); while(1){ int i=sync_video_packet(d_video); if(i==0x1B3) break; // found it! if(!i || !skip_video_packet(d_video)){ if(verbose) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n"); mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_MpegNoSequHdr); return 0; } } mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); // sh_video=d_video->sh;sh_video->ds=d_video; // mpeg2_init(); // ========= Read & process sequence header & extension ============ if(!videobuffer) videobuffer=(char*)memalign(8,VIDEOBUFFER_SIZE); if(!videobuffer){ mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_ShMemAllocFail); return 0; } if(!read_video_packet(d_video)){ mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_CannotReadMpegSequHdr); return 0; } if(mp_header_process_sequence_header (&picture, &videobuffer[4])) { mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_BadMpegSequHdr); return 0; } if(sync_video_packet(d_video)==0x1B5){ // next packet is seq. ext. // videobuf_len=0; int pos=videobuf_len; if(!read_video_packet(d_video)){ mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_CannotReadMpegSequHdrEx); return 0; } if(mp_header_process_extension (&picture, &videobuffer[pos+4])) { mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_BadMpegSequHdrEx); return 0; } } // printf("picture.fps=%d\n",picture.fps); // fill aspect info: switch(picture.aspect_ratio_information){ case 2: // PAL/NTSC SVCD/DVD 4:3 case 8: // PAL VCD 4:3 case 12: // NTSC VCD 4:3 sh_video->aspect=4.0/3.0; break; case 3: // PAL/NTSC Widescreen SVCD/DVD 16:9 sh_video->aspect=16.0/9.0; break; default: fprintf(stderr,"Detected unknown aspect_ratio_information in mpeg sequence header.\n" "Please report the aspect value (%i) along with the movie type (VGA,PAL,NTSC," "SECAM) and the movie resolution (720x576,352x240,480x480,...) to the MPlayer" " developers, so that we can add support for it!\nAssuming 1:1 aspect for now.\n", picture.aspect_ratio_information); case 1: // VGA 1:1 - do not prescale sh_video->aspect=0.0; break; } // display info: sh_video->format=picture.mpeg1?0x10000001:0x10000002; // mpeg video sh_video->fps=picture.fps*0.0001f; if(!sh_video->fps){ // if(!force_fps){ // fprintf(stderr,"FPS not specified (or invalid) in the header! Use the -fps option!\n"); // return 0; // } sh_video->frametime=0; } else { sh_video->frametime=10000.0f/(float)picture.fps; } sh_video->disp_w=picture.display_picture_width; sh_video->disp_h=picture.display_picture_height; // bitrate: if(picture.bitrate!=0x3FFFF) // unspecified/VBR ? sh_video->i_bps=1000*picture.bitrate/16; // info: mp_dbg(MSGT_DECVIDEO,MSGL_DBG2,"mpeg bitrate: %d (%X)\n",picture.bitrate,picture.bitrate); mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: %s %dx%d (aspect %d) %4.2f fps %5.1f kbps (%4.1f kbyte/s)\n", picture.mpeg1?"MPEG1":"MPEG2", sh_video->disp_w,sh_video->disp_h, picture.aspect_ratio_information, sh_video->fps, picture.bitrate*0.5f, picture.bitrate/16.0f ); break; } } // switch(file_format) return 1; } int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps){ demux_stream_t *d_video=sh_video->ds; demuxer_t *demuxer=d_video->demuxer; float frame_time=1; float pts1=d_video->pts; // unsigned char* start=NULL; int in_size=0; *start=NULL; if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS){ int in_frame=0; //float newfps; //videobuf_len=0; while(videobuf_len=0x1B0){ // not slice code -> end of frame #if 1 // send END OF FRAME code: videobuffer[videobuf_len+0]=0; videobuffer[videobuf_len+1]=0; videobuffer[videobuf_len+2]=1; videobuffer[videobuf_len+3]=0xFF; videobuf_len+=4; #endif if(!i) return -1; // EOF break; } } else { //if(i==0x100) in_frame=1; // picture startcode if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode else if(!i) return -1; // EOF } //if(grab_frames==2 && (i==0x1B3 || i==0x1B8)) grab_frames=1; if(!read_video_packet(d_video)) return -1; // EOF //printf("read packet 0x%X, len=%d\n",i,videobuf_len); // process headers: switch(i){ case 0x1B3: mp_header_process_sequence_header (&picture, buffer);break; case 0x1B5: mp_header_process_extension (&picture, buffer);break; } } // if(videobuf_len>max_framesize) max_framesize=videobuf_len; // debug //printf("--- SEND %d bytes\n",videobuf_len); // if(grab_frames==1){ // FILE *f=fopen("grab.mpg","ab"); // fwrite(videobuffer,videobuf_len-4,1,f); // fclose(f); // } *start=videobuffer; in_size=videobuf_len; //blit_frame=decode_video(video_out,sh_video,videobuffer,videobuf_len,drop_frame); #if 1 // get mpeg fps: //newfps=frameratecode2framerate[picture->frame_rate_code]*0.0001f; if((int)(sh_video->fps*10000+0.5)!=picture.fps) if(!force_fps){ mp_msg(MSGT_CPLAYER,MSGL_WARN,"Warning! FPS changed %5.3f -> %5.3f (%f) [%d] \n",sh_video->fps,picture.fps*0.0001,sh_video->fps-picture.fps*0.0001,picture.frame_rate_code); sh_video->fps=picture.fps*0.0001; sh_video->frametime=10000.0f/(float)picture.fps; } #endif // fix mpeg2 frametime: frame_time=(picture.display_time)*0.01f; picture.display_time=100; videobuf_len=0; } else { // frame-based file formats: (AVI,ASF,MOV) in_size=ds_get_packet(d_video,start); if(in_size<0) return -1; // EOF // if(in_size>max_framesize) max_framesize=in_size; // blit_frame=decode_video(video_out,sh_video,start,in_size,drop_frame); } // vdecode_time=video_time_usage-vdecode_time; //------------------------ frame decoded. -------------------- // Increase video timers: sh_video->num_frames+=frame_time; ++sh_video->num_frames_decoded; frame_time*=sh_video->frametime; if(demuxer->file_format==DEMUXER_TYPE_ASF && !force_fps){ // .ASF files has no fixed FPS - just frame durations! float d=d_video->pts-pts1; if(d>=0 && d<5) frame_time=d; if(d>0){ if(verbose) if((int)sh_video->fps==1000) mp_msg(MSGT_CPLAYER,MSGL_STATUS,"\rASF framerate: %d fps \n",(int)(1.0f/d)); sh_video->frametime=d; // 1ms sh_video->fps=1.0f/d; } } else if(demuxer->file_format==DEMUXER_TYPE_MOV && !force_fps){ // .MOV files has no fixed FPS - just frame durations! frame_time=d_video->pts-pts1; } if(demuxer->file_format==DEMUXER_TYPE_MPEG_PS) d_video->pts+=frame_time; if(frame_time_ptr) *frame_time_ptr=frame_time; return in_size; }