/src/vlc/modules/demux/mpeg/ts_metadata.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * ts_metadata.c : TS demuxer metadata handling |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2016 - VideoLAN Authors |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation; either version 2.1 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | *****************************************************************************/ |
19 | | #ifdef HAVE_CONFIG_H |
20 | | # include "config.h" |
21 | | #endif |
22 | | |
23 | | #include <vlc_common.h> |
24 | | #include <vlc_meta.h> |
25 | | #include <vlc_es_out.h> |
26 | | #include <vlc_block.h> |
27 | | |
28 | | #include "ts_pid.h" |
29 | | #include "ts_streams.h" |
30 | | #include "ts_streams_private.h" |
31 | | #include "ts_metadata.h" |
32 | | |
33 | | #include "../../meta_engine/ID3Tag.h" |
34 | | #include "../../meta_engine/ID3Meta.h" |
35 | | |
36 | | #include <assert.h> |
37 | | |
38 | | static int ID3TAG_Parse_Handler( uint32_t i_tag, const uint8_t *p_payload, |
39 | | size_t i_payload, void *p_priv ) |
40 | 0 | { |
41 | 0 | vlc_meta_t *p_meta = (vlc_meta_t *) p_priv; |
42 | |
|
43 | 0 | (void) ID3HandleTag( p_payload, i_payload, i_tag, p_meta, NULL ); |
44 | |
|
45 | 0 | return VLC_SUCCESS; |
46 | 0 | } |
47 | | |
48 | | typedef struct |
49 | | { |
50 | | es_out_t *out; |
51 | | ts_stream_t *p_stream; |
52 | | block_t *p_head; |
53 | | block_t **pp_tail; |
54 | | uint8_t i_sequence_number; |
55 | | } Metadata_stream_processor_context_t; |
56 | | |
57 | | static void Metadata_stream_processor_Reset( ts_stream_processor_t *h ) |
58 | 0 | { |
59 | 0 | Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv; |
60 | 0 | block_ChainRelease(ctx->p_head); |
61 | 0 | ctx->p_head = NULL; |
62 | 0 | ctx->pp_tail = &ctx->p_head; |
63 | 0 | } |
64 | | |
65 | | static void Metadata_stream_processor_Delete( ts_stream_processor_t *h ) |
66 | 0 | { |
67 | 0 | Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv; |
68 | 0 | block_ChainRelease(ctx->p_head); |
69 | 0 | free( ctx ); |
70 | 0 | free( h ); |
71 | 0 | } |
72 | | |
73 | | static block_t * Metadata_stream_processor_AggregateMAU( ts_stream_processor_t *h, |
74 | | uint8_t i_sequence, block_t *p_block, |
75 | | size_t i_cellsize ) |
76 | 0 | { |
77 | 0 | Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv; |
78 | 0 |
|
79 | 0 | bool b_corrupt = ctx->p_head && i_sequence != ((ctx->i_sequence_number + 1) & 0xFF); |
80 | 0 |
|
81 | 0 | if( unlikely(p_block->i_buffer > i_cellsize) ) |
82 | 0 | { |
83 | 0 | block_t *cell = block_Duplicate( p_block ); |
84 | 0 | if( cell ) |
85 | 0 | { |
86 | 0 | cell->i_buffer = i_cellsize; |
87 | 0 | block_ChainLastAppend( &ctx->pp_tail, cell ); |
88 | 0 | } |
89 | 0 | p_block->i_buffer -= i_cellsize; |
90 | 0 | p_block->i_buffer += i_cellsize; |
91 | 0 | } |
92 | 0 | else |
93 | 0 | { |
94 | 0 | assert( p_block->i_buffer == i_cellsize ); |
95 | 0 | block_ChainLastAppend( &ctx->pp_tail, p_block ); |
96 | 0 | p_block = NULL; |
97 | 0 | } |
98 | 0 |
|
99 | 0 | ctx->i_sequence_number = i_sequence; |
100 | 0 | if( b_corrupt ) |
101 | 0 | Metadata_stream_processor_Reset( h ); |
102 | 0 |
|
103 | 0 | return p_block; |
104 | 0 | } |
105 | | |
106 | | static block_t * Metadata_stream_processor_OutputMAU( ts_stream_processor_t *h ) |
107 | 0 | { |
108 | 0 | Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv; |
109 | 0 |
|
110 | 0 | block_t *p_chain = ctx->p_head; |
111 | 0 | if( !p_chain ) |
112 | 0 | return NULL; |
113 | 0 | ctx->p_head = NULL; |
114 | 0 | ctx->pp_tail = &ctx->p_head; |
115 | 0 | return block_ChainGather( p_chain ); |
116 | 0 | } |
117 | | |
118 | | static block_t * Metadata_stream_processor_PushMAU( ts_stream_processor_t *h, |
119 | | const ts_es_t *p_es, block_t *p_block ) |
120 | 0 | { |
121 | 0 | block_t *p_return_chain = NULL; |
122 | 0 | block_t **pp_return = &p_return_chain; |
123 | 0 |
|
124 | 0 | while( p_block->i_buffer >= 5 ) |
125 | 0 | { |
126 | 0 | const uint8_t i_service_id = p_block->p_buffer[0]; |
127 | 0 | const uint8_t i_sequence = p_block->p_buffer[1]; |
128 | 0 | const uint8_t i_fragment_indication = p_block->p_buffer[2] >> 6; |
129 | 0 | const uint16_t i_length = GetWBE(&p_block->p_buffer[3]); |
130 | 0 |
|
131 | 0 | p_block->i_buffer -= 5; |
132 | 0 | p_block->p_buffer += 5; |
133 | 0 |
|
134 | 0 | if( p_block->i_buffer < i_length ) |
135 | 0 | break; |
136 | 0 |
|
137 | 0 | if( i_service_id == p_es->metadata.i_service_id ) |
138 | 0 | { |
139 | 0 | if( i_fragment_indication == 0x03 ) /* FULL AU */ |
140 | 0 | { |
141 | 0 | Metadata_stream_processor_Reset( h ); /* flush anything that not went to last frag */ |
142 | 0 | p_block = Metadata_stream_processor_AggregateMAU( h, i_sequence, p_block, i_length ); |
143 | 0 | } |
144 | 0 | else |
145 | 0 | { |
146 | 0 | if( i_fragment_indication == 0x02 ) /* First */ |
147 | 0 | Metadata_stream_processor_Reset( h ); /* flush anything that not went to last frag */ |
148 | 0 | p_block = Metadata_stream_processor_AggregateMAU( h, i_sequence, p_block, i_length ); |
149 | 0 | if( i_fragment_indication == 0x01 ) /* Last */ |
150 | 0 | { |
151 | 0 | block_t *out = Metadata_stream_processor_OutputMAU( h ); |
152 | 0 | if( out ) |
153 | 0 | block_ChainLastAppend( &pp_return, out ); |
154 | 0 | } |
155 | 0 | } |
156 | 0 | } |
157 | 0 |
|
158 | 0 | if( !p_block ) |
159 | 0 | break; |
160 | 0 |
|
161 | 0 | p_block->i_buffer -= i_length; |
162 | 0 | p_block->i_buffer += i_length; |
163 | 0 | }; |
164 | 0 |
|
165 | 0 | if( p_block ) |
166 | 0 | block_Release( p_block ); |
167 | 0 |
|
168 | 0 | return p_return_chain; |
169 | 0 | } |
170 | | |
171 | | static block_t * Metadata_stream_processor_Push( ts_stream_processor_t *h, uint8_t i_stream_id, block_t *p_block ) |
172 | 0 | { |
173 | 0 | Metadata_stream_processor_context_t *ctx = (Metadata_stream_processor_context_t *) h->priv; |
174 | 0 | ts_es_t *p_es = ctx->p_stream->p_es; |
175 | |
|
176 | 0 | if( i_stream_id == 0xbd && /* Transport in PES packets, 2.12.3 */ |
177 | 0 | p_es->metadata.i_format_identifier == METADATA_IDENTIFIER_ID3 ) |
178 | 0 | { |
179 | 0 | vlc_meta_t *p_meta = vlc_meta_New(); |
180 | 0 | if( p_meta ) |
181 | 0 | { |
182 | 0 | (void) ID3TAG_Parse( p_block->p_buffer, p_block->i_buffer, ID3TAG_Parse_Handler, p_meta ); |
183 | 0 | es_out_Control( ctx->out, ES_OUT_SET_GROUP_META, p_es->p_program->i_number, p_meta ); |
184 | 0 | vlc_meta_Delete( p_meta ); |
185 | 0 | } |
186 | 0 | } |
187 | |
|
188 | 0 | return p_block; |
189 | 0 | } |
190 | | |
191 | | ts_stream_processor_t *Metadata_stream_processor_New( ts_stream_t *p_stream, es_out_t *out ) |
192 | 0 | { |
193 | 0 | ts_stream_processor_t *h = malloc(sizeof(*h)); |
194 | 0 | if(!h) |
195 | 0 | return NULL; |
196 | | |
197 | 0 | Metadata_stream_processor_context_t *ctx = malloc( sizeof(Metadata_stream_processor_context_t) ); |
198 | 0 | if(!ctx) |
199 | 0 | { |
200 | 0 | free(h); |
201 | 0 | return NULL; |
202 | 0 | } |
203 | 0 | ctx->out = out; |
204 | 0 | ctx->p_stream = p_stream; |
205 | 0 | ctx->i_sequence_number = 0; |
206 | 0 | ctx->p_head = NULL; |
207 | 0 | ctx->pp_tail = &ctx->p_head; |
208 | |
|
209 | 0 | h->priv = ctx; |
210 | 0 | h->pf_delete = Metadata_stream_processor_Delete; |
211 | 0 | h->pf_push = Metadata_stream_processor_Push; |
212 | 0 | h->pf_reset = Metadata_stream_processor_Reset; |
213 | |
|
214 | 0 | return h; |
215 | 0 | } |