Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * MJPEG/AVI1 to JPEG/JFIF bitstream format filter | |
3 | * Copyright (c) 2010 Adrian Daerr and Nicolas George | |
4 | * | |
5 | * This file is part of FFmpeg. | |
6 | * | |
7 | * FFmpeg is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * FFmpeg is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with FFmpeg; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Adapted from mjpeg2jpeg.c, with original copyright: | |
24 | * Paris 2010 Adrian Daerr, public domain | |
25 | */ | |
26 | ||
27 | #include <string.h> | |
28 | ||
29 | #include "libavutil/error.h" | |
30 | #include "libavutil/mem.h" | |
31 | ||
32 | #include "avcodec.h" | |
33 | #include "mjpeg.h" | |
34 | ||
35 | static const uint8_t jpeg_header[] = { | |
36 | 0xff, 0xd8, // SOI | |
37 | 0xff, 0xe0, // APP0 | |
38 | 0x00, 0x10, // APP0 header size (including | |
39 | // this field, but excluding preceding) | |
40 | 0x4a, 0x46, 0x49, 0x46, 0x00, // ID string 'JFIF\0' | |
41 | 0x01, 0x01, // version | |
42 | 0x00, // bits per type | |
43 | 0x00, 0x00, // X density | |
44 | 0x00, 0x00, // Y density | |
45 | 0x00, // X thumbnail size | |
46 | 0x00, // Y thumbnail size | |
47 | }; | |
48 | ||
49 | static const int dht_segment_size = 420; | |
50 | static const uint8_t dht_segment_head[] = { 0xFF, 0xC4, 0x01, 0xA2, 0x00 }; | |
51 | static const uint8_t dht_segment_frag[] = { | |
52 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, | |
53 | 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, | |
54 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | |
55 | }; | |
56 | ||
57 | static uint8_t *append(uint8_t *buf, const uint8_t *src, int size) | |
58 | { | |
59 | memcpy(buf, src, size); | |
60 | return buf + size; | |
61 | } | |
62 | ||
63 | static uint8_t *append_dht_segment(uint8_t *buf) | |
64 | { | |
65 | buf = append(buf, dht_segment_head, sizeof(dht_segment_head)); | |
66 | buf = append(buf, avpriv_mjpeg_bits_dc_luminance + 1, 16); | |
67 | buf = append(buf, dht_segment_frag, sizeof(dht_segment_frag)); | |
68 | buf = append(buf, avpriv_mjpeg_val_dc, 12); | |
69 | *(buf++) = 0x10; | |
70 | buf = append(buf, avpriv_mjpeg_bits_ac_luminance + 1, 16); | |
71 | buf = append(buf, avpriv_mjpeg_val_ac_luminance, 162); | |
72 | *(buf++) = 0x11; | |
73 | buf = append(buf, avpriv_mjpeg_bits_ac_chrominance + 1, 16); | |
74 | buf = append(buf, avpriv_mjpeg_val_ac_chrominance, 162); | |
75 | return buf; | |
76 | } | |
77 | ||
78 | static int mjpeg2jpeg_filter(AVBitStreamFilterContext *bsfc, | |
79 | AVCodecContext *avctx, const char *args, | |
80 | uint8_t **poutbuf, int *poutbuf_size, | |
81 | const uint8_t *buf, int buf_size, | |
82 | int keyframe) | |
83 | { | |
84 | int input_skip, output_size; | |
85 | uint8_t *output, *out; | |
86 | ||
87 | if (buf_size < 12) { | |
88 | av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); | |
89 | return AVERROR_INVALIDDATA; | |
90 | } | |
91 | if (memcmp("AVI1", buf + 6, 4)) { | |
92 | av_log(avctx, AV_LOG_ERROR, "input is not MJPEG/AVI1\n"); | |
93 | return AVERROR_INVALIDDATA; | |
94 | } | |
95 | input_skip = (buf[4] << 8) + buf[5] + 4; | |
96 | if (buf_size < input_skip) { | |
97 | av_log(avctx, AV_LOG_ERROR, "input is truncated\n"); | |
98 | return AVERROR_INVALIDDATA; | |
99 | } | |
100 | output_size = buf_size - input_skip + | |
101 | sizeof(jpeg_header) + dht_segment_size; | |
102 | output = out = av_malloc(output_size); | |
103 | if (!output) | |
104 | return AVERROR(ENOMEM); | |
105 | out = append(out, jpeg_header, sizeof(jpeg_header)); | |
106 | out = append_dht_segment(out); | |
107 | out = append(out, buf + input_skip, buf_size - input_skip); | |
108 | *poutbuf = output; | |
109 | *poutbuf_size = output_size; | |
110 | return 1; | |
111 | } | |
112 | ||
113 | AVBitStreamFilter ff_mjpeg2jpeg_bsf = { | |
114 | .name = "mjpeg2jpeg", | |
115 | .filter = mjpeg2jpeg_filter, | |
116 | }; |