On Sat, 6 Dec 2014, Thomas Volkert wrote:
From: Thomas Volkert <[email protected]>
---
Changelog | 1 +
libavcodec/h261.h | 1 +
libavcodec/h261enc.c | 4 +-
libavcodec/mpegvideo_enc.c | 10 +++
libavformat/Makefile | 2 +
libavformat/rtpdec.c | 1 +
libavformat/rtpdec_formats.h | 1 +
libavformat/rtpdec_h261.c | 202 +++++++++++++++++++++++++++++++++++++++++++
libavformat/rtpenc.c | 4 +
libavformat/rtpenc.h | 1 +
libavformat/rtpenc_h261.c | 85 ++++++++++++++++++
libavformat/sdp.c | 13 +++
libavformat/version.h | 4 +-
13 files changed, 325 insertions(+), 4 deletions(-)
create mode 100644 libavformat/rtpdec_h261.c
create mode 100644 libavformat/rtpenc_h261.c
diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index 8775eac..8d3849b 100644
--- a/libavcodec/mpegvideo_enc.c
+++ b/libavcodec/mpegvideo_enc.c
@@ -2623,6 +2623,12 @@ static int encode_thread(AVCodecContext *c, void *arg){
if(s->start_mb_y == mb_y && mb_y > 0 && mb_x==0) is_gob_start=1;
switch(s->codec_id){
+ case AV_CODEC_ID_H261:
+ //FIXME: hard-coded deactivation of extra GOB headers
within frames,
+ // it allows for a correct h261 video stream and
correct presentation at receiver side,
+ // but it does not support decoding restart of a
frame halfway through a packet
+ is_gob_start=0;
+ break;
case AV_CODEC_ID_H263:
case AV_CODEC_ID_H263P:
if(!s->h263_slice_structured)
Ok, so I finally had a closer look at this. The issue seems to be that the
h261 encoder doesn't support encoding "slices" (or including extra GOB
headers inside the frame), even after your change to try to call
ff_h261_encode_gob_header below.
To reproduce this issue, try e.g.
./avconv -i ... -s 176x144 -an -c:v h261 test.avi
(which plays back just fine with avplay)
./avconv -i ... -s 176x144 -an -c:v h261 -ps 1 test.avi
(which produces an avi which doesn't decode correctly)
Note that as long as the caller doesn't ever set the -ps parameter (or the
rtp_payload_size field), this never was an issue at all.
Instead of trying to enable "slicing" and then disabling it here with a
FIXME, we can just disable rtp_mode earlier in the initialization.
+static int h261_handle_packet(AVFormatContext *ctx, PayloadContext
*rtp_h261_ctx,
+ AVStream *st, AVPacket *pkt, uint32_t *timestamp,
+ const uint8_t *buf, int len, uint16_t seq,
+ int flags)
+{
+ int sbit, ebit, gobn, mbap, quant;
+ int res;
+
+ /* drop data of previous packets in case of non-continuous (loss) packet
stream */
+ if (rtp_h261_ctx->buf && rtp_h261_ctx->timestamp != *timestamp) {
+ h261_free_dyn_buffer(&rtp_h261_ctx->buf);
+ }
At this point we should clear the endbyte_bits field as well, so we won't
try to use some buffered bits from an earlier frame - I noticed this is
missing in rtpdec_h263_rfc2190.c as well, I'll fix that separately.
I'm generally not a huge fan of naming a commonly used context (which is
used all over this function) something as verbose as rtp_h261_ctx - but I
guess that's a personal opinion.
diff --git a/libavformat/rtpenc_h261.c b/libavformat/rtpenc_h261.c
new file mode 100644
index 0000000..f7cf5cc
--- /dev/null
+++ b/libavformat/rtpenc_h261.c
@@ -0,0 +1,85 @@
+/*
+ * RTP packetization for H.261 video (RFC 4587)
+ * Copyright (c) 2014 Thomas Volkert <[email protected]>
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avformat.h"
+#include "rtpenc.h"
+
+#define RTP_H261_HEADER_SIZE 4
+
+void ff_rtp_send_h261(AVFormatContext *ctx, const uint8_t *frame_buf, int
frame_size)
+{
+ int cur_frame_size;
+ int last_packet_of_frame;
+ int max_packet_size;
+ RTPMuxContext *rtp_ctx = ctx->priv_data;
+
+ /* use the default 90 KHz time stamp */
+ rtp_ctx->timestamp = rtp_ctx->cur_timestamp;
+ max_packet_size = rtp_ctx->max_payload_size;
+
+ /* continue as long as not all frame data is processed */
+ while (frame_size > 0) {
+ /*
+ encode the H.261 payload header according to section 4.1 of RFC 4587:
+ (uses 4 bytes between RTP header and H.261 stream per packet)
+
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |SBIT |EBIT |I|V| GOBN | MBAP | QUANT | HMVD | VMVD |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Start bit position (SBIT): 3 bits
+ End bit position (EBIT): 3 bits
+ INTRA-frame encoded data (I): 1 bit
+ Motion Vector flag (V): 1 bit
+ GOB number (GOBN): 4 bits
+ Macroblock address predictor (MBAP): 5 bits
+ Quantizer (QUANT): 5 bits
+ Horizontal motion vector data (HMVD): 5 bits
+ Vertical motion vector data (VMVD): 5 bits
+
+ */
+ rtp_ctx->buf[0] = 1;
+ rtp_ctx->buf[1] = 0;
+ rtp_ctx->buf[2] = 0;
+ rtp_ctx->buf[3] = 0;
This pretends that we actually start at a GOB boundary, but if such
markers aren't available, we just cut blindly, and these fields lie about
the content of the packet - that's not nice. We should at least warn the
user about this - if the receiver happens to be able to decode it
correctly despite this, that's good, but strictly speaking, we're
generating incorrect data.
+
+ cur_frame_size = FFMIN(max_packet_size - RTP_H261_HEADER_SIZE,
frame_size);
+
+ /* look for a better place to split the frame into packets. */
+ if (cur_frame_size < frame_size) {
+ const uint8_t *packet_end =
ff_h263_find_resync_marker_reverse(frame_buf,
+
frame_buf + cur_frame_size);
+ cur_frame_size = packet_end - frame_buf;
H261 doesn't use the same resync marker as H263, so this doesn't work.
Instead of looking for 0x00, 0x00, you should be looking for 0x00, 0x01.
But as long as we have disabled the insertion of extra GOB headers in the
encoder, this won't ever actually find anything.
I'll send a new patchset that fixes the issues I points out, and does some
minor cleanups as I preferred things.
// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel