/src/vlc/modules/demux/asf/asf.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * asf.c : ASF demux module |
3 | | ***************************************************************************** |
4 | | * Copyright © 2002-2004, 2006-2008, 2010 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation; either version 2.1 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program; if not, write to the Free Software Foundation, |
20 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
21 | | *****************************************************************************/ |
22 | | |
23 | | /***************************************************************************** |
24 | | * Preamble |
25 | | *****************************************************************************/ |
26 | | |
27 | | #ifdef HAVE_CONFIG_H |
28 | | # include "config.h" |
29 | | #endif |
30 | | |
31 | | #include <vlc_common.h> |
32 | | #include <vlc_arrays.h> |
33 | | #include <vlc_plugin.h> |
34 | | #include <vlc_demux.h> |
35 | | #include <vlc_dialog.h> |
36 | | |
37 | | #include <vlc_meta.h> /* vlc_meta_Set*, vlc_meta_New */ |
38 | | #include <vlc_access.h> /* GET_PRIVATE_ID_STATE */ |
39 | | #include <vlc_codecs.h> /* VLC_BITMAPINFOHEADER, WAVEFORMATEX */ |
40 | | #include <vlc_vout.h> |
41 | | |
42 | | #include <limits.h> |
43 | | #include <stdckdint.h> |
44 | | |
45 | | #include "asfpacket.h" |
46 | | #include "libasf.h" |
47 | | #include "assert.h" |
48 | | |
49 | | /* TODO |
50 | | * - add support for the newly added object: language, bitrate, |
51 | | * extended stream properties. |
52 | | */ |
53 | | |
54 | | /***************************************************************************** |
55 | | * Module descriptor |
56 | | *****************************************************************************/ |
57 | | static int Open ( vlc_object_t * ); |
58 | | static void Close ( vlc_object_t * ); |
59 | | |
60 | 108 | vlc_module_begin () |
61 | 54 | set_subcategory( SUBCAT_INPUT_DEMUX ) |
62 | 54 | set_description( N_("ASF/WMV demuxer") ) |
63 | 54 | set_capability( "demux", 200 ) |
64 | 108 | set_callbacks( Open, Close ) |
65 | 54 | add_shortcut( "asf", "wmv" ) |
66 | 54 | add_file_extension("asf") |
67 | 54 | add_file_extension("wma") |
68 | 54 | add_file_extension("wmv") |
69 | 54 | vlc_module_end () |
70 | | |
71 | | |
72 | | /***************************************************************************** |
73 | | * Local prototypes |
74 | | *****************************************************************************/ |
75 | | static int Demux ( demux_t * ); |
76 | | static int Control( demux_t *, int i_query, va_list args ); |
77 | | |
78 | 39.3G | #define MAX_ASF_TRACKS (ASF_MAX_STREAMNUMBER + 1) |
79 | | #define ASF_PREROLL_FROM_CURRENT -1 |
80 | | |
81 | | /* callbacks for packet parser */ |
82 | | static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, |
83 | | vlc_tick_t i_time ); |
84 | | static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time); |
85 | | static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime ); |
86 | | static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys, |
87 | | uint8_t i_stream_number ); |
88 | | static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe ); |
89 | | static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame ); |
90 | | static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, |
91 | | uint8_t i_ratio_x, uint8_t i_ratio_y ); |
92 | | |
93 | | typedef struct |
94 | | { |
95 | | int i_cat; |
96 | | |
97 | | es_out_id_t *p_es; |
98 | | es_format_t *p_fmt; /* format backup for video changes */ |
99 | | bool b_selected; |
100 | | |
101 | | vlc_tick_t i_time; /* track time*/ |
102 | | |
103 | | asf_track_info_t info; |
104 | | |
105 | | struct |
106 | | { |
107 | | block_t *p_first; |
108 | | block_t **pp_last; |
109 | | } queue; |
110 | | |
111 | | } asf_track_t; |
112 | | |
113 | | typedef struct |
114 | | { |
115 | | vlc_tick_t i_time; /* s */ |
116 | | vlc_tick_t i_sendtime; |
117 | | vlc_tick_t i_length; /* length of file */ |
118 | | uint64_t i_bitrate; /* global file bitrate */ |
119 | | bool b_eos; /* end of current stream */ |
120 | | bool b_eof; /* end of current media */ |
121 | | |
122 | | asf_object_root_t *p_root; |
123 | | asf_object_file_properties_t *p_fp; |
124 | | |
125 | | unsigned int i_track; |
126 | | asf_track_t *track[MAX_ASF_TRACKS]; /* track number is stored on 7 bits */ |
127 | | |
128 | | uint64_t i_data_begin; |
129 | | uint64_t i_data_end; |
130 | | |
131 | | bool b_index; |
132 | | bool b_canfastseek; |
133 | | bool b_pcr_sent; |
134 | | uint8_t i_seek_track; |
135 | | uint8_t i_access_selected_track[ES_CATEGORY_COUNT]; /* mms, depends on access algorithm */ |
136 | | unsigned int i_wait_keyframe; |
137 | | |
138 | | vlc_tick_t i_preroll_start; |
139 | | |
140 | | asf_packet_sys_t packet_sys; |
141 | | |
142 | | vlc_meta_t *meta; |
143 | | } demux_sys_t; |
144 | | |
145 | | static int DemuxInit( demux_t * ); |
146 | | static void DemuxEnd( demux_t * ); |
147 | | |
148 | | static void FlushQueue( asf_track_t * ); |
149 | | static void FlushQueues( demux_t *p_demux ); |
150 | | |
151 | | /***************************************************************************** |
152 | | * Open: check file and initializes ASF structures |
153 | | *****************************************************************************/ |
154 | | static int Open( vlc_object_t * p_this ) |
155 | 8.36k | { |
156 | 8.36k | demux_t *p_demux = (demux_t *)p_this; |
157 | 8.36k | demux_sys_t *p_sys; |
158 | 8.36k | vlc_guid_t guid; |
159 | 8.36k | const uint8_t *p_peek; |
160 | | |
161 | | /* A little test to see if it could be a asf stream */ |
162 | 8.36k | if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) < 16 ) return VLC_EGENERIC; |
163 | | |
164 | 8.35k | ASF_GetGUID( &guid, p_peek ); |
165 | 8.35k | if( !guidcmp( &guid, &asf_object_header_guid ) ) return VLC_EGENERIC; |
166 | | |
167 | | /* Set p_demux fields */ |
168 | 7.34k | p_demux->pf_demux = Demux; |
169 | 7.34k | p_demux->pf_control = Control; |
170 | 7.34k | p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) ); |
171 | | |
172 | | /* Load the headers */ |
173 | 7.34k | if( DemuxInit( p_demux ) ) |
174 | 4.62k | { |
175 | 4.62k | free( p_sys ); |
176 | 4.62k | return VLC_EGENERIC; |
177 | 4.62k | } |
178 | | |
179 | 2.72k | p_sys->packet_sys.priv = p_demux; |
180 | 2.72k | p_sys->packet_sys.s = p_demux->s; |
181 | 2.72k | p_sys->packet_sys.logger = p_demux->obj.logger; |
182 | 2.72k | p_sys->packet_sys.b_deduplicate = false; |
183 | 2.72k | p_sys->packet_sys.b_can_hold_multiple_packets = false; |
184 | 2.72k | p_sys->packet_sys.pf_doskip = Packet_DoSkip; |
185 | 2.72k | p_sys->packet_sys.pf_send = Packet_Enqueue; |
186 | 2.72k | p_sys->packet_sys.pf_gettrackinfo = Packet_GetTrackInfo; |
187 | 2.72k | p_sys->packet_sys.pf_updatetime = Packet_UpdateTime; |
188 | 2.72k | p_sys->packet_sys.pf_updatesendtime = Packet_SetSendTime; |
189 | 2.72k | p_sys->packet_sys.pf_setaspectratio = Packet_SetAR; |
190 | | |
191 | 2.72k | return VLC_SUCCESS; |
192 | 7.34k | } |
193 | | |
194 | | /***************************************************************************** |
195 | | * Demux: read packet and send them to decoders |
196 | | *****************************************************************************/ |
197 | 699M | #define CHUNK VLC_TICK_FROM_MS(100) |
198 | | static int Demux( demux_t *p_demux ) |
199 | 152M | { |
200 | 152M | demux_sys_t *p_sys = p_demux->p_sys; |
201 | | |
202 | 915M | for( int i=0; i<ES_CATEGORY_COUNT; i++ ) |
203 | 762M | { |
204 | 762M | if ( p_sys->i_access_selected_track[i] > 0 ) |
205 | 0 | { |
206 | 0 | es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE, |
207 | 0 | p_sys->track[p_sys->i_access_selected_track[i]]->p_es, true ); |
208 | 0 | p_sys->i_access_selected_track[i] = 0; |
209 | 0 | } |
210 | 762M | } |
211 | | |
212 | | /* Get selected tracks, especially for computing PCR */ |
213 | 19.6G | for( int i=0; i<MAX_ASF_TRACKS; i++ ) |
214 | 19.5G | { |
215 | 19.5G | asf_track_t *tk = p_sys->track[i]; |
216 | 19.5G | if ( !tk ) continue; |
217 | 160M | if ( tk->p_es ) |
218 | 156M | es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, & tk->b_selected ); |
219 | 4.08M | else |
220 | 4.08M | tk->b_selected = false; |
221 | 160M | } |
222 | | |
223 | 153M | while( !p_sys->b_eos && ( p_sys->i_sendtime - p_sys->i_time - CHUNK < 0 || |
224 | 98.4M | ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) < |
225 | 98.4M | p_sys->p_fp->i_preroll ) ) |
226 | 1.28M | { |
227 | | /* Read and demux a packet */ |
228 | 1.28M | if( DemuxASFPacket( &p_sys->packet_sys, |
229 | 1.28M | p_sys->p_fp->i_min_data_packet_size, |
230 | 1.28M | p_sys->p_fp->i_max_data_packet_size, |
231 | 1.28M | p_sys->i_data_begin, p_sys->i_data_end ) <= 0 ) |
232 | 3.03k | { |
233 | 3.03k | p_sys->b_eos = true; |
234 | | /* Check if we have concatenated files */ |
235 | 3.03k | const uint8_t *p_peek; |
236 | 3.03k | if( vlc_stream_Peek( p_demux->s, &p_peek, 16 ) == 16 ) |
237 | 2.23k | { |
238 | 2.23k | vlc_guid_t guid; |
239 | | |
240 | 2.23k | ASF_GetGUID( &guid, p_peek ); |
241 | 2.23k | p_sys->b_eof = !guidcmp( &guid, &asf_object_header_guid ); |
242 | 2.23k | if( !p_sys->b_eof ) |
243 | 2.23k | msg_Warn( p_demux, "found a new ASF header" ); |
244 | 2.23k | } |
245 | 805 | else |
246 | 805 | { |
247 | 805 | p_sys->b_eof = true; |
248 | 103k | for ( int i=0; i<MAX_ASF_TRACKS; i++ ) |
249 | 103k | { |
250 | 103k | asf_track_t *tk = p_sys->track[i]; |
251 | 103k | if ( tk && tk->info.p_frame ) |
252 | 319 | Packet_Enqueue( &p_sys->packet_sys, i, &tk->info.p_frame ); |
253 | 103k | } |
254 | 805 | } |
255 | 3.03k | } |
256 | | |
257 | 1.28M | if ( p_sys->i_time == VLC_TICK_INVALID ) |
258 | 1.27M | p_sys->i_time = p_sys->i_sendtime; |
259 | 1.28M | } |
260 | | |
261 | 152M | if( p_sys->b_eos || ( p_sys->i_sendtime - p_sys->i_time - CHUNK >= 0 && |
262 | 98.4M | ( p_sys->i_sendtime - p_sys->i_time - CHUNK ) >= |
263 | 98.4M | p_sys->p_fp->i_preroll ) ) |
264 | 152M | { |
265 | 152M | bool b_data = Block_Dequeue( p_demux, p_sys->i_time + CHUNK ); |
266 | | |
267 | 152M | if( p_sys->i_time != VLC_TICK_INVALID ) |
268 | 152M | { |
269 | 152M | p_sys->i_time += CHUNK; |
270 | 152M | p_sys->b_pcr_sent = true; |
271 | 152M | es_out_SetPCR( p_demux->out, p_sys->i_time ); |
272 | | #ifdef ASF_DEBUG |
273 | | msg_Dbg( p_demux, "Demux Loop Setting PCR to %"PRId64, p_sys->i_time ); |
274 | | #endif |
275 | 152M | } |
276 | | |
277 | 152M | if ( !b_data && p_sys->b_eos ) |
278 | 3.03k | { |
279 | 3.03k | if( p_sys->i_time != VLC_TICK_INVALID ) |
280 | 922 | es_out_SetPCR( p_demux->out, p_sys->i_time ); |
281 | | |
282 | | /* We end this stream */ |
283 | 3.03k | if( !p_sys->b_eof ) |
284 | 366 | { |
285 | 366 | DemuxEnd( p_demux ); |
286 | | |
287 | | /* And we prepare to read the next one */ |
288 | 366 | if( DemuxInit( p_demux ) ) |
289 | 54 | { |
290 | 54 | msg_Err( p_demux, "failed to load the new header" ); |
291 | 54 | return VLC_DEMUXER_EOF; |
292 | 54 | } |
293 | 312 | es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); |
294 | 312 | } |
295 | 2.67k | else |
296 | 2.67k | return VLC_DEMUXER_EOF; |
297 | 3.03k | } |
298 | 152M | } |
299 | | |
300 | 152M | return 1; |
301 | 152M | } |
302 | | |
303 | | /***************************************************************************** |
304 | | * Close: frees unused data |
305 | | *****************************************************************************/ |
306 | | static void Close( vlc_object_t * p_this ) |
307 | 2.72k | { |
308 | 2.72k | demux_t *p_demux = (demux_t *)p_this; |
309 | | |
310 | 2.72k | DemuxEnd( p_demux ); |
311 | | |
312 | 2.72k | free( p_demux->p_sys ); |
313 | 2.72k | } |
314 | | |
315 | | /***************************************************************************** |
316 | | * WaitKeyframe: computes the number of frames to wait for a keyframe |
317 | | *****************************************************************************/ |
318 | | static void WaitKeyframe( demux_t *p_demux ) |
319 | 0 | { |
320 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
321 | 0 | if ( ! p_sys->i_seek_track ) |
322 | 0 | { |
323 | 0 | for ( int i=0; i<MAX_ASF_TRACKS; i++ ) |
324 | 0 | { |
325 | 0 | asf_track_t *tk = p_sys->track[i]; |
326 | 0 | if ( tk && tk->info.p_sp && tk->i_cat == VIDEO_ES && tk->b_selected ) |
327 | 0 | { |
328 | 0 | p_sys->i_seek_track = tk->info.p_sp->i_stream_number; |
329 | 0 | break; |
330 | 0 | } |
331 | 0 | } |
332 | 0 | } |
333 | |
|
334 | 0 | if ( p_sys->i_seek_track ) |
335 | 0 | { |
336 | | /* Skip forward at least 1 min */ |
337 | 0 | asf_track_t *tk = p_sys->track[p_sys->i_seek_track]; |
338 | 0 | if ( tk->info.p_esp && tk->info.p_esp->i_average_time_per_frame ) |
339 | 0 | { |
340 | | /* 1 min if fastseek, otherwise 5 sec */ |
341 | | /* That's a guess for bandwidth */ |
342 | 0 | msftime_t i_maxwaittime = MSFTIME_FROM_SEC( p_sys->b_canfastseek ? 60 : 5); |
343 | 0 | uint64_t frames = i_maxwaittime / tk->info.p_esp->i_average_time_per_frame; |
344 | 0 | p_sys->i_wait_keyframe = __MIN( frames, UINT_MAX ); |
345 | 0 | } |
346 | 0 | else |
347 | 0 | { |
348 | 0 | p_sys->i_wait_keyframe = ( p_sys->b_canfastseek ) ? 25 * 30 : 25 * 5; |
349 | 0 | } |
350 | 0 | } |
351 | 0 | else |
352 | 0 | { |
353 | 0 | p_sys->i_wait_keyframe = 0; |
354 | 0 | } |
355 | |
|
356 | 0 | } |
357 | | |
358 | | /***************************************************************************** |
359 | | * SeekIndex: goto to i_date or i_percent |
360 | | *****************************************************************************/ |
361 | | static int SeekPercent( demux_t *p_demux, int i_query, va_list args ) |
362 | 0 | { |
363 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
364 | |
|
365 | 0 | WaitKeyframe( p_demux ); |
366 | |
|
367 | 0 | msg_Dbg( p_demux, "seek with percent: waiting %i frames", p_sys->i_wait_keyframe ); |
368 | 0 | return demux_vaControlHelper( p_demux->s, __MIN( INT64_MAX, p_sys->i_data_begin ), |
369 | 0 | __MIN( INT64_MAX, p_sys->i_data_end ), |
370 | 0 | __MIN( INT64_MAX, p_sys->i_bitrate ), |
371 | 0 | __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ), |
372 | 0 | i_query, args ); |
373 | 0 | } |
374 | | |
375 | | static int SeekIndex( demux_t *p_demux, vlc_tick_t i_date, float f_pos ) |
376 | 0 | { |
377 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
378 | 0 | asf_object_index_t *p_index; |
379 | |
|
380 | 0 | msg_Dbg( p_demux, "seek with index: %i seconds, position %f", |
381 | 0 | i_date >= 0 ? (int)SEC_FROM_VLC_TICK(i_date) : -1, f_pos ); |
382 | |
|
383 | 0 | if( i_date < 0 ) |
384 | 0 | i_date = p_sys->i_length * f_pos; |
385 | |
|
386 | 0 | p_sys->i_preroll_start = i_date - p_sys->p_fp->i_preroll; |
387 | 0 | if ( p_sys->i_preroll_start < 0 ) p_sys->i_preroll_start = 0; |
388 | |
|
389 | 0 | p_index = ASF_FindObject( p_sys->p_root, &asf_object_simple_index_guid, 0 ); |
390 | |
|
391 | 0 | uint64_t i_entry = MSFTIME_FROM_VLC_TICK(p_sys->i_preroll_start) / p_index->i_index_entry_time_interval; |
392 | 0 | if( i_entry >= p_index->i_index_entry_count ) |
393 | 0 | { |
394 | 0 | msg_Warn( p_demux, "Incomplete index" ); |
395 | 0 | return VLC_EGENERIC; |
396 | 0 | } |
397 | | |
398 | 0 | WaitKeyframe( p_demux ); |
399 | |
|
400 | 0 | uint64_t i_offset = (uint64_t)p_index->index_entry[i_entry].i_packet_number * |
401 | 0 | p_sys->p_fp->i_min_data_packet_size; |
402 | |
|
403 | 0 | if ( vlc_stream_Seek( p_demux->s, i_offset + p_sys->i_data_begin ) == VLC_SUCCESS ) |
404 | 0 | { |
405 | 0 | es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TICK_0 + i_date ); |
406 | 0 | return VLC_SUCCESS; |
407 | 0 | } |
408 | 0 | else return VLC_EGENERIC; |
409 | 0 | } |
410 | | |
411 | | static void SeekPrepare( demux_t *p_demux ) |
412 | 0 | { |
413 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
414 | |
|
415 | 0 | p_sys->b_eof = false; |
416 | 0 | p_sys->b_eos = false; |
417 | 0 | p_sys->b_pcr_sent = false; |
418 | 0 | p_sys->i_time = VLC_TICK_INVALID; |
419 | 0 | p_sys->i_sendtime = VLC_TICK_INVALID; |
420 | 0 | p_sys->i_preroll_start = ASFPACKET_PREROLL_FROM_CURRENT; |
421 | |
|
422 | 0 | for( int i = 0; i < MAX_ASF_TRACKS ; i++ ) |
423 | 0 | { |
424 | 0 | asf_track_t *tk = p_sys->track[i]; |
425 | 0 | if( tk ) |
426 | 0 | { |
427 | 0 | FlushQueue( tk ); |
428 | 0 | tk->i_time = VLC_TICK_INVALID; |
429 | 0 | } |
430 | 0 | } |
431 | |
|
432 | 0 | es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); |
433 | 0 | } |
434 | | |
435 | | /***************************************************************************** |
436 | | * Control: |
437 | | *****************************************************************************/ |
438 | | static int Control( demux_t *p_demux, int i_query, va_list args ) |
439 | 0 | { |
440 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
441 | 0 | vlc_meta_t *p_meta; |
442 | 0 | vlc_tick_t i64; |
443 | 0 | int i; |
444 | 0 | double f, *pf; |
445 | |
|
446 | 0 | switch( i_query ) |
447 | 0 | { |
448 | 0 | case DEMUX_GET_LENGTH: |
449 | 0 | *va_arg( args, vlc_tick_t * ) = p_sys->i_length; |
450 | 0 | return VLC_SUCCESS; |
451 | | |
452 | 0 | case DEMUX_GET_TIME: |
453 | 0 | if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC; |
454 | 0 | *va_arg( args, vlc_tick_t * ) = p_sys->i_time; |
455 | 0 | return VLC_SUCCESS; |
456 | | |
457 | 0 | case DEMUX_SET_TIME: |
458 | 0 | if ( !p_sys->p_fp || |
459 | 0 | ! ( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) ) |
460 | 0 | return VLC_EGENERIC; |
461 | | |
462 | 0 | SeekPrepare( p_demux ); |
463 | |
|
464 | 0 | if( p_sys->b_index && p_sys->i_length != 0 ) |
465 | 0 | { |
466 | 0 | va_list acpy; |
467 | 0 | va_copy( acpy, args ); |
468 | 0 | i64 = va_arg( acpy, vlc_tick_t ); |
469 | 0 | va_end( acpy ); |
470 | |
|
471 | 0 | if( !SeekIndex( p_demux, i64, -1 ) ) |
472 | 0 | return VLC_SUCCESS; |
473 | 0 | } |
474 | 0 | return SeekPercent( p_demux, i_query, args ); |
475 | | |
476 | 0 | case DEMUX_SET_ES: |
477 | 0 | { |
478 | 0 | i = va_arg( args, int ); |
479 | 0 | int i_ret; |
480 | 0 | if ( i >= 0 ) |
481 | 0 | { |
482 | 0 | msg_Dbg( p_demux, "Requesting access to enable stream %d", i ); |
483 | 0 | i_ret = vlc_stream_Control( p_demux->s, |
484 | 0 | STREAM_SET_PRIVATE_ID_STATE, i, true ); |
485 | 0 | } |
486 | 0 | else |
487 | 0 | { /* i contains -1 * es_category */ |
488 | 0 | msg_Dbg( p_demux, "Requesting access to disable stream %d", i ); |
489 | 0 | i_ret = vlc_stream_Control( p_demux->s, |
490 | 0 | STREAM_SET_PRIVATE_ID_STATE, i, |
491 | 0 | false ); |
492 | 0 | } |
493 | |
|
494 | 0 | if ( i_ret == VLC_SUCCESS ) |
495 | 0 | { |
496 | 0 | asf_track_t *tk; |
497 | 0 | if( i >= 0 ) |
498 | 0 | { |
499 | 0 | tk = p_sys->track[i]; |
500 | 0 | } |
501 | 0 | else |
502 | 0 | { |
503 | 0 | for( int j = 0; j < MAX_ASF_TRACKS ; j++ ) |
504 | 0 | { |
505 | 0 | tk = p_sys->track[j]; |
506 | 0 | if( !tk || !tk->p_fmt || tk->i_cat != -1 * i ) |
507 | 0 | continue; |
508 | 0 | FlushQueue( tk ); |
509 | 0 | tk->i_time = VLC_TICK_INVALID; |
510 | 0 | } |
511 | 0 | } |
512 | |
|
513 | 0 | p_sys->i_seek_track = 0; |
514 | 0 | if ( ( tk && tk->i_cat == VIDEO_ES ) || i == -1 * VIDEO_ES ) |
515 | 0 | WaitKeyframe( p_demux ); |
516 | 0 | } |
517 | 0 | return i_ret; |
518 | 0 | } |
519 | | |
520 | 0 | case DEMUX_SET_ES_LIST: |
521 | 0 | return VLC_EGENERIC; /* TODO */ |
522 | | |
523 | 0 | case DEMUX_GET_POSITION: |
524 | 0 | if( p_sys->i_time == VLC_TICK_INVALID ) return VLC_EGENERIC; |
525 | 0 | if( p_sys->i_length != 0 ) |
526 | 0 | { |
527 | 0 | pf = va_arg( args, double * ); |
528 | 0 | *pf = p_sys->i_time / (double)p_sys->i_length; |
529 | 0 | return VLC_SUCCESS; |
530 | 0 | } |
531 | 0 | return demux_vaControlHelper( p_demux->s, |
532 | 0 | __MIN( INT64_MAX, p_sys->i_data_begin ), |
533 | 0 | __MIN( INT64_MAX, p_sys->i_data_end ), |
534 | 0 | __MIN( INT64_MAX, p_sys->i_bitrate ), |
535 | 0 | __MIN( INT16_MAX, p_sys->p_fp->i_min_data_packet_size ), |
536 | 0 | i_query, args ); |
537 | | |
538 | 0 | case DEMUX_SET_POSITION: |
539 | 0 | if ( !p_sys->p_fp || |
540 | 0 | ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) ) |
541 | 0 | return VLC_EGENERIC; |
542 | | |
543 | 0 | SeekPrepare( p_demux ); |
544 | |
|
545 | 0 | if( p_sys->b_index && p_sys->i_length != 0 ) |
546 | 0 | { |
547 | 0 | va_list acpy; |
548 | 0 | va_copy( acpy, args ); |
549 | 0 | f = va_arg( acpy, double ); |
550 | 0 | va_end( acpy ); |
551 | |
|
552 | 0 | if( !SeekIndex( p_demux, -1, f ) ) |
553 | 0 | return VLC_SUCCESS; |
554 | 0 | } |
555 | 0 | return SeekPercent( p_demux, i_query, args ); |
556 | | |
557 | 0 | case DEMUX_GET_META: |
558 | 0 | p_meta = va_arg( args, vlc_meta_t * ); |
559 | 0 | vlc_meta_Merge( p_meta, p_sys->meta ); |
560 | 0 | return VLC_SUCCESS; |
561 | | |
562 | 0 | case DEMUX_CAN_SEEK: |
563 | 0 | if ( !p_sys->p_fp || |
564 | 0 | ( !( p_sys->p_fp->i_flags & ASF_FILE_PROPERTIES_SEEKABLE ) && !p_sys->b_index ) ) |
565 | 0 | { |
566 | 0 | bool *pb_bool = va_arg( args, bool * ); |
567 | 0 | *pb_bool = false; |
568 | 0 | return VLC_SUCCESS; |
569 | 0 | } |
570 | | /* fall through */ |
571 | 0 | default: |
572 | 0 | return demux_vaControlHelper( p_demux->s, |
573 | 0 | __MIN( INT64_MAX, p_sys->i_data_begin ), |
574 | 0 | __MIN( INT64_MAX, p_sys->i_data_end), |
575 | 0 | __MIN( INT64_MAX, p_sys->i_bitrate ), |
576 | 0 | ( p_sys->p_fp ) ? __MIN( INT_MAX, p_sys->p_fp->i_min_data_packet_size ) : 1, |
577 | 0 | i_query, args ); |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | /***************************************************************************** |
582 | | * |
583 | | *****************************************************************************/ |
584 | | static void Packet_SetAR( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, |
585 | | uint8_t i_ratio_x, uint8_t i_ratio_y ) |
586 | 0 | { |
587 | 0 | demux_t *p_demux = p_packetsys->priv; |
588 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
589 | 0 | asf_track_t *tk = p_sys->track[i_stream_number]; |
590 | |
|
591 | 0 | if ( !tk->p_fmt || (tk->p_fmt->video.i_sar_num == i_ratio_x && tk->p_fmt->video.i_sar_den == i_ratio_y ) ) |
592 | 0 | return; |
593 | | |
594 | 0 | tk->p_fmt->video.i_sar_num = i_ratio_x; |
595 | 0 | tk->p_fmt->video.i_sar_den = i_ratio_y; |
596 | 0 | if( tk->p_es ) |
597 | 0 | es_out_Control( p_demux->out, ES_OUT_SET_ES_FMT, tk->p_es, tk->p_fmt ); |
598 | 0 | } |
599 | | |
600 | | static void Packet_SetSendTime( asf_packet_sys_t *p_packetsys, vlc_tick_t i_time ) |
601 | 14.4k | { |
602 | 14.4k | demux_t *p_demux = p_packetsys->priv; |
603 | 14.4k | demux_sys_t *p_sys = p_demux->p_sys; |
604 | | |
605 | 14.4k | p_sys->i_sendtime = VLC_TICK_0 + i_time; |
606 | 14.4k | } |
607 | | |
608 | | static void Packet_UpdateTime( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, |
609 | | vlc_tick_t i_time ) |
610 | 5.11k | { |
611 | 5.11k | demux_t *p_demux = p_packetsys->priv; |
612 | 5.11k | demux_sys_t *p_sys = p_demux->p_sys; |
613 | 5.11k | asf_track_t *tk = p_sys->track[i_stream_number]; |
614 | | |
615 | 5.11k | if ( tk ) |
616 | 5.11k | tk->i_time = VLC_TICK_0 + i_time; |
617 | 5.11k | } |
618 | | |
619 | | static asf_track_info_t * Packet_GetTrackInfo( asf_packet_sys_t *p_packetsys, |
620 | | uint8_t i_stream_number ) |
621 | 43.1k | { |
622 | 43.1k | demux_t *p_demux = p_packetsys->priv; |
623 | 43.1k | demux_sys_t *p_sys = p_demux->p_sys; |
624 | 43.1k | asf_track_t *tk = p_sys->track[i_stream_number]; |
625 | | |
626 | 43.1k | if (!tk) |
627 | 27.4k | return NULL; |
628 | 15.7k | else |
629 | 15.7k | return & tk->info; |
630 | 43.1k | } |
631 | | |
632 | | static bool Packet_DoSkip( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, bool b_packet_keyframe ) |
633 | 15.3k | { |
634 | 15.3k | demux_t *p_demux = p_packetsys->priv; |
635 | 15.3k | demux_sys_t *p_sys = p_demux->p_sys; |
636 | 15.3k | const asf_track_t *tk = p_sys->track[i_stream_number]; |
637 | | |
638 | 15.3k | if( tk == NULL ) |
639 | 0 | { |
640 | 0 | msg_Warn( p_demux, "undeclared stream[Id 0x%x]", i_stream_number ); |
641 | 0 | return true; |
642 | 0 | } |
643 | | |
644 | 15.3k | if( p_sys->i_wait_keyframe ) |
645 | 0 | { |
646 | 0 | if ( i_stream_number == p_sys->i_seek_track ) |
647 | 0 | { |
648 | 0 | if ( !b_packet_keyframe ) |
649 | 0 | { |
650 | 0 | p_sys->i_wait_keyframe--; |
651 | 0 | return true; |
652 | 0 | } |
653 | 0 | else |
654 | 0 | p_sys->i_wait_keyframe = 0; |
655 | 0 | } |
656 | 0 | else |
657 | 0 | return true; |
658 | 0 | } |
659 | | |
660 | 15.3k | if( !tk->p_es ) |
661 | 890 | return true; |
662 | | |
663 | 14.4k | return false; |
664 | 15.3k | } |
665 | | |
666 | | static void Packet_Enqueue( asf_packet_sys_t *p_packetsys, uint8_t i_stream_number, block_t **pp_frame ) |
667 | 78.2k | { |
668 | 78.2k | demux_t *p_demux = p_packetsys->priv; |
669 | 78.2k | demux_sys_t *p_sys = p_demux->p_sys; |
670 | 78.2k | asf_track_t *tk = p_sys->track[i_stream_number]; |
671 | 78.2k | if ( !tk ) |
672 | 0 | return; |
673 | | |
674 | 78.2k | block_t *p_gather = block_ChainGather( *pp_frame ); |
675 | 78.2k | if( p_gather ) |
676 | 78.2k | { |
677 | 78.2k | block_ChainLastAppend( & tk->queue.pp_last, p_gather ); |
678 | | #ifdef ASF_DEBUG |
679 | | msg_Dbg( p_demux, " enqueue packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_gather->i_dts, p_gather->i_pts, p_sys->i_time ); |
680 | | #endif |
681 | 78.2k | } |
682 | | |
683 | 78.2k | *pp_frame = NULL; |
684 | 78.2k | } |
685 | | |
686 | | static bool Block_Dequeue( demux_t *p_demux, vlc_tick_t i_nexttime ) |
687 | 152M | { |
688 | 152M | demux_sys_t *p_sys = p_demux->p_sys; |
689 | 152M | bool b_tracks_have_data = false; |
690 | 19.6G | for( int i = 0; i < MAX_ASF_TRACKS; i++ ) |
691 | 19.5G | { |
692 | 19.5G | asf_track_t *tk = p_sys->track[i]; |
693 | 19.5G | if (!tk) |
694 | 19.3G | continue; |
695 | 160M | b_tracks_have_data |= (tk->queue.p_first != NULL); |
696 | 160M | while( tk->queue.p_first && tk->queue.p_first->i_dts <= i_nexttime ) |
697 | 78.2k | { |
698 | 78.2k | block_t *p_block = tk->queue.p_first; |
699 | 78.2k | tk->queue.p_first = p_block->p_next; |
700 | 78.2k | if( tk->queue.p_first == NULL ) |
701 | 996 | tk->queue.pp_last = &tk->queue.p_first; |
702 | 77.2k | else |
703 | 77.2k | p_block->p_next = NULL; |
704 | | |
705 | 78.2k | if( !p_sys->b_pcr_sent && p_sys->i_time != VLC_TICK_INVALID ) |
706 | 764 | { |
707 | 764 | p_sys->b_pcr_sent = true; |
708 | 764 | es_out_SetPCR( p_demux->out, p_sys->i_time ); |
709 | | #ifdef ASF_DEBUG |
710 | | msg_Dbg( p_demux, " dequeue setting PCR to %"PRId64, p_sys->i_time ); |
711 | | #endif |
712 | 764 | } |
713 | | |
714 | | #ifdef ASF_DEBUG |
715 | | msg_Dbg( p_demux, " sending packet dts %"PRId64" pts %"PRId64" pcr %"PRId64, p_block->i_dts, p_block->i_pts, p_sys->i_time ); |
716 | | #endif |
717 | 78.2k | es_out_Send( p_demux->out, tk->p_es, p_block ); |
718 | 78.2k | } |
719 | 160M | } |
720 | 152M | return b_tracks_have_data; |
721 | 152M | } |
722 | | |
723 | | /***************************************************************************** |
724 | | * |
725 | | *****************************************************************************/ |
726 | | typedef struct asf_es_priorities_t |
727 | | { |
728 | | uint16_t *pi_stream_numbers; |
729 | | uint16_t i_count; |
730 | | } asf_es_priorities_t; |
731 | | |
732 | | /* Fills up our exclusion list */ |
733 | | static void ASF_fillup_es_priorities_ex( demux_sys_t *p_sys, void *p_hdr, |
734 | | asf_es_priorities_t *p_prios ) |
735 | 1.62k | { |
736 | | /* Find stream exclusions */ |
737 | 1.62k | asf_object_advanced_mutual_exclusion_t *p_mutex = |
738 | 1.62k | ASF_FindObject( p_hdr, &asf_object_advanced_mutual_exclusion, 0 ); |
739 | 1.62k | if (! p_mutex ) return; |
740 | | |
741 | 0 | p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof(*p_prios->pi_stream_numbers) ); |
742 | 0 | if ( !p_prios->pi_stream_numbers ) return; |
743 | | |
744 | 0 | if ( p_mutex->i_stream_number_count ) |
745 | 0 | { |
746 | | /* Just set highest prio on highest in the group */ |
747 | 0 | for ( uint16_t i = 1; i < p_mutex->i_stream_number_count; i++ ) |
748 | 0 | { |
749 | 0 | if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break; |
750 | 0 | p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_mutex->pi_stream_number[ i ]; |
751 | 0 | } |
752 | 0 | } |
753 | 0 | } |
754 | | |
755 | | /* Fills up our bitrate exclusion list */ |
756 | | static void ASF_fillup_es_bitrate_priorities_ex( demux_sys_t *p_sys, void *p_hdr, |
757 | | asf_es_priorities_t *p_prios ) |
758 | 1.62k | { |
759 | | /* Find bitrate exclusions */ |
760 | 1.62k | asf_object_bitrate_mutual_exclusion_t *p_bitrate_mutex = |
761 | 1.62k | ASF_FindObject( p_hdr, &asf_object_bitrate_mutual_exclusion_guid, 0 ); |
762 | 1.62k | if (! p_bitrate_mutex ) return; |
763 | | |
764 | 0 | p_prios->pi_stream_numbers = vlc_alloc( p_sys->i_track, sizeof(*p_prios->pi_stream_numbers) ); |
765 | 0 | if ( !p_prios->pi_stream_numbers ) return; |
766 | | |
767 | 0 | if ( p_bitrate_mutex->i_stream_number_count ) |
768 | 0 | { |
769 | | /* Just remove < highest */ |
770 | 0 | for ( uint16_t i = 1; i < p_bitrate_mutex->i_stream_number_count; i++ ) |
771 | 0 | { |
772 | 0 | if ( p_prios->i_count > p_sys->i_track || i > p_sys->i_track ) break; |
773 | 0 | p_prios->pi_stream_numbers[ p_prios->i_count++ ] = p_bitrate_mutex->pi_stream_numbers[ i ]; |
774 | 0 | } |
775 | 0 | } |
776 | |
|
777 | 0 | } |
778 | | |
779 | 8.01k | #define GET_CHECKED( target, getter, maxtarget, temp ) \ |
780 | 8.01k | {\ |
781 | 8.01k | temp i_temp = getter;\ |
782 | 8.01k | if ( i_temp > maxtarget ) {\ |
783 | 20 | msg_Warn( p_demux, "rejecting stream %u : " #target " overflow", i_stream );\ |
784 | 20 | es_format_Clean( &fmt );\ |
785 | 20 | goto error;\ |
786 | 7.99k | } else {\ |
787 | 7.99k | target = i_temp;\ |
788 | 7.99k | }\ |
789 | 8.01k | } |
790 | | |
791 | | static int DemuxInit( demux_t *p_demux ) |
792 | 7.71k | { |
793 | 7.71k | demux_sys_t *p_sys = p_demux->p_sys; |
794 | 7.71k | asf_es_priorities_t fmt_priorities_ex = { NULL, 0 }; |
795 | 7.71k | asf_es_priorities_t fmt_priorities_bitrate_ex = { NULL, 0 }; |
796 | | |
797 | | /* init context */ |
798 | 7.71k | p_sys->i_time = VLC_TICK_INVALID; |
799 | 7.71k | p_sys->i_sendtime = VLC_TICK_INVALID; |
800 | 7.71k | p_sys->i_length = 0; |
801 | 7.71k | p_sys->b_eos = false; |
802 | 7.71k | p_sys->b_eof = false; |
803 | 7.71k | p_sys->i_bitrate = 0; |
804 | 7.71k | p_sys->p_root = NULL; |
805 | 7.71k | p_sys->p_fp = NULL; |
806 | 7.71k | p_sys->b_index = 0; |
807 | 7.71k | p_sys->i_track = 0; |
808 | 7.71k | p_sys->i_seek_track = 0; |
809 | 7.71k | p_sys->b_pcr_sent = false; |
810 | 7.71k | p_sys->i_wait_keyframe = 0; |
811 | 995k | for( int i = 0; i < MAX_ASF_TRACKS; i++ ) |
812 | 987k | { |
813 | 987k | p_sys->track[i] = NULL; |
814 | 987k | } |
815 | 7.71k | p_sys->i_data_begin = 0; |
816 | 7.71k | p_sys->i_data_end = 0; |
817 | 7.71k | p_sys->i_preroll_start = 0; |
818 | 7.71k | p_sys->meta = NULL; |
819 | | |
820 | | /* Now load all object ( except raw data ) */ |
821 | 7.71k | vlc_stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, |
822 | 7.71k | &p_sys->b_canfastseek ); |
823 | 7.71k | if( !(p_sys->p_root = ASF_ReadObjectRoot(p_demux->s, p_sys->b_canfastseek)) ) |
824 | 4.38k | { |
825 | 4.38k | msg_Warn( p_demux, "ASF plugin discarded (not a valid file)" ); |
826 | 4.38k | return VLC_EGENERIC; |
827 | 4.38k | } |
828 | 3.32k | p_sys->p_fp = p_sys->p_root->p_fp; |
829 | | |
830 | 3.32k | if( p_sys->p_fp->i_min_data_packet_size != p_sys->p_fp->i_max_data_packet_size ) |
831 | 74 | { |
832 | 74 | msg_Warn( p_demux, "ASF plugin discarded (invalid file_properties object)" ); |
833 | 74 | goto error; |
834 | 74 | } |
835 | | |
836 | 3.25k | if ( ASF_FindObject( p_sys->p_root->p_hdr, |
837 | 3.25k | &asf_object_content_encryption_guid, 0 ) != NULL |
838 | 3.25k | || ASF_FindObject( p_sys->p_root->p_hdr, |
839 | 3.25k | &asf_object_extended_content_encryption_guid, 0 ) != NULL |
840 | 3.25k | || ASF_FindObject( p_sys->p_root->p_hdr, |
841 | 3.25k | &asf_object_advanced_content_encryption_guid, 0 ) != NULL ) |
842 | 0 | { |
843 | 0 | vlc_dialog_display_error( p_demux, _("Could not demux ASF stream"), "%s", |
844 | 0 | ("DRM protected streams are not supported.") ); |
845 | 0 | goto error; |
846 | 0 | } |
847 | | |
848 | 3.25k | p_sys->i_track = ASF_CountObject( p_sys->p_root->p_hdr, |
849 | 3.25k | &asf_object_stream_properties_guid ); |
850 | 3.25k | if( p_sys->i_track == 0 ) |
851 | 197 | { |
852 | 197 | msg_Warn( p_demux, "ASF plugin discarded (cannot find any stream!)" ); |
853 | 197 | goto error; |
854 | 197 | } |
855 | 3.05k | msg_Dbg( p_demux, "found %u streams", p_sys->i_track ); |
856 | | |
857 | | /* check if index is available */ |
858 | 3.05k | asf_object_index_t *p_index = ASF_FindObject( p_sys->p_root, |
859 | 3.05k | &asf_object_simple_index_guid, 0 ); |
860 | 3.05k | const bool b_index = p_index && p_index->i_index_entry_count; |
861 | | |
862 | | /* Find the extended header if any */ |
863 | 3.05k | asf_object_t *p_hdr_ext = ASF_FindObject( p_sys->p_root->p_hdr, |
864 | 3.05k | &asf_object_header_extension_guid, 0 ); |
865 | | |
866 | 3.05k | asf_object_language_list_t *p_languages = NULL; |
867 | | |
868 | 3.05k | if( p_hdr_ext ) |
869 | 1.62k | { |
870 | 1.62k | p_languages = ASF_FindObject( p_hdr_ext, &asf_object_language_list, 0 ); |
871 | | |
872 | 1.62k | ASF_fillup_es_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_ex ); |
873 | 1.62k | ASF_fillup_es_bitrate_priorities_ex( p_sys, p_hdr_ext, &fmt_priorities_bitrate_ex ); |
874 | 1.62k | } |
875 | | |
876 | 3.05k | const bool b_mms = !strncasecmp( p_demux->psz_url, "mms:", 4 ); |
877 | 3.05k | bool b_dvrms = false; |
878 | | |
879 | 3.05k | if( b_mms ) |
880 | 0 | { |
881 | 0 | es_out_Control( p_demux->out, ES_OUT_SET_ES_CAT_POLICY, |
882 | 0 | VIDEO_ES, ES_OUT_ES_POLICY_EXCLUSIVE ); |
883 | 0 | } |
884 | | |
885 | 6.47k | for( unsigned i_stream = 0; i_stream < p_sys->i_track; i_stream++ ) |
886 | 3.43k | { |
887 | 3.43k | asf_track_t *tk; |
888 | 3.43k | asf_object_stream_properties_t *p_sp; |
889 | 3.43k | asf_object_extended_stream_properties_t *p_esp; |
890 | 3.43k | bool b_access_selected; |
891 | | |
892 | 3.43k | p_sp = ASF_FindObject( p_sys->p_root->p_hdr, |
893 | 3.43k | &asf_object_stream_properties_guid, |
894 | 3.43k | i_stream ); |
895 | 3.43k | p_esp = NULL; |
896 | | |
897 | | /* Ignore duplicated streams numbers */ |
898 | 3.43k | if (p_sys->track[p_sp->i_stream_number]) |
899 | 7 | continue; |
900 | | |
901 | 3.42k | tk = p_sys->track[p_sp->i_stream_number] = malloc( sizeof( asf_track_t ) ); |
902 | 3.42k | if (!tk) |
903 | 0 | goto error; |
904 | 3.42k | memset( tk, 0, sizeof( asf_track_t ) ); |
905 | | |
906 | 3.42k | ASFPacketTrackInit( &tk->info ); |
907 | 3.42k | tk->i_time = VLC_TICK_INVALID; |
908 | 3.42k | tk->info.p_sp = p_sp; |
909 | 3.42k | tk->p_es = NULL; |
910 | 3.42k | tk->queue.p_first = NULL; |
911 | 3.42k | tk->queue.pp_last = &tk->queue.p_first; |
912 | 3.42k | tk->info.i_pkt = 0; |
913 | 3.42k | tk->info.i_pktcount = 0; |
914 | | |
915 | 3.42k | if ( !b_mms ) |
916 | 3.42k | { |
917 | | /* Check (not mms) if this track is selected (ie will receive data) */ |
918 | 3.42k | if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE, |
919 | 3.42k | (int) p_sp->i_stream_number, |
920 | 3.42k | &b_access_selected ) && |
921 | 0 | !b_access_selected ) |
922 | 0 | { |
923 | 0 | tk->i_cat = UNKNOWN_ES; |
924 | 0 | msg_Dbg( p_demux, "ignoring not selected stream(ID:%u) (by access)", |
925 | 0 | p_sp->i_stream_number ); |
926 | 0 | continue; |
927 | 0 | } |
928 | 3.42k | } |
929 | | |
930 | | /* Find the associated extended_stream_properties if any */ |
931 | 3.42k | if( p_hdr_ext ) |
932 | 1.97k | { |
933 | 1.97k | int i_ext_stream = ASF_CountObject( p_hdr_ext, |
934 | 1.97k | &asf_object_extended_stream_properties_guid ); |
935 | 2.24k | for( int i = 0; i < i_ext_stream; i++ ) |
936 | 685 | { |
937 | 685 | asf_object_t *p_tmp = |
938 | 685 | ASF_FindObject( p_hdr_ext, |
939 | 685 | &asf_object_extended_stream_properties_guid, i ); |
940 | 685 | if( p_tmp->ext_stream.i_stream_number == p_sp->i_stream_number ) |
941 | 417 | { |
942 | 417 | p_esp = &p_tmp->ext_stream; |
943 | 417 | tk->info.p_esp = p_esp; |
944 | 417 | break; |
945 | 417 | } |
946 | 685 | } |
947 | 1.97k | } |
948 | | |
949 | | /* Check for DVR-MS */ |
950 | 3.42k | if( p_esp ) |
951 | 1.95k | for( uint16_t i=0; i<p_esp->i_payload_extension_system_count && !b_dvrms; i++ ) |
952 | 1.53k | b_dvrms = guidcmp( &p_esp->p_ext[i].i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid ); |
953 | | |
954 | 3.42k | es_format_t fmt; |
955 | | |
956 | 3.42k | if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_audio ) && |
957 | 2.19k | p_sp->i_type_specific_data_length >= sizeof( WAVEFORMATEX ) - 2 ) |
958 | 2.12k | { |
959 | 2.12k | uint8_t *p_data = p_sp->p_type_specific_data; |
960 | 2.12k | int i_format; |
961 | | |
962 | 2.12k | es_format_Init( &fmt, AUDIO_ES, 0 ); |
963 | 2.12k | i_format = GetWLE( &p_data[0] ); |
964 | 2.12k | wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL ); |
965 | | |
966 | 2.12k | GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ), |
967 | 2.12k | 255, uint16_t ); |
968 | 2.10k | GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ), |
969 | 2.10k | UINT_MAX, uint32_t ); |
970 | 2.10k | GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8, |
971 | 2.10k | UINT_MAX, uint32_t ); |
972 | 2.10k | fmt.audio.i_blockalign = GetWLE( &p_data[12] ); |
973 | 2.10k | fmt.audio.i_bitspersample = GetWLE( &p_data[14] ); |
974 | | |
975 | 2.10k | if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) && |
976 | 477 | i_format != WAVE_FORMAT_MPEGLAYER3 && |
977 | 472 | i_format != WAVE_FORMAT_MPEG ) |
978 | 471 | { |
979 | 471 | GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ), |
980 | 471 | p_sp->i_type_specific_data_length - |
981 | 471 | sizeof( WAVEFORMATEX ) ), |
982 | 471 | INT_MAX, uint32_t ); |
983 | 471 | fmt.p_extra = malloc( fmt.i_extra ); |
984 | 471 | memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], |
985 | 471 | fmt.i_extra ); |
986 | 471 | } |
987 | 2.10k | msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)", |
988 | 2.10k | (char*)&fmt.i_codec, GetWLE( p_data ), p_sp->i_stream_number ); |
989 | 2.10k | } |
990 | 1.30k | else if( guidcmp( &p_sp->i_stream_type, |
991 | 1.30k | &asf_object_stream_type_video ) && |
992 | 397 | p_sp->i_type_specific_data_length >= 11 + |
993 | 397 | sizeof( VLC_BITMAPINFOHEADER ) ) |
994 | 361 | { |
995 | 361 | uint8_t *p_data = &p_sp->p_type_specific_data[11]; |
996 | | |
997 | 361 | es_format_Init( &fmt, VIDEO_ES, |
998 | 361 | VLC_FOURCC( p_data[16], p_data[17], |
999 | 361 | p_data[18], p_data[19] ) ); |
1000 | | |
1001 | 361 | GET_CHECKED( fmt.video.i_width, GetDWLE( p_data + 4 ), |
1002 | 361 | UINT_MAX, uint32_t ); |
1003 | 361 | GET_CHECKED( fmt.video.i_height, GetDWLE( p_data + 8 ), |
1004 | 361 | UINT_MAX, uint32_t ); |
1005 | 361 | fmt.video.i_visible_width = fmt.video.i_width; |
1006 | 361 | fmt.video.i_visible_height = fmt.video.i_height; |
1007 | | |
1008 | 361 | if( p_esp && p_esp->i_average_time_per_frame > 0 ) |
1009 | 156 | { |
1010 | 156 | fmt.video.i_frame_rate = 10000000; |
1011 | 156 | GET_CHECKED( fmt.video.i_frame_rate_base, |
1012 | 156 | p_esp->i_average_time_per_frame, |
1013 | 156 | UINT_MAX, uint64_t ); |
1014 | 148 | } |
1015 | | |
1016 | 353 | if( fmt.i_codec == VLC_FOURCC( 'D','V','R',' ') ) |
1017 | 0 | { |
1018 | | /* DVR-MS special ASF */ |
1019 | 0 | fmt.i_codec = VLC_CODEC_MPGV; |
1020 | 0 | } |
1021 | | |
1022 | 353 | if( p_sp->i_type_specific_data_length > 11 + |
1023 | 353 | sizeof( VLC_BITMAPINFOHEADER ) ) |
1024 | 330 | { |
1025 | 330 | GET_CHECKED( fmt.i_extra, __MIN( GetDWLE( p_data ), |
1026 | 330 | p_sp->i_type_specific_data_length - 11 - |
1027 | 330 | sizeof( VLC_BITMAPINFOHEADER ) ), |
1028 | 330 | UINT_MAX, uint32_t ); |
1029 | 330 | fmt.p_extra = malloc( fmt.i_extra ); |
1030 | 330 | memcpy( fmt.p_extra, &p_data[sizeof( VLC_BITMAPINFOHEADER )], |
1031 | 330 | fmt.i_extra ); |
1032 | 330 | } |
1033 | | |
1034 | | /* Look for an aspect ratio */ |
1035 | 353 | if( p_sys->p_root->p_metadata ) |
1036 | 239 | { |
1037 | 239 | asf_object_metadata_t *p_meta = p_sys->p_root->p_metadata; |
1038 | 239 | unsigned int i_aspect_x = 0, i_aspect_y = 0; |
1039 | 239 | uint32_t i; |
1040 | 1.49k | for( i = 0; i < p_meta->i_record_entries_count; i++ ) |
1041 | 1.25k | { |
1042 | 1.25k | if( !p_meta->record[i].psz_name ) |
1043 | 28 | continue; |
1044 | 1.22k | if( !strcmp( p_meta->record[i].psz_name, "AspectRatioX" ) ) |
1045 | 0 | { |
1046 | 0 | if( (!i_aspect_x && !p_meta->record[i].i_stream) || |
1047 | 0 | p_meta->record[i].i_stream == |
1048 | 0 | p_sp->i_stream_number ) |
1049 | 0 | GET_CHECKED( i_aspect_x, p_meta->record[i].i_val, |
1050 | 0 | UINT_MAX, uint64_t ); |
1051 | 0 | } |
1052 | 1.22k | if( !strcmp( p_meta->record[i].psz_name, "AspectRatioY" ) ) |
1053 | 0 | { |
1054 | 0 | if( (!i_aspect_y && !p_meta->record[i].i_stream) || |
1055 | 0 | p_meta->record[i].i_stream == |
1056 | 0 | p_sp->i_stream_number ) |
1057 | 0 | GET_CHECKED( i_aspect_y, p_meta->record[i].i_val, |
1058 | 0 | UINT_MAX, uint64_t ); |
1059 | 0 | } |
1060 | 1.22k | } |
1061 | | |
1062 | 239 | if( i_aspect_x && i_aspect_y ) |
1063 | 0 | { |
1064 | 0 | fmt.video.i_sar_num = i_aspect_x; |
1065 | 0 | fmt.video.i_sar_den = i_aspect_y; |
1066 | 0 | } |
1067 | 239 | } |
1068 | | |
1069 | | /* If there is a video track then use the index for seeking */ |
1070 | 353 | p_sys->b_index = b_index; |
1071 | | |
1072 | 353 | msg_Dbg( p_demux, "added new video stream(codec:%4.4s,ID:%d)", |
1073 | 353 | (char*)&fmt.i_codec, p_sp->i_stream_number ); |
1074 | 353 | } |
1075 | 944 | else if( guidcmp( &p_sp->i_stream_type, &asf_object_stream_type_binary ) && |
1076 | 0 | p_sp->i_type_specific_data_length >= 64 ) |
1077 | 0 | { |
1078 | 0 | vlc_guid_t i_major_media_type; |
1079 | 0 | ASF_GetGUID( &i_major_media_type, p_sp->p_type_specific_data ); |
1080 | 0 | msg_Dbg( p_demux, "stream(ID:%d) major type " GUID_FMT, p_sp->i_stream_number, |
1081 | 0 | GUID_PRINT(i_major_media_type) ); |
1082 | |
|
1083 | 0 | vlc_guid_t i_media_subtype; |
1084 | 0 | ASF_GetGUID( &i_media_subtype, &p_sp->p_type_specific_data[16] ); |
1085 | 0 | msg_Dbg( p_demux, "stream(ID:%d) subtype " GUID_FMT, p_sp->i_stream_number, |
1086 | 0 | GUID_PRINT(i_media_subtype) ); |
1087 | | |
1088 | | //uint32_t i_fixed_size_samples = GetDWBE( &p_sp->p_type_specific_data[32] ); |
1089 | | //uint32_t i_temporal_compression = GetDWBE( &p_sp->p_type_specific_data[36] ); |
1090 | | //uint32_t i_sample_size = GetDWBE( &p_sp->p_type_specific_data[40] ); |
1091 | |
|
1092 | 0 | vlc_guid_t i_format_type; |
1093 | 0 | ASF_GetGUID( &i_format_type, &p_sp->p_type_specific_data[44] ); |
1094 | 0 | msg_Dbg( p_demux, "stream(ID:%d) format type " GUID_FMT, p_sp->i_stream_number, |
1095 | 0 | GUID_PRINT(i_format_type) ); |
1096 | | |
1097 | | //uint32_t i_format_data_size = GetDWBE( &p_sp->p_type_specific_data[60] ); |
1098 | 0 | uint8_t *p_data = p_sp->p_type_specific_data + 64; |
1099 | 0 | unsigned int i_data = p_sp->i_type_specific_data_length - 64; |
1100 | |
|
1101 | 0 | msg_Dbg( p_demux, "Ext stream header detected. datasize = %d", p_sp->i_type_specific_data_length ); |
1102 | 0 | if( guidcmp( &i_major_media_type, &asf_object_extended_stream_type_audio ) && |
1103 | 0 | i_data >= sizeof( WAVEFORMATEX ) - 2) |
1104 | 0 | { |
1105 | 0 | uint16_t i_format; |
1106 | 0 | es_format_Init( &fmt, AUDIO_ES, 0 ); |
1107 | |
|
1108 | 0 | i_format = GetWLE( &p_data[0] ); |
1109 | 0 | if( i_format == 0 ) |
1110 | 0 | fmt.i_codec = VLC_CODEC_A52; |
1111 | 0 | else |
1112 | 0 | wf_tag_to_fourcc( i_format, &fmt.i_codec, NULL ); |
1113 | |
|
1114 | 0 | GET_CHECKED( fmt.audio.i_channels, GetWLE( &p_data[2] ), |
1115 | 0 | 255, uint16_t ); |
1116 | 0 | GET_CHECKED( fmt.audio.i_rate, GetDWLE( &p_data[4] ), |
1117 | 0 | UINT_MAX, uint32_t ); |
1118 | 0 | GET_CHECKED( fmt.i_bitrate, GetDWLE( &p_data[8] ) * 8, |
1119 | 0 | UINT_MAX, uint32_t ); |
1120 | 0 | fmt.audio.i_blockalign = GetWLE( &p_data[12] ); |
1121 | 0 | fmt.audio.i_bitspersample = GetWLE( &p_data[14] ); |
1122 | |
|
1123 | 0 | if( p_sp->i_type_specific_data_length > sizeof( WAVEFORMATEX ) && |
1124 | 0 | i_format != WAVE_FORMAT_MPEGLAYER3 && |
1125 | 0 | i_format != WAVE_FORMAT_MPEG && i_data >= 19 ) |
1126 | 0 | { |
1127 | 0 | GET_CHECKED( fmt.i_extra, __MIN( GetWLE( &p_data[16] ), |
1128 | 0 | p_sp->i_type_specific_data_length - |
1129 | 0 | sizeof( WAVEFORMATEX ) - 64), |
1130 | 0 | INT_MAX, uint32_t ); |
1131 | 0 | fmt.p_extra = malloc( fmt.i_extra ); |
1132 | 0 | if ( fmt.p_extra ) |
1133 | 0 | memcpy( fmt.p_extra, &p_data[sizeof( WAVEFORMATEX )], fmt.i_extra ); |
1134 | 0 | else |
1135 | 0 | fmt.i_extra = 0; |
1136 | 0 | } |
1137 | | |
1138 | 0 | msg_Dbg( p_demux, "added new audio stream (codec:%4.4s(0x%x),ID:%d)", |
1139 | 0 | (char*)&fmt.i_codec, i_format, p_sp->i_stream_number ); |
1140 | 0 | } |
1141 | 0 | else |
1142 | 0 | { |
1143 | 0 | es_format_Init( &fmt, UNKNOWN_ES, 0 ); |
1144 | 0 | } |
1145 | 0 | } |
1146 | 944 | else |
1147 | 944 | { |
1148 | 944 | es_format_Init( &fmt, UNKNOWN_ES, 0 ); |
1149 | 944 | } |
1150 | | |
1151 | 3.40k | if( b_dvrms ) |
1152 | 0 | { |
1153 | 0 | fmt.i_original_fourcc = VLC_FOURCC( 'D','V','R',' '); |
1154 | 0 | fmt.b_packetized = false; |
1155 | 0 | } |
1156 | | |
1157 | 3.40k | if( fmt.i_codec == VLC_CODEC_MP4A ) |
1158 | 201 | fmt.b_packetized = false; |
1159 | | |
1160 | 3.40k | tk->i_cat = tk->info.i_cat = fmt.i_cat; |
1161 | 3.40k | if( fmt.i_cat != UNKNOWN_ES ) |
1162 | 2.46k | { |
1163 | 2.46k | if( p_esp && p_languages && |
1164 | 239 | p_esp->i_language_index < p_languages->i_language && |
1165 | 233 | p_languages->ppsz_language[p_esp->i_language_index] ) |
1166 | 230 | { |
1167 | 230 | fmt.psz_language = strdup( p_languages->ppsz_language[p_esp->i_language_index] ); |
1168 | 230 | char *p; |
1169 | 230 | if( fmt.psz_language && (p = strchr( fmt.psz_language, '-' )) ) |
1170 | 226 | *p = '\0'; |
1171 | 230 | } |
1172 | | |
1173 | | /* Set our priority so we won't get multiple videos */ |
1174 | 2.46k | int i_priority = ES_PRIORITY_SELECTABLE_MIN; |
1175 | 2.46k | for( uint16_t i = 0; i < fmt_priorities_ex.i_count; i++ ) |
1176 | 0 | { |
1177 | 0 | if ( fmt_priorities_ex.pi_stream_numbers[i] == p_sp->i_stream_number ) |
1178 | 0 | { |
1179 | 0 | i_priority = ES_PRIORITY_NOT_DEFAULTABLE; |
1180 | 0 | break; |
1181 | 0 | } |
1182 | 0 | } |
1183 | 2.46k | for( uint16_t i = 0; i < fmt_priorities_bitrate_ex.i_count; i++ ) |
1184 | 0 | { |
1185 | 0 | if ( fmt_priorities_bitrate_ex.pi_stream_numbers[i] == p_sp->i_stream_number ) |
1186 | 0 | { |
1187 | 0 | i_priority = ES_PRIORITY_NOT_DEFAULTABLE; |
1188 | 0 | break; |
1189 | 0 | } |
1190 | 0 | } |
1191 | 2.46k | fmt.i_priority = i_priority; |
1192 | | |
1193 | 2.46k | if ( i_stream <= INT_MAX ) |
1194 | 2.46k | fmt.i_id = i_stream; |
1195 | 0 | else |
1196 | 2.46k | msg_Warn( p_demux, "Can't set fmt.i_id to match stream id %u", i_stream ); |
1197 | | |
1198 | 2.46k | if ( fmt.i_cat == VIDEO_ES ) |
1199 | 353 | { |
1200 | | /* Backup our video format */ |
1201 | 353 | tk->p_fmt = malloc( sizeof( es_format_t ) ); |
1202 | 353 | if ( tk->p_fmt ) |
1203 | 353 | es_format_Copy( tk->p_fmt, &fmt ); |
1204 | 353 | } |
1205 | | |
1206 | 2.46k | fmt.i_id = tk->info.p_sp->i_stream_number; |
1207 | | |
1208 | 2.46k | tk->p_es = es_out_Add( p_demux->out, &fmt ); |
1209 | | |
1210 | 2.46k | if( !vlc_stream_Control( p_demux->s, STREAM_GET_PRIVATE_ID_STATE, |
1211 | 2.46k | (int) p_sp->i_stream_number, |
1212 | 2.46k | &b_access_selected ) && |
1213 | 0 | b_access_selected ) |
1214 | 0 | { |
1215 | 0 | p_sys->i_access_selected_track[fmt.i_cat] = p_sp->i_stream_number; |
1216 | 0 | } |
1217 | | |
1218 | 2.46k | } |
1219 | 944 | else |
1220 | 944 | { |
1221 | 944 | msg_Dbg( p_demux, "ignoring unknown stream(ID:%d)", |
1222 | 944 | p_sp->i_stream_number ); |
1223 | 944 | } |
1224 | | |
1225 | 3.40k | es_format_Clean( &fmt ); |
1226 | 3.40k | } |
1227 | | |
1228 | 3.03k | p_sys->i_data_begin = p_sys->p_root->p_data->i_object_pos + 50; |
1229 | 3.03k | if( p_sys->p_root->p_data->i_object_size > 50 ) /* see libasf ASF_OBJECT_DATA <= 50 handling */ |
1230 | 2.88k | { /* local file */ |
1231 | 2.88k | p_sys->i_data_end = p_sys->p_root->p_data->i_object_pos + |
1232 | 2.88k | p_sys->p_root->p_data->i_object_size; |
1233 | 2.88k | p_sys->i_data_end = __MIN( (uint64_t)stream_Size( p_demux->s ), p_sys->i_data_end ); |
1234 | 2.88k | } |
1235 | 156 | else |
1236 | 156 | { /* live/broacast */ |
1237 | 156 | p_sys->i_data_end = 0; |
1238 | 156 | } |
1239 | | |
1240 | | /* go to first packet */ |
1241 | 3.03k | if( vlc_stream_Seek( p_demux->s, p_sys->i_data_begin ) != VLC_SUCCESS ) |
1242 | 0 | goto error; |
1243 | | |
1244 | | /* try to calculate movie time */ |
1245 | 3.03k | if( p_sys->p_fp->i_data_packets_count > 0 ) |
1246 | 2.98k | { |
1247 | 2.98k | uint64_t i_count; |
1248 | 2.98k | uint64_t i_size = stream_Size( p_demux->s ); |
1249 | | |
1250 | 2.98k | if( p_sys->i_data_end > 0 && i_size > p_sys->i_data_end ) |
1251 | 72 | { |
1252 | 72 | i_size = p_sys->i_data_end; |
1253 | 72 | } |
1254 | | |
1255 | | /* real number of packets */ |
1256 | 2.98k | i_count = ( i_size - p_sys->i_data_begin ) / |
1257 | 2.98k | p_sys->p_fp->i_min_data_packet_size; |
1258 | | |
1259 | | /* calculate the time duration in micro-s */ |
1260 | 2.98k | if ( ckd_mul(&p_sys->i_length, VLC_TICK_FROM_MSFTIME(p_sys->p_fp->i_play_duration), i_count) ) |
1261 | 106 | p_sys->i_length = 0; |
1262 | 2.98k | p_sys->i_length = p_sys->i_length / |
1263 | 2.98k | (vlc_tick_t)p_sys->p_fp->i_data_packets_count; |
1264 | 2.98k | if( p_sys->i_length <= p_sys->p_fp->i_preroll ) |
1265 | 2.62k | p_sys->i_length = 0; |
1266 | 360 | else |
1267 | 360 | { |
1268 | 360 | p_sys->i_length -= p_sys->p_fp->i_preroll; |
1269 | 360 | p_sys->i_bitrate = 8 * i_size * CLOCK_FREQ / p_sys->i_length; |
1270 | 360 | } |
1271 | 2.98k | } |
1272 | | |
1273 | | /* Create meta information */ |
1274 | 3.03k | p_sys->meta = vlc_meta_New(); |
1275 | | |
1276 | 3.03k | asf_object_content_description_t *p_cd; |
1277 | 3.03k | if( ( p_cd = ASF_FindObject( p_sys->p_root->p_hdr, |
1278 | 3.03k | &asf_object_content_description_guid, 0 ) ) ) |
1279 | 620 | { |
1280 | 620 | if( p_cd->psz_title && *p_cd->psz_title ) |
1281 | 561 | { |
1282 | 561 | vlc_meta_SetTitle( p_sys->meta, p_cd->psz_title ); |
1283 | 561 | } |
1284 | 620 | if( p_cd->psz_artist && *p_cd->psz_artist ) |
1285 | 552 | { |
1286 | 552 | vlc_meta_SetArtist( p_sys->meta, p_cd->psz_artist ); |
1287 | 552 | } |
1288 | 620 | if( p_cd->psz_copyright && *p_cd->psz_copyright ) |
1289 | 538 | { |
1290 | 538 | vlc_meta_SetCopyright( p_sys->meta, p_cd->psz_copyright ); |
1291 | 538 | } |
1292 | 620 | if( p_cd->psz_description && *p_cd->psz_description ) |
1293 | 63 | { |
1294 | 63 | vlc_meta_SetDescription( p_sys->meta, p_cd->psz_description ); |
1295 | 63 | } |
1296 | 620 | if( p_cd->psz_rating && *p_cd->psz_rating ) |
1297 | 5 | { |
1298 | 5 | vlc_meta_SetRating( p_sys->meta, p_cd->psz_rating ); |
1299 | 5 | } |
1300 | 620 | } |
1301 | 3.03k | asf_object_extended_content_description_t *p_ecd; |
1302 | 3.03k | if( ( p_ecd = ASF_FindObject( p_sys->p_root->p_hdr, |
1303 | 3.03k | &asf_object_extended_content_description, 0 ) ) ) |
1304 | 626 | { |
1305 | 4.54k | for( int i = 0; i < p_ecd->i_count; i++ ) |
1306 | 3.92k | { |
1307 | | |
1308 | 3.92k | #define set_meta( name, vlc_type ) \ |
1309 | 31.3k | if( p_ecd->ppsz_name[i] && !strncmp( p_ecd->ppsz_name[i], name, strlen(name) ) ) \ |
1310 | 31.3k | vlc_meta_Set( p_sys->meta, vlc_type, p_ecd->ppsz_value[i] ); |
1311 | | |
1312 | 3.92k | set_meta( "WM/AlbumTitle", vlc_meta_Album ) |
1313 | 3.92k | else set_meta( "WM/TrackNumber", vlc_meta_TrackNumber ) |
1314 | 3.92k | else set_meta( "WM/Year", vlc_meta_Date ) |
1315 | 3.92k | else set_meta( "WM/Genre", vlc_meta_Genre ) |
1316 | 3.92k | else set_meta( "WM/Genre", vlc_meta_Genre ) |
1317 | 3.92k | else set_meta( "WM/AlbumArtist", vlc_meta_AlbumArtist ) |
1318 | 3.92k | else set_meta( "WM/Publisher", vlc_meta_Publisher ) |
1319 | 3.92k | else set_meta( "WM/PartOfSet", vlc_meta_DiscNumber ) |
1320 | 3.92k | else if( p_ecd->ppsz_value[i] != NULL && p_ecd->ppsz_name[i] && |
1321 | 3.16k | *p_ecd->ppsz_value[i] != '\0' && /* no empty value */ |
1322 | 2.03k | *p_ecd->ppsz_value[i] != '{' && /* no guid value */ |
1323 | 2.03k | *p_ecd->ppsz_name[i] != '{' ) /* no guid name */ |
1324 | 2.02k | vlc_meta_SetExtra( p_sys->meta, p_ecd->ppsz_name[i], p_ecd->ppsz_value[i] ); |
1325 | | /* TODO map WM/Composer, WM/Provider, WM/PartOfSet, PeakValue, AverageLevel */ |
1326 | 3.92k | #undef set_meta |
1327 | 3.92k | } |
1328 | 626 | } |
1329 | | |
1330 | | /// \todo Fix Child meta for ASF tracks |
1331 | | #if 0 |
1332 | | for( i_stream = 0, i = 0; i < MAX_ASF_TRACKS; i++ ) |
1333 | | { |
1334 | | asf_object_codec_list_t *p_cl = ASF_FindObject( p_sys->p_root->p_hdr, |
1335 | | &asf_object_codec_list_guid, 0 ); |
1336 | | |
1337 | | if( p_sys->track[i] ) |
1338 | | { |
1339 | | vlc_meta_t *tk = vlc_meta_New(); |
1340 | | TAB_APPEND( p_sys->meta->i_track, p_sys->meta->track, tk ); |
1341 | | |
1342 | | if( p_cl && i_stream < p_cl->i_codec_entries_count ) |
1343 | | { |
1344 | | if( p_cl->codec[i_stream].psz_name && |
1345 | | *p_cl->codec[i_stream].psz_name ) |
1346 | | { |
1347 | | vlc_meta_Add( tk, VLC_META_CODEC_NAME, |
1348 | | p_cl->codec[i_stream].psz_name ); |
1349 | | } |
1350 | | if( p_cl->codec[i_stream].psz_description && |
1351 | | *p_cl->codec[i_stream].psz_description ) |
1352 | | { |
1353 | | vlc_meta_Add( tk, VLC_META_CODEC_DESCRIPTION, |
1354 | | p_cl->codec[i_stream].psz_description ); |
1355 | | } |
1356 | | } |
1357 | | i_stream++; |
1358 | | } |
1359 | | } |
1360 | | #endif |
1361 | 3.03k | free( fmt_priorities_ex.pi_stream_numbers ); |
1362 | 3.03k | free( fmt_priorities_bitrate_ex.pi_stream_numbers ); |
1363 | | |
1364 | 3.03k | p_sys->packet_sys.pi_preroll = &p_sys->p_fp->i_preroll; |
1365 | 3.03k | p_sys->packet_sys.pi_preroll_start = &p_sys->i_preroll_start; |
1366 | 3.03k | p_sys->packet_sys.b_can_hold_multiple_packets = false; |
1367 | | |
1368 | 3.03k | return VLC_SUCCESS; |
1369 | | |
1370 | 291 | error: |
1371 | 291 | free( fmt_priorities_ex.pi_stream_numbers ); |
1372 | 291 | free( fmt_priorities_bitrate_ex.pi_stream_numbers ); |
1373 | 291 | DemuxEnd( p_demux ); |
1374 | 291 | return VLC_EGENERIC; |
1375 | 3.03k | } |
1376 | | |
1377 | | /***************************************************************************** |
1378 | | * FlushQueues: flushes tail packets and send queues |
1379 | | *****************************************************************************/ |
1380 | | static void FlushQueue( asf_track_t *tk ) |
1381 | 3.42k | { |
1382 | 3.42k | ASFPacketTrackReset( &tk->info ); |
1383 | 3.42k | if( tk->queue.p_first ) |
1384 | 0 | { |
1385 | 0 | block_ChainRelease( tk->queue.p_first ); |
1386 | 0 | tk->queue.p_first = NULL; |
1387 | 0 | tk->queue.pp_last = &tk->queue.p_first; |
1388 | 0 | } |
1389 | 3.42k | } |
1390 | | |
1391 | | static void FlushQueues( demux_t *p_demux ) |
1392 | 3.38k | { |
1393 | 3.38k | demux_sys_t *p_sys = p_demux->p_sys; |
1394 | 436k | for ( unsigned int i = 0; i < MAX_ASF_TRACKS; i++ ) |
1395 | 433k | { |
1396 | 433k | asf_track_t *tk = p_sys->track[i]; |
1397 | 433k | if( !tk ) |
1398 | 429k | continue; |
1399 | 3.42k | FlushQueue( tk ); |
1400 | 3.42k | } |
1401 | 3.38k | } |
1402 | | |
1403 | | /***************************************************************************** |
1404 | | * |
1405 | | *****************************************************************************/ |
1406 | | static void DemuxEnd( demux_t *p_demux ) |
1407 | 3.38k | { |
1408 | 3.38k | demux_sys_t *p_sys = p_demux->p_sys; |
1409 | | |
1410 | 3.38k | if( p_sys->p_root ) |
1411 | 3.32k | { |
1412 | 3.32k | ASF_FreeObjectRoot( p_demux->s, p_sys->p_root ); |
1413 | 3.32k | p_sys->p_root = NULL; |
1414 | 3.32k | p_sys->p_fp = NULL; |
1415 | 3.32k | } |
1416 | 3.38k | if( p_sys->meta ) |
1417 | 3.03k | { |
1418 | 3.03k | vlc_meta_Delete( p_sys->meta ); |
1419 | 3.03k | p_sys->meta = NULL; |
1420 | 3.03k | } |
1421 | | |
1422 | 3.38k | FlushQueues( p_demux ); |
1423 | | |
1424 | 436k | for( int i = 0; i < MAX_ASF_TRACKS; i++ ) |
1425 | 433k | { |
1426 | 433k | asf_track_t *tk = p_sys->track[i]; |
1427 | | |
1428 | 433k | if( tk ) |
1429 | 3.42k | { |
1430 | 3.42k | if( tk->p_es ) |
1431 | 2.46k | { |
1432 | 2.46k | es_out_Del( p_demux->out, tk->p_es ); |
1433 | 2.46k | } |
1434 | 3.42k | if ( tk->p_fmt ) |
1435 | 353 | { |
1436 | 353 | es_format_Clean( tk->p_fmt ); |
1437 | 353 | free( tk->p_fmt ); |
1438 | 353 | } |
1439 | 3.42k | free( tk ); |
1440 | 3.42k | } |
1441 | 433k | p_sys->track[i] = 0; |
1442 | 433k | } |
1443 | 3.38k | } |