[FFmpeg-devel] [PATCH] libavformat/rtpdec_jpeg.c: quantization table headers not sent in every frame packet
Hayden Myers
HMyers at skylinenet.net
Tue Aug 24 02:23:12 EEST 2021
MJPEG streams coming from Genetec VMS provide a quantization table
for each frame, but only in the first packet. Before the packet data is
copied to the frame buffer, a check is done to compare the fragment
offset against the frame - header. The header is computed at
the beginning of each frame. The offset ends up with a value of -132
because the header size includes the quantization table data, but the
packet buffer doesn't.
Created a function to detect if a quantization header isn't present when
it should be, and use this to offset the extra bytes reported in the
jpeg header.
Signed-off-by: Hayden Myers <hmyers at skylinenet.net>
cleanup
---
libavformat/rtpdec_jpeg.c | 54 ++++++++++++++++++++++++++++++++++++---
1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/libavformat/rtpdec_jpeg.c b/libavformat/rtpdec_jpeg.c
index b32d074136..6e1c6d6b44 100644
--- a/libavformat/rtpdec_jpeg.c
+++ b/libavformat/rtpdec_jpeg.c
@@ -211,6 +211,52 @@ static void create_default_qtables(uint8_t *qtables, uint8_t q)
}
}
+/*
+ * If the q header isn't present in th packet, subtract from the
+ * jpeg header. The first packet in the frame could contain the q header.
+ *
+ * Some implementation do not include the quanization header with each packet.
+ * I'm specifically calling out Genetec VMS, but it could be rooted in specific
+ * cameras.
+ *
+ * @param ctx - The context, just used for logging.
+ * @param buf - current packet buffer
+ * @param q - quantizer value
+ *
+ * @return the number of bytes to remove if q header isn't present in the packet
+ * ,or 0 if the header is detected, or q <=127.
+ *
+ */
+static int get_q_hdr_bytes_to_remove(AVFormatContext *ctx, const uint8_t *buf,
+ uint8_t q)
+{
+ int ret=0, mbz=0, precision=0;
+
+ /* Use the first byte to detect if the quantization table header is
+ * present. If mbz isn't zero, and the precision byte isn't <= 1 quant
+ * table isn't present, and we're into jpeg image payload data already.
+ */
+ mbz = AV_RB8(buf); /* reserved byte should always be 0 */
+ precision = AV_RB8(buf + 1); /* size of coefficients */
+ /* best attempt to determine if the q header is present. Dont remove
+ * anything if a qtable is detected or q < 128.
+ */
+ if ((mbz == 0 && precision <= 1) || q < 128) {
+ ret = 0;
+ // no header detected in pkt, must remove q hdr bytes
+ } else {
+ //1 byte - reserved MBZ
+ //1 byte - precision
+ //2 bytes - length
+ ret += 4;
+ //128 bytes - 2 * 64 byte tables (8bit precision)
+ ret += 128;
+ av_log(ctx,AV_LOG_WARNING,
+ "Q header missing, reducing jpeg->hdr_size\n");
+ }
+ return ret;
+}
+
static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
AVStream *st, AVPacket *pkt, uint32_t *timestamp,
const uint8_t *buf, int len, uint16_t seq,
@@ -220,7 +266,7 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
const uint8_t *qtables = NULL;
uint16_t qtable_len;
uint32_t off;
- int ret, dri = 0;
+ int ret, dri = 0, q_hdr_bytes_to_remove = 0;
if (len < 8) {
av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
@@ -235,6 +281,7 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
height = AV_RB8(buf + 7); /* frame height in 8 pixel blocks */
buf += 8;
len -= 8;
+ q_hdr_bytes_to_remove = get_q_hdr_bytes_to_remove(ctx, buf, q);
if (type & 0x40) {
if (len < 4) {
@@ -350,9 +397,8 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
return AVERROR_INVALIDDATA;
}
- if (off != avio_tell(jpeg->frame) - jpeg->hdr_size) {
- av_log(ctx, AV_LOG_ERROR,
- "Missing packets; dropping frame.\n");
+ if (off != (avio_tell(jpeg->frame) - (jpeg->hdr_size - q_hdr_bytes_to_remove))) {
+ av_log(ctx, AV_LOG_ERROR, "Missing packets; dropping frame.\n");
return AVERROR(EAGAIN);
}
--
2.20.1
Hayden Myers
Principal Software Engineer
t: (410) 590-2027
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image219806.png
Type: image/png
Size: 36556 bytes
Desc: image219806.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image702984.png
Type: image/png
Size: 7149 bytes
Desc: image702984.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image797673.png
Type: image/png
Size: 842 bytes
Desc: image797673.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment-0002.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image774070.png
Type: image/png
Size: 817 bytes
Desc: image774070.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment-0003.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image207987.png
Type: image/png
Size: 919 bytes
Desc: image207987.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment-0004.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image579044.png
Type: image/png
Size: 653 bytes
Desc: image579044.png
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20210823/cfaf0f9b/attachment-0005.png>
More information about the ffmpeg-devel
mailing list