FFmpeg
rtpenc_h261.c
Go to the documentation of this file.
1 /*
2  * RTP packetization for H.261 video (RFC 4587)
3  * Copyright (c) 2014 Thomas Volkert <thomas@homer-conferencing.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "avformat.h"
23 #include "rtpenc.h"
24 
25 #define RTP_H261_HEADER_SIZE 4
26 
27 static const uint8_t *find_resync_marker_reverse(const uint8_t *restrict start,
28  const uint8_t *restrict end)
29 {
30  const uint8_t *p = end - 1;
31  start += 1; /* Make sure we never return the original start. */
32  for (; p > start; p--) {
33  if (p[0] == 0 && p[1] == 1)
34  return p;
35  }
36  return end;
37 }
38 
39 void ff_rtp_send_h261(AVFormatContext *ctx, const uint8_t *frame_buf, int frame_size)
40 {
41  int cur_frame_size;
42  int last_packet_of_frame;
43  RTPMuxContext *rtp_ctx = ctx->priv_data;
44 
45  /* use the default 90 KHz time stamp */
46  rtp_ctx->timestamp = rtp_ctx->cur_timestamp;
47 
48  /* continue as long as not all frame data is processed */
49  while (frame_size > 0) {
50  /*
51  * encode the H.261 payload header according to section 4.1 of RFC 4587:
52  * (uses 4 bytes between RTP header and H.261 stream per packet)
53  *
54  * 0 1 2 3
55  * 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
56  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57  * |SBIT |EBIT |I|V| GOBN | MBAP | QUANT | HMVD | VMVD |
58  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59  *
60  * Start bit position (SBIT): 3 bits
61  * End bit position (EBIT): 3 bits
62  * INTRA-frame encoded data (I): 1 bit
63  * Motion Vector flag (V): 1 bit
64  * GOB number (GOBN): 4 bits
65  * Macroblock address predictor (MBAP): 5 bits
66  * Quantizer (QUANT): 5 bits
67  * Horizontal motion vector data (HMVD): 5 bits
68  * Vertical motion vector data (VMVD): 5 bits
69  */
70  rtp_ctx->buf[0] = 1; /* sbit=0, ebit=0, i=0, v=1 */
71  rtp_ctx->buf[1] = 0; /* gobn=0, mbap=0 */
72  rtp_ctx->buf[2] = 0; /* quant=0, hmvd=5 */
73  rtp_ctx->buf[3] = 0; /* vmvd=0 */
74  if (frame_size < 2 || frame_buf[0] != 0 || frame_buf[1] != 1) {
75  /* A full, correct fix for this would be to make the H.261 encoder
76  * support inserting extra GOB headers (triggered by setting e.g.
77  * "-ps 1"), and including information about macroblock boundaries
78  * (such as for h263_rfc2190). */
80  "RTP/H.261 packet not cut at a GOB boundary, not signaled correctly\n");
81  }
82 
83  cur_frame_size = FFMIN(rtp_ctx->max_payload_size - RTP_H261_HEADER_SIZE, frame_size);
84 
85  /* look for a better place to split the frame into packets */
86  if (cur_frame_size < frame_size) {
87  const uint8_t *packet_end = find_resync_marker_reverse(frame_buf,
88  frame_buf + cur_frame_size);
89  cur_frame_size = packet_end - frame_buf;
90  }
91 
92  /* calculate the "marker" bit for the RTP header */
93  last_packet_of_frame = cur_frame_size == frame_size;
94 
95  /* complete and send RTP packet */
96  memcpy(&rtp_ctx->buf[RTP_H261_HEADER_SIZE], frame_buf, cur_frame_size);
97  ff_rtp_send_data(ctx, rtp_ctx->buf, RTP_H261_HEADER_SIZE + cur_frame_size, last_packet_of_frame);
98 
99  frame_buf += cur_frame_size;
100  frame_size -= cur_frame_size;
101  }
102 }
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
ff_rtp_send_data
void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m)
Definition: rtpenc.c:336
RTP_H261_HEADER_SIZE
#define RTP_H261_HEADER_SIZE
Definition: rtpenc_h261.c:25
frame_size
int frame_size
Definition: mxfenc.c:2429
ctx
AVFormatContext * ctx
Definition: movenc.c:49
RTPMuxContext::cur_timestamp
uint32_t cur_timestamp
Definition: rtpenc.h:37
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
find_resync_marker_reverse
static const uint8_t * find_resync_marker_reverse(const uint8_t *restrict start, const uint8_t *restrict end)
Definition: rtpenc_h261.c:27
RTPMuxContext
Definition: rtpenc.h:27
RTPMuxContext::buf
uint8_t * buf
Definition: rtpenc.h:49
RTPMuxContext::timestamp
uint32_t timestamp
Definition: rtpenc.h:35
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
rtpenc.h
avformat.h
ff_rtp_send_h261
void ff_rtp_send_h261(AVFormatContext *ctx, const uint8_t *frame_buf, int frame_size)
Definition: rtpenc_h261.c:39
RTPMuxContext::max_payload_size
int max_payload_size
Definition: rtpenc.h:38
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1328