contrib/gpg-error: simplify darwin triplet handling
[vlc.git] / modules / demux / mock.c
blob6f6d555199770f6850abee3b816a3da716cc94a2
1 /*****************************************************************************
2 * mock.c : mock demux module for vlc
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
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.
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.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <ctype.h>
26 #include <limits.h>
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_aout.h>
31 #include <vlc_picture.h>
32 #include <vlc_demux.h>
33 #include <vlc_input.h>
34 #include <vlc_vector.h>
37 struct mock_track
39 es_format_t fmt;
40 es_out_id_t *id;
42 typedef struct VLC_VECTOR(struct mock_track *) mock_track_vector;
44 static ssize_t
45 var_InheritSsize(vlc_object_t *obj, const char *name)
47 int64_t value = var_InheritInteger(obj, name);
48 return value >= 0 ? value : -1;
51 static unsigned
52 var_InheritUnsigned(vlc_object_t *obj, const char *name)
54 int64_t value = var_InheritInteger(obj, name);
55 return value >= 0 && value < UINT_MAX ? value : UINT_MAX;
58 static vlc_fourcc_t
59 var_InheritFourcc(vlc_object_t *obj, const char *name)
61 char *var_value = var_InheritString(obj, name);
62 if (!var_value)
63 return 0;
65 size_t var_len = strlen(var_value);
66 if (var_len > 4)
68 free(var_value);
69 return 0;
72 /* Pad with spaces if the string len is less than 4 */
73 char value[] = " ";
74 strcpy(value, var_value);
75 if (var_len != 4)
76 value[var_len] = ' ';
77 free(var_value);
79 vlc_fourcc_t fourcc;
80 memcpy(&fourcc, value, 4);
81 return fourcc;
84 /* var_name, type, module_header_type, getter, default_value */
85 #define LIST_OPTIONS \
86 X(length, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_FROM_MS(5000)) \
87 X(audio_track_count, ssize_t, add_integer, var_InheritSsize, 0) \
88 X(audio_channels, unsigned, add_integer, var_InheritUnsigned, 2) \
89 X(audio_format, vlc_fourcc_t, add_string, var_InheritFourcc, "u8") \
90 X(audio_rate, unsigned, add_integer, var_InheritUnsigned, 44100) \
91 X(audio_packetized, bool, add_bool, var_InheritBool, true) \
92 X(audio_sample_length, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_FROM_MS(40) ) \
93 X(video_track_count, ssize_t, add_integer, var_InheritSsize, 0) \
94 X(video_chroma, vlc_fourcc_t, add_string, var_InheritFourcc, "I420") \
95 X(video_width, unsigned, add_integer, var_InheritUnsigned, 640) \
96 X(video_height, unsigned, add_integer, var_InheritUnsigned, 480) \
97 X(video_frame_rate, unsigned, add_integer, var_InheritUnsigned, 25) \
98 X(video_frame_rate_base, unsigned, add_integer, var_InheritUnsigned, 1) \
99 X(video_packetized, bool, add_bool, var_InheritBool, true) \
100 X(input_sample_length, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_FROM_MS(40) ) \
101 X(sub_track_count, ssize_t, add_integer, var_InheritSsize, 0) \
102 X(sub_packetized, bool, add_bool, var_InheritBool, true) \
103 X(title_count, ssize_t, add_integer, var_InheritSsize, 0 ) \
104 X(chapter_count, ssize_t, add_integer, var_InheritSsize, 0) \
105 X(null_names, bool, add_bool, var_InheritBool, false) \
106 X(program_count, ssize_t, add_integer, var_InheritSsize, 0) \
107 X(can_seek, bool, add_bool, var_InheritBool, true) \
108 X(can_pause, bool, add_bool, var_InheritBool, true) \
109 X(can_control_pace, bool, add_bool, var_InheritBool, true) \
110 X(can_control_rate, bool, add_bool, var_InheritBool, true) \
111 X(can_record, bool, add_bool, var_InheritBool, true) \
112 X(error, bool, add_bool, var_InheritBool, false) \
113 X(pts_delay, unsigned, add_integer, var_InheritUnsigned, MS_FROM_VLC_TICK(DEFAULT_PTS_DELAY)) \
114 X(add_video_track_at, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_INVALID ) \
115 X(add_audio_track_at, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_INVALID ) \
116 X(add_spu_track_at, vlc_tick_t, add_integer, var_InheritInteger, VLC_TICK_INVALID ) \
118 struct demux_sys
120 mock_track_vector tracks;
121 vlc_tick_t pts;
122 vlc_tick_t audio_pts;
123 vlc_tick_t video_pts;
125 int current_title;
126 vlc_tick_t chapter_gap;
128 unsigned int updates;
130 #define X(var_name, type, module_header_type, getter, default_value) \
131 type var_name;
132 LIST_OPTIONS
133 #undef X
136 static input_title_t *
137 CreateTitle(demux_t *demux, size_t idx)
139 struct demux_sys *sys = demux->p_sys;
141 input_title_t *t = vlc_input_title_New();
142 if (!t)
143 return NULL;
145 t->i_length = sys->length;
146 if (!sys->null_names
147 && asprintf(&t->psz_name, "Mock Title %zu", idx) == -1)
149 t->psz_name = NULL;
150 vlc_input_title_Delete(t);
151 return NULL;
153 t->seekpoint = vlc_alloc(sys->chapter_count, sizeof(*t->seekpoint));
154 if (!t->seekpoint)
156 vlc_input_title_Delete(t);
157 return NULL;
160 for (ssize_t i = 0; i < sys->chapter_count; ++i)
162 t->seekpoint[i] = vlc_seekpoint_New();
163 if (!t->seekpoint[i])
165 vlc_input_title_Delete(t);
166 return NULL;
168 t->i_seekpoint++;
169 if (!sys->null_names
170 && asprintf(&t->seekpoint[i]->psz_name, "Mock Chapter %zu-%zu", idx, i)
171 == -1)
173 vlc_input_title_Delete(t);
174 return NULL;
176 t->seekpoint[i]->i_time_offset = i * sys->chapter_gap;
178 return t;
181 static int
182 Control(demux_t *demux, int query, va_list args)
184 struct demux_sys *sys = demux->p_sys;
186 switch (query)
188 case DEMUX_CAN_SEEK:
189 *va_arg(args, bool *) = sys->can_seek;
190 return VLC_SUCCESS;
191 case DEMUX_CAN_PAUSE:
192 *va_arg(args, bool *) = sys->can_pause;
193 return VLC_SUCCESS;
194 case DEMUX_CAN_CONTROL_PACE:
195 *va_arg(args, bool *) = sys->can_control_pace;
196 return VLC_SUCCESS;
197 case DEMUX_GET_PTS_DELAY:
198 *va_arg(args, vlc_tick_t *) = VLC_TICK_FROM_MS(sys->pts_delay);
199 return VLC_SUCCESS;
200 case DEMUX_GET_META:
201 return VLC_EGENERIC;
202 case DEMUX_GET_SIGNAL:
203 return VLC_EGENERIC;
204 case DEMUX_SET_PAUSE_STATE:
205 return sys->can_pause ? VLC_SUCCESS : VLC_EGENERIC;
206 case DEMUX_SET_TITLE:
207 if (sys->title_count > 0)
209 int new_title = va_arg(args, int);
210 if (new_title >= sys->title_count)
211 return VLC_EGENERIC;
212 sys->current_title = new_title;
213 sys->pts = sys->audio_pts = sys->video_pts = VLC_TICK_0;
214 sys->updates |= INPUT_UPDATE_TITLE;
215 return VLC_SUCCESS;
217 return VLC_EGENERIC;
218 case DEMUX_SET_SEEKPOINT:
219 if (sys->chapter_gap != VLC_TICK_INVALID)
221 const int seekpoint_idx = va_arg(args, int);
222 if (seekpoint_idx < sys->chapter_count)
224 sys->pts = sys->audio_pts = sys->video_pts =
225 (seekpoint_idx * sys->chapter_gap) + VLC_TICK_0;
226 return VLC_SUCCESS;
229 return VLC_EGENERIC;
230 case DEMUX_TEST_AND_CLEAR_FLAGS:
232 unsigned *restrict flags = va_arg(args, unsigned *);
233 *flags &= sys->updates;
234 sys->updates &= ~*flags;
235 return VLC_SUCCESS;
237 case DEMUX_GET_TITLE:
238 if (sys->title_count > 0)
240 *va_arg(args, int *) = sys->current_title;
241 return VLC_SUCCESS;
243 return VLC_EGENERIC;
244 case DEMUX_GET_SEEKPOINT:
245 if (sys->chapter_gap != VLC_TICK_INVALID)
247 *va_arg(args, int *) = sys->pts / sys->chapter_gap;
248 return VLC_SUCCESS;
250 return VLC_EGENERIC;
251 case DEMUX_GET_POSITION:
252 *va_arg(args, double *) = sys->pts / (double) sys->length;
253 return VLC_SUCCESS;
254 case DEMUX_SET_POSITION:
255 if (!sys->can_seek)
256 return VLC_EGENERIC;
257 sys->pts = sys->video_pts = sys->audio_pts = va_arg(args, double) * sys->length;
258 return VLC_SUCCESS;
259 case DEMUX_GET_LENGTH:
260 *va_arg(args, vlc_tick_t *) = sys->length;
261 return VLC_SUCCESS;
262 case DEMUX_GET_TIME:
263 *va_arg(args, vlc_tick_t *) = sys->pts;
264 return VLC_SUCCESS;
265 case DEMUX_SET_TIME:
266 if (!sys->can_seek)
267 return VLC_EGENERIC;
268 sys->pts = sys->video_pts = sys->audio_pts = va_arg(args, vlc_tick_t);
269 return VLC_SUCCESS;
270 case DEMUX_GET_TITLE_INFO:
271 if (sys->title_count > 0)
273 input_title_t ***titles = va_arg(args, input_title_t ***);
274 *titles = vlc_alloc(sys->title_count, sizeof(*titles));
275 if (!*titles)
276 return VLC_ENOMEM;
277 for (ssize_t i = 0; i < sys->title_count; ++i)
279 (*titles)[i] = CreateTitle(demux, i);
280 if (!(*titles)[i])
282 while (i--)
283 vlc_input_title_Delete((*titles)[i - 1]);
284 free(*titles);
285 *titles = NULL;
286 return VLC_ENOMEM;
289 *va_arg(args, int *) = sys->title_count;
290 *va_arg(args, int *) = 0;
291 *va_arg(args, int *) = 0;
292 return VLC_SUCCESS;
294 return VLC_EGENERIC;
295 case DEMUX_SET_GROUP_DEFAULT:
296 return VLC_EGENERIC;
297 case DEMUX_SET_GROUP_ALL:
298 return VLC_EGENERIC;
299 case DEMUX_SET_GROUP_LIST:
300 return VLC_EGENERIC;
301 case DEMUX_SET_ES:
302 return VLC_EGENERIC;
303 case DEMUX_SET_ES_LIST:
304 return VLC_EGENERIC;
305 case DEMUX_SET_NEXT_DEMUX_TIME:
306 return VLC_EGENERIC;
307 case DEMUX_GET_FPS:
308 return VLC_EGENERIC;
309 case DEMUX_HAS_UNSUPPORTED_META:
310 return VLC_EGENERIC;
311 case DEMUX_GET_ATTACHMENTS:
312 return VLC_EGENERIC;
313 case DEMUX_CAN_RECORD:
314 *va_arg(args, bool *) = sys->can_record;
315 return VLC_SUCCESS;
316 case DEMUX_SET_RECORD_STATE:
317 return sys->can_record ? VLC_SUCCESS : VLC_EGENERIC;
318 case DEMUX_CAN_CONTROL_RATE:
319 *va_arg(args, bool *) = sys->can_control_rate;
320 return VLC_SUCCESS;
321 case DEMUX_SET_RATE:
322 return sys->can_control_rate ? VLC_SUCCESS : VLC_EGENERIC;
323 case DEMUX_IS_PLAYLIST:
324 return VLC_EGENERIC;
325 case DEMUX_NAV_ACTIVATE:
326 return VLC_EGENERIC;
327 case DEMUX_NAV_UP:
328 return VLC_EGENERIC;
329 case DEMUX_NAV_DOWN:
330 return VLC_EGENERIC;
331 case DEMUX_NAV_LEFT:
332 return VLC_EGENERIC;
333 case DEMUX_NAV_RIGHT:
334 return VLC_EGENERIC;
335 case DEMUX_NAV_POPUP:
336 return VLC_EGENERIC;
337 case DEMUX_NAV_MENU:
338 return VLC_EGENERIC;
339 default:
340 return VLC_EGENERIC;
344 static block_t *
345 CreateAudioBlock(demux_t *demux, struct mock_track *track, vlc_tick_t length)
347 const int64_t samples =
348 samples_from_vlc_tick(length, track->fmt.audio.i_rate);
349 const int64_t bytes = samples / track->fmt.audio.i_frame_length
350 * track->fmt.audio.i_bytes_per_frame;
351 block_t *b = block_Alloc(bytes);
352 if (!b)
353 return NULL;
354 memset(b->p_buffer, 0, b->i_buffer);
355 return b;
356 (void) demux;
359 struct video_block
361 block_t b;
362 picture_t *pic;
365 static void
366 video_block_free_cb(block_t *b)
368 struct video_block *video = container_of(b, struct video_block, b);
369 picture_Release(video->pic);
370 free(video);
373 static block_t *
374 CreateVideoBlock(demux_t *demux, struct mock_track *track)
376 struct demux_sys *sys = demux->p_sys;
377 picture_t *pic = picture_NewFromFormat(&track->fmt.video);
378 if (!pic)
379 return NULL;
381 struct video_block *video = malloc(sizeof(*video));
382 if (!video)
384 picture_Release(pic);
385 return NULL;
387 video->pic = pic;
389 static const struct vlc_block_callbacks cbs =
391 .free = video_block_free_cb
394 size_t block_len = 0;
395 for (int i = 0; i < pic->i_planes; ++i)
396 block_len += pic->p[i].i_lines * pic->p[i].i_pitch;
397 memset(pic->p[0].p_pixels, (sys->video_pts / VLC_TICK_FROM_MS(10)) % 255,
398 block_len);
399 return block_Init(&video->b, &cbs, pic->p[0].p_pixels, block_len);
400 (void) demux;
403 static block_t *
404 CreateSubBlock(demux_t *demux, struct mock_track *track)
406 struct demux_sys *sys = demux->p_sys;
407 char *text;
408 if (asprintf(&text, "subtitle @ %"PRId64, sys->video_pts) == -1)
409 return NULL;
410 size_t len = strlen(text) + 1;
412 block_t *b = block_Alloc(len);
413 if (!b)
415 free(text);
416 return NULL;
419 memcpy(b->p_buffer, text, len);
420 b->i_buffer = len;
422 free(text);
423 return b;
424 (void) track;
427 static int
428 AppendMockTrack(demux_t *demux, const es_format_t *fmt, int id, int group,
429 bool packetized)
431 struct demux_sys *sys = demux->p_sys;
432 struct mock_track *mock_track = malloc(sizeof(*mock_track));
433 if (!mock_track)
434 return VLC_EGENERIC;
435 mock_track->fmt = *fmt;
436 mock_track->fmt.i_id = id;
437 mock_track->fmt.i_group = group;
438 mock_track->fmt.b_packetized = packetized;
439 mock_track->id = es_out_Add(demux->out, & mock_track->fmt);
440 if (!mock_track->id)
442 free(mock_track);
443 return VLC_ENOMEM;
445 bool success = vlc_vector_push(&sys->tracks, mock_track);
446 assert(success); (void) success; /* checked by reserve() */
447 return VLC_SUCCESS;
450 static int
451 InitVideoTracks(demux_t *demux, int group, size_t count)
453 struct demux_sys *sys = demux->p_sys;
455 if (count == 0)
456 return VLC_SUCCESS;
458 const vlc_chroma_description_t *desc =
459 vlc_fourcc_GetChromaDescription(sys->video_chroma);
460 if (!desc || desc->plane_count == 0)
461 sys->video_chroma = 0;
463 const bool frame_rate_ok =
464 sys->video_frame_rate != 0 && sys->video_frame_rate != UINT_MAX &&
465 sys->video_frame_rate_base != 0 && sys->video_frame_rate_base != UINT_MAX;
466 const bool chroma_ok = sys->video_chroma != 0;
467 const bool size_ok = sys->video_width != UINT_MAX &&
468 sys->video_height != UINT_MAX;
470 if (sys->video_frame_rate == 0 || sys->video_frame_rate_base == 0
471 || sys->video_chroma == 0)
472 if (!frame_rate_ok || !chroma_ok || !size_ok)
474 if (!frame_rate_ok)
475 msg_Err(demux, "Invalid video frame rate");
476 if (!chroma_ok)
477 msg_Err(demux, "Invalid video chroma");
478 if (!size_ok)
479 msg_Err(demux, "Invalid video size");
480 return VLC_EGENERIC;
483 for (size_t i = 0; i < count; ++i)
485 es_format_t fmt;
486 es_format_Init(&fmt, VIDEO_ES, sys->video_chroma);
487 fmt.video.i_chroma = fmt.i_codec;
488 fmt.video.i_width = fmt.video.i_visible_width = sys->video_width;
489 fmt.video.i_height = fmt.video.i_visible_height = sys->video_height;
490 fmt.video.i_frame_rate = sys->video_frame_rate;
491 fmt.video.i_frame_rate_base = sys->video_frame_rate_base;
493 if (AppendMockTrack(demux, &fmt, i, group, sys->video_packetized))
494 return VLC_ENOMEM;
496 return VLC_SUCCESS;
499 static int
500 InitAudioTracks(demux_t *demux, int group, size_t count)
502 struct demux_sys *sys = demux->p_sys;
504 if (count == 0)
505 return VLC_SUCCESS;
507 const bool rate_ok = sys->audio_rate > 0 && sys->audio_rate != UINT_MAX;
508 const bool format_ok = aout_BitsPerSample(sys->audio_format) != 0;
509 const bool channels_ok = sys->audio_channels > 0 &&
510 sys->audio_channels <= AOUT_CHAN_MAX;
512 if (!rate_ok || !format_ok || !channels_ok)
514 if (!rate_ok)
515 msg_Err(demux, "Invalid audio rate");
516 if (!format_ok)
517 msg_Err(demux, "Invalid audio format");
518 if (!channels_ok)
519 msg_Err(demux, "Invalid audio channels");
520 return VLC_EGENERIC;
523 uint16_t physical_channels = 0;
524 switch (sys->audio_channels)
526 case 1: physical_channels = AOUT_CHAN_CENTER; break;
527 case 2: physical_channels = AOUT_CHANS_2_0; break;
528 case 3: physical_channels = AOUT_CHANS_2_1; break;
529 case 4: physical_channels = AOUT_CHANS_4_0; break;
530 case 5: physical_channels = AOUT_CHANS_4_1; break;
531 case 6: physical_channels = AOUT_CHANS_6_0; break;
532 case 7: physical_channels = AOUT_CHANS_7_0; break;
533 case 8: physical_channels = AOUT_CHANS_7_1; break;
534 case 9: physical_channels = AOUT_CHANS_8_1; break;
535 default: vlc_assert_unreachable();
538 for (size_t i = 0; i < count; ++i)
540 es_format_t fmt;
541 es_format_Init(&fmt, AUDIO_ES, sys->audio_format);
542 fmt.audio.i_format = fmt.i_codec;
543 fmt.audio.i_rate = sys->audio_rate;
544 fmt.audio.i_physical_channels = physical_channels;
545 aout_FormatPrepare(&fmt.audio);
547 if (AppendMockTrack(demux, &fmt, i, group, sys->audio_packetized))
548 return VLC_ENOMEM;
551 return VLC_SUCCESS;
554 static int
555 InitSubTracks(demux_t *demux, int group, size_t count)
557 struct demux_sys *sys = demux->p_sys;
559 if (count == 0)
560 return VLC_SUCCESS;
562 for (size_t i = 0; i < count; ++i)
564 es_format_t fmt;
565 es_format_Init(&fmt, SPU_ES, VLC_CODEC_SUBT);
567 if (AppendMockTrack(demux, &fmt, i, group, sys->sub_packetized))
568 return VLC_ENOMEM;
571 return VLC_SUCCESS;
574 static int
575 DemuxAudio(demux_t *demux, vlc_tick_t step_length, vlc_tick_t end_pts)
577 struct demux_sys *sys = demux->p_sys;
579 while (sys->audio_pts < end_pts)
581 struct mock_track *track;
582 vlc_vector_foreach(track, &sys->tracks)
584 block_t *block;
585 switch (track->fmt.i_cat)
587 case AUDIO_ES:
588 block = CreateAudioBlock(demux, track, step_length);
589 break;
590 default:
591 continue;
593 if (!block)
594 return VLC_EGENERIC;
596 block->i_length = step_length;
597 block->i_pts = block->i_dts = sys->audio_pts;
599 int ret = es_out_Send(demux->out, track->id, block);
600 if (ret != VLC_SUCCESS)
601 return ret;
603 sys->audio_pts += step_length;
605 return VLC_SUCCESS;
608 static int
609 DemuxVideo(demux_t *demux, vlc_tick_t step_length, vlc_tick_t end_pts)
611 struct demux_sys *sys = demux->p_sys;
613 while (sys->video_pts < end_pts)
615 struct mock_track *track;
616 vlc_vector_foreach(track, &sys->tracks)
618 block_t *block;
619 switch (track->fmt.i_cat)
621 case VIDEO_ES:
622 block = CreateVideoBlock(demux, track);
623 break;
624 case SPU_ES:
625 block = CreateSubBlock(demux, track);
626 break;
627 default:
628 continue;
630 if (!block)
631 return VLC_EGENERIC;
633 block->i_length = step_length;
634 block->i_pts = block->i_dts = sys->video_pts;
636 int ret = es_out_Send(demux->out, track->id, block);
637 if (ret != VLC_SUCCESS)
638 return ret;
640 sys->video_pts += step_length;
642 return VLC_SUCCESS;
645 static int
646 Demux(demux_t *demux)
648 struct demux_sys *sys = demux->p_sys;
650 if (sys->error)
651 return VLC_DEMUXER_EGENERIC;
653 if (sys->audio_track_count > 0
654 && (sys->video_track_count > 0 || sys->sub_track_count > 0))
655 sys->pts = __MIN(sys->audio_pts, sys->video_pts);
656 else if (sys->audio_track_count > 0)
657 sys->pts = sys->audio_pts;
658 else if (sys->video_track_count > 0 || sys->sub_track_count > 0)
659 sys->pts = sys->video_pts;
661 if (sys->pts > sys->length)
662 sys->pts = sys->length;
663 es_out_SetPCR(demux->out, sys->pts);
665 const vlc_tick_t video_step_length =
666 (sys->video_track_count > 0 || sys->sub_track_count > 0) ?
667 VLC_TICK_FROM_SEC(1) * sys->video_frame_rate_base
668 / sys->video_frame_rate : 0;
670 const vlc_tick_t audio_step_length =
671 sys->audio_track_count > 0 ? sys->audio_sample_length : 0;
673 const vlc_tick_t step_length = __MAX(audio_step_length, video_step_length);
675 int ret = VLC_SUCCESS;
676 bool audio_eof = true, video_eof = true, input_eof = true;
677 if (sys->audio_track_count > 0)
679 ret = DemuxAudio(demux, audio_step_length,
680 __MIN(step_length + sys->audio_pts, sys->length));
681 if (sys->audio_pts + audio_step_length < sys->length)
682 audio_eof = false;
685 if (ret == VLC_SUCCESS
686 && (sys->video_track_count > 0 || sys->sub_track_count > 0))
688 ret = DemuxVideo(demux, video_step_length,
689 __MIN(step_length + sys->video_pts, sys->length));
690 if (sys->video_pts + video_step_length < sys->length)
691 video_eof = false;
694 /* No audio/video/sub: simulate that we read some inputs */
695 if (step_length == 0)
697 sys->pts += sys->input_sample_length;
698 if (sys->pts + sys->input_sample_length < sys->length)
699 input_eof = false;
702 if (ret != VLC_SUCCESS)
703 return VLC_DEMUXER_EGENERIC;
705 /* Add late tracks if any */
706 if (sys->add_video_track_at != VLC_TICK_INVALID &&
707 sys->add_video_track_at <= sys->pts)
709 sys->add_video_track_at = VLC_TICK_INVALID;
711 ret = InitVideoTracks(demux, 0, 1);
712 if (ret != VLC_SUCCESS)
713 return VLC_DEMUXER_EGENERIC;
714 sys->video_track_count++;
715 sys->video_pts = sys->pts;
716 video_eof = false;
719 if (sys->add_audio_track_at != VLC_TICK_INVALID &&
720 sys->add_audio_track_at <= sys->pts)
722 sys->add_audio_track_at = VLC_TICK_INVALID;
724 ret = InitAudioTracks(demux, 0, 1);
725 if (ret != VLC_SUCCESS)
726 return VLC_DEMUXER_EGENERIC;
727 sys->audio_track_count++;
728 sys->audio_pts = sys->pts;
729 audio_eof = false;
732 if (sys->add_spu_track_at != VLC_TICK_INVALID &&
733 sys->add_spu_track_at <= sys->pts)
735 sys->add_spu_track_at = VLC_TICK_INVALID;
737 ret = InitSubTracks(demux, 0, 1);
738 if (ret != VLC_SUCCESS)
739 return VLC_DEMUXER_EGENERIC;
740 sys->sub_track_count++;
741 sys->video_pts = sys->pts;
742 video_eof = false;
745 return audio_eof && video_eof && input_eof ? VLC_DEMUXER_EOF
746 : VLC_DEMUXER_SUCCESS;
749 static void
750 Close(vlc_object_t *obj)
752 demux_t *demux = (demux_t*)obj;
753 struct demux_sys *sys = demux->p_sys;
755 struct mock_track *track;
756 vlc_vector_foreach(track, &sys->tracks)
758 es_out_Del(demux->out, track->id);
759 free(track);
761 vlc_vector_clear(&sys->tracks);
764 static int
765 Open(vlc_object_t *obj)
767 demux_t *demux = (demux_t*)obj;
769 if (demux->out == NULL)
770 return VLC_EGENERIC;
771 struct demux_sys *sys = vlc_obj_malloc(obj, sizeof(*sys));
772 if (!sys)
773 return VLC_ENOMEM;
775 demux->p_sys = sys;
777 if (var_LocationParse(obj, demux->psz_location, "mock-") != VLC_SUCCESS)
778 return VLC_ENOMEM;
780 #define X(var_name, type, module_header_type, getter, default_value) \
781 sys->var_name = getter(obj, "mock-"#var_name);
782 LIST_OPTIONS
783 #undef X
785 if (sys->chapter_count > 0 && sys->title_count == 0)
786 sys->title_count++;
788 const bool length_ok = sys->length >= 0;
789 const bool tracks_ok = sys->video_track_count >= 0 &&
790 sys->audio_track_count >= 0 &&
791 sys->sub_track_count >= 0;
792 const bool titles_ok = sys->title_count >= 0;
793 const bool chapters_ok = sys->chapter_count >= 0;
794 const bool programs_ok = sys->program_count >= 0;
796 if (!length_ok || !tracks_ok || !titles_ok || !chapters_ok || !programs_ok)
798 if (!length_ok)
799 msg_Err(demux, "Invalid length");
800 if (!tracks_ok)
801 msg_Err(demux, "Invalid track count");
802 if (!titles_ok)
803 msg_Err(demux, "Invalid title count");
804 if (!chapters_ok)
805 msg_Err(demux, "Invalid chapter count");
806 if (!programs_ok)
807 msg_Err(demux, "Invalid program count");
808 return VLC_EGENERIC;
811 if (sys->program_count == 0)
812 sys->program_count = 1;
813 size_t track_count = (sys->video_track_count + sys->audio_track_count +
814 sys->sub_track_count) * sys->program_count;
815 vlc_vector_init(&sys->tracks);
816 if (track_count > 0)
818 bool success = vlc_vector_reserve(&sys->tracks, track_count);
819 if (!success)
820 return VLC_ENOMEM;
823 int ret;
824 for (ssize_t i = 0; i < sys->program_count; ++i)
826 ret = InitVideoTracks(demux, i, sys->video_track_count);
827 if (ret != VLC_SUCCESS)
828 goto error;
830 ret = InitAudioTracks(demux, i, sys->audio_track_count);
831 if (ret != VLC_SUCCESS)
832 goto error;
834 ret = InitSubTracks(demux, i, sys->sub_track_count);
835 if (ret != VLC_SUCCESS)
836 goto error;
840 sys->pts = sys->audio_pts = sys->video_pts = VLC_TICK_0;
841 sys->current_title = 0;
842 sys->chapter_gap = sys->chapter_count > 0 ?
843 (sys->length / sys->chapter_count) : VLC_TICK_INVALID;
844 sys->updates = 0;
846 demux->pf_control = Control;
847 demux->pf_demux = Demux;
849 return VLC_SUCCESS;
850 error:
851 Close(obj);
852 demux->p_sys = NULL;
853 return ret;
856 #define X(var_name, type, module_header_type, getter, default_value) \
857 module_header_type("mock-"#var_name, default_value, NULL, NULL, true) \
858 change_volatile() \
859 change_safe()
861 vlc_module_begin()
862 set_description("mock access demux")
863 set_capability("access", 0)
864 set_category(CAT_INPUT)
865 set_subcategory(SUBCAT_INPUT_ACCESS)
866 set_callbacks(Open, Close)
867 LIST_OPTIONS
868 add_shortcut("mock")
869 vlc_module_end()
871 #undef X