From 81401c1fbc79c3350e91ef15dd25b50afa9e5d4d Mon Sep 17 00:00:00 2001 From: Juanjo Date: Sat, 9 Feb 2002 16:59:56 +0000 Subject: [PATCH] - Fixes on RTP and GOB headers for H.263. - RTP callback system implemented for H.263/H.263+. - Bug fix on DC coefficients of H.263. - H.263 decoder now returns PTS on picture number. Originally committed as revision 292 to svn://svn.ffmpeg.org/ffmpeg/trunk --- Changelog | 1 + libavcodec/avcodec.h | 8 ++++++ libavcodec/h263.c | 54 +++++++++++++++++++++++++++----------- libavcodec/h263dec.c | 5 ++++ libavcodec/mpegvideo.c | 59 ++++++++++++++++++++++++++++-------------- libavcodec/mpegvideo.h | 2 ++ 6 files changed, 94 insertions(+), 35 deletions(-) diff --git a/Changelog b/Changelog index 95422897aa..30d04a1ac0 100644 --- a/Changelog +++ b/Changelog @@ -7,6 +7,7 @@ version 0.4.6: - 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) +- bug fix on DC coefficients 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) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 9b027091e2..cc374c1cab 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -115,6 +115,14 @@ typedef struct AVCodecContext { /* 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 RTP callcack: This function is called */ + /* every time the encoder as a packet to send */ + /* Depends on the encoder if the data starts */ + /* with a Start Code (it should) H.263 does */ + void (*rtp_callback)(void *data, int size, int packet_number); + /* the following fields are ignored */ void *opaque; /* can be used to carry app specific stuff */ diff --git a/libavcodec/h263.c b/libavcodec/h263.c index da694411f0..3710af8f77 100644 --- a/libavcodec/h263.c +++ b/libavcodec/h263.c @@ -62,7 +62,12 @@ void h263_encode_picture_header(MpegEncContext * s, int picture_number) int format; align_put_bits(&s->pb); - put_bits(&s->pb, 22, 0x20); + + /* Update the pointer to last GOB */ + s->ptr_lastgob = s->pb.buf_ptr; + s->gob_number = 0; + + put_bits(&s->pb, 22, 0x20); /* PSC */ put_bits(&s->pb, 8, ((s->picture_number * 30 * FRAME_RATE_BASE) / s->frame_rate) & 0xff); @@ -151,22 +156,36 @@ int h263_encode_gob_header(MpegEncContext * s, int mb_line) if (pdif >= s->rtp_payload_size) { /* Bad luck, packet must be cut before */ align_put_bits(&s->pb); + flush_put_bits(&s->pb); + /* Call the RTP callback to send the last GOB */ + if (s->rtp_callback) { + pdif = s->pb.buf_ptr - s->ptr_lastgob; + s->rtp_callback(s->ptr_lastgob, pdif, s->gob_number); + } s->ptr_lastgob = s->pb.buf_ptr; put_bits(&s->pb, 17, 1); /* GBSC */ - s->gob_number = mb_line; + s->gob_number = mb_line / s->gob_index; put_bits(&s->pb, 5, s->gob_number); /* GN */ - put_bits(&s->pb, 2, 1); /* GFID */ + put_bits(&s->pb, 2, s->pict_type == I_TYPE); /* GFID */ put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + //fprintf(stderr,"\nGOB: %2d size: %d", s->gob_number - 1, pdif); 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); + flush_put_bits(&s->pb); + /* Call the RTP callback to send the last GOB */ + if (s->rtp_callback) { + pdif = s->pb.buf_ptr - s->ptr_lastgob; + s->rtp_callback(s->ptr_lastgob, pdif, s->gob_number); + } s->ptr_lastgob = s->pb.buf_ptr; put_bits(&s->pb, 17, 1); /* GBSC */ - s->gob_number = mb_line; + s->gob_number = mb_line / s->gob_index; put_bits(&s->pb, 5, s->gob_number); /* GN */ - put_bits(&s->pb, 2, 1); /* GFID */ + put_bits(&s->pb, 2, s->pict_type == I_TYPE); /* GFID */ put_bits(&s->pb, 5, s->qscale); /* GQUANT */ + //fprintf(stderr,"\nGOB: %2d size: %d", s->gob_number - 1, pdif); return pdif; } } @@ -413,20 +432,25 @@ static void h263_encode_block(MpegEncContext * s, DCTELEM * block, int n) RLTable *rl = &rl_inter; if (s->mb_intra) { - /* DC coef */ - level = block[0]; + /* DC coef */ + level = block[0]; /* 255 cannot be represented, so we clamp */ if (level > 254) { level = 254; block[0] = 254; } - if (level == 128) - put_bits(&s->pb, 8, 0xff); - else - put_bits(&s->pb, 8, level & 0xff); - i = 1; + /* 0 cannot be represented also */ + else if (!level) { + level = 1; + block[0] = 1; + } + if (level == 128) + put_bits(&s->pb, 8, 0xff); + else + put_bits(&s->pb, 8, level & 0xff); + i = 1; } else { - i = 0; + i = 0; } /* AC coefs */ @@ -1241,8 +1265,8 @@ int h263_decode_picture_header(MpegEncContext *s) /* picture header */ if (get_bits(&s->gb, 22) != 0x20) return -1; - skip_bits(&s->gb, 8); /* picture timestamp */ - + s->picture_number = get_bits(&s->gb, 8); /* picture timestamp */ + if (get_bits1(&s->gb) != 1) return -1; /* marker */ if (get_bits1(&s->gb) != 0) diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index aadeb8bd68..ce2c12d165 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -225,6 +225,11 @@ static int h263_decode_frame(AVCodecContext *avctx, pict->linesize[2] = s->linesize / 2; avctx->quality = s->qscale; + + /* Return the Picture timestamp as the frame number */ + /* we substract 1 because it is added on utils.c */ + avctx->frame_number = s->picture_number - 1; + *data_size = sizeof(AVPicture); return buf_size; } diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 72b8058a22..4c86c52372 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -264,6 +264,8 @@ int MPV_encode_init(AVCodecContext *avctx) s->gop_size = avctx->gop_size; s->rtp_mode = avctx->rtp_mode; s->rtp_payload_size = avctx->rtp_payload_size; + if (avctx->rtp_callback) + s->rtp_callback = avctx->rtp_callback; s->avctx = avctx; if (s->gop_size <= 1) { @@ -868,7 +870,7 @@ void MPV_decode_mb(MpegEncContext *s, DCTELEM block[6][64]) static void encode_picture(MpegEncContext *s, int picture_number) { - int mb_x, mb_y, wrap, last_gob; + int mb_x, mb_y, wrap, last_gob, pdif = 0; UINT8 *ptr; int i, motion_x, motion_y; @@ -919,7 +921,7 @@ static void encode_picture(MpegEncContext *s, int picture_number) 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->out_format == FMT_H263 && !s->h263_pred && !s->h263_msmpeg4) { if (s->height <= 400) s->gob_index = 1; else if (s->height <= 800) @@ -930,16 +932,17 @@ static void encode_picture(MpegEncContext *s, int picture_number) 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; + /* TODO: Put all this stuff in a separate generic function */ + if (s->rtp_mode) { + if (!mb_y) { + s->ptr_lastgob = s->pb.buf; + s->ptr_last_mb_line = s->pb.buf; + } else if (s->out_format == FMT_H263 && !s->h263_pred && !s->h263_msmpeg4 && !(mb_y % s->gob_index)) { + last_gob = h263_encode_gob_header(s, mb_y); + if (last_gob) { + s->first_gob_line = 1; + } + } } for(mb_x=0; mb_x < s->mb_width; mb_x++) { @@ -1046,14 +1049,18 @@ static void encode_picture(MpegEncContext *s, int picture_number) 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; + /* Obtain average GOB size for RTP */ + if (s->rtp_mode) { + if (!mb_y) + s->mb_line_avgsize = s->pb.buf_ptr - s->ptr_last_mb_line; + else if (!(mb_y % s->gob_index)) { + s->mb_line_avgsize = (s->mb_line_avgsize + s->pb.buf_ptr - s->ptr_last_mb_line) >> 1; + s->ptr_last_mb_line = s->pb.buf_ptr; + } + //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->first_gob_line = 0; + } } if (s->h263_msmpeg4) @@ -1061,6 +1068,18 @@ static void encode_picture(MpegEncContext *s, int picture_number) //if (s->gob_number) // fprintf(stderr,"\nNumber of GOB: %d", s->gob_number); + + /* Send the last GOB if RTP */ + if (s->rtp_mode) { + flush_put_bits(&s->pb); + pdif = s->pb.buf_ptr - s->ptr_lastgob; + /* Call the RTP callback to send the last GOB */ + if (s->rtp_callback) + s->rtp_callback(s->ptr_lastgob, pdif, s->gob_number); + s->ptr_lastgob = s->pb.buf_ptr; + //fprintf(stderr,"\nGOB: %2d size: %d (last)", s->gob_number, pdif); + } + } static int dct_quantize_c(MpegEncContext *s, diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 6cf4688d99..a12f198c26 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -201,8 +201,10 @@ typedef struct MpegEncContext { int first_slice; /* RTP specific */ + /* These are explained on avcodec.h */ int rtp_mode; int rtp_payload_size; + void (*rtp_callback)(void *data, int size, int packet_number); UINT8 *ptr_lastgob; UINT8 *ptr_last_mb_line; UINT32 mb_line_avgsize;