From 70a7a6b4507e5b383707e6a9b8c02c17eadd91cc Mon Sep 17 00:00:00 2001 From: nicodvb Date: Wed, 12 Jan 2005 20:43:53 +0000 Subject: [PATCH] automatic fps calculation for mpeg4 in raw stream/mpeg-ts git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@14478 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmpdemux/mpeg_hdr.c | 111 +++++++++++++++++++++++++++++++++++++++++- libmpdemux/mpeg_hdr.h | 5 ++ libmpdemux/video.c | 52 +++++++++++++++++++- 3 files changed, 166 insertions(+), 2 deletions(-) diff --git a/libmpdemux/mpeg_hdr.c b/libmpdemux/mpeg_hdr.c index 65be35d779..f4a4d672fe 100644 --- a/libmpdemux/mpeg_hdr.c +++ b/libmpdemux/mpeg_hdr.c @@ -27,7 +27,7 @@ int mp_header_process_sequence_header (mp_mpeg_header_t * picture, unsigned char int width, height; if ((buffer[6] & 0x20) != 0x20){ - printf("missing marker bit!\n"); + fprintf(stderr, "missing marker bit!\n"); return 1; /* missing marker_bit */ } @@ -101,3 +101,112 @@ int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buf return 0; } + +//MPEG4 HEADERS +static unsigned char getbits(unsigned char *buffer, unsigned int from, unsigned char len) +{ + unsigned int n; + unsigned char m, u, l, y; + + n = from / 8; + m = from % 8; + u = 8 - m; + l = (len > u ? len - u : 0); + + y = (buffer[n] << m); + if(8 > len) + y >>= (8-len); + if(l) + y |= (buffer[n+1] >> (8-l)); + + //fprintf(stderr, "GETBITS(%d -> %d): bytes=0x%x 0x%x, n=%d, m=%d, l=%d, u=%d, Y=%d\n", + // from, (int) len, (int) buffer[n],(int) buffer[n+1], n, (int) m, (int) l, (int) u, (int) y); + return y; +} + +static int read_timeinc(mp_mpeg_header_t * picture, unsigned char * buffer, int n) +{ + if(picture->timeinc_bits > 8) { + picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits - 8) << 8; + n += picture->timeinc_bits - 8; + picture->timeinc_unit |= getbits(buffer, n, 8); + n += 8; + } else { + picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits); + n += picture->timeinc_bits; + } + //fprintf(stderr, "TIMEINC2: %d, bits: %d\n", picture->timeinc_unit, picture->timeinc_bits); + return n; +} + +int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer) +{ + unsigned int n, aspect=0, aspectw=0, aspecth=0, x=1, v; + + //begins with 0x0000012x + picture->fps = 0; + picture->timeinc_bits = picture->timeinc_resolution = picture->timeinc_unit = 0; + n = 9; + if(getbits(buffer, n, 1)) + n += 7; + n++; + aspect=getbits(buffer, n, 4); + n += 4; + if(aspect == 0x0f) { + aspectw = getbits(buffer, n, 8); + n += 8; + aspecth = getbits(buffer, n, 8); + n += 8; + } + + if(getbits(buffer, n, 1)) { + n += 4; + if(getbits(buffer, n, 1)) + n += 79; + n++; + } else n++; + + n+=3; + + picture->timeinc_resolution = getbits(buffer, n, 8) << 8; + n += 8; + picture->timeinc_resolution |= getbits(buffer, n, 8); + n += 8; + + picture->timeinc_bits = 0; + v = picture->timeinc_resolution - 1; + while(v && (x<16)) { + v>>=1; + picture->timeinc_bits++; + } + picture->timeinc_bits = (picture->timeinc_bits > 1 ? picture->timeinc_bits : 1); + + n++; //marker bit + + if(getbits(buffer, n, 1)) { //fixed_vop_timeinc + n++; + n = read_timeinc(picture, buffer, n); + + if(picture->timeinc_unit) + picture->fps = (picture->timeinc_resolution * 10000) / picture->timeinc_unit; + } + + //fprintf(stderr, "ASPECT: %d, PARW=%d, PARH=%d, TIMEINCRESOLUTION: %d, FIXED_TIMEINC: %d (number of bits: %d), FPS: %u\n", + // aspect, aspectw, aspecth, picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_bits, picture->fps); + + return 0; +} + +int mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer) +{ + int n; + n = 0; + picture->picture_type = getbits(buffer, n, 2); + n += 2; + while(getbits(buffer, n, 1)) + n++; + n++; + getbits(buffer, n, 1); + n++; + n = read_timeinc(picture, buffer, n); +} diff --git a/libmpdemux/mpeg_hdr.h b/libmpdemux/mpeg_hdr.h index 96ebe4fba9..05b78660b5 100644 --- a/libmpdemux/mpeg_hdr.h +++ b/libmpdemux/mpeg_hdr.h @@ -15,7 +15,12 @@ typedef struct { int progressive_frame; int top_field_first; int display_time; // secs*100 + //the following are for mpeg4 + int timeinc_resolution, timeinc_bits, timeinc_unit; + int picture_type; } mp_mpeg_header_t; int mp_header_process_sequence_header (mp_mpeg_header_t * picture, unsigned char * buffer); int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer); +int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer); +int mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer); diff --git a/libmpdemux/video.c b/libmpdemux/video.c index 99e65aa71a..dc22ade845 100644 --- a/libmpdemux/video.c +++ b/libmpdemux/video.c @@ -116,6 +116,7 @@ switch(video_codec){ break; } case VIDEO_MPEG4: { + int pos = 0, vop_cnt=0, units[3]; videobuf_len=0; videobuf_code_len=0; mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Start code... ");fflush(stdout); while(1){ @@ -142,7 +143,14 @@ switch(video_codec){ return 0; } } - mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\nSearching for Video Object Plane Start code... ");fflush(stdout); + pos = videobuf_len+4; + if(!read_video_packet(d_video)){ + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Layer Header\n"); + return 0; + } + mp4_header_process_vol(&picture, &(videobuffer[pos])); + mp_msg(MSGT_DECVIDEO,MSGL_V,"OK! FPS SEEMS TO BE %.3f\nSearching for Video Object Plane Start code... ", sh_video->fps);fflush(stdout); + mp4_init: while(1){ int i=sync_video_packet(d_video); if(i==0x1B6) break; // found it! @@ -151,6 +159,48 @@ switch(video_codec){ return 0; } } + pos = videobuf_len+4; + if(!read_video_packet(d_video)){ + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Plane Header\n"); + return 0; + } + mp4_header_process_vop(&picture, &(videobuffer[pos])); + units[vop_cnt] = picture.timeinc_unit; + vop_cnt++; + //mp_msg(MSGT_DECVIDEO,MSGL_V, "TYPE: %d, unit: %d\n", picture.picture_type, picture.timeinc_unit); + if(!picture.fps) { + int i, mn, md, mx, diff; + if(vop_cnt < 3) + goto mp4_init; + + i=0; + mn = mx = units[0]; + for(i=0; i<3; i++) { + if(units[i] < mn) + mn = units[i]; + if(units[i] > mx) + mx = units[i]; + } + md = mn; + for(i=0; i<3; i++) { + if((units[i] > mn) && (units[i] < mx)) + md = units[i]; + } + mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %d, mid: %d, max: %d\n", mn, md, mx); + if(mx - md > md - mn) + diff = md - mn; + else + diff = mx - md; + if(diff > 0){ + picture.fps = (picture.timeinc_resolution * 10000) / diff; + mp_msg(MSGT_DECVIDEO,MSGL_V, "FPS seems to be: %d/10000, resolution: %d, delta_units: %d\n", picture.fps, picture.timeinc_resolution, diff); + } + } + if(picture.fps) { + sh_video->fps=picture.fps*0.0001f; + sh_video->frametime=10000.0f/(float)picture.fps; + mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %d/10000\n", picture.fps); + } mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); sh_video->format=0x10000004; break;