packetizer: hevc: add poc debug
[vlc.git] / modules / stream_filter / skiptags.c
blob5399cbb4e0bfd7b0917c53219c89b3afc77ab102
1 /*****************************************************************************
2 * skiptags.c:
3 *****************************************************************************
4 * Copyright © 2005-2008 VLC authors and VideoLAN
5 * Copyright © 2016-2017 Rémi Denis-Courmont
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program 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
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_stream.h>
33 #include <vlc_block.h>
35 #define MAX_TAGS 16
36 #define MAX_TAG_SIZE (1<<17)
38 struct skiptags_sys_t
40 uint64_t header_skip;
41 /* TODO? also discard trailer tags? */
42 block_t *p_tags;
45 static struct skiptags_sys_t * skiptags_sys_New(void)
47 struct skiptags_sys_t *sys = malloc(sizeof (*sys));
48 if(sys)
50 sys->header_skip = 0;
51 sys->p_tags = NULL;
53 return sys;
56 static void skiptags_sys_Delete(struct skiptags_sys_t *sys)
58 block_ChainRelease(sys->p_tags);
59 free(sys);
62 static uint_fast32_t SkipID3Tag(stream_t *s)
64 const uint8_t *peek;
66 /* Get 10-bytes ID3 header */
67 if (vlc_stream_Peek(s, &peek, 10) < 10)
68 return 0;
69 if (memcmp(peek, "ID3", 3))
70 return 0;
72 uint_fast8_t version = peek[3];
73 uint_fast8_t revision = peek[4];
74 bool has_footer = (peek[5] & 0x10) != 0;
75 uint_fast32_t size = 10u + (peek[6] << 21) + (peek[7] << 14)
76 + (peek[8] << 7) + peek[9] + (has_footer ? 10u : 0u);
78 /* Skip the entire tag */
79 msg_Dbg(s, "ID3v2.%"PRIuFAST8" revision %"PRIuFAST8" tag found, "
80 "skipping %"PRIuFAST32" bytes", version, revision, size);
82 return size;
85 static uint_fast32_t SkipAPETag(stream_t *s)
87 const uint8_t *peek;
89 /* Get 32-bytes APE header */
90 if (vlc_stream_Peek(s, &peek, 32) < 32)
91 return 0;
92 if (memcmp(peek, "APETAGEX", 8))
93 return 0;
95 uint_fast32_t version = GetDWLE(peek + 8);
96 if (version != 1000 && version != 2000)
97 return 0;
99 uint_fast32_t size = GetDWLE(peek + 12);
100 if (size > SSIZE_MAX - 32u)
101 return 0; /* impossibly long tag */
103 uint_fast32_t flags = GetDWLE(peek + 16);
104 if ((flags & (1u << 29)) == 0)
105 return 0;
107 if (flags & (1u << 30))
108 size += 32;
110 msg_Dbg(s, "AP2 v%"PRIuFAST32" tag found, "
111 "skipping %"PRIuFAST32" bytes", version / 1000, size);
112 return size;
115 static bool SkipTag(stream_t *s, uint_fast32_t (*skipper)(stream_t *),
116 block_t **pp_block, unsigned *pi_tags_count)
118 uint_fast64_t offset = vlc_stream_Tell(s);
119 uint_fast32_t size = skipper(s);
120 if(size> 0)
122 /* Skip the entire tag */
123 ssize_t read;
124 if(*pi_tags_count < MAX_TAGS && size <= MAX_TAG_SIZE)
126 *pp_block = vlc_stream_Block(s, size);
127 read = *pp_block ? (ssize_t)(*pp_block)->i_buffer : -1;
129 else
131 read = vlc_stream_Read(s, NULL, size);
134 if(read < (ssize_t)size)
136 block_ChainRelease(*pp_block);
137 *pp_block = NULL;
138 if (unlikely(read < 0))
139 { /* I/O error, try to restore offset. If it fails, screwed. */
140 if (vlc_stream_Seek(s, offset))
141 msg_Err(s, "seek failure");
142 return false;
145 else (*pi_tags_count)++;
147 return size != 0;
150 static ssize_t Read(stream_t *stream, void *buf, size_t buflen)
152 return vlc_stream_Read(stream->s, buf, buflen);
155 static int ReadDir(stream_t *stream, input_item_node_t *node)
157 (void) stream; (void) node;
158 return VLC_EGENERIC;
161 static int Seek(stream_t *stream, uint64_t offset)
163 const struct skiptags_sys_t *sys = stream->p_sys;
165 if (unlikely(offset + sys->header_skip < offset))
166 return -1;
167 return vlc_stream_Seek(stream->s, sys->header_skip + offset);
170 static int Control(stream_t *stream, int query, va_list args)
172 const struct skiptags_sys_t *sys = stream->p_sys;
173 /* In principles, we should return the meta-data embedded in the skipped
174 * tags in STREAM_GET_META. But the meta engine is devoted to that already.
176 if( query == STREAM_GET_TAGS && sys->p_tags )
178 *va_arg( args, const block_t ** ) = sys->p_tags;
179 return VLC_SUCCESS;
182 return vlc_stream_vaControl(stream->s, query, args);
185 static int Open(vlc_object_t *obj)
187 stream_t *stream = (stream_t *)obj;
188 stream_t *s = stream->s;
189 struct skiptags_sys_t *sys;
191 block_t *p_tags = NULL, *p_tag = NULL;
192 unsigned i_tagscount = 0;
194 while (SkipTag(s, SkipID3Tag, &p_tag, &i_tagscount)||
195 SkipTag(s, SkipAPETag, &p_tag, &i_tagscount))
197 if(p_tag)
199 p_tag->p_next = p_tags;
200 p_tags = p_tag;
201 p_tag = NULL;
205 uint_fast64_t offset = vlc_stream_Tell(s);
206 if (offset == 0 || !(sys = skiptags_sys_New()))
208 block_ChainRelease( p_tags );
209 return VLC_EGENERIC; /* nothing to do */
212 sys->header_skip = offset;
213 sys->p_tags = p_tags;
214 stream->p_sys = sys;
215 stream->pf_read = Read;
216 stream->pf_readdir = ReadDir;
217 stream->pf_seek = Seek;
218 stream->pf_control = Control;
219 return VLC_SUCCESS;
222 static void Close(vlc_object_t *obj)
224 stream_t *stream = (stream_t *)obj;
225 struct skiptags_sys_t *sys = (struct skiptags_sys_t *) stream->p_sys;
227 skiptags_sys_Delete(sys);
230 vlc_module_begin()
231 set_category(CAT_INPUT)
232 set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
233 set_capability("stream_filter", 30)
235 set_description(N_("APE/ID3 tags-skipping filter"))
236 set_callbacks(Open, Close)
237 vlc_module_end()