/src/ffmpeg/libavformat/flac_picture.c
Line | Count | Source |
1 | | /* |
2 | | * Raw FLAC picture parser |
3 | | * Copyright (c) 2001 Fabrice Bellard |
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 | | #include "libavutil/intreadwrite.h" |
23 | | #include "libavcodec/bytestream.h" |
24 | | #include "libavcodec/png.h" |
25 | | #include "avformat.h" |
26 | | #include "avio_internal.h" |
27 | | #include "demux.h" |
28 | | #include "flac_picture.h" |
29 | | #include "id3v2.h" |
30 | | #include "internal.h" |
31 | | |
32 | 6.04k | #define MAX_TRUNC_PICTURE_SIZE (500 * 1024 * 1024) |
33 | | |
34 | | int ff_flac_parse_picture(AVFormatContext *s, uint8_t **bufp, int buf_size, |
35 | | int truncate_workaround) |
36 | 22.5k | { |
37 | 22.5k | const CodecMime *mime = ff_id3v2_mime_tags; |
38 | 22.5k | enum AVCodecID id = AV_CODEC_ID_NONE; |
39 | 22.5k | AVBufferRef *data = NULL; |
40 | 22.5k | uint8_t mimetype[64], *buf = *bufp; |
41 | 22.5k | const uint8_t *desc = NULL; |
42 | 22.5k | GetByteContext g; |
43 | 22.5k | AVStream *st; |
44 | 22.5k | int width, height, ret = 0; |
45 | 22.5k | unsigned int type; |
46 | 22.5k | uint32_t len, left, trunclen = 0; |
47 | | |
48 | 22.5k | if (buf_size < 34) { |
49 | 1.51k | av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); |
50 | 1.51k | if (s->error_recognition & AV_EF_EXPLODE) |
51 | 0 | return AVERROR_INVALIDDATA; |
52 | 1.51k | return 0; |
53 | 1.51k | } |
54 | | |
55 | 21.0k | bytestream2_init(&g, buf, buf_size); |
56 | | |
57 | | /* read the picture type */ |
58 | 21.0k | type = bytestream2_get_be32u(&g); |
59 | 21.0k | if (type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) { |
60 | 20.6k | av_log(s, AV_LOG_ERROR, "Invalid picture type: %d.\n", type); |
61 | 20.6k | if (s->error_recognition & AV_EF_EXPLODE) { |
62 | 0 | return AVERROR_INVALIDDATA; |
63 | 0 | } |
64 | 20.6k | type = 0; |
65 | 20.6k | } |
66 | | |
67 | | /* picture mimetype */ |
68 | 21.0k | len = bytestream2_get_be32u(&g); |
69 | 21.0k | if (len <= 0 || len >= sizeof(mimetype)) { |
70 | 2.23k | av_log(s, AV_LOG_ERROR, "Could not read mimetype from an attached " |
71 | 2.23k | "picture.\n"); |
72 | 2.23k | if (s->error_recognition & AV_EF_EXPLODE) |
73 | 0 | return AVERROR_INVALIDDATA; |
74 | 2.23k | return 0; |
75 | 2.23k | } |
76 | 18.8k | if (len + 24 > bytestream2_get_bytes_left(&g)) { |
77 | 170 | av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); |
78 | 170 | if (s->error_recognition & AV_EF_EXPLODE) |
79 | 0 | return AVERROR_INVALIDDATA; |
80 | 170 | return 0; |
81 | 170 | } |
82 | 18.6k | bytestream2_get_bufferu(&g, mimetype, len); |
83 | 18.6k | mimetype[len] = 0; |
84 | | |
85 | 172k | while (mime->id != AV_CODEC_ID_NONE) { |
86 | 172k | if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { |
87 | 18.2k | id = mime->id; |
88 | 18.2k | break; |
89 | 18.2k | } |
90 | 154k | mime++; |
91 | 154k | } |
92 | 18.6k | if (id == AV_CODEC_ID_NONE) { |
93 | 408 | av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s.\n", |
94 | 408 | mimetype); |
95 | 408 | return 0; |
96 | 408 | } |
97 | | |
98 | | /* picture description */ |
99 | 18.2k | len = bytestream2_get_be32u(&g); |
100 | 18.2k | if (len > bytestream2_get_bytes_left(&g) - 20) { |
101 | 689 | av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); |
102 | 689 | if (s->error_recognition & AV_EF_EXPLODE) |
103 | 0 | return AVERROR_INVALIDDATA; |
104 | 689 | return 0; |
105 | 689 | } |
106 | 17.5k | if (len > 0) { |
107 | 5.95k | desc = g.buffer; |
108 | 5.95k | bytestream2_skipu(&g, len); |
109 | 5.95k | } |
110 | | |
111 | | /* picture metadata */ |
112 | 17.5k | width = bytestream2_get_be32u(&g); |
113 | 17.5k | ((uint8_t*)g.buffer)[-4] = '\0'; // NUL-terminate desc. |
114 | 17.5k | height = bytestream2_get_be32u(&g); |
115 | 17.5k | bytestream2_skipu(&g, 8); |
116 | | |
117 | | /* picture data */ |
118 | 17.5k | len = bytestream2_get_be32u(&g); |
119 | | |
120 | 17.5k | left = bytestream2_get_bytes_left(&g); |
121 | 17.5k | if (len <= 0 || len > left) { |
122 | 3.02k | if (len > MAX_TRUNC_PICTURE_SIZE || len >= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { |
123 | 869 | av_log(s, AV_LOG_ERROR, "Attached picture metadata block too big %"PRIu32"\n", len); |
124 | 869 | if (s->error_recognition & AV_EF_EXPLODE) |
125 | 0 | return AVERROR_INVALIDDATA; |
126 | 869 | return 0; |
127 | 869 | } |
128 | | |
129 | | // Workaround bug for flac muxers that writs truncated metadata picture block size if |
130 | | // the picture size do not fit in 24 bits. lavf flacenc used to have the issue and based |
131 | | // on existing broken files other unknown flac muxers seems to truncate also. |
132 | 2.15k | if (truncate_workaround && |
133 | 2.15k | s->strict_std_compliance <= FF_COMPLIANCE_NORMAL && |
134 | 2.15k | len > left && (len & 0xffffff) == left) { |
135 | 10 | av_log(s, AV_LOG_INFO, "Correcting truncated metadata picture size from %"PRIu32" to %"PRIu32"\n", left, len); |
136 | 10 | trunclen = len - left; |
137 | 2.14k | } else { |
138 | 2.14k | av_log(s, AV_LOG_ERROR, "Attached picture metadata block too short\n"); |
139 | 2.14k | if (s->error_recognition & AV_EF_EXPLODE) |
140 | 0 | return AVERROR_INVALIDDATA; |
141 | 2.14k | return 0; |
142 | 2.14k | } |
143 | 2.15k | } |
144 | 14.5k | if (trunclen == 0 && len >= buf_size - (buf_size >> 4)) { |
145 | 6 | data = av_buffer_create(buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE, |
146 | 6 | av_buffer_default_free, NULL, 0); |
147 | 6 | if (!data) |
148 | 0 | return AVERROR(ENOMEM); |
149 | 6 | *bufp = NULL; |
150 | 6 | data->data += bytestream2_tell(&g); |
151 | 6 | data->size = len + AV_INPUT_BUFFER_PADDING_SIZE; |
152 | 14.5k | } else { |
153 | 14.5k | if (!(data = av_buffer_alloc(len + AV_INPUT_BUFFER_PADDING_SIZE))) |
154 | 0 | return AVERROR(ENOMEM); |
155 | | |
156 | 14.5k | if (trunclen == 0) { |
157 | 14.5k | bytestream2_get_bufferu(&g, data->data, len); |
158 | 14.5k | } else { |
159 | | // If truncation was detected copy all data from block and |
160 | | // read missing bytes not included in the block size. |
161 | 10 | bytestream2_get_bufferu(&g, data->data, left); |
162 | 10 | ret = ffio_read_size(s->pb, data->data + len - trunclen, trunclen); |
163 | 10 | if (ret < 0) |
164 | 10 | goto fail; |
165 | 10 | } |
166 | 14.5k | } |
167 | 14.5k | memset(data->data + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); |
168 | | |
169 | 14.5k | if (AV_RB64(data->data) == PNGSIG) |
170 | 83 | id = AV_CODEC_ID_PNG; |
171 | | |
172 | 14.5k | ret = ff_add_attached_pic(s, NULL, NULL, &data, 0); |
173 | 14.5k | if (ret < 0) |
174 | 2 | RETURN_ERROR(ret); |
175 | | |
176 | 14.5k | st = s->streams[s->nb_streams - 1]; |
177 | 14.5k | st->codecpar->codec_id = id; |
178 | 14.5k | st->codecpar->width = width; |
179 | 14.5k | st->codecpar->height = height; |
180 | 14.5k | av_dict_set(&st->metadata, "comment", ff_id3v2_picture_types[type], 0); |
181 | 14.5k | if (desc) |
182 | 5.14k | av_dict_set(&st->metadata, "title", desc, 0); |
183 | | |
184 | 14.5k | return 0; |
185 | | |
186 | 12 | fail: |
187 | 12 | av_buffer_unref(&data); |
188 | | |
189 | 12 | return ret; |
190 | 14.5k | } |