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 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
31 #include <vlc_picture.h>
32 #include <vlc_demux.h>
33 #include <vlc_input.h>
34 #include <vlc_vector.h>
42 typedef struct VLC_VECTOR(struct mock_track
*) mock_track_vector
;
45 var_InheritSsize(vlc_object_t
*obj
, const char *name
)
47 int64_t value
= var_InheritInteger(obj
, name
);
48 return value
>= 0 ? value
: -1;
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
;
59 var_InheritFourcc(vlc_object_t
*obj
, const char *name
)
61 char *var_value
= var_InheritString(obj
, name
);
65 size_t var_len
= strlen(var_value
);
72 /* Pad with spaces if the string len is less than 4 */
74 strcpy(value
, var_value
);
80 memcpy(&fourcc
, value
, 4);
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 ) \
120 mock_track_vector tracks
;
122 vlc_tick_t audio_pts
;
123 vlc_tick_t video_pts
;
126 vlc_tick_t chapter_gap
;
128 unsigned int updates
;
130 #define X(var_name, type, module_header_type, getter, default_value) \
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();
145 t
->i_length
= sys
->length
;
147 && asprintf(&t
->psz_name
, "Mock Title %zu", idx
) == -1)
150 vlc_input_title_Delete(t
);
153 t
->seekpoint
= vlc_alloc(sys
->chapter_count
, sizeof(*t
->seekpoint
));
156 vlc_input_title_Delete(t
);
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
);
170 && asprintf(&t
->seekpoint
[i
]->psz_name
, "Mock Chapter %zu-%zu", idx
, i
)
173 vlc_input_title_Delete(t
);
176 t
->seekpoint
[i
]->i_time_offset
= i
* sys
->chapter_gap
;
182 Control(demux_t
*demux
, int query
, va_list args
)
184 struct demux_sys
*sys
= demux
->p_sys
;
189 *va_arg(args
, bool *) = sys
->can_seek
;
191 case DEMUX_CAN_PAUSE
:
192 *va_arg(args
, bool *) = sys
->can_pause
;
194 case DEMUX_CAN_CONTROL_PACE
:
195 *va_arg(args
, bool *) = sys
->can_control_pace
;
197 case DEMUX_GET_PTS_DELAY
:
198 *va_arg(args
, vlc_tick_t
*) = VLC_TICK_FROM_MS(sys
->pts_delay
);
202 case DEMUX_GET_SIGNAL
:
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
)
212 sys
->current_title
= new_title
;
213 sys
->pts
= sys
->audio_pts
= sys
->video_pts
= VLC_TICK_0
;
214 sys
->updates
|= INPUT_UPDATE_TITLE
;
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
;
230 case DEMUX_TEST_AND_CLEAR_FLAGS
:
232 unsigned *restrict flags
= va_arg(args
, unsigned *);
233 *flags
&= sys
->updates
;
234 sys
->updates
&= ~*flags
;
237 case DEMUX_GET_TITLE
:
238 if (sys
->title_count
> 0)
240 *va_arg(args
, int *) = sys
->current_title
;
244 case DEMUX_GET_SEEKPOINT
:
245 if (sys
->chapter_gap
!= VLC_TICK_INVALID
)
247 *va_arg(args
, int *) = sys
->pts
/ sys
->chapter_gap
;
251 case DEMUX_GET_POSITION
:
252 *va_arg(args
, double *) = sys
->pts
/ (double) sys
->length
;
254 case DEMUX_SET_POSITION
:
257 sys
->pts
= sys
->video_pts
= sys
->audio_pts
= va_arg(args
, double) * sys
->length
;
259 case DEMUX_GET_LENGTH
:
260 *va_arg(args
, vlc_tick_t
*) = sys
->length
;
263 *va_arg(args
, vlc_tick_t
*) = sys
->pts
;
268 sys
->pts
= sys
->video_pts
= sys
->audio_pts
= va_arg(args
, vlc_tick_t
);
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
));
277 for (ssize_t i
= 0; i
< sys
->title_count
; ++i
)
279 (*titles
)[i
] = CreateTitle(demux
, i
);
283 vlc_input_title_Delete((*titles
)[i
- 1]);
289 *va_arg(args
, int *) = sys
->title_count
;
290 *va_arg(args
, int *) = 0;
291 *va_arg(args
, int *) = 0;
295 case DEMUX_SET_GROUP_DEFAULT
:
297 case DEMUX_SET_GROUP_ALL
:
299 case DEMUX_SET_GROUP_LIST
:
303 case DEMUX_SET_ES_LIST
:
305 case DEMUX_SET_NEXT_DEMUX_TIME
:
309 case DEMUX_HAS_UNSUPPORTED_META
:
311 case DEMUX_GET_ATTACHMENTS
:
313 case DEMUX_CAN_RECORD
:
314 *va_arg(args
, bool *) = sys
->can_record
;
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
;
322 return sys
->can_control_rate
? VLC_SUCCESS
: VLC_EGENERIC
;
323 case DEMUX_IS_PLAYLIST
:
325 case DEMUX_NAV_ACTIVATE
:
333 case DEMUX_NAV_RIGHT
:
335 case DEMUX_NAV_POPUP
:
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
);
354 memset(b
->p_buffer
, 0, b
->i_buffer
);
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
);
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
);
381 struct video_block
*video
= malloc(sizeof(*video
));
384 picture_Release(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,
399 return block_Init(&video
->b
, &cbs
, pic
->p
[0].p_pixels
, block_len
);
404 CreateSubBlock(demux_t
*demux
, struct mock_track
*track
)
406 struct demux_sys
*sys
= demux
->p_sys
;
408 if (asprintf(&text
, "subtitle @ %"PRId64
, sys
->video_pts
) == -1)
410 size_t len
= strlen(text
) + 1;
412 block_t
*b
= block_Alloc(len
);
419 memcpy(b
->p_buffer
, text
, len
);
428 AppendMockTrack(demux_t
*demux
, const es_format_t
*fmt
, int id
, int group
,
431 struct demux_sys
*sys
= demux
->p_sys
;
432 struct mock_track
*mock_track
= malloc(sizeof(*mock_track
));
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
);
445 bool success
= vlc_vector_push(&sys
->tracks
, mock_track
);
446 assert(success
); (void) success
; /* checked by reserve() */
451 InitVideoTracks(demux_t
*demux
, int group
, size_t count
)
453 struct demux_sys
*sys
= demux
->p_sys
;
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
)
475 msg_Err(demux
, "Invalid video frame rate");
477 msg_Err(demux
, "Invalid video chroma");
479 msg_Err(demux
, "Invalid video size");
483 for (size_t i
= 0; i
< count
; ++i
)
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
))
500 InitAudioTracks(demux_t
*demux
, int group
, size_t count
)
502 struct demux_sys
*sys
= demux
->p_sys
;
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
)
515 msg_Err(demux
, "Invalid audio rate");
517 msg_Err(demux
, "Invalid audio format");
519 msg_Err(demux
, "Invalid audio channels");
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
)
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
))
555 InitSubTracks(demux_t
*demux
, int group
, size_t count
)
557 struct demux_sys
*sys
= demux
->p_sys
;
562 for (size_t i
= 0; i
< count
; ++i
)
565 es_format_Init(&fmt
, SPU_ES
, VLC_CODEC_SUBT
);
567 if (AppendMockTrack(demux
, &fmt
, i
, group
, sys
->sub_packetized
))
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
)
585 switch (track
->fmt
.i_cat
)
588 block
= CreateAudioBlock(demux
, track
, step_length
);
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
)
603 sys
->audio_pts
+= step_length
;
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
)
619 switch (track
->fmt
.i_cat
)
622 block
= CreateVideoBlock(demux
, track
);
625 block
= CreateSubBlock(demux
, track
);
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
)
640 sys
->video_pts
+= step_length
;
646 Demux(demux_t
*demux
)
648 struct demux_sys
*sys
= demux
->p_sys
;
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
)
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
)
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
)
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
;
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
;
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
;
745 return audio_eof
&& video_eof
&& input_eof
? VLC_DEMUXER_EOF
746 : VLC_DEMUXER_SUCCESS
;
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
);
761 vlc_vector_clear(&sys
->tracks
);
765 Open(vlc_object_t
*obj
)
767 demux_t
*demux
= (demux_t
*)obj
;
769 if (demux
->out
== NULL
)
771 struct demux_sys
*sys
= vlc_obj_malloc(obj
, sizeof(*sys
));
777 if (var_LocationParse(obj
, demux
->psz_location
, "mock-") != VLC_SUCCESS
)
780 #define X(var_name, type, module_header_type, getter, default_value) \
781 sys->var_name = getter(obj, "mock-"#var_name);
785 if (sys
->chapter_count
> 0 && sys
->title_count
== 0)
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
)
799 msg_Err(demux
, "Invalid length");
801 msg_Err(demux
, "Invalid track count");
803 msg_Err(demux
, "Invalid title count");
805 msg_Err(demux
, "Invalid chapter count");
807 msg_Err(demux
, "Invalid program count");
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
);
818 bool success
= vlc_vector_reserve(&sys
->tracks
, track_count
);
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
)
830 ret
= InitAudioTracks(demux
, i
, sys
->audio_track_count
);
831 if (ret
!= VLC_SUCCESS
)
834 ret
= InitSubTracks(demux
, i
, sys
->sub_track_count
);
835 if (ret
!= VLC_SUCCESS
)
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
;
846 demux
->pf_control
= Control
;
847 demux
->pf_demux
= Demux
;
856 #define X(var_name, type, module_header_type, getter, default_value) \
857 module_header_type("mock-"#var_name, default_value, NULL, NULL, true) \
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
)