# HG changeset patch # User nicodvb # Date 1109275361 0 # Node ID 0bd50330e6886b541716cf539c26d5b828537708 # Parent 05eab20de47669b6972c1e0ca2555b2fde72c61f framerate autodetection for H264 in raw/ts streams diff -r 05eab20de476 -r 0bd50330e688 libmpdemux/mpeg_hdr.c --- a/libmpdemux/mpeg_hdr.c Thu Feb 24 17:46:19 2005 +0000 +++ b/libmpdemux/mpeg_hdr.c Thu Feb 24 20:02:41 2005 +0000 @@ -210,3 +210,151 @@ n++; n = read_timeinc(picture, buffer, n); } + +#define min(a, b) ((a) <= (b) ? (a) : (b)) + +static unsigned int read_golomb(unsigned char *buffer, unsigned int *init) +{ + unsigned int x, v = 0, v2 = 0, m, len = 0, n = *init; + + while(getbits(buffer, n++, 1) == 0) + len++; + + x = len + n; + while(n < x) + { + m = min(x - n, 8); + v |= getbits(buffer, n, m); + n += m; + if(x - n > 8) + v <<= 8; + } + + v2 = 1; + for(n = 0; n < len; n++) + v2 <<= 1; + v2 = (v2 - 1) + v; + + //fprintf(stderr, "READ_GOLOMB(%u), V=2^%u + %u-1 = %u\n", *init, len, v, v2); + *init = x; + return v2; +} + + +static int h264_parse_vui(mp_mpeg_header_t * picture, unsigned char * buf, unsigned int n) +{ + unsigned int overscan, vsp_color, chroma, timing, fixed_fps; + + if(getbits(buf, n++, 1)) + { + picture->aspect_ratio_information = getbits(buf, n, 8); + n += 8; + if(picture->aspect_ratio_information == 255) + { + picture->display_picture_width = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8); + n += 16; + + picture->display_picture_height = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8); + n += 16; + } + } + + if(overscan=getbits(buf, n++, 1)) + n++; + if(vsp_color=getbits(buf, n++, 1)) + { + n += 4; + if(getbits(buf, n++, 1)) + n += 24; + } + if(chroma=getbits(buf, n++, 1)) + { + read_golomb(buf, &n); + read_golomb(buf, &n); + } + if(timing=getbits(buf, n++, 1)) + { + picture->timeinc_unit = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8); + n += 32; + + picture->timeinc_resolution = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8); + n += 32; + + fixed_fps = getbits(buf, n, 1); + + if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0) + picture->fps = (picture->timeinc_resolution * 10000) / picture->timeinc_unit; + } + + //fprintf(stderr, "H264_PARSE_VUI, OVESCAN=%u, VSP_COLOR=%u, CHROMA=%u, TIMING=%u, DISPW=%u, DISPH=%u, TIMERES=%u, TIMEINC=%u, FIXED_FPS=%u\n", overscan, vsp_color, chroma, timing, picture->display_picture_width, picture->display_picture_height, + // picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_unit, fixed_fps); + + return n; +} + +int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len) +{ + unsigned int n = 0, m = 0, v, i, j; + unsigned char *dest; + + dest = (unsigned char*) malloc(len); + if(! dest) + return 0; + j = i = 0; + while(i <= len-3) + { + if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3) + { + dest[j] = dest[j+1] = 0; + j += 2; + i += 3; + } + else + { + dest[j] = buf[i]; + j++; + i++; + } + } + dest[j] = buf[len-2]; + dest[j+1] = buf[len-1]; + j += 2; + len = j+1; + buf = dest; + + picture->fps = picture->timeinc_unit = picture->timeinc_resolution = 0; + n = 24; + read_golomb(buf, &n); + read_golomb(buf, &n); + v = read_golomb(buf, &n); + if(v == 0) + read_golomb(buf, &n); + else if(v == 1) + { + getbits(buf, n++, 1); + read_golomb(buf, &n); + read_golomb(buf, &n); + v = read_golomb(buf, &n); + for(i = 0; i < v; i++) + read_golomb(buf, &n); + } + read_golomb(buf, &n); + getbits(buf, n++, 1); + read_golomb(buf, &n); + read_golomb(buf, &n); + if(!getbits(buf, n++, 1)) + getbits(buf, n++, 1); + getbits(buf, n++, 1); + if(getbits(buf, n++, 1)) + { + read_golomb(buf, &n); + read_golomb(buf, &n); + read_golomb(buf, &n); + read_golomb(buf, &n); + } + if(getbits(buf, n++, 1)) + n = h264_parse_vui(picture, buf, n); + + free(dest); + return n; +} diff -r 05eab20de476 -r 0bd50330e688 libmpdemux/mpeg_hdr.h --- a/libmpdemux/mpeg_hdr.h Thu Feb 24 17:46:19 2005 +0000 +++ b/libmpdemux/mpeg_hdr.h Thu Feb 24 20:02:41 2005 +0000 @@ -24,3 +24,4 @@ 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); +int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len); diff -r 05eab20de476 -r 0bd50330e688 libmpdemux/video.c --- a/libmpdemux/video.c Thu Feb 24 17:46:19 2005 +0000 +++ b/libmpdemux/video.c Thu Feb 24 20:02:41 2005 +0000 @@ -206,6 +206,7 @@ break; } case VIDEO_H264: { + int pos = 0; videobuf_len=0; videobuf_code_len=0; mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence parameter set... ");fflush(stdout); while(1){ @@ -222,6 +223,12 @@ mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_ShMemAllocFail); return 0; } + pos = videobuf_len+4; + if(!read_video_packet(d_video)){ + mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read sequence parameter set\n"); + return 0; + } + h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos); mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for picture parameter set... ");fflush(stdout); while(1){ int i=sync_video_packet(d_video); @@ -243,6 +250,11 @@ } mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n"); sh_video->format=0x10000005; + 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); + } break; } case VIDEO_MPEG12: { @@ -495,7 +507,19 @@ // while(videobuf_len 0) { + sh_video->fps=picture.fps*0.0001f; + sh_video->frametime=10000.0f/(float)picture.fps; + } + i=sync_video_packet(d_video); + if(!i) return -1; + if(!read_video_packet(d_video)) return -1; // EOF + } if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) break; } *start=videobuffer; in_size=videobuf_len;