[FFmpeg-devel] [PATCH v3] avformat/rtpdec_rfc4175: support non-zero based line numbers
Kah Goh
villastar at yahoo.com.au
Thu Nov 7 16:27:31 EET 2019
On Mon, Sep 30, 2019 at 09:27:20PM +0800, Kah Goh wrote:
> There are differing standards that define different starting line
> numbers. For example, VSF TR-03 says the line numbers starts at 1,
> whereas SMPTE 2110-20 says it should start at 0.
>
> This change adds support for non-zero based line numbers and addresses
> the following issues when it starts at 1:
> - The first scan line was being incorrectly interpreted as the second
> scan line. This means the first line in the frame was never being
> populated.
> - The last packet for the video frame would be treated as invalid
> because it would have been copied outside of the frame. Consequently,
> the packet would never be "finalized" and the next packet triggers a
> missed RTP marker ("Missed previous RTP marker" would keep being
> logged).
>
> VSF TR-03: http://www.videoservicesforum.org/download/technical_recommendations/VSF_TR-03_2015-11-12.pdf
>
> Co-Authored-By: Jacob Siddall <kobe at live.com.au>
> Co-Authored-By: Kah Goh <villastar at yahoo.com.au>
> Signed-off-by: Kah Goh <villastar at yahoo.com.au>
> ---
> libavformat/rtpdec_rfc4175.c | 49 +++++++++++++++++++++++++++++++++---
> 1 file changed, 45 insertions(+), 4 deletions(-)
>
> diff --git a/libavformat/rtpdec_rfc4175.c b/libavformat/rtpdec_rfc4175.c
> index e9c62c1389..47d5d23dd6 100644
> --- a/libavformat/rtpdec_rfc4175.c
> +++ b/libavformat/rtpdec_rfc4175.c
> @@ -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,
> @@ -188,7 +202,7 @@ static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data,
>
> /* and now iterate over every scan lines */
> do {
> - int copy_offset;
> + int copy_offset, copy_to_line;
>
> if (payload_len < data->pgroup)
> return AVERROR_INVALIDDATA;
> @@ -199,17 +213,34 @@ 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;
>
> if (length > payload_len)
> 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)
> + copy_to_line = line - data->first_line_number;
> + if (copy_to_line < 0)
> + /* This means the first line number we have calculated is too large, which indicates that we
> + may have received some bad data. */
> return AVERROR_INVALIDDATA;
>
> + /* prevent ill-formed packets to write after buffer's end */
> + copy_offset = (copy_to_line * 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 +249,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 +272,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,
> };
> --
> 2.23.0
>
Ping
More information about the ffmpeg-devel
mailing list