yading@11: /* yading@11: * RTP JPEG-compressed Video Depacketizer, RFC 2435 yading@11: * Copyright (c) 2012 Samuel Pitoiset yading@11: * yading@11: * This file is part of FFmpeg. yading@11: * yading@11: * FFmpeg is free software; you can redistribute it and/or yading@11: * modify it under the terms of the GNU Lesser General Public yading@11: * License as published by the Free Software Foundation; either yading@11: * version 2.1 of the License, or (at your option) any later version. yading@11: * yading@11: * FFmpeg is distributed in the hope that it will be useful, yading@11: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@11: * Lesser General Public License for more details. yading@11: * yading@11: * You should have received a copy of the GNU Lesser General Public yading@11: * License along with FFmpeg; if not, write to the Free Software yading@11: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@11: */ yading@11: yading@11: #include "avformat.h" yading@11: #include "rtpdec.h" yading@11: #include "rtpdec_formats.h" yading@11: #include "libavutil/intreadwrite.h" yading@11: #include "libavcodec/mjpeg.h" yading@11: #include "libavcodec/bytestream.h" yading@11: yading@11: /** yading@11: * RTP/JPEG specific private data. yading@11: */ yading@11: struct PayloadContext { yading@11: AVIOContext *frame; ///< current frame buffer yading@11: uint32_t timestamp; ///< current frame timestamp yading@11: int hdr_size; ///< size of the current frame header yading@11: uint8_t qtables[128][128]; yading@11: uint8_t qtables_len[128]; yading@11: }; yading@11: yading@11: static const uint8_t default_quantizers[128] = { yading@11: /* luma table */ yading@11: 16, 11, 12, 14, 12, 10, 16, 14, yading@11: 13, 14, 18, 17, 16, 19, 24, 40, yading@11: 26, 24, 22, 22, 24, 49, 35, 37, yading@11: 29, 40, 58, 51, 61, 60, 57, 51, yading@11: 56, 55, 64, 72, 92, 78, 64, 68, yading@11: 87, 69, 55, 56, 80, 109, 81, 87, yading@11: 95, 98, 103, 104, 103, 62, 77, 113, yading@11: 121, 112, 100, 120, 92, 101, 103, 99, yading@11: yading@11: /* chroma table */ yading@11: 17, 18, 18, 24, 21, 24, 47, 26, yading@11: 26, 47, 99, 66, 56, 66, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99, yading@11: 99, 99, 99, 99, 99, 99, 99, 99 yading@11: }; yading@11: yading@11: static PayloadContext *jpeg_new_context(void) yading@11: { yading@11: return av_mallocz(sizeof(PayloadContext)); yading@11: } yading@11: yading@11: static inline void free_frame_if_needed(PayloadContext *jpeg) yading@11: { yading@11: if (jpeg->frame) { yading@11: uint8_t *p; yading@11: avio_close_dyn_buf(jpeg->frame, &p); yading@11: av_free(p); yading@11: jpeg->frame = NULL; yading@11: } yading@11: } yading@11: yading@11: static void jpeg_free_context(PayloadContext *jpeg) yading@11: { yading@11: free_frame_if_needed(jpeg); yading@11: av_free(jpeg); yading@11: } yading@11: yading@11: static int jpeg_create_huffman_table(PutByteContext *p, int table_class, yading@11: int table_id, const uint8_t *bits_table, yading@11: const uint8_t *value_table) yading@11: { yading@11: int i, n = 0; yading@11: yading@11: bytestream2_put_byte(p, table_class << 4 | table_id); yading@11: yading@11: for (i = 1; i <= 16; i++) { yading@11: n += bits_table[i]; yading@11: bytestream2_put_byte(p, bits_table[i]); yading@11: } yading@11: yading@11: for (i = 0; i < n; i++) { yading@11: bytestream2_put_byte(p, value_table[i]); yading@11: } yading@11: return n + 17; yading@11: } yading@11: yading@11: static void jpeg_put_marker(PutByteContext *pbc, int code) yading@11: { yading@11: bytestream2_put_byte(pbc, 0xff); yading@11: bytestream2_put_byte(pbc, code); yading@11: } yading@11: yading@11: static int jpeg_create_header(uint8_t *buf, int size, uint32_t type, uint32_t w, yading@11: uint32_t h, const uint8_t *qtable, int nb_qtable) yading@11: { yading@11: PutByteContext pbc; yading@11: uint8_t *dht_size_ptr; yading@11: int dht_size, i; yading@11: yading@11: bytestream2_init_writer(&pbc, buf, size); yading@11: yading@11: /* Convert from blocks to pixels. */ yading@11: w <<= 3; yading@11: h <<= 3; yading@11: yading@11: /* SOI */ yading@11: jpeg_put_marker(&pbc, SOI); yading@11: yading@11: /* JFIF header */ yading@11: jpeg_put_marker(&pbc, APP0); yading@11: bytestream2_put_be16(&pbc, 16); yading@11: bytestream2_put_buffer(&pbc, "JFIF", 5); yading@11: bytestream2_put_be16(&pbc, 0x0201); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: bytestream2_put_be16(&pbc, 1); yading@11: bytestream2_put_be16(&pbc, 1); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: yading@11: /* DQT */ yading@11: jpeg_put_marker(&pbc, DQT); yading@11: bytestream2_put_be16(&pbc, 2 + nb_qtable * (1 + 64)); yading@11: yading@11: for (i = 0; i < nb_qtable; i++) { yading@11: bytestream2_put_byte(&pbc, i); yading@11: yading@11: /* Each table is an array of 64 values given in zig-zag yading@11: * order, identical to the format used in a JFIF DQT yading@11: * marker segment. */ yading@11: bytestream2_put_buffer(&pbc, qtable + 64 * i, 64); yading@11: } yading@11: yading@11: /* DHT */ yading@11: jpeg_put_marker(&pbc, DHT); yading@11: dht_size_ptr = pbc.buffer; yading@11: bytestream2_put_be16(&pbc, 0); yading@11: yading@11: dht_size = 2; yading@11: dht_size += jpeg_create_huffman_table(&pbc, 0, 0,avpriv_mjpeg_bits_dc_luminance, yading@11: avpriv_mjpeg_val_dc); yading@11: dht_size += jpeg_create_huffman_table(&pbc, 0, 1, avpriv_mjpeg_bits_dc_chrominance, yading@11: avpriv_mjpeg_val_dc); yading@11: dht_size += jpeg_create_huffman_table(&pbc, 1, 0, avpriv_mjpeg_bits_ac_luminance, yading@11: avpriv_mjpeg_val_ac_luminance); yading@11: dht_size += jpeg_create_huffman_table(&pbc, 1, 1, avpriv_mjpeg_bits_ac_chrominance, yading@11: avpriv_mjpeg_val_ac_chrominance); yading@11: AV_WB16(dht_size_ptr, dht_size); yading@11: yading@11: /* SOF0 */ yading@11: jpeg_put_marker(&pbc, SOF0); yading@11: bytestream2_put_be16(&pbc, 17); /* size */ yading@11: bytestream2_put_byte(&pbc, 8); /* bits per component */ yading@11: bytestream2_put_be16(&pbc, h); yading@11: bytestream2_put_be16(&pbc, w); yading@11: bytestream2_put_byte(&pbc, 3); /* number of components */ yading@11: bytestream2_put_byte(&pbc, 1); /* component number */ yading@11: bytestream2_put_byte(&pbc, (2 << 4) | (type ? 2 : 1)); /* hsample/vsample */ yading@11: bytestream2_put_byte(&pbc, 0); /* matrix number */ yading@11: bytestream2_put_byte(&pbc, 2); /* component number */ yading@11: bytestream2_put_byte(&pbc, 1 << 4 | 1); /* hsample/vsample */ yading@11: bytestream2_put_byte(&pbc, nb_qtable == 2 ? 1 : 0); /* matrix number */ yading@11: bytestream2_put_byte(&pbc, 3); /* component number */ yading@11: bytestream2_put_byte(&pbc, 1 << 4 | 1); /* hsample/vsample */ yading@11: bytestream2_put_byte(&pbc, nb_qtable == 2 ? 1 : 0); /* matrix number */ yading@11: yading@11: /* SOS */ yading@11: jpeg_put_marker(&pbc, SOS); yading@11: bytestream2_put_be16(&pbc, 12); yading@11: bytestream2_put_byte(&pbc, 3); yading@11: bytestream2_put_byte(&pbc, 1); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: bytestream2_put_byte(&pbc, 2); yading@11: bytestream2_put_byte(&pbc, 17); yading@11: bytestream2_put_byte(&pbc, 3); yading@11: bytestream2_put_byte(&pbc, 17); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: bytestream2_put_byte(&pbc, 63); yading@11: bytestream2_put_byte(&pbc, 0); yading@11: yading@11: /* Return the length in bytes of the JPEG header. */ yading@11: return bytestream2_tell_p(&pbc); yading@11: } yading@11: yading@11: static void create_default_qtables(uint8_t *qtables, uint8_t q) yading@11: { yading@11: int factor = q; yading@11: int i; yading@11: yading@11: factor = av_clip(q, 1, 99); yading@11: yading@11: if (q < 50) yading@11: q = 5000 / factor; yading@11: else yading@11: q = 200 - factor * 2; yading@11: yading@11: for (i = 0; i < 128; i++) { yading@11: int val = (default_quantizers[i] * q + 50) / 100; yading@11: yading@11: /* Limit the quantizers to 1 <= q <= 255. */ yading@11: val = av_clip(val, 1, 255); yading@11: qtables[i] = val; yading@11: } yading@11: } yading@11: yading@11: static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg, yading@11: AVStream *st, AVPacket *pkt, uint32_t *timestamp, yading@11: const uint8_t *buf, int len, uint16_t seq, yading@11: int flags) yading@11: { yading@11: uint8_t type, q, width, height; yading@11: const uint8_t *qtables = NULL; yading@11: uint16_t qtable_len; yading@11: uint32_t off; yading@11: int ret; yading@11: yading@11: if (len < 8) { yading@11: av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: yading@11: /* Parse the main JPEG header. */ yading@11: off = AV_RB24(buf + 1); /* fragment byte offset */ yading@11: type = AV_RB8(buf + 4); /* id of jpeg decoder params */ yading@11: q = AV_RB8(buf + 5); /* quantization factor (or table id) */ yading@11: width = AV_RB8(buf + 6); /* frame width in 8 pixel blocks */ yading@11: height = AV_RB8(buf + 7); /* frame height in 8 pixel blocks */ yading@11: buf += 8; yading@11: len -= 8; yading@11: yading@11: /* Parse the restart marker header. */ yading@11: if (type > 63) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Unimplemented RTP/JPEG restart marker header.\n"); yading@11: return AVERROR_PATCHWELCOME; yading@11: } yading@11: if (type > 1) { yading@11: av_log(ctx, AV_LOG_ERROR, "Unimplemented RTP/JPEG type %d\n", type); yading@11: return AVERROR_PATCHWELCOME; yading@11: } yading@11: yading@11: /* Parse the quantization table header. */ yading@11: if (off == 0) { yading@11: /* Start of JPEG data packet. */ yading@11: uint8_t new_qtables[128]; yading@11: uint8_t hdr[1024]; yading@11: yading@11: if (q > 127) { yading@11: uint8_t precision; yading@11: if (len < 4) { yading@11: av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: yading@11: /* The first byte is reserved for future use. */ yading@11: precision = AV_RB8(buf + 1); /* size of coefficients */ yading@11: qtable_len = AV_RB16(buf + 2); /* length in bytes */ yading@11: buf += 4; yading@11: len -= 4; yading@11: yading@11: if (precision) yading@11: av_log(ctx, AV_LOG_WARNING, "Only 8-bit precision is supported.\n"); yading@11: yading@11: if (qtable_len > 0) { yading@11: if (len < qtable_len) { yading@11: av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: qtables = buf; yading@11: buf += qtable_len; yading@11: len -= qtable_len; yading@11: if (q < 255) { yading@11: if (jpeg->qtables_len[q - 128] && yading@11: (jpeg->qtables_len[q - 128] != qtable_len || yading@11: memcmp(qtables, &jpeg->qtables[q - 128][0], qtable_len))) { yading@11: av_log(ctx, AV_LOG_WARNING, yading@11: "Quantization tables for q=%d changed\n", q); yading@11: } else if (!jpeg->qtables_len[q - 128] && qtable_len <= 128) { yading@11: memcpy(&jpeg->qtables[q - 128][0], qtables, yading@11: qtable_len); yading@11: jpeg->qtables_len[q - 128] = qtable_len; yading@11: } yading@11: } yading@11: } else { yading@11: if (q == 255) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Invalid RTP/JPEG packet. Quantization tables not found.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: if (!jpeg->qtables_len[q - 128]) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "No quantization tables known for q=%d yet.\n", q); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: qtables = &jpeg->qtables[q - 128][0]; yading@11: qtable_len = jpeg->qtables_len[q - 128]; yading@11: } yading@11: } else { /* q <= 127 */ yading@11: if (q == 0 || q > 99) { yading@11: av_log(ctx, AV_LOG_ERROR, "Reserved q value %d\n", q); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: create_default_qtables(new_qtables, q); yading@11: qtables = new_qtables; yading@11: qtable_len = sizeof(new_qtables); yading@11: } yading@11: yading@11: /* Skip the current frame in case of the end packet yading@11: * has been lost somewhere. */ yading@11: free_frame_if_needed(jpeg); yading@11: yading@11: if ((ret = avio_open_dyn_buf(&jpeg->frame)) < 0) yading@11: return ret; yading@11: jpeg->timestamp = *timestamp; yading@11: yading@11: /* Generate a frame and scan headers that can be prepended to the yading@11: * RTP/JPEG data payload to produce a JPEG compressed image in yading@11: * interchange format. */ yading@11: jpeg->hdr_size = jpeg_create_header(hdr, sizeof(hdr), type, width, yading@11: height, qtables, yading@11: qtable_len / 64); yading@11: yading@11: /* Copy JPEG header to frame buffer. */ yading@11: avio_write(jpeg->frame, hdr, jpeg->hdr_size); yading@11: } yading@11: yading@11: if (!jpeg->frame) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Received packet without a start chunk; dropping frame.\n"); yading@11: return AVERROR(EAGAIN); yading@11: } yading@11: yading@11: if (jpeg->timestamp != *timestamp) { yading@11: /* Skip the current frame if timestamp is incorrect. yading@11: * A start packet has been lost somewhere. */ yading@11: free_frame_if_needed(jpeg); yading@11: av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match.\n"); yading@11: return AVERROR_INVALIDDATA; yading@11: } yading@11: yading@11: if (off != avio_tell(jpeg->frame) - jpeg->hdr_size) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Missing packets; dropping frame.\n"); yading@11: return AVERROR(EAGAIN); yading@11: } yading@11: yading@11: /* Copy data to frame buffer. */ yading@11: avio_write(jpeg->frame, buf, len); yading@11: yading@11: if (flags & RTP_FLAG_MARKER) { yading@11: /* End of JPEG data packet. */ yading@11: uint8_t buf[2] = { 0xff, EOI }; yading@11: yading@11: /* Put EOI marker. */ yading@11: avio_write(jpeg->frame, buf, sizeof(buf)); yading@11: yading@11: /* Prepare the JPEG packet. */ yading@11: if ((ret = ff_rtp_finalize_packet(pkt, &jpeg->frame, st->index)) < 0) { yading@11: av_log(ctx, AV_LOG_ERROR, yading@11: "Error occurred when getting frame buffer.\n"); yading@11: return ret; yading@11: } yading@11: yading@11: return 0; yading@11: } yading@11: yading@11: return AVERROR(EAGAIN); yading@11: } yading@11: yading@11: RTPDynamicProtocolHandler ff_jpeg_dynamic_handler = { yading@11: .enc_name = "JPEG", yading@11: .codec_type = AVMEDIA_TYPE_VIDEO, yading@11: .codec_id = AV_CODEC_ID_MJPEG, yading@11: .alloc = jpeg_new_context, yading@11: .free = jpeg_free_context, yading@11: .parse_packet = jpeg_parse_packet, yading@11: .static_payload_id = 26, yading@11: };