diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index cb0e241329..41d584381b 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -453,7 +453,11 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) break; case CODEC_ID_H263: if (s->flags & FF_RTP_FLAG_RFC2190) { - ff_rtp_send_h263_rfc2190(s1, pkt->data, size); + int mb_info_size = 0; + const uint8_t *mb_info = + av_packet_get_side_data(pkt, AV_PKT_DATA_H263_MB_INFO, + &mb_info_size); + ff_rtp_send_h263_rfc2190(s1, pkt->data, size, mb_info, mb_info_size); break; } /* Fallthrough */ diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h index 2bb2b815c3..322cee061b 100644 --- a/libavformat/rtpenc.h +++ b/libavformat/rtpenc.h @@ -78,7 +78,8 @@ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size); -void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf1, int size); +void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf1, int size, + const uint8_t *mb_info, int mb_info_size); void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_latm(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size); diff --git a/libavformat/rtpenc_h263_rfc2190.c b/libavformat/rtpenc_h263_rfc2190.c index 305c1a27c8..f714d010f4 100644 --- a/libavformat/rtpenc_h263_rfc2190.c +++ b/libavformat/rtpenc_h263_rfc2190.c @@ -34,8 +34,15 @@ struct H263Info { int tr; }; +struct H263State { + int gobn; + int mba; + int hmv1, vmv1, hmv2, vmv2; + int quant; +}; + static void send_mode_a(AVFormatContext *s1, const struct H263Info *info, - const uint8_t *buf, int len, int m) + const uint8_t *buf, int len, int ebits, int m) { RTPMuxContext *s = s1->priv_data; PutBitContext pb; @@ -44,7 +51,7 @@ static void send_mode_a(AVFormatContext *s1, const struct H263Info *info, put_bits(&pb, 1, 0); /* F - 0, mode A */ put_bits(&pb, 1, 0); /* P - 0, normal I/P */ put_bits(&pb, 3, 0); /* SBIT - 0 bits */ - put_bits(&pb, 3, 0); /* EBIT - 0 bits */ + put_bits(&pb, 3, ebits); /* EBIT */ put_bits(&pb, 3, info->src); /* SRC - source format */ put_bits(&pb, 1, info->i); /* I - inter/intra */ put_bits(&pb, 1, info->u); /* U - unrestricted motion vector */ @@ -60,12 +67,47 @@ static void send_mode_a(AVFormatContext *s1, const struct H263Info *info, ff_rtp_send_data(s1, s->buf, len + 4, m); } -void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size) +static void send_mode_b(AVFormatContext *s1, const struct H263Info *info, + const struct H263State *state, const uint8_t *buf, + int len, int sbits, int ebits, int m) { RTPMuxContext *s = s1->priv_data; - int len; + PutBitContext pb; + + init_put_bits(&pb, s->buf, 64); + put_bits(&pb, 1, 1); /* F - 1, mode B */ + put_bits(&pb, 1, 0); /* P - 0, mode B */ + put_bits(&pb, 3, sbits); /* SBIT - 0 bits */ + put_bits(&pb, 3, ebits); /* EBIT - 0 bits */ + put_bits(&pb, 3, info->src); /* SRC - source format */ + put_bits(&pb, 5, state->quant); /* QUANT - quantizer for the first MB */ + put_bits(&pb, 5, state->gobn); /* GOBN - GOB number */ + put_bits(&pb, 9, state->mba); /* MBA - MB address */ + put_bits(&pb, 2, 0); /* R - reserved */ + put_bits(&pb, 1, info->i); /* I - inter/intra */ + put_bits(&pb, 1, info->u); /* U - unrestricted motion vector */ + put_bits(&pb, 1, info->s); /* S - syntax-baesd arithmetic coding */ + put_bits(&pb, 1, info->a); /* A - advanced prediction */ + put_bits(&pb, 7, state->hmv1); /* HVM1 - horizontal motion vector 1 */ + put_bits(&pb, 7, state->vmv1); /* VMV1 - vertical motion vector 1 */ + put_bits(&pb, 7, state->hmv2); /* HVM2 - horizontal motion vector 2 */ + put_bits(&pb, 7, state->vmv2); /* VMV2 - vertical motion vector 2 */ + flush_put_bits(&pb); + memcpy(s->buf + 8, buf, len); + + ff_rtp_send_data(s1, s->buf, len + 8, m); +} + +void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size, + const uint8_t *mb_info, int mb_info_size) +{ + RTPMuxContext *s = s1->priv_data; + int len, sbits = 0, ebits = 0; GetBitContext gb; struct H263Info info = { 0 }; + struct H263State state = { 0 }; + int mb_info_pos = 0, mb_info_count = mb_info_size / 12; + const uint8_t *buf_base = buf; s->timestamp = s->cur_timestamp; @@ -83,22 +125,71 @@ void ff_rtp_send_h263_rfc2190(AVFormatContext *s1, const uint8_t *buf, int size) } while (size > 0) { - len = FFMIN(s->max_payload_size - 4, size); + struct H263State packet_start_state = state; + len = FFMIN(s->max_payload_size - 8, size); /* Look for a better place to split the frame into packets. */ if (len < size) { const uint8_t *end = ff_h263_find_resync_marker_reverse(buf, buf + len); len = end - buf; - if (len == s->max_payload_size - 4) - av_log(s1, AV_LOG_WARNING, - "No GOB boundary found within MTU size, splitting at " - "a random boundary\n"); + if (len == s->max_payload_size - 8) { + /* Skip mb info prior to the start of the current ptr */ + while (mb_info_pos < mb_info_count) { + uint32_t pos = AV_RL32(&mb_info[12*mb_info_pos])/8; + if (pos >= buf - buf_base) + break; + mb_info_pos++; + } + /* Find the first mb info past the end pointer */ + while (mb_info_pos + 1 < mb_info_count) { + uint32_t pos = AV_RL32(&mb_info[12*(mb_info_pos + 1)])/8; + if (pos >= end - buf_base) + break; + mb_info_pos++; + } + if (mb_info_pos < mb_info_count) { + const uint8_t *ptr = &mb_info[12*mb_info_pos]; + uint32_t bit_pos = AV_RL32(ptr); + uint32_t pos = (bit_pos + 7)/8; + if (pos <= end - buf_base) { + state.quant = ptr[4]; + state.gobn = ptr[5]; + state.mba = AV_RL16(&ptr[6]); + state.hmv1 = (int8_t) ptr[8]; + state.vmv1 = (int8_t) ptr[9]; + state.hmv2 = (int8_t) ptr[10]; + state.vmv2 = (int8_t) ptr[11]; + ebits = 8 * pos - bit_pos; + len = pos - (buf - buf_base); + mb_info_pos++; + } else { + av_log(s1, AV_LOG_ERROR, + "Unable to split H263 packet, use -mb_info %d " + "or lower.\n", s->max_payload_size - 8); + } + } else { + av_log(s1, AV_LOG_ERROR, "Unable to split H263 packet, " + "use -mb_info %d or -ps 1.\n", + s->max_payload_size - 8); + } + } } - send_mode_a(s1, &info, buf, len, len == size); + if (size > 2 && !buf[0] && !buf[1]) + send_mode_a(s1, &info, buf, len, ebits, len == size); + else + send_mode_b(s1, &info, &packet_start_state, buf, len, sbits, + ebits, len == size); + if (ebits) { + sbits = 8 - ebits; + len--; + } else { + sbits = 0; + } buf += len; size -= len; + ebits = 0; } }