- GOB headers for H.263 coding on RTP mode. - Improved GOB header detection for H.263 decoder. Originally committed as revision 222 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -5,6 +5,14 @@ version 0.4.6: | |||||
| - recoded dct and motion vector search with gcc (no longer depends on | - recoded dct and motion vector search with gcc (no longer depends on | ||||
| nasm). | nasm). | ||||
| - fix quantization bug in AC3 encoder. | - fix quantization bug in AC3 encoder. | ||||
| - added GOB header parsing on H.263/H.263+ decoder. (Juanjo) | |||||
| - bug fix on MCBPC tables of H.263. (Juanjo) | |||||
| - added Advanced Prediction Mode on H.263/H.263+ decoder. (Juanjo) | |||||
| - now we can decode H.263 streams found on QuickTime files. (Juanjo) | |||||
| - now we can decode H.263 streams found on VIVO v1 files.(Juanjo) | |||||
| - preliminary RTP "friendly" mode for H.263/H.263+ coding. (Juanjo) | |||||
| - added GOB header for H.263/H.263+ coding on RTP mode. (Juanjo) | |||||
| - now H.263 picture size is returned on the first decoded frame. (Juanjo) | |||||
| version 0.4.5: | version 0.4.5: | ||||
| @@ -103,6 +103,19 @@ typedef struct AVCodecContext { | |||||
| struct AVCodec *codec; | struct AVCodec *codec; | ||||
| void *priv_data; | void *priv_data; | ||||
| /* The following data is for RTP friendly coding */ | |||||
| /* By now only H.263/H.263+ coder honours this */ | |||||
| int rtp_mode; /* 1 for activate RTP friendly-mode */ | |||||
| /* highers numbers represent more error-prone */ | |||||
| /* enviroments, by now just "1" exist */ | |||||
| int rtp_payload_size; /* The size of the RTP payload, the coder will */ | |||||
| /* do it's best to deliver a chunk with size */ | |||||
| /* below rtp_payload_size, the chunk will start */ | |||||
| /* with a start code on some codecs like H.263 */ | |||||
| /* This doesn't take account of any particular */ | |||||
| /* headers inside the transmited RTP payload */ | |||||
| /* the following fields are ignored */ | /* the following fields are ignored */ | ||||
| void *opaque; /* can be used to carry app specific stuff */ | void *opaque; /* can be used to carry app specific stuff */ | ||||
| char codec_name[32]; | char codec_name[32]; | ||||
| @@ -239,8 +252,8 @@ void avcodec_register_all(void); | |||||
| #ifdef FF_POSTPROCESS | #ifdef FF_POSTPROCESS | ||||
| #ifndef MBC | #ifndef MBC | ||||
| #define MBC 120 | |||||
| #define MBR 72 | |||||
| #define MBC 48 | |||||
| #define MBR 36 | |||||
| #endif | #endif | ||||
| extern int quant_store[MBR+1][MBC+1]; // [Review] | extern int quant_store[MBR+1][MBC+1]; // [Review] | ||||
| #endif | #endif | ||||
| @@ -140,12 +140,45 @@ void h263_encode_picture_header(MpegEncContext * s, int picture_number) | |||||
| put_bits(&s->pb, 1, 0); /* no PEI */ | put_bits(&s->pb, 1, 0); /* no PEI */ | ||||
| } | } | ||||
| int h263_encode_gob_header(MpegEncContext * s, int mb_line) | |||||
| { | |||||
| int pdif=0; | |||||
| /* Check to see if we need to put a new GBSC */ | |||||
| /* for RTP packetization */ | |||||
| if (s->rtp_mode) { | |||||
| pdif = s->pb.buf_ptr - s->ptr_lastgob; | |||||
| if (pdif >= s->rtp_payload_size) { | |||||
| /* Bad luck, packet must be cut before */ | |||||
| align_put_bits(&s->pb); | |||||
| s->ptr_lastgob = s->pb.buf_ptr; | |||||
| put_bits(&s->pb, 17, 1); /* GBSC */ | |||||
| s->gob_number = mb_line; | |||||
| put_bits(&s->pb, 5, s->gob_number); /* GN */ | |||||
| put_bits(&s->pb, 2, 1); /* GFID */ | |||||
| put_bits(&s->pb, 5, s->qscale); /* GQUANT */ | |||||
| return pdif; | |||||
| } else if (pdif + s->mb_line_avgsize >= s->rtp_payload_size) { | |||||
| /* Cut the packet before we can't */ | |||||
| align_put_bits(&s->pb); | |||||
| s->ptr_lastgob = s->pb.buf_ptr; | |||||
| put_bits(&s->pb, 17, 1); /* GBSC */ | |||||
| s->gob_number = mb_line; | |||||
| put_bits(&s->pb, 5, s->gob_number); /* GN */ | |||||
| put_bits(&s->pb, 2, 1); /* GFID */ | |||||
| put_bits(&s->pb, 5, s->qscale); /* GQUANT */ | |||||
| return pdif; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void h263_encode_mb(MpegEncContext * s, | void h263_encode_mb(MpegEncContext * s, | ||||
| DCTELEM block[6][64], | DCTELEM block[6][64], | ||||
| int motion_x, int motion_y) | int motion_x, int motion_y) | ||||
| { | { | ||||
| int cbpc, cbpy, i, cbp, pred_x, pred_y; | int cbpc, cbpy, i, cbp, pred_x, pred_y; | ||||
| // printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); | // printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); | ||||
| if (!s->mb_intra) { | if (!s->mb_intra) { | ||||
| /* compute cbp */ | /* compute cbp */ | ||||
| @@ -772,42 +805,38 @@ void h263_decode_init_vlc(MpegEncContext *s) | |||||
| } | } | ||||
| } | } | ||||
| int h263_decode_mb(MpegEncContext *s, | |||||
| DCTELEM block[6][64]) | |||||
| int h263_decode_gob_header(MpegEncContext *s) | |||||
| { | { | ||||
| int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; | |||||
| unsigned int val; | |||||
| INT16 *mot_val; | |||||
| static INT8 quant_tab[4] = { -1, -2, 1, 2 }; | |||||
| unsigned int gfid; | |||||
| unsigned int val, gfid; | |||||
| /* Check for GOB Start Code */ | /* Check for GOB Start Code */ | ||||
| if (s->mb_x == 0) { | |||||
| val = show_bits(&s->gb, 16); | |||||
| if (val == 0) { | |||||
| /* We have a GBSC probably with GSTUFF */ | |||||
| skip_bits(&s->gb, 16); /* Drop the zeros */ | |||||
| while (get_bits1(&s->gb) == 0); /* Seek the '1' bit */ | |||||
| val = show_bits(&s->gb, 16); | |||||
| if (val == 0) { | |||||
| /* We have a GBSC probably with GSTUFF */ | |||||
| skip_bits(&s->gb, 16); /* Drop the zeros */ | |||||
| while (get_bits1(&s->gb) == 0); /* Seek the '1' bit */ | |||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| fprintf(stderr,"\nGOB Start Code at MB %d\n", | |||||
| (s->mb_y * s->mb_width) + s->mb_x); | |||||
| fprintf(stderr,"\nGOB Start Code at MB %d\n", (s->mb_y * s->mb_width) + s->mb_x); | |||||
| #endif | #endif | ||||
| s->gob_number = get_bits(&s->gb, 5); /* GN */ | |||||
| gfid = get_bits(&s->gb, 2); /* GFID */ | |||||
| s->qscale = get_bits(&s->gb, 5); /* GQUANT */ | |||||
| s->gob_number = get_bits(&s->gb, 5); /* GN */ | |||||
| gfid = get_bits(&s->gb, 2); /* GFID */ | |||||
| s->qscale = get_bits(&s->gb, 5); /* GQUANT */ | |||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| fprintf(stderr, "\nGN: %u GFID: %u Quant: %u\n", gn, gfid, s->qscale); | |||||
| fprintf(stderr, "\nGN: %u GFID: %u Quant: %u\n", gn, gfid, s->qscale); | |||||
| #endif | #endif | ||||
| } | |||||
| return 1; | |||||
| } | } | ||||
| /* FIXME: In the future H.263+ will have intra prediction */ | |||||
| /* and we are gonna need another way to detect MPEG4 */ | |||||
| if (!s->h263_pred) { | |||||
| if (s->mb_y == s->gob_number) | |||||
| s->first_gob_line = 1; | |||||
| else | |||||
| s->first_gob_line = 0; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| int h263_decode_mb(MpegEncContext *s, | |||||
| DCTELEM block[6][64]) | |||||
| { | |||||
| int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; | |||||
| INT16 *mot_val; | |||||
| static INT8 quant_tab[4] = { -1, -2, 1, 2 }; | |||||
| if (s->pict_type == P_TYPE) { | if (s->pict_type == P_TYPE) { | ||||
| if (get_bits1(&s->gb)) { | if (get_bits1(&s->gb)) { | ||||
| /* skip mb */ | /* skip mb */ | ||||
| @@ -140,6 +140,12 @@ static int h263_decode_frame(AVCodecContext *avctx, | |||||
| /* decode each macroblock */ | /* decode each macroblock */ | ||||
| for(s->mb_y=0; s->mb_y < s->mb_height; s->mb_y++) { | for(s->mb_y=0; s->mb_y < s->mb_height; s->mb_y++) { | ||||
| /* Check for GOB headers on H.263 */ | |||||
| /* FIXME: In the future H.263+ will have intra prediction */ | |||||
| /* and we are gonna need another way to detect MPEG4 */ | |||||
| if (s->mb_y && !s->h263_pred) { | |||||
| s->first_gob_line = h263_decode_gob_header(s); | |||||
| } | |||||
| for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { | for(s->mb_x=0; s->mb_x < s->mb_width; s->mb_x++) { | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); | printf("**mb x=%d y=%d\n", s->mb_x, s->mb_y); | ||||
| @@ -249,6 +249,9 @@ int MPV_encode_init(AVCodecContext *avctx) | |||||
| s->width = avctx->width; | s->width = avctx->width; | ||||
| s->height = avctx->height; | s->height = avctx->height; | ||||
| s->gop_size = avctx->gop_size; | s->gop_size = avctx->gop_size; | ||||
| s->rtp_mode = avctx->rtp_mode; | |||||
| s->rtp_payload_size = avctx->rtp_payload_size; | |||||
| if (s->gop_size <= 1) { | if (s->gop_size <= 1) { | ||||
| s->intra_only = 1; | s->intra_only = 1; | ||||
| s->gop_size = 12; | s->gop_size = 12; | ||||
| @@ -276,6 +279,8 @@ int MPV_encode_init(AVCodecContext *avctx) | |||||
| break; | break; | ||||
| case CODEC_ID_H263P: | case CODEC_ID_H263P: | ||||
| s->out_format = FMT_H263; | s->out_format = FMT_H263; | ||||
| s->rtp_mode = 1; | |||||
| s->rtp_payload_size = 1200; | |||||
| s->h263_plus = 1; | s->h263_plus = 1; | ||||
| s->unrestricted_mv = 1; | s->unrestricted_mv = 1; | ||||
| @@ -819,7 +824,7 @@ void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]) | |||||
| static void encode_picture(MpegEncContext *s, int picture_number) | static void encode_picture(MpegEncContext *s, int picture_number) | ||||
| { | { | ||||
| int mb_x, mb_y, wrap; | |||||
| int mb_x, mb_y, wrap, last_gob; | |||||
| UINT8 *ptr; | UINT8 *ptr; | ||||
| int i, motion_x, motion_y; | int i, motion_x, motion_y; | ||||
| @@ -869,7 +874,29 @@ static void encode_picture(MpegEncContext *s, int picture_number) | |||||
| s->mv_type = MV_TYPE_16X16; | s->mv_type = MV_TYPE_16X16; | ||||
| s->mv_dir = MV_DIR_FORWARD; | s->mv_dir = MV_DIR_FORWARD; | ||||
| /* Get the GOB height based on picture height */ | |||||
| if (s->out_format == FMT_H263 && s->h263_plus) { | |||||
| if (s->height <= 400) | |||||
| s->gob_index = 1; | |||||
| else if (s->height <= 800) | |||||
| s->gob_index = 2; | |||||
| else | |||||
| s->gob_index = 4; | |||||
| } | |||||
| for(mb_y=0; mb_y < s->mb_height; mb_y++) { | for(mb_y=0; mb_y < s->mb_height; mb_y++) { | ||||
| /* Put GOB header based on RTP MTU */ | |||||
| if (!mb_y) { | |||||
| s->ptr_lastgob = s->pb.buf_ptr; | |||||
| s->ptr_last_mb_line = s->pb.buf_ptr; | |||||
| } else if (s->out_format == FMT_H263 && s->h263_plus) { | |||||
| last_gob = h263_encode_gob_header(s, mb_y); | |||||
| if (last_gob) { | |||||
| //fprintf(stderr,"\nLast GOB size: %d", last_gob); | |||||
| s->first_gob_line = 1; | |||||
| } else | |||||
| s->first_gob_line = 0; | |||||
| } | |||||
| for(mb_x=0; mb_x < s->mb_width; mb_x++) { | for(mb_x=0; mb_x < s->mb_width; mb_x++) { | ||||
| s->mb_x = mb_x; | s->mb_x = mb_x; | ||||
| @@ -981,7 +1008,17 @@ static void encode_picture(MpegEncContext *s, int picture_number) | |||||
| MPV_decode_mb(s, s->block); | MPV_decode_mb(s, s->block); | ||||
| } | } | ||||
| /* Obtain average MB line size for RTP */ | |||||
| if (!mb_y) | |||||
| s->mb_line_avgsize = s->pb.buf_ptr - s->ptr_last_mb_line; | |||||
| else | |||||
| s->mb_line_avgsize = (s->mb_line_avgsize + s->pb.buf_ptr - s->ptr_last_mb_line) >> 1; | |||||
| //fprintf(stderr, "\nMB line: %d\tSize: %u\tAvg. Size: %u", s->mb_y, | |||||
| // (s->pb.buf_ptr - s->ptr_last_mb_line), s->mb_line_avgsize); | |||||
| s->ptr_last_mb_line = s->pb.buf_ptr; | |||||
| } | } | ||||
| //if (s->gob_number) | |||||
| // fprintf(stderr,"\nNumber of GOB: %d", s->gob_number); | |||||
| } | } | ||||
| static int dct_quantize(MpegEncContext *s, | static int dct_quantize(MpegEncContext *s, | ||||
| @@ -131,6 +131,7 @@ typedef struct MpegEncContext { | |||||
| /* H.263 specific */ | /* H.263 specific */ | ||||
| int gob_number; | int gob_number; | ||||
| int gob_index; | |||||
| int first_gob_line; | int first_gob_line; | ||||
| /* H.263+ specific */ | /* H.263+ specific */ | ||||
| @@ -185,7 +186,14 @@ typedef struct MpegEncContext { | |||||
| int interlaced_dct; | int interlaced_dct; | ||||
| int last_qscale; | int last_qscale; | ||||
| int first_slice; | int first_slice; | ||||
| /* RTP specific */ | |||||
| int rtp_mode; | |||||
| int rtp_payload_size; | |||||
| UINT8 *ptr_lastgob; | |||||
| UINT8 *ptr_last_mb_line; | |||||
| UINT32 mb_line_avgsize; | |||||
| DCTELEM block[6][64] __align8; | DCTELEM block[6][64] __align8; | ||||
| void (*dct_unquantize)(struct MpegEncContext *s, | void (*dct_unquantize)(struct MpegEncContext *s, | ||||
| DCTELEM *block, int n, int qscale); | DCTELEM *block, int n, int qscale); | ||||
| @@ -236,7 +244,7 @@ typedef struct RLTable { | |||||
| void init_rl(RLTable *rl); | void init_rl(RLTable *rl); | ||||
| void init_vlc_rl(RLTable *rl); | void init_vlc_rl(RLTable *rl); | ||||
| static inline int get_rl_index(const RLTable *rl, int last, int run, int level) | |||||
| extern inline int get_rl_index(const RLTable *rl, int last, int run, int level) | |||||
| { | { | ||||
| int index; | int index; | ||||
| index = rl->index_run[last][run]; | index = rl->index_run[last][run]; | ||||
| @@ -251,6 +259,7 @@ void h263_encode_mb(MpegEncContext *s, | |||||
| DCTELEM block[6][64], | DCTELEM block[6][64], | ||||
| int motion_x, int motion_y); | int motion_x, int motion_y); | ||||
| void h263_encode_picture_header(MpegEncContext *s, int picture_number); | void h263_encode_picture_header(MpegEncContext *s, int picture_number); | ||||
| int h263_encode_gob_header(MpegEncContext * s, int mb_line); | |||||
| void h263_dc_scale(MpegEncContext *s); | void h263_dc_scale(MpegEncContext *s); | ||||
| INT16 *h263_pred_motion(MpegEncContext * s, int block, | INT16 *h263_pred_motion(MpegEncContext * s, int block, | ||||
| int *px, int *py); | int *px, int *py); | ||||
| @@ -261,6 +270,7 @@ void h263_encode_init_vlc(MpegEncContext *s); | |||||
| void h263_decode_init_vlc(MpegEncContext *s); | void h263_decode_init_vlc(MpegEncContext *s); | ||||
| int h263_decode_picture_header(MpegEncContext *s); | int h263_decode_picture_header(MpegEncContext *s); | ||||
| int h263_decode_gob_header(MpegEncContext *s); | |||||
| int mpeg4_decode_picture_header(MpegEncContext * s); | int mpeg4_decode_picture_header(MpegEncContext * s); | ||||
| int intel_h263_decode_picture_header(MpegEncContext *s); | int intel_h263_decode_picture_header(MpegEncContext *s); | ||||
| int h263_decode_mb(MpegEncContext *s, | int h263_decode_mb(MpegEncContext *s, | ||||