1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * RTP JPEG-compressed video Packetizer, RFC 2435
3cabdff1aSopenharmony_ci * Copyright (c) 2012 Samuel Pitoiset
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include "libavcodec/bytestream.h"
23cabdff1aSopenharmony_ci#include "libavcodec/mjpeg.h"
24cabdff1aSopenharmony_ci#include "libavcodec/jpegtables.h"
25cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
26cabdff1aSopenharmony_ci#include "rtpenc.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_civoid ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buf, int size)
29cabdff1aSopenharmony_ci{
30cabdff1aSopenharmony_ci    RTPMuxContext *s = s1->priv_data;
31cabdff1aSopenharmony_ci    const uint8_t *qtables[4] = { NULL };
32cabdff1aSopenharmony_ci    int nb_qtables = 0;
33cabdff1aSopenharmony_ci    uint8_t type;
34cabdff1aSopenharmony_ci    uint8_t w, h;
35cabdff1aSopenharmony_ci    uint8_t *p;
36cabdff1aSopenharmony_ci    int off = 0; /* fragment offset of the current JPEG frame */
37cabdff1aSopenharmony_ci    int len;
38cabdff1aSopenharmony_ci    int i;
39cabdff1aSopenharmony_ci    int default_huffman_tables = 0;
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_ci    s->buf_ptr   = s->buf;
42cabdff1aSopenharmony_ci    s->timestamp = s->cur_timestamp;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    /* convert video pixel dimensions from pixels to blocks */
45cabdff1aSopenharmony_ci    w = AV_CEIL_RSHIFT(s1->streams[0]->codecpar->width, 3);
46cabdff1aSopenharmony_ci    h = AV_CEIL_RSHIFT(s1->streams[0]->codecpar->height, 3);
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_ci    /* get the pixel format type or fail */
49cabdff1aSopenharmony_ci    if (s1->streams[0]->codecpar->format == AV_PIX_FMT_YUVJ422P ||
50cabdff1aSopenharmony_ci        (s1->streams[0]->codecpar->color_range == AVCOL_RANGE_JPEG &&
51cabdff1aSopenharmony_ci         s1->streams[0]->codecpar->format == AV_PIX_FMT_YUV422P)) {
52cabdff1aSopenharmony_ci        type = 0;
53cabdff1aSopenharmony_ci    } else if (s1->streams[0]->codecpar->format == AV_PIX_FMT_YUVJ420P ||
54cabdff1aSopenharmony_ci               (s1->streams[0]->codecpar->color_range == AVCOL_RANGE_JPEG &&
55cabdff1aSopenharmony_ci                s1->streams[0]->codecpar->format == AV_PIX_FMT_YUV420P)) {
56cabdff1aSopenharmony_ci        type = 1;
57cabdff1aSopenharmony_ci    } else {
58cabdff1aSopenharmony_ci        av_log(s1, AV_LOG_ERROR, "Unsupported pixel format\n");
59cabdff1aSopenharmony_ci        return;
60cabdff1aSopenharmony_ci    }
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_ci    /* preparse the header for getting some info */
63cabdff1aSopenharmony_ci    for (i = 0; i < size; i++) {
64cabdff1aSopenharmony_ci        if (buf[i] != 0xff)
65cabdff1aSopenharmony_ci            continue;
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci        if (buf[i + 1] == DQT) {
68cabdff1aSopenharmony_ci            int tables, j;
69cabdff1aSopenharmony_ci            if (buf[i + 4] & 0xF0)
70cabdff1aSopenharmony_ci                av_log(s1, AV_LOG_WARNING,
71cabdff1aSopenharmony_ci                       "Only 8-bit precision is supported.\n");
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci            /* a quantization table is 64 bytes long */
74cabdff1aSopenharmony_ci            tables = AV_RB16(&buf[i + 2]) / 65;
75cabdff1aSopenharmony_ci            if (i + 5 + tables * 65 > size) {
76cabdff1aSopenharmony_ci                av_log(s1, AV_LOG_ERROR, "Too short JPEG header. Aborted!\n");
77cabdff1aSopenharmony_ci                return;
78cabdff1aSopenharmony_ci            }
79cabdff1aSopenharmony_ci            if (nb_qtables + tables > 4) {
80cabdff1aSopenharmony_ci                av_log(s1, AV_LOG_ERROR, "Invalid number of quantisation tables\n");
81cabdff1aSopenharmony_ci                return;
82cabdff1aSopenharmony_ci            }
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci            for (j = 0; j < tables; j++)
85cabdff1aSopenharmony_ci                qtables[nb_qtables + j] = buf + i + 5 + j * 65;
86cabdff1aSopenharmony_ci            nb_qtables += tables;
87cabdff1aSopenharmony_ci        } else if (buf[i + 1] == SOF0) {
88cabdff1aSopenharmony_ci            if (buf[i + 14] != 17 || buf[i + 17] != 17) {
89cabdff1aSopenharmony_ci                av_log(s1, AV_LOG_ERROR,
90cabdff1aSopenharmony_ci                       "Only 1x1 chroma blocks are supported. Aborted!\n");
91cabdff1aSopenharmony_ci                return;
92cabdff1aSopenharmony_ci            }
93cabdff1aSopenharmony_ci        } else if (buf[i + 1] == DHT) {
94cabdff1aSopenharmony_ci            int dht_size = AV_RB16(&buf[i + 2]);
95cabdff1aSopenharmony_ci            default_huffman_tables |= 1 << 4;
96cabdff1aSopenharmony_ci            i += 3;
97cabdff1aSopenharmony_ci            dht_size -= 2;
98cabdff1aSopenharmony_ci            if (i + dht_size >= size)
99cabdff1aSopenharmony_ci                continue;
100cabdff1aSopenharmony_ci            while (dht_size > 0)
101cabdff1aSopenharmony_ci                switch (buf[i + 1]) {
102cabdff1aSopenharmony_ci                case 0x00:
103cabdff1aSopenharmony_ci                    if (   dht_size >= 29
104cabdff1aSopenharmony_ci                        && !memcmp(buf + i +  2, ff_mjpeg_bits_dc_luminance + 1, 16)
105cabdff1aSopenharmony_ci                        && !memcmp(buf + i + 18, ff_mjpeg_val_dc, 12)) {
106cabdff1aSopenharmony_ci                        default_huffman_tables |= 1;
107cabdff1aSopenharmony_ci                        i += 29;
108cabdff1aSopenharmony_ci                        dht_size -= 29;
109cabdff1aSopenharmony_ci                    } else {
110cabdff1aSopenharmony_ci                        i += dht_size;
111cabdff1aSopenharmony_ci                        dht_size = 0;
112cabdff1aSopenharmony_ci                    }
113cabdff1aSopenharmony_ci                    break;
114cabdff1aSopenharmony_ci                case 0x01:
115cabdff1aSopenharmony_ci                    if (   dht_size >= 29
116cabdff1aSopenharmony_ci                        && !memcmp(buf + i +  2, ff_mjpeg_bits_dc_chrominance + 1, 16)
117cabdff1aSopenharmony_ci                        && !memcmp(buf + i + 18, ff_mjpeg_val_dc, 12)) {
118cabdff1aSopenharmony_ci                        default_huffman_tables |= 1 << 1;
119cabdff1aSopenharmony_ci                        i += 29;
120cabdff1aSopenharmony_ci                        dht_size -= 29;
121cabdff1aSopenharmony_ci                    } else {
122cabdff1aSopenharmony_ci                        i += dht_size;
123cabdff1aSopenharmony_ci                        dht_size = 0;
124cabdff1aSopenharmony_ci                    }
125cabdff1aSopenharmony_ci                    break;
126cabdff1aSopenharmony_ci                case 0x10:
127cabdff1aSopenharmony_ci                    if (   dht_size >= 179
128cabdff1aSopenharmony_ci                        && !memcmp(buf + i +  2, ff_mjpeg_bits_ac_luminance   + 1, 16)
129cabdff1aSopenharmony_ci                        && !memcmp(buf + i + 18, ff_mjpeg_val_ac_luminance, 162)) {
130cabdff1aSopenharmony_ci                        default_huffman_tables |= 1 << 2;
131cabdff1aSopenharmony_ci                        i += 179;
132cabdff1aSopenharmony_ci                        dht_size -= 179;
133cabdff1aSopenharmony_ci                    } else {
134cabdff1aSopenharmony_ci                        i += dht_size;
135cabdff1aSopenharmony_ci                        dht_size = 0;
136cabdff1aSopenharmony_ci                    }
137cabdff1aSopenharmony_ci                    break;
138cabdff1aSopenharmony_ci                case 0x11:
139cabdff1aSopenharmony_ci                    if (   dht_size >= 179
140cabdff1aSopenharmony_ci                        && !memcmp(buf + i +  2, ff_mjpeg_bits_ac_chrominance + 1, 16)
141cabdff1aSopenharmony_ci                        && !memcmp(buf + i + 18, ff_mjpeg_val_ac_chrominance, 162)) {
142cabdff1aSopenharmony_ci                        default_huffman_tables |= 1 << 3;
143cabdff1aSopenharmony_ci                        i += 179;
144cabdff1aSopenharmony_ci                        dht_size -= 179;
145cabdff1aSopenharmony_ci                    } else {
146cabdff1aSopenharmony_ci                        i += dht_size;
147cabdff1aSopenharmony_ci                        dht_size = 0;
148cabdff1aSopenharmony_ci                    }
149cabdff1aSopenharmony_ci                    break;
150cabdff1aSopenharmony_ci                default:
151cabdff1aSopenharmony_ci                    i += dht_size;
152cabdff1aSopenharmony_ci                    dht_size = 0;
153cabdff1aSopenharmony_ci                    continue;
154cabdff1aSopenharmony_ci            }
155cabdff1aSopenharmony_ci        } else if (buf[i + 1] == SOS) {
156cabdff1aSopenharmony_ci            /* SOS is last marker in the header */
157cabdff1aSopenharmony_ci            i += AV_RB16(&buf[i + 2]) + 2;
158cabdff1aSopenharmony_ci            if (i > size) {
159cabdff1aSopenharmony_ci                av_log(s1, AV_LOG_ERROR,
160cabdff1aSopenharmony_ci                       "Insufficient data. Aborted!\n");
161cabdff1aSopenharmony_ci                return;
162cabdff1aSopenharmony_ci            }
163cabdff1aSopenharmony_ci            break;
164cabdff1aSopenharmony_ci        }
165cabdff1aSopenharmony_ci    }
166cabdff1aSopenharmony_ci    if (default_huffman_tables && default_huffman_tables != 31) {
167cabdff1aSopenharmony_ci        av_log(s1, AV_LOG_ERROR,
168cabdff1aSopenharmony_ci               "RFC 2435 requires standard Huffman tables for jpeg\n");
169cabdff1aSopenharmony_ci        return;
170cabdff1aSopenharmony_ci    }
171cabdff1aSopenharmony_ci    if (nb_qtables && nb_qtables != 2)
172cabdff1aSopenharmony_ci        av_log(s1, AV_LOG_WARNING,
173cabdff1aSopenharmony_ci               "RFC 2435 suggests two quantization tables, %d provided\n",
174cabdff1aSopenharmony_ci               nb_qtables);
175cabdff1aSopenharmony_ci
176cabdff1aSopenharmony_ci    /* skip JPEG header */
177cabdff1aSopenharmony_ci    buf  += i;
178cabdff1aSopenharmony_ci    size -= i;
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    for (i = size - 2; i >= 0; i--) {
181cabdff1aSopenharmony_ci        if (buf[i] == 0xff && buf[i + 1] == EOI) {
182cabdff1aSopenharmony_ci            /* Remove the EOI marker */
183cabdff1aSopenharmony_ci            size = i;
184cabdff1aSopenharmony_ci            break;
185cabdff1aSopenharmony_ci        }
186cabdff1aSopenharmony_ci    }
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_ci    p = s->buf_ptr;
189cabdff1aSopenharmony_ci    while (size > 0) {
190cabdff1aSopenharmony_ci        int hdr_size = 8;
191cabdff1aSopenharmony_ci
192cabdff1aSopenharmony_ci        if (off == 0 && nb_qtables)
193cabdff1aSopenharmony_ci            hdr_size += 4 + 64 * nb_qtables;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci        /* payload max in one packet */
196cabdff1aSopenharmony_ci        len = FFMIN(size, s->max_payload_size - hdr_size);
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_ci        /* set main header */
199cabdff1aSopenharmony_ci        bytestream_put_byte(&p, 0);
200cabdff1aSopenharmony_ci        bytestream_put_be24(&p, off);
201cabdff1aSopenharmony_ci        bytestream_put_byte(&p, type);
202cabdff1aSopenharmony_ci        bytestream_put_byte(&p, 255);
203cabdff1aSopenharmony_ci        bytestream_put_byte(&p, w);
204cabdff1aSopenharmony_ci        bytestream_put_byte(&p, h);
205cabdff1aSopenharmony_ci
206cabdff1aSopenharmony_ci        if (off == 0 && nb_qtables) {
207cabdff1aSopenharmony_ci            /* set quantization tables header */
208cabdff1aSopenharmony_ci            bytestream_put_byte(&p, 0);
209cabdff1aSopenharmony_ci            bytestream_put_byte(&p, 0);
210cabdff1aSopenharmony_ci            bytestream_put_be16(&p, 64 * nb_qtables);
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci            for (i = 0; i < nb_qtables; i++)
213cabdff1aSopenharmony_ci                bytestream_put_buffer(&p, qtables[i], 64);
214cabdff1aSopenharmony_ci        }
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_ci        /* copy payload data */
217cabdff1aSopenharmony_ci        memcpy(p, buf, len);
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci        /* marker bit is last packet in frame */
220cabdff1aSopenharmony_ci        ff_rtp_send_data(s1, s->buf, len + hdr_size, size == len);
221cabdff1aSopenharmony_ci
222cabdff1aSopenharmony_ci        buf  += len;
223cabdff1aSopenharmony_ci        size -= len;
224cabdff1aSopenharmony_ci        off  += len;
225cabdff1aSopenharmony_ci        p     = s->buf;
226cabdff1aSopenharmony_ci    }
227cabdff1aSopenharmony_ci}
228