- 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/trunktags/v0.5
| @@ -7,6 +7,7 @@ version 0.4.6: | |||||
| - fix quantization bug in AC3 encoder. | - fix quantization bug in AC3 encoder. | ||||
| - added GOB header parsing on H.263/H.263+ decoder. (Juanjo) | - added GOB header parsing on H.263/H.263+ decoder. (Juanjo) | ||||
| - bug fix on MCBPC tables of H.263. (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) | - 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 QuickTime files. (Juanjo) | ||||
| - now we can decode H.263 streams found on VIVO v1 files.(Juanjo) | - now we can decode H.263 streams found on VIVO v1 files.(Juanjo) | ||||
| @@ -115,6 +115,14 @@ typedef struct AVCodecContext { | |||||
| /* with a start code on some codecs like H.263 */ | /* with a start code on some codecs like H.263 */ | ||||
| /* This doesn't take account of any particular */ | /* This doesn't take account of any particular */ | ||||
| /* headers inside the transmited RTP payload */ | /* 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 */ | /* 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 */ | ||||
| @@ -62,7 +62,12 @@ void h263_encode_picture_header(MpegEncContext * s, int picture_number) | |||||
| int format; | int format; | ||||
| align_put_bits(&s->pb); | 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) / | put_bits(&s->pb, 8, ((s->picture_number * 30 * FRAME_RATE_BASE) / | ||||
| s->frame_rate) & 0xff); | s->frame_rate) & 0xff); | ||||
| @@ -151,22 +156,36 @@ int h263_encode_gob_header(MpegEncContext * s, int mb_line) | |||||
| if (pdif >= s->rtp_payload_size) { | if (pdif >= s->rtp_payload_size) { | ||||
| /* Bad luck, packet must be cut before */ | /* Bad luck, packet must be cut before */ | ||||
| align_put_bits(&s->pb); | 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; | s->ptr_lastgob = s->pb.buf_ptr; | ||||
| put_bits(&s->pb, 17, 1); /* GBSC */ | 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, 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 */ | put_bits(&s->pb, 5, s->qscale); /* GQUANT */ | ||||
| //fprintf(stderr,"\nGOB: %2d size: %d", s->gob_number - 1, pdif); | |||||
| return pdif; | return pdif; | ||||
| } else if (pdif + s->mb_line_avgsize >= s->rtp_payload_size) { | } else if (pdif + s->mb_line_avgsize >= s->rtp_payload_size) { | ||||
| /* Cut the packet before we can't */ | /* Cut the packet before we can't */ | ||||
| align_put_bits(&s->pb); | 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; | s->ptr_lastgob = s->pb.buf_ptr; | ||||
| put_bits(&s->pb, 17, 1); /* GBSC */ | 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, 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 */ | put_bits(&s->pb, 5, s->qscale); /* GQUANT */ | ||||
| //fprintf(stderr,"\nGOB: %2d size: %d", s->gob_number - 1, pdif); | |||||
| return pdif; | return pdif; | ||||
| } | } | ||||
| } | } | ||||
| @@ -413,20 +432,25 @@ static void h263_encode_block(MpegEncContext * s, DCTELEM * block, int n) | |||||
| RLTable *rl = &rl_inter; | RLTable *rl = &rl_inter; | ||||
| if (s->mb_intra) { | if (s->mb_intra) { | ||||
| /* DC coef */ | |||||
| level = block[0]; | |||||
| /* DC coef */ | |||||
| level = block[0]; | |||||
| /* 255 cannot be represented, so we clamp */ | /* 255 cannot be represented, so we clamp */ | ||||
| if (level > 254) { | if (level > 254) { | ||||
| level = 254; | level = 254; | ||||
| block[0] = 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 { | } else { | ||||
| i = 0; | |||||
| i = 0; | |||||
| } | } | ||||
| /* AC coefs */ | /* AC coefs */ | ||||
| @@ -1241,8 +1265,8 @@ int h263_decode_picture_header(MpegEncContext *s) | |||||
| /* picture header */ | /* picture header */ | ||||
| if (get_bits(&s->gb, 22) != 0x20) | if (get_bits(&s->gb, 22) != 0x20) | ||||
| return -1; | 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) | if (get_bits1(&s->gb) != 1) | ||||
| return -1; /* marker */ | return -1; /* marker */ | ||||
| if (get_bits1(&s->gb) != 0) | if (get_bits1(&s->gb) != 0) | ||||
| @@ -225,6 +225,11 @@ static int h263_decode_frame(AVCodecContext *avctx, | |||||
| pict->linesize[2] = s->linesize / 2; | pict->linesize[2] = s->linesize / 2; | ||||
| avctx->quality = s->qscale; | 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); | *data_size = sizeof(AVPicture); | ||||
| return buf_size; | return buf_size; | ||||
| } | } | ||||
| @@ -264,6 +264,8 @@ int MPV_encode_init(AVCodecContext *avctx) | |||||
| s->gop_size = avctx->gop_size; | s->gop_size = avctx->gop_size; | ||||
| s->rtp_mode = avctx->rtp_mode; | s->rtp_mode = avctx->rtp_mode; | ||||
| s->rtp_payload_size = avctx->rtp_payload_size; | s->rtp_payload_size = avctx->rtp_payload_size; | ||||
| if (avctx->rtp_callback) | |||||
| s->rtp_callback = avctx->rtp_callback; | |||||
| s->avctx = avctx; | s->avctx = avctx; | ||||
| if (s->gop_size <= 1) { | 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) | 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; | UINT8 *ptr; | ||||
| int i, motion_x, motion_y; | 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; | s->mv_dir = MV_DIR_FORWARD; | ||||
| /* Get the GOB height based on picture height */ | /* 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) | if (s->height <= 400) | ||||
| s->gob_index = 1; | s->gob_index = 1; | ||||
| else if (s->height <= 800) | 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++) { | for(mb_y=0; mb_y < s->mb_height; mb_y++) { | ||||
| /* Put GOB header based on RTP MTU */ | /* 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++) { | 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); | 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) | if (s->h263_msmpeg4) | ||||
| @@ -1061,6 +1068,18 @@ static void encode_picture(MpegEncContext *s, int picture_number) | |||||
| //if (s->gob_number) | //if (s->gob_number) | ||||
| // fprintf(stderr,"\nNumber of GOB: %d", 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, | static int dct_quantize_c(MpegEncContext *s, | ||||
| @@ -201,8 +201,10 @@ typedef struct MpegEncContext { | |||||
| int first_slice; | int first_slice; | ||||
| /* RTP specific */ | /* RTP specific */ | ||||
| /* These are explained on avcodec.h */ | |||||
| int rtp_mode; | int rtp_mode; | ||||
| int rtp_payload_size; | int rtp_payload_size; | ||||
| void (*rtp_callback)(void *data, int size, int packet_number); | |||||
| UINT8 *ptr_lastgob; | UINT8 *ptr_lastgob; | ||||
| UINT8 *ptr_last_mb_line; | UINT8 *ptr_last_mb_line; | ||||
| UINT32 mb_line_avgsize; | UINT32 mb_line_avgsize; | ||||