@@ -25,6 +25,7 @@
#include "rtpdec_formats.h"
#include "libavutil/avstring.h"
#include "libavutil/pixdesc.h"
+#include <stdbool.h>
struct PayloadContext {
char *sampling;
@@ -37,6 +38,12 @@ struct PayloadContext {
unsigned int pgroup; /* size of the pixel group in bytes */
unsigned int xinc;
+ /* The line number of the first line in the frame (usually either 0 or 1). */
+ int first_line_number;
+
+ /* This is set to true once the first line number is confirmed. */
+ bool first_line_number_known;
+
uint32_t timestamp;
};
@@ -136,6 +143,13 @@ static int rfc4175_finalize_packet(PayloadContext *data, AVPacket *pkt,
return ret;
}
+static int rfc4175_initialize(AVFormatContext *s, int st_index, PayloadContext *data)
+{
+ data->first_line_number = 0;
+ data->first_line_number_known = false;
+ return 0;
+}
+
static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
AVStream *st, AVPacket *pkt, uint32_t *timestamp,
const uint8_t * buf, int len,
@@ -199,6 +213,11 @@ static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
cont = headers[4] & 0x80;
headers += 6;
+ if (line == 0) {
+ data->first_line_number = 0;
+ data->first_line_number_known = true;
+ }
+
if (length % data->pgroup)
return AVERROR_INVALIDDATA;
@@ -206,9 +225,15 @@ static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
length = payload_len;
/* prevent ill-formed packets to write after buffer's end */
- copy_offset = (line * data->width + offset) * data->pgroup / data->xinc;
- if (copy_offset + length > data->frame_size)
- return AVERROR_INVALIDDATA;
+ copy_offset = ((line - data->first_line_number) * data->width + offset) * data->pgroup / data->xinc;
+ if (copy_offset + length > data->frame_size) {
+ if (data->first_line_number_known)
+ return AVERROR_INVALIDDATA;
+
+ // This would happen if the line numbering is 1 based. We still need to check for the RTP flag
+ // marker (as per after the while loop).
+ break;
+ }
dest = data->frame + copy_offset;
memcpy(dest, payload, length);
@@ -218,6 +243,15 @@ static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
} while (cont);
if ((flags & RTP_FLAG_MARKER)) {
+ if (!data->first_line_number_known) {
+ data->first_line_number = line - data->height + 1;
+ if (data->first_line_number < 0) {
+ // This could happen if the frame does not fill up the entire height.
+ data->first_line_number = 0;
+ av_log(ctx, AV_LOG_WARNING, "Video frame does not fill entire height");
+ }
+ data->first_line_number_known = true;
+ }
return rfc4175_finalize_packet(data, pkt, st->index);
} else if (missed_last_packet) {
return 0;
@@ -232,5 +266,6 @@ const RTPDynamicProtocolHandler ff_rfc4175_rtp_handler = {
.codec_id = AV_CODEC_ID_BITPACKED,
.priv_data_size = sizeof(PayloadContext),
.parse_sdp_a_line = rfc4175_parse_sdp_line,
+ .init = rfc4175_initialize,
.parse_packet = rfc4175_handle_packet,
};