2 * GStreamer parser backend
4 * Copyright 2010 Maarten Lankhorst for CodeWeavers
5 * Copyright 2010 Aric Stewart for CodeWeavers
6 * Copyright 2019-2020 Zebediah Figura
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library 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 GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include <gst/video/video.h>
35 #include <gst/audio/audio.h>
36 #include <gst/tag/tag.h>
39 #define WIN32_NO_STATUS
43 #include "unix_private.h"
47 GST_AUTOPLUG_SELECT_TRY
,
48 GST_AUTOPLUG_SELECT_EXPOSE
,
49 GST_AUTOPLUG_SELECT_SKIP
,
50 } GstAutoplugSelectResult
;
54 typedef BOOL (*init_gst_cb
)(struct wg_parser
*parser
);
56 struct input_cache_chunk
66 struct wg_parser_stream
**streams
;
67 unsigned int stream_count
;
69 GstElement
*container
, *decodebin
;
73 guint64 file_size
, start_offset
, next_offset
, stop_offset
;
74 guint64 next_pull_offset
;
76 pthread_t push_thread
;
78 pthread_mutex_t mutex
;
80 pthread_cond_t init_cond
;
81 bool output_compressed
;
82 bool no_more_pads
, has_duration
, error
;
85 pthread_cond_t read_cond
, read_done_cond
;
99 struct input_cache_chunk input_cache_chunks
[4];
101 static const unsigned int input_cache_chunk_size
= 512 << 10;
103 struct wg_parser_stream
105 struct wg_parser
*parser
;
109 GstElement
*flip
, *decodebin
;
111 struct wg_format preferred_format
, current_format
, codec_format
;
113 pthread_cond_t event_cond
, event_empty_cond
;
117 bool flushing
, eos
, enabled
, has_caps
, has_tags
, has_buffer
, no_more_pads
;
120 gchar
*tags
[WG_PARSER_TAG_COUNT
];
123 static struct wg_parser
*get_parser(wg_parser_t parser
)
125 return (struct wg_parser
*)(ULONG_PTR
)parser
;
128 static struct wg_parser_stream
*get_stream(wg_parser_stream_t stream
)
130 return (struct wg_parser_stream
*)(ULONG_PTR
)stream
;
133 static bool format_is_compressed(struct wg_format
*format
)
135 return format
->major_type
!= WG_MAJOR_TYPE_UNKNOWN
136 && format
->major_type
!= WG_MAJOR_TYPE_VIDEO
137 && format
->major_type
!= WG_MAJOR_TYPE_AUDIO
;
140 static NTSTATUS
wg_parser_get_stream_count(void *args
)
142 struct wg_parser_get_stream_count_params
*params
= args
;
144 params
->count
= get_parser(params
->parser
)->stream_count
;
148 static NTSTATUS
wg_parser_get_stream(void *args
)
150 struct wg_parser_get_stream_params
*params
= args
;
152 params
->stream
= (wg_parser_stream_t
)(ULONG_PTR
)get_parser(params
->parser
)->streams
[params
->index
];
156 static NTSTATUS
wg_parser_get_next_read_offset(void *args
)
158 struct wg_parser_get_next_read_offset_params
*params
= args
;
159 struct wg_parser
*parser
= get_parser(params
->parser
);
161 pthread_mutex_lock(&parser
->mutex
);
163 while (parser
->sink_connected
&& !parser
->read_request
.size
)
164 pthread_cond_wait(&parser
->read_cond
, &parser
->mutex
);
166 if (!parser
->sink_connected
)
168 pthread_mutex_unlock(&parser
->mutex
);
169 return VFW_E_WRONG_STATE
;
172 params
->offset
= parser
->read_request
.offset
;
173 params
->size
= parser
->read_request
.size
;
175 pthread_mutex_unlock(&parser
->mutex
);
179 static NTSTATUS
wg_parser_push_data(void *args
)
181 const struct wg_parser_push_data_params
*params
= args
;
182 struct wg_parser
*parser
= get_parser(params
->parser
);
183 const void *data
= params
->data
;
184 uint32_t size
= params
->size
;
186 pthread_mutex_lock(&parser
->mutex
);
194 /* Note that we don't allocate the buffer until we have a size.
195 * midiparse passes a NULL buffer and a size of UINT_MAX, in an
196 * apparent attempt to read the whole input stream at once. */
197 if (!parser
->read_request
.buffer
)
198 parser
->read_request
.buffer
= gst_buffer_new_and_alloc(size
);
199 gst_buffer_map(parser
->read_request
.buffer
, &map_info
, GST_MAP_WRITE
);
200 memcpy(map_info
.data
, data
, size
);
201 gst_buffer_unmap(parser
->read_request
.buffer
, &map_info
);
202 parser
->read_request
.ret
= GST_FLOW_OK
;
206 parser
->read_request
.ret
= GST_FLOW_EOS
;
211 parser
->read_request
.ret
= GST_FLOW_ERROR
;
213 parser
->read_request
.done
= true;
214 parser
->read_request
.size
= 0;
216 pthread_mutex_unlock(&parser
->mutex
);
217 pthread_cond_signal(&parser
->read_done_cond
);
222 static NTSTATUS
wg_parser_stream_get_preferred_format(void *args
)
224 const struct wg_parser_stream_get_preferred_format_params
*params
= args
;
226 *params
->format
= get_stream(params
->stream
)->preferred_format
;
230 static NTSTATUS
wg_parser_stream_get_codec_format(void *args
)
232 struct wg_parser_stream_get_codec_format_params
*params
= args
;
233 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
235 *params
->format
= format_is_compressed(&stream
->codec_format
) ?
236 stream
->codec_format
:
237 stream
->preferred_format
;
241 static NTSTATUS
wg_parser_stream_enable(void *args
)
243 const struct wg_parser_stream_enable_params
*params
= args
;
244 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
245 const struct wg_format
*format
= params
->format
;
246 struct wg_parser
*parser
= stream
->parser
;
248 pthread_mutex_lock(&parser
->mutex
);
250 stream
->current_format
= *format
;
251 stream
->enabled
= true;
253 pthread_mutex_unlock(&parser
->mutex
);
255 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
257 bool flip
= (format
->u
.video
.height
< 0);
259 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method", flip
? "vertical-flip" : "none");
262 push_event(stream
->my_sink
, gst_event_new_reconfigure());
266 static NTSTATUS
wg_parser_stream_disable(void *args
)
268 struct wg_parser_stream
*stream
= get_stream(*(wg_parser_stream_t
*)args
);
269 struct wg_parser
*parser
= stream
->parser
;
271 pthread_mutex_lock(&parser
->mutex
);
272 stream
->enabled
= false;
273 stream
->current_format
.major_type
= WG_MAJOR_TYPE_UNKNOWN
;
274 pthread_mutex_unlock(&parser
->mutex
);
275 pthread_cond_signal(&stream
->event_empty_cond
);
279 static GstBuffer
*wait_parser_stream_buffer(struct wg_parser
*parser
, struct wg_parser_stream
*stream
)
281 GstBuffer
*buffer
= NULL
;
283 /* Note that we can both have a buffer and stream->eos, in which case we
284 * must return the buffer. */
286 while (stream
->enabled
&& !(buffer
= stream
->buffer
) && !stream
->eos
)
287 pthread_cond_wait(&stream
->event_cond
, &parser
->mutex
);
292 static NTSTATUS
wg_parser_stream_get_buffer(void *args
)
294 const struct wg_parser_stream_get_buffer_params
*params
= args
;
295 struct wg_parser_buffer
*wg_buffer
= params
->buffer
;
296 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
297 struct wg_parser
*parser
= get_parser(params
->parser
);
301 pthread_mutex_lock(&parser
->mutex
);
304 buffer
= wait_parser_stream_buffer(parser
, stream
);
307 /* Find the earliest buffer by PTS.
309 * Native seems to behave similarly to this with the wm async reader, although our
310 * unit tests show that it's not entirely consistent—some frames are received
311 * slightly out of order. It's possible that one stream is being manually offset
312 * to account for decoding latency.
314 * The behaviour with the wm sync reader, when stream 0 is requested, seems
315 * consistent with this hypothesis, but with a much larger offset—the video
316 * stream seems to be "behind" by about 150 ms.
318 * The main reason for doing this is that the video and audio stream probably
319 * don't have quite the same "frame rate", and we don't want to force one stream
320 * to decode faster just to keep up with the other. Delivering samples in PTS
321 * order should avoid that problem. */
322 GstBuffer
*earliest
= NULL
;
324 for (i
= 0; i
< parser
->stream_count
; ++i
)
326 if (!(buffer
= wait_parser_stream_buffer(parser
, parser
->streams
[i
])))
328 /* invalid PTS is GST_CLOCK_TIME_NONE == (guint64)-1, so this will prefer valid timestamps. */
329 if (!earliest
|| GST_BUFFER_PTS(buffer
) < GST_BUFFER_PTS(earliest
))
331 stream
= parser
->streams
[i
];
341 pthread_mutex_unlock(&parser
->mutex
);
345 /* FIXME: Should we use gst_segment_to_stream_time_full()? Under what
346 * circumstances is the stream time not equal to the buffer PTS? Note
347 * that this will need modification to wg_parser_stream_notify_qos() as
350 if ((wg_buffer
->has_pts
= GST_BUFFER_PTS_IS_VALID(buffer
)))
351 wg_buffer
->pts
= GST_BUFFER_PTS(buffer
) / 100;
352 if ((wg_buffer
->has_duration
= GST_BUFFER_DURATION_IS_VALID(buffer
)))
353 wg_buffer
->duration
= GST_BUFFER_DURATION(buffer
) / 100;
354 wg_buffer
->discontinuity
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DISCONT
);
355 wg_buffer
->preroll
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_LIVE
);
356 wg_buffer
->delta
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DELTA_UNIT
);
357 wg_buffer
->size
= gst_buffer_get_size(buffer
);
358 wg_buffer
->stream
= stream
->number
;
360 pthread_mutex_unlock(&parser
->mutex
);
364 static NTSTATUS
wg_parser_stream_copy_buffer(void *args
)
366 const struct wg_parser_stream_copy_buffer_params
*params
= args
;
367 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
368 struct wg_parser
*parser
= stream
->parser
;
369 uint32_t offset
= params
->offset
;
370 uint32_t size
= params
->size
;
372 pthread_mutex_lock(&parser
->mutex
);
376 pthread_mutex_unlock(&parser
->mutex
);
377 return VFW_E_WRONG_STATE
;
380 assert(offset
< stream
->map_info
.size
);
381 assert(offset
+ size
<= stream
->map_info
.size
);
382 memcpy(params
->data
, stream
->map_info
.data
+ offset
, size
);
384 pthread_mutex_unlock(&parser
->mutex
);
388 static NTSTATUS
wg_parser_stream_release_buffer(void *args
)
390 struct wg_parser_stream
*stream
= get_stream(*(wg_parser_stream_t
*)args
);
391 struct wg_parser
*parser
= stream
->parser
;
393 pthread_mutex_lock(&parser
->mutex
);
395 assert(stream
->buffer
);
397 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
398 gst_buffer_unref(stream
->buffer
);
399 stream
->buffer
= NULL
;
401 pthread_mutex_unlock(&parser
->mutex
);
402 pthread_cond_signal(&stream
->event_empty_cond
);
407 static NTSTATUS
wg_parser_stream_get_duration(void *args
)
409 struct wg_parser_stream_get_duration_params
*params
= args
;
411 params
->duration
= get_stream(params
->stream
)->duration
;
415 static NTSTATUS
wg_parser_stream_get_tag(void *args
)
417 struct wg_parser_stream_get_tag_params
*params
= args
;
418 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
421 if (params
->tag
>= WG_PARSER_TAG_COUNT
)
422 return STATUS_INVALID_PARAMETER
;
423 if (!stream
->tags
[params
->tag
])
424 return STATUS_NOT_FOUND
;
425 if ((len
= strlen(stream
->tags
[params
->tag
]) + 1) > *params
->size
)
428 return STATUS_BUFFER_TOO_SMALL
;
430 memcpy(params
->buffer
, stream
->tags
[params
->tag
], len
);
431 return STATUS_SUCCESS
;
434 static NTSTATUS
wg_parser_stream_seek(void *args
)
436 GstSeekType start_type
= GST_SEEK_TYPE_SET
, stop_type
= GST_SEEK_TYPE_SET
;
437 const struct wg_parser_stream_seek_params
*params
= args
;
438 DWORD start_flags
= params
->start_flags
;
439 DWORD stop_flags
= params
->stop_flags
;
440 const struct wg_parser_stream
*stream
;
441 GstSeekFlags flags
= 0;
443 stream
= get_stream(params
->stream
);
445 if (start_flags
& AM_SEEKING_SeekToKeyFrame
)
446 flags
|= GST_SEEK_FLAG_KEY_UNIT
;
447 if (start_flags
& AM_SEEKING_Segment
)
448 flags
|= GST_SEEK_FLAG_SEGMENT
;
449 if (!(start_flags
& AM_SEEKING_NoFlush
))
450 flags
|= GST_SEEK_FLAG_FLUSH
;
452 if ((start_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
453 start_type
= GST_SEEK_TYPE_NONE
;
454 if ((stop_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
455 stop_type
= GST_SEEK_TYPE_NONE
;
457 if (!push_event(stream
->my_sink
, gst_event_new_seek(params
->rate
, GST_FORMAT_TIME
,
458 flags
, start_type
, params
->start_pos
* 100, stop_type
,
459 params
->stop_pos
== stream
->duration
? -1 : params
->stop_pos
* 100)))
460 GST_ERROR("Failed to seek.");
465 static NTSTATUS
wg_parser_stream_notify_qos(void *args
)
467 const struct wg_parser_stream_notify_qos_params
*params
= args
;
468 struct wg_parser_stream
*stream
= get_stream(params
->stream
);
469 GstClockTimeDiff diff
= params
->diff
* 100;
470 GstClockTime stream_time
;
473 /* We return timestamps in stream time, i.e. relative to the start of the
474 * file (or other medium), but gst_event_new_qos() expects the timestamp in
476 stream_time
= gst_segment_to_running_time(&stream
->segment
, GST_FORMAT_TIME
, params
->timestamp
* 100);
477 if (diff
< (GstClockTimeDiff
)-stream_time
)
479 if (stream_time
== -1)
481 /* This can happen legitimately if the sample falls outside of the
482 * segment bounds. GStreamer elements shouldn't present the sample in
483 * that case, but DirectShow doesn't care. */
484 GST_LOG("Ignoring QoS event.");
487 if (!(event
= gst_event_new_qos(params
->underflow
? GST_QOS_TYPE_UNDERFLOW
: GST_QOS_TYPE_OVERFLOW
,
488 params
->proportion
, diff
, stream_time
)))
489 GST_ERROR("Failed to create QOS event.");
490 push_event(stream
->my_sink
, event
);
495 static bool parser_no_more_pads(struct wg_parser
*parser
)
499 for (i
= 0; i
< parser
->stream_count
; ++i
)
501 if (!parser
->streams
[i
]->no_more_pads
)
505 return parser
->no_more_pads
;
508 static gboolean
autoplug_continue_cb(GstElement
* decodebin
, GstPad
*pad
, GstCaps
* caps
, gpointer user
)
510 struct wg_format format
;
512 wg_format_from_caps(&format
, caps
);
514 return !format_is_compressed(&format
);
517 static GstAutoplugSelectResult
autoplug_select_cb(GstElement
*bin
, GstPad
*pad
,
518 GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
520 struct wg_parser
*parser
= user
;
521 const char *name
= gst_element_factory_get_longname(fact
);
522 const char *klass
= gst_element_factory_get_klass(fact
);
524 GST_INFO("Using \"%s\".", name
);
526 if (strstr(name
, "Player protection"))
528 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
529 return GST_AUTOPLUG_SELECT_SKIP
;
531 if (!strcmp(name
, "Fluendo Hardware Accelerated Video Decoder"))
533 GST_WARNING("Disabled video acceleration since it breaks in wine.");
534 return GST_AUTOPLUG_SELECT_SKIP
;
537 if (!parser
->sink_caps
&& strstr(klass
, GST_ELEMENT_FACTORY_KLASS_DEMUXER
))
538 parser
->sink_caps
= g_strdup(gst_structure_get_name(gst_caps_get_structure(caps
, 0)));
540 return GST_AUTOPLUG_SELECT_TRY
;
543 static void no_more_pads_cb(GstElement
*element
, gpointer user
)
545 struct wg_parser
*parser
= user
;
547 GST_DEBUG("parser %p.", parser
);
549 pthread_mutex_lock(&parser
->mutex
);
550 parser
->no_more_pads
= true;
551 pthread_mutex_unlock(&parser
->mutex
);
552 pthread_cond_signal(&parser
->init_cond
);
555 static gboolean
sink_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
557 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
558 struct wg_parser
*parser
= stream
->parser
;
560 GST_LOG("stream %p, type \"%s\".", stream
, GST_EVENT_TYPE_NAME(event
));
564 case GST_EVENT_SEGMENT
:
565 pthread_mutex_lock(&parser
->mutex
);
568 const GstSegment
*segment
;
570 gst_event_parse_segment(event
, &segment
);
572 if (segment
->format
!= GST_FORMAT_TIME
)
574 pthread_mutex_unlock(&parser
->mutex
);
575 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment
->format
));
579 gst_segment_copy_into(segment
, &stream
->segment
);
581 pthread_mutex_unlock(&parser
->mutex
);
585 pthread_mutex_lock(&parser
->mutex
);
588 pthread_cond_signal(&stream
->event_cond
);
590 pthread_cond_signal(&parser
->init_cond
);
591 pthread_mutex_unlock(&parser
->mutex
);
594 case GST_EVENT_FLUSH_START
:
595 pthread_mutex_lock(&parser
->mutex
);
599 stream
->flushing
= true;
600 pthread_cond_signal(&stream
->event_empty_cond
);
604 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
605 gst_buffer_unref(stream
->buffer
);
606 stream
->buffer
= NULL
;
610 pthread_mutex_unlock(&parser
->mutex
);
613 case GST_EVENT_FLUSH_STOP
:
617 gst_event_parse_flush_stop(event
, &reset_time
);
620 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
622 pthread_mutex_lock(&parser
->mutex
);
626 stream
->flushing
= false;
628 pthread_mutex_unlock(&parser
->mutex
);
636 gst_event_parse_caps(event
, &caps
);
637 pthread_mutex_lock(&parser
->mutex
);
638 wg_format_from_caps(&stream
->preferred_format
, caps
);
639 stream
->has_caps
= true;
640 pthread_mutex_unlock(&parser
->mutex
);
641 pthread_cond_signal(&parser
->init_cond
);
646 pthread_mutex_lock(&parser
->mutex
);
647 stream
->has_tags
= true;
648 pthread_cond_signal(&parser
->init_cond
);
649 pthread_mutex_unlock(&parser
->mutex
);
653 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
655 gst_event_unref(event
);
659 static GstFlowReturn
sink_chain_cb(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buffer
)
661 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
662 struct wg_parser
*parser
= stream
->parser
;
664 GST_LOG("stream %p, buffer %p.", stream
, buffer
);
666 pthread_mutex_lock(&parser
->mutex
);
668 if (!stream
->has_buffer
)
670 stream
->has_buffer
= true;
671 pthread_cond_signal(&parser
->init_cond
);
674 /* Allow this buffer to be flushed by GStreamer. We are effectively
675 * implementing a queue object here. */
677 while (stream
->enabled
&& !stream
->flushing
&& stream
->buffer
)
678 pthread_cond_wait(&stream
->event_empty_cond
, &parser
->mutex
);
680 if (!stream
->enabled
)
682 GST_LOG("Stream is disabled; discarding buffer.");
683 pthread_mutex_unlock(&parser
->mutex
);
684 gst_buffer_unref(buffer
);
688 if (stream
->flushing
)
690 pthread_mutex_unlock(&parser
->mutex
);
691 GST_DEBUG("Stream is flushing; discarding buffer.");
692 gst_buffer_unref(buffer
);
693 return GST_FLOW_FLUSHING
;
696 if (!gst_buffer_map(buffer
, &stream
->map_info
, GST_MAP_READ
))
698 pthread_mutex_unlock(&parser
->mutex
);
699 GST_ERROR("Failed to map buffer.");
700 gst_buffer_unref(buffer
);
701 return GST_FLOW_ERROR
;
704 stream
->buffer
= buffer
;
706 pthread_mutex_unlock(&parser
->mutex
);
707 pthread_cond_signal(&stream
->event_cond
);
709 /* The chain callback is given a reference to the buffer. Transfer that
710 * reference to the stream object, which will release it in
711 * wg_parser_stream_release_buffer(). */
713 GST_LOG("Buffer queued.");
717 static gboolean
sink_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
719 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
720 struct wg_parser
*parser
= stream
->parser
;
722 GST_LOG("stream %p, type \"%s\".", stream
, gst_query_type_get_name(query
->type
));
728 GstCaps
*caps
, *filter
, *temp
;
731 gst_query_parse_caps(query
, &filter
);
733 pthread_mutex_lock(&parser
->mutex
);
734 caps
= wg_format_to_caps(&stream
->current_format
);
735 pthread_mutex_unlock(&parser
->mutex
);
740 /* Clear some fields that shouldn't prevent us from connecting. */
741 for (i
= 0; i
< gst_caps_get_size(caps
); ++i
)
742 gst_structure_remove_fields(gst_caps_get_structure(caps
, i
),
743 "framerate", "pixel-aspect-ratio", NULL
);
745 GST_LOG("Stream caps are \"%" GST_PTR_FORMAT
"\".", caps
);
749 temp
= gst_caps_intersect(caps
, filter
);
750 gst_caps_unref(caps
);
754 gst_query_set_caps_result(query
, caps
);
755 gst_caps_unref(caps
);
759 case GST_QUERY_ACCEPT_CAPS
:
761 struct wg_format format
;
765 pthread_mutex_lock(&parser
->mutex
);
767 if (stream
->current_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
769 pthread_mutex_unlock(&parser
->mutex
);
770 gst_query_set_accept_caps_result(query
, TRUE
);
774 gst_query_parse_accept_caps(query
, &caps
);
775 wg_format_from_caps(&format
, caps
);
776 ret
= wg_format_compare(&format
, &stream
->current_format
);
778 pthread_mutex_unlock(&parser
->mutex
);
781 GST_WARNING("Rejecting caps \"%" GST_PTR_FORMAT
"\".", caps
);
782 gst_query_set_accept_caps_result(query
, ret
);
787 return gst_pad_query_default (pad
, parent
, query
);
791 static struct wg_parser_stream
*create_stream(struct wg_parser
*parser
)
793 struct wg_parser_stream
*stream
, **new_array
;
796 if (!(new_array
= realloc(parser
->streams
, (parser
->stream_count
+ 1) * sizeof(*parser
->streams
))))
798 parser
->streams
= new_array
;
800 if (!(stream
= calloc(1, sizeof(*stream
))))
803 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
805 stream
->parser
= parser
;
806 stream
->number
= parser
->stream_count
;
807 stream
->no_more_pads
= true;
808 stream
->current_format
.major_type
= WG_MAJOR_TYPE_UNKNOWN
;
809 pthread_cond_init(&stream
->event_cond
, NULL
);
810 pthread_cond_init(&stream
->event_empty_cond
, NULL
);
812 sprintf(pad_name
, "qz_sink_%u", parser
->stream_count
);
813 stream
->my_sink
= gst_pad_new(pad_name
, GST_PAD_SINK
);
814 gst_pad_set_element_private(stream
->my_sink
, stream
);
815 gst_pad_set_chain_function(stream
->my_sink
, sink_chain_cb
);
816 gst_pad_set_event_function(stream
->my_sink
, sink_event_cb
);
817 gst_pad_set_query_function(stream
->my_sink
, sink_query_cb
);
819 parser
->streams
[parser
->stream_count
++] = stream
;
823 static void free_stream(struct wg_parser_stream
*stream
)
827 gst_object_unref(stream
->my_sink
);
831 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
832 gst_buffer_unref(stream
->buffer
);
833 stream
->buffer
= NULL
;
836 pthread_cond_destroy(&stream
->event_cond
);
837 pthread_cond_destroy(&stream
->event_empty_cond
);
839 for (i
= 0; i
< ARRAY_SIZE(stream
->tags
); ++i
)
842 g_free(stream
->tags
[i
]);
847 static bool stream_create_post_processing_elements(GstPad
*pad
, struct wg_parser_stream
*stream
)
849 GstElement
*element
= NULL
, *first
= NULL
, *last
= NULL
;
850 struct wg_parser
*parser
= stream
->parser
;
854 caps
= gst_pad_query_caps(pad
, NULL
);
855 name
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
856 gst_caps_unref(caps
);
858 if (!strcmp(name
, "video/x-raw"))
860 /* DirectShow can express interlaced video, but downstream filters can't
861 * necessarily consume it. In particular, the video renderer can't. */
862 if (!(element
= create_element("deinterlace", "good"))
863 || !append_element(parser
->container
, element
, &first
, &last
))
866 /* decodebin considers many YUV formats to be "raw", but some quartz
867 * filters can't handle those. Also, videoflip can't handle all "raw"
868 * formats either. Add a videoconvert to swap color spaces. */
869 if (!(element
= create_element("videoconvert", "base"))
870 || !append_element(parser
->container
, element
, &first
, &last
))
873 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
874 if (!(element
= create_element("videoflip", "good"))
875 || !append_element(parser
->container
, element
, &first
, &last
))
877 stream
->flip
= element
;
879 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
880 * to do the final conversion. */
881 if (!(element
= create_element("videoconvert", "base"))
882 || !append_element(parser
->container
, element
, &first
, &last
))
885 if (!link_src_to_element(pad
, first
) || !link_element_to_sink(last
, stream
->my_sink
))
888 else if (!strcmp(name
, "audio/x-raw"))
890 /* Currently our dsound can't handle 64-bit formats or all
891 * surround-sound configurations. Native dsound can't always handle
892 * 64-bit formats either. Add an audioconvert to allow changing bit
893 * depth and channel count. */
894 if (!(element
= create_element("audioconvert", "base"))
895 || !append_element(parser
->container
, element
, &first
, &last
))
898 if (!link_src_to_element(pad
, first
) || !link_element_to_sink(last
, stream
->my_sink
))
903 return link_src_to_sink(pad
, stream
->my_sink
);
909 static void stream_decodebin_no_more_pads_cb(GstElement
*element
, gpointer user
)
911 struct wg_parser_stream
*stream
= user
;
912 struct wg_parser
*parser
= stream
->parser
;
914 GST_DEBUG("stream %p, parser %p, element %p.", stream
, parser
, element
);
916 pthread_mutex_lock(&parser
->mutex
);
917 stream
->no_more_pads
= true;
918 pthread_mutex_unlock(&parser
->mutex
);
919 pthread_cond_signal(&parser
->init_cond
);
922 static void stream_decodebin_pad_added_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
924 struct wg_parser_stream
*stream
= user
;
925 struct wg_parser
*parser
= stream
->parser
;
927 GST_LOG("stream %p, parser %p, element %p, pad %p.", stream
, parser
, element
, pad
);
929 if (gst_pad_is_linked(pad
))
932 if (!stream_create_post_processing_elements(pad
, stream
))
934 gst_pad_set_active(stream
->my_sink
, 1);
937 static bool stream_decodebin_create(struct wg_parser_stream
*stream
)
939 struct wg_parser
*parser
= stream
->parser
;
941 GST_LOG("stream %p, parser %p.", stream
, parser
);
943 if (!(stream
->decodebin
= create_element("decodebin", "base")))
945 gst_bin_add(GST_BIN(parser
->container
), stream
->decodebin
);
947 g_signal_connect(stream
->decodebin
, "pad-added", G_CALLBACK(stream_decodebin_pad_added_cb
), stream
);
948 g_signal_connect(stream
->decodebin
, "autoplug-select", G_CALLBACK(autoplug_select_cb
), stream
);
949 g_signal_connect(stream
->decodebin
, "no-more-pads", G_CALLBACK(stream_decodebin_no_more_pads_cb
), stream
);
951 pthread_mutex_lock(&parser
->mutex
);
952 stream
->no_more_pads
= false;
953 pthread_mutex_unlock(&parser
->mutex
);
954 gst_element_sync_state_with_parent(stream
->decodebin
);
956 GST_LOG("Created stream decodebin %p for %u.", stream
->decodebin
, stream
->number
);
961 static void pad_added_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
963 struct wg_parser_stream
*stream
;
964 struct wg_parser
*parser
= user
;
967 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
969 if (gst_pad_is_linked(pad
))
972 if (!(stream
= create_stream(parser
)))
975 caps
= gst_pad_query_caps(pad
, NULL
);
976 wg_format_from_caps(&stream
->codec_format
, caps
);
977 gst_caps_unref(caps
);
979 /* For compressed stream, create an extra decodebin to decode it. */
980 if (!parser
->output_compressed
&& format_is_compressed(&stream
->codec_format
))
982 if (!stream_decodebin_create(stream
))
984 GST_ERROR("Failed to create decodebin for stream %u.", stream
->number
);
988 if (!link_src_to_element(pad
, stream
->decodebin
))
989 GST_ERROR("Failed to link pad %p to stream decodebin %p for stream %u.",
990 pad
, stream
->decodebin
, stream
->number
);
995 if (!stream_create_post_processing_elements(pad
, stream
))
997 gst_pad_set_active(stream
->my_sink
, 1);
1000 static void pad_removed_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
1002 struct wg_parser
*parser
= user
;
1007 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
1009 for (i
= 0; i
< parser
->stream_count
; ++i
)
1011 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1012 GstPad
*stream_decodebin_sink_peer
= NULL
;
1013 GstPad
*stream_decodebin_sink
= NULL
;
1015 if (stream
->decodebin
)
1017 stream_decodebin_sink
= gst_element_get_static_pad(stream
->decodebin
, "sink");
1018 stream_decodebin_sink_peer
= gst_pad_get_peer(stream_decodebin_sink
);
1021 if (stream_decodebin_sink_peer
== pad
)
1023 gst_pad_unlink(pad
, stream_decodebin_sink
);
1027 if (stream_decodebin_sink_peer
)
1028 gst_object_unref(stream_decodebin_sink_peer
);
1029 if (stream_decodebin_sink
)
1030 gst_object_unref(stream_decodebin_sink
);
1036 name
= gst_pad_get_name(pad
);
1037 GST_WARNING("No pin matching pad \"%s\" found.", name
);
1041 static GstFlowReturn
issue_read_request(struct wg_parser
*parser
, guint64 offset
, guint size
, GstBuffer
**buffer
)
1045 pthread_mutex_lock(&parser
->mutex
);
1047 assert(!parser
->read_request
.size
);
1048 parser
->read_request
.buffer
= *buffer
;
1049 parser
->read_request
.offset
= offset
;
1050 parser
->read_request
.size
= size
;
1051 parser
->read_request
.done
= false;
1052 pthread_cond_signal(&parser
->read_cond
);
1054 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
1055 * the upstream pin to flush if necessary. We should never be blocked on
1056 * read_thread() not running. */
1058 while (!parser
->read_request
.done
)
1059 pthread_cond_wait(&parser
->read_done_cond
, &parser
->mutex
);
1061 *buffer
= parser
->read_request
.buffer
;
1062 ret
= parser
->read_request
.ret
;
1064 pthread_mutex_unlock(&parser
->mutex
);
1066 GST_LOG("Request returned %s.", gst_flow_get_name(ret
));
1071 static struct input_cache_chunk
* get_cache_entry(struct wg_parser
*parser
, guint64 position
)
1073 struct input_cache_chunk chunk
;
1076 for (i
= 0; i
< ARRAY_SIZE(parser
->input_cache_chunks
); i
++)
1078 chunk
= parser
->input_cache_chunks
[i
];
1080 if (chunk
.data
&& position
== chunk
.position
)
1084 memmove(&parser
->input_cache_chunks
[1], &parser
->input_cache_chunks
[0], i
* sizeof(chunk
));
1085 parser
->input_cache_chunks
[0] = chunk
;
1088 return &parser
->input_cache_chunks
[0];
1095 static GstFlowReturn
read_cached_chunk(struct wg_parser
*parser
, guint64 chunk_position
, unsigned int chunk_offset
, GstBuffer
*buffer
, guint64 buffer_offset
)
1097 struct input_cache_chunk
*chunk
;
1098 GstBuffer
*chunk_buffer
;
1102 if ((chunk
= get_cache_entry(parser
, chunk_position
)))
1104 if (!!gst_buffer_fill(buffer
, buffer_offset
, chunk
->data
+ chunk_offset
, input_cache_chunk_size
- chunk_offset
))
1107 return GST_FLOW_ERROR
;
1110 chunk
= &parser
->input_cache_chunks
[ ARRAY_SIZE(parser
->input_cache_chunks
) - 1 ];
1112 if (!(chunk_data
= chunk
->data
))
1113 chunk_data
= malloc(input_cache_chunk_size
);
1115 chunk_buffer
= gst_buffer_new_wrapped_full(0, chunk_data
, input_cache_chunk_size
, 0, input_cache_chunk_size
, NULL
, NULL
);
1116 ret
= issue_read_request(parser
, chunk_position
, input_cache_chunk_size
, &chunk_buffer
);
1117 gst_buffer_unref(chunk_buffer
);
1119 if (ret
!= GST_FLOW_OK
)
1126 memmove(&parser
->input_cache_chunks
[1], &parser
->input_cache_chunks
[0], (ARRAY_SIZE(parser
->input_cache_chunks
) - 1) * sizeof(*chunk
));
1127 parser
->input_cache_chunks
[0].data
= chunk_data
;
1128 parser
->input_cache_chunks
[0].position
= chunk_position
;
1130 chunk
= &parser
->input_cache_chunks
[0];
1131 if (!!gst_buffer_fill(buffer
, buffer_offset
, chunk
->data
+ chunk_offset
, input_cache_chunk_size
- chunk_offset
))
1134 return GST_FLOW_ERROR
;
1137 static GstFlowReturn
read_input_cache(struct wg_parser
*parser
, guint64 offset
, guint size
, GstBuffer
**buffer
)
1139 unsigned int i
, chunk_count
, chunk_offset
, buffer_offset
= 0;
1140 GstBuffer
*working_buffer
;
1141 guint64 chunk_position
;
1144 working_buffer
= *buffer
;
1145 if (!working_buffer
)
1146 working_buffer
= gst_buffer_new_and_alloc(size
);
1148 chunk_position
= offset
- (offset
% input_cache_chunk_size
);
1149 chunk_count
= (offset
+ size
+ input_cache_chunk_size
- chunk_position
- 1) / input_cache_chunk_size
;
1150 chunk_offset
= offset
- chunk_position
;
1152 for (i
= 0; i
< chunk_count
; i
++)
1154 if ((ret
= read_cached_chunk(parser
, chunk_position
, chunk_offset
, working_buffer
, buffer_offset
)) != GST_FLOW_OK
)
1157 gst_buffer_unref(working_buffer
);
1161 chunk_position
+= input_cache_chunk_size
;
1162 buffer_offset
+= input_cache_chunk_size
- chunk_offset
;
1166 *buffer
= working_buffer
;
1170 static GstFlowReturn
src_getrange_cb(GstPad
*pad
, GstObject
*parent
,
1171 guint64 offset
, guint size
, GstBuffer
**buffer
)
1173 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1175 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, size %u, buffer %p.", pad
, offset
, size
, *buffer
);
1177 if (offset
== GST_BUFFER_OFFSET_NONE
)
1178 offset
= parser
->next_pull_offset
;
1179 parser
->next_pull_offset
= offset
+ size
;
1183 /* asfreader occasionally asks for zero bytes. gst_buffer_map() will
1184 * return NULL in this case. Avoid confusing the read thread by asking
1185 * it for zero bytes. */
1187 *buffer
= gst_buffer_new_and_alloc(0);
1188 gst_buffer_set_size(*buffer
, 0);
1189 GST_LOG("Returning empty buffer.");
1193 if (size
>= input_cache_chunk_size
|| sizeof(void*) == 4)
1194 return issue_read_request(parser
, offset
, size
, buffer
);
1196 if (offset
>= parser
->file_size
)
1197 return GST_FLOW_EOS
;
1199 if ((offset
+ size
) >= parser
->file_size
)
1200 size
= parser
->file_size
- offset
;
1202 return read_input_cache(parser
, offset
, size
, buffer
);
1205 static gboolean
src_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
1207 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1210 GST_LOG("parser %p, type %s.", parser
, GST_QUERY_TYPE_NAME(query
));
1212 switch (GST_QUERY_TYPE(query
))
1214 case GST_QUERY_DURATION
:
1215 gst_query_parse_duration(query
, &format
, NULL
);
1216 if (format
== GST_FORMAT_PERCENT
)
1218 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
1221 else if (format
== GST_FORMAT_BYTES
)
1223 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
1228 case GST_QUERY_SEEKING
:
1229 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
1230 if (format
!= GST_FORMAT_BYTES
)
1232 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format
));
1235 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
1238 case GST_QUERY_SCHEDULING
:
1239 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
1240 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PUSH
);
1241 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
1245 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
1250 static void *push_data(void *arg
)
1252 struct wg_parser
*parser
= arg
;
1256 GST_DEBUG("Starting push thread.");
1258 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
1260 GST_ERROR("Failed to allocate memory.");
1264 max_size
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
1271 if (parser
->next_offset
>= max_size
)
1273 size
= min(16384, max_size
- parser
->next_offset
);
1275 if ((ret
= src_getrange_cb(parser
->my_src
, NULL
, parser
->next_offset
, size
, &buffer
)) < 0)
1277 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret
));
1281 parser
->next_offset
+= size
;
1283 buffer
->duration
= buffer
->pts
= -1;
1284 if ((ret
= gst_pad_push(parser
->my_src
, buffer
)) < 0)
1286 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret
));
1291 gst_buffer_unref(buffer
);
1293 push_event(parser
->my_src
, gst_event_new_eos());
1295 GST_DEBUG("Stopping push thread.");
1300 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
1302 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1306 if (parser
->push_thread
)
1308 pthread_join(parser
->push_thread
, NULL
);
1309 parser
->push_thread
= 0;
1312 else if (!parser
->push_thread
)
1316 if ((ret
= pthread_create(&parser
->push_thread
, NULL
, push_data
, parser
)))
1318 GST_ERROR("Failed to create push thread: %s", strerror(errno
));
1319 parser
->push_thread
= 0;
1326 static gboolean
src_activate_mode_cb(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
1328 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1330 GST_DEBUG("%s source pad for parser %p in %s mode.",
1331 activate
? "Activating" : "Deactivating", parser
, gst_pad_mode_get_name(mode
));
1335 case GST_PAD_MODE_PULL
:
1337 case GST_PAD_MODE_PUSH
:
1338 return activate_push(pad
, activate
);
1339 case GST_PAD_MODE_NONE
:
1345 static GstBusSyncReply
bus_handler_cb(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
1347 struct wg_parser
*parser
= user
;
1348 gchar
*dbg_info
= NULL
;
1351 GST_DEBUG("parser %p, message type %s.", parser
, GST_MESSAGE_TYPE_NAME(msg
));
1355 case GST_MESSAGE_ERROR
:
1356 gst_message_parse_error(msg
, &err
, &dbg_info
);
1359 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1360 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1364 pthread_mutex_lock(&parser
->mutex
);
1365 parser
->error
= true;
1366 pthread_mutex_unlock(&parser
->mutex
);
1367 pthread_cond_signal(&parser
->init_cond
);
1370 case GST_MESSAGE_WARNING
:
1371 gst_message_parse_warning(msg
, &err
, &dbg_info
);
1372 if (parser
->warn_on
)
1374 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1375 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1381 case GST_MESSAGE_DURATION_CHANGED
:
1382 pthread_mutex_lock(&parser
->mutex
);
1383 parser
->has_duration
= true;
1384 pthread_mutex_unlock(&parser
->mutex
);
1385 pthread_cond_signal(&parser
->init_cond
);
1391 gst_message_unref(msg
);
1392 return GST_BUS_DROP
;
1395 static gboolean
src_perform_seek(struct wg_parser
*parser
, GstEvent
*event
)
1397 BOOL thread
= !!parser
->push_thread
;
1398 GstSeekType cur_type
, stop_type
;
1399 GstFormat seek_format
;
1400 GstEvent
*flush_event
;
1406 gst_event_parse_seek(event
, &rate
, &seek_format
, &flags
,
1407 &cur_type
, &cur
, &stop_type
, &stop
);
1409 if (seek_format
!= GST_FORMAT_BYTES
)
1411 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format
));
1415 seqnum
= gst_event_get_seqnum(event
);
1417 /* send flush start */
1418 if (flags
& GST_SEEK_FLAG_FLUSH
)
1420 flush_event
= gst_event_new_flush_start();
1421 gst_event_set_seqnum(flush_event
, seqnum
);
1422 push_event(parser
->my_src
, flush_event
);
1424 gst_pad_set_active(parser
->my_src
, 1);
1427 parser
->next_offset
= parser
->start_offset
= cur
;
1429 /* and prepare to continue streaming */
1430 if (flags
& GST_SEEK_FLAG_FLUSH
)
1432 flush_event
= gst_event_new_flush_stop(TRUE
);
1433 gst_event_set_seqnum(flush_event
, seqnum
);
1434 push_event(parser
->my_src
, flush_event
);
1436 gst_pad_set_active(parser
->my_src
, 1);
1442 static gboolean
src_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
1444 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1445 gboolean ret
= TRUE
;
1447 GST_LOG("parser %p, type \"%s\".", parser
, GST_EVENT_TYPE_NAME(event
));
1449 switch (event
->type
)
1451 case GST_EVENT_SEEK
:
1452 ret
= src_perform_seek(parser
, event
);
1455 case GST_EVENT_FLUSH_START
:
1456 case GST_EVENT_FLUSH_STOP
:
1458 case GST_EVENT_RECONFIGURE
:
1462 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
1466 gst_event_unref(event
);
1470 static void query_tags(struct wg_parser_stream
*stream
)
1472 GstPad
*peer
= gst_pad_get_peer(stream
->my_sink
);
1473 const gchar
*struct_name
;
1474 GstEvent
*tag_event
;
1477 stream
->tags
[WG_PARSER_TAG_NAME
] = NULL
;
1478 stream
->tags
[WG_PARSER_TAG_LANGUAGE
] = NULL
;
1481 while ((tag_event
= gst_pad_get_sticky_event(peer
, GST_EVENT_TAG
, i
++)))
1483 GstTagList
*tag_list
;
1485 gst_event_parse_tag(tag_event
, &tag_list
);
1487 if (!stream
->tags
[WG_PARSER_TAG_NAME
])
1489 /* Extract stream name from Quick Time demuxer private tag where it puts unrecognized chunks. */
1494 guint tag_count
= gst_tag_list_get_tag_size(tag_list
, "private-qt-tag");
1496 for (j
= 0; j
< tag_count
; ++j
)
1498 if (!(val
= gst_tag_list_get_value_index(tag_list
, "private-qt-tag", j
)))
1500 if (!GST_VALUE_HOLDS_SAMPLE(val
) || !(sample
= gst_value_get_sample(val
)))
1502 struct_name
= gst_structure_get_name(gst_sample_get_info(sample
));
1503 if (!struct_name
|| strcmp(struct_name
, "application/x-gst-qt-name-tag"))
1505 if (!(buf
= gst_sample_get_buffer(sample
)))
1507 if ((size
= gst_buffer_get_size(buf
)) < 8)
1510 if (!(stream
->tags
[WG_PARSER_TAG_NAME
] = g_malloc(size
+ 1)))
1512 if (gst_buffer_extract(buf
, 8, stream
->tags
[WG_PARSER_TAG_NAME
], size
) != size
)
1514 g_free(stream
->tags
[WG_PARSER_TAG_NAME
]);
1515 stream
->tags
[WG_PARSER_TAG_NAME
] = NULL
;
1518 stream
->tags
[WG_PARSER_TAG_NAME
][size
] = 0;
1522 if (!stream
->tags
[WG_PARSER_TAG_LANGUAGE
])
1524 gchar
*lang_code
= NULL
;
1526 gst_tag_list_get_string(tag_list
, GST_TAG_LANGUAGE_CODE
, &lang_code
);
1527 if (stream
->parser
->sink_caps
&& !strcmp(stream
->parser
->sink_caps
, "video/quicktime"))
1529 /* For QuickTime media, we convert the language tags to ISO 639-1. */
1530 const gchar
*lang_code_iso_639_1
= lang_code
? gst_tag_get_language_code_iso_639_1(lang_code
) : NULL
;
1531 stream
->tags
[WG_PARSER_TAG_LANGUAGE
] = lang_code_iso_639_1
? g_strdup(lang_code_iso_639_1
) : NULL
;
1535 stream
->tags
[WG_PARSER_TAG_LANGUAGE
] = lang_code
;
1538 gst_event_unref(tag_event
);
1540 gst_object_unref(peer
);
1543 static NTSTATUS
wg_parser_connect(void *args
)
1545 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE("quartz_src",
1546 GST_PAD_SRC
, GST_PAD_ALWAYS
, GST_STATIC_CAPS_ANY
);
1547 const struct wg_parser_connect_params
*params
= args
;
1548 struct wg_parser
*parser
= get_parser(params
->parser
);
1552 parser
->file_size
= params
->file_size
;
1553 parser
->sink_connected
= true;
1557 parser
->bus
= gst_bus_new();
1558 gst_bus_set_sync_handler(parser
->bus
, bus_handler_cb
, parser
, NULL
);
1561 parser
->container
= gst_bin_new(NULL
);
1562 gst_element_set_bus(parser
->container
, parser
->bus
);
1564 parser
->my_src
= gst_pad_new_from_static_template(&src_template
, "quartz-src");
1565 gst_pad_set_getrange_function(parser
->my_src
, src_getrange_cb
);
1566 gst_pad_set_query_function(parser
->my_src
, src_query_cb
);
1567 gst_pad_set_activatemode_function(parser
->my_src
, src_activate_mode_cb
);
1568 gst_pad_set_event_function(parser
->my_src
, src_event_cb
);
1569 gst_pad_set_element_private(parser
->my_src
, parser
);
1571 parser
->start_offset
= parser
->next_offset
= parser
->stop_offset
= 0;
1572 parser
->next_pull_offset
= 0;
1573 parser
->error
= false;
1575 if (!parser
->init_gst(parser
))
1578 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1579 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1580 if (ret
== GST_STATE_CHANGE_FAILURE
)
1582 GST_ERROR("Failed to play stream.");
1586 pthread_mutex_lock(&parser
->mutex
);
1588 while (!parser_no_more_pads(parser
) && !parser
->error
)
1589 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1592 pthread_mutex_unlock(&parser
->mutex
);
1596 for (i
= 0; i
< parser
->stream_count
; ++i
)
1598 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1601 /* If we received a buffer, waiting for tags or caps does not make sense anymore. */
1602 while ((!stream
->has_caps
|| !stream
->has_tags
) && !parser
->error
&& !stream
->has_buffer
)
1603 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1605 /* GStreamer doesn't actually provide any guarantees about when duration
1606 * is available, even for seekable streams. It's basically built for
1607 * applications that don't care, e.g. movie players that can display
1608 * a duration once it's available, and update it visually if a better
1609 * estimate is found. This doesn't really match well with DirectShow or
1610 * Media Foundation, which both expect duration to be available
1611 * immediately on connecting, so we have to use some complex heuristics
1612 * to try to actually get a usable duration.
1614 * Some elements (avidemux, wavparse, qtdemux) record duration almost
1615 * immediately, before fixing caps. Such elements don't send
1616 * duration-changed messages. Therefore always try querying duration
1617 * after caps have been found.
1619 * Some elements (mpegaudioparse) send duration-changed. In the case of
1620 * a mp3 stream without seek tables it will not be sent immediately, but
1621 * only after enough frames have been parsed to form an estimate. They
1622 * may send it multiple times with increasingly accurate estimates, but
1623 * unfortunately we have no way of knowing whether another estimate will
1624 * be sent, so we always take the first one. We assume that if the
1625 * duration is not immediately available then the element will always
1626 * send duration-changed.
1633 pthread_mutex_unlock(&parser
->mutex
);
1636 if (gst_pad_peer_query_duration(stream
->my_sink
, GST_FORMAT_TIME
, &duration
))
1638 stream
->duration
= duration
/ 100;
1644 stream
->duration
= 0;
1645 GST_WARNING("Failed to query duration.");
1649 /* Elements based on GstBaseParse send duration-changed before
1650 * actually updating the duration in GStreamer versions prior
1651 * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
1652 * receiving duration-changed we have to continue polling until
1653 * the query succeeds. */
1654 if (parser
->has_duration
)
1656 pthread_mutex_unlock(&parser
->mutex
);
1658 pthread_mutex_lock(&parser
->mutex
);
1662 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1668 /* Now that we're fully initialized, enable the stream so that further
1669 * samples get queued instead of being discarded. We don't actually need
1670 * the samples (in particular, the frontend should seek before
1671 * attempting to read anything), but we don't want to waste CPU time
1672 * trying to decode them. */
1673 stream
->enabled
= true;
1676 pthread_mutex_unlock(&parser
->mutex
);
1678 parser
->next_offset
= 0;
1682 if (parser
->container
)
1683 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1685 gst_object_unref(parser
->my_src
);
1687 for (i
= 0; i
< parser
->stream_count
; ++i
)
1688 free_stream(parser
->streams
[i
]);
1689 parser
->stream_count
= 0;
1690 free(parser
->streams
);
1691 parser
->streams
= NULL
;
1693 if (parser
->container
)
1695 gst_element_set_bus(parser
->container
, NULL
);
1696 gst_object_unref(parser
->container
);
1697 parser
->container
= NULL
;
1700 g_free(parser
->sink_caps
);
1701 parser
->sink_caps
= NULL
;
1703 pthread_mutex_lock(&parser
->mutex
);
1704 parser
->sink_connected
= false;
1705 pthread_mutex_unlock(&parser
->mutex
);
1706 pthread_cond_signal(&parser
->read_cond
);
1711 static NTSTATUS
wg_parser_disconnect(void *args
)
1713 struct wg_parser
*parser
= get_parser(*(wg_parser_t
*)args
);
1716 /* Unblock all of our streams. */
1717 pthread_mutex_lock(&parser
->mutex
);
1718 for (i
= 0; i
< parser
->stream_count
; ++i
)
1720 parser
->streams
[i
]->flushing
= true;
1721 pthread_cond_signal(&parser
->streams
[i
]->event_empty_cond
);
1723 pthread_mutex_unlock(&parser
->mutex
);
1725 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1726 gst_object_unref(parser
->my_src
);
1727 parser
->my_src
= NULL
;
1729 pthread_mutex_lock(&parser
->mutex
);
1730 parser
->sink_connected
= false;
1731 pthread_mutex_unlock(&parser
->mutex
);
1732 pthread_cond_signal(&parser
->read_cond
);
1734 for (i
= 0; i
< parser
->stream_count
; ++i
)
1735 free_stream(parser
->streams
[i
]);
1737 parser
->stream_count
= 0;
1738 free(parser
->streams
);
1739 parser
->streams
= NULL
;
1741 gst_element_set_bus(parser
->container
, NULL
);
1742 gst_object_unref(parser
->container
);
1743 parser
->container
= NULL
;
1745 g_free(parser
->sink_caps
);
1746 parser
->sink_caps
= NULL
;
1748 for (i
= 0; i
< ARRAY_SIZE(parser
->input_cache_chunks
); i
++)
1750 free(parser
->input_cache_chunks
[i
].data
);
1751 parser
->input_cache_chunks
[i
].data
= NULL
;
1757 static BOOL
decodebin_parser_init_gst(struct wg_parser
*parser
)
1759 GstElement
*element
;
1761 if (!(element
= create_element("decodebin", "base")))
1764 gst_bin_add(GST_BIN(parser
->container
), element
);
1765 parser
->decodebin
= element
;
1767 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1768 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1769 g_signal_connect(element
, "autoplug-continue", G_CALLBACK(autoplug_continue_cb
), parser
);
1770 g_signal_connect(element
, "autoplug-select", G_CALLBACK(autoplug_select_cb
), parser
);
1771 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1773 pthread_mutex_lock(&parser
->mutex
);
1774 parser
->no_more_pads
= false;
1775 pthread_mutex_unlock(&parser
->mutex
);
1777 if (!link_src_to_element(parser
->my_src
, element
))
1783 static BOOL
avi_parser_init_gst(struct wg_parser
*parser
)
1785 GstElement
*element
;
1787 if (!(element
= create_element("avidemux", "good")))
1790 gst_bin_add(GST_BIN(parser
->container
), element
);
1792 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1793 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1794 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1796 pthread_mutex_lock(&parser
->mutex
);
1797 parser
->no_more_pads
= false;
1798 pthread_mutex_unlock(&parser
->mutex
);
1800 if (!link_src_to_element(parser
->my_src
, element
))
1806 static BOOL
wave_parser_init_gst(struct wg_parser
*parser
)
1808 struct wg_parser_stream
*stream
;
1809 GstElement
*element
;
1811 if (!(element
= create_element("wavparse", "good")))
1814 gst_bin_add(GST_BIN(parser
->container
), element
);
1816 if (!link_src_to_element(parser
->my_src
, element
))
1819 if (!(stream
= create_stream(parser
)))
1822 if (!link_element_to_sink(element
, stream
->my_sink
))
1824 gst_pad_set_active(stream
->my_sink
, 1);
1826 parser
->no_more_pads
= true;
1831 static NTSTATUS
wg_parser_create(void *args
)
1833 static const init_gst_cb init_funcs
[] =
1835 [WG_PARSER_DECODEBIN
] = decodebin_parser_init_gst
,
1836 [WG_PARSER_AVIDEMUX
] = avi_parser_init_gst
,
1837 [WG_PARSER_WAVPARSE
] = wave_parser_init_gst
,
1840 struct wg_parser_create_params
*params
= args
;
1841 struct wg_parser
*parser
;
1843 if (!(parser
= calloc(1, sizeof(*parser
))))
1844 return E_OUTOFMEMORY
;
1846 pthread_mutex_init(&parser
->mutex
, NULL
);
1847 pthread_cond_init(&parser
->init_cond
, NULL
);
1848 pthread_cond_init(&parser
->read_cond
, NULL
);
1849 pthread_cond_init(&parser
->read_done_cond
, NULL
);
1850 parser
->init_gst
= init_funcs
[params
->type
];
1851 parser
->output_compressed
= params
->output_compressed
;
1852 parser
->err_on
= params
->err_on
;
1853 parser
->warn_on
= params
->warn_on
;
1854 GST_DEBUG("Created winegstreamer parser %p.", parser
);
1855 params
->parser
= (wg_parser_t
)(ULONG_PTR
)parser
;
1859 static NTSTATUS
wg_parser_destroy(void *args
)
1861 struct wg_parser
*parser
= get_parser(*(wg_parser_t
*)args
);
1865 gst_bus_set_sync_handler(parser
->bus
, NULL
, NULL
, NULL
);
1866 gst_object_unref(parser
->bus
);
1869 pthread_mutex_destroy(&parser
->mutex
);
1870 pthread_cond_destroy(&parser
->init_cond
);
1871 pthread_cond_destroy(&parser
->read_cond
);
1872 pthread_cond_destroy(&parser
->read_done_cond
);
1878 const unixlib_entry_t __wine_unix_call_funcs
[] =
1880 #define X(name) [unix_ ## name] = name
1881 X(wg_init_gstreamer
),
1883 X(wg_parser_create
),
1884 X(wg_parser_destroy
),
1886 X(wg_parser_connect
),
1887 X(wg_parser_disconnect
),
1889 X(wg_parser_get_next_read_offset
),
1890 X(wg_parser_push_data
),
1892 X(wg_parser_get_stream_count
),
1893 X(wg_parser_get_stream
),
1895 X(wg_parser_stream_get_preferred_format
),
1896 X(wg_parser_stream_get_codec_format
),
1897 X(wg_parser_stream_enable
),
1898 X(wg_parser_stream_disable
),
1900 X(wg_parser_stream_get_buffer
),
1901 X(wg_parser_stream_copy_buffer
),
1902 X(wg_parser_stream_release_buffer
),
1903 X(wg_parser_stream_notify_qos
),
1905 X(wg_parser_stream_get_duration
),
1906 X(wg_parser_stream_get_tag
),
1907 X(wg_parser_stream_seek
),
1909 X(wg_transform_create
),
1910 X(wg_transform_destroy
),
1911 X(wg_transform_set_output_format
),
1913 X(wg_transform_push_data
),
1914 X(wg_transform_read_data
),
1915 X(wg_transform_get_status
),
1916 X(wg_transform_drain
),
1917 X(wg_transform_flush
),
1920 X(wg_muxer_destroy
),
1921 X(wg_muxer_add_stream
),
1923 X(wg_muxer_push_sample
),
1926 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs
) == unix_wg_funcs_count
);
1930 typedef ULONG PTR32
;
1932 static NTSTATUS
wow64_wg_parser_push_data(void *args
) {
1939 struct wg_parser_push_data_params params
=
1941 .parser
= params32
->parser
,
1942 .data
= ULongToPtr(params32
->data
),
1943 .size
= params32
->size
,
1946 return wg_parser_push_data(¶ms
);
1949 static NTSTATUS
wow64_wg_parser_stream_get_preferred_format(void *args
)
1953 wg_parser_stream_t stream
;
1956 struct wg_parser_stream_get_preferred_format_params params
=
1958 .stream
= params32
->stream
,
1959 .format
= ULongToPtr(params32
->format
),
1962 return wg_parser_stream_get_preferred_format(¶ms
);
1965 static NTSTATUS
wow64_wg_parser_stream_get_codec_format(void *args
)
1969 wg_parser_stream_t stream
;
1972 struct wg_parser_stream_get_codec_format_params params
=
1974 .stream
= params32
->stream
,
1975 .format
= ULongToPtr(params32
->format
),
1978 return wg_parser_stream_get_codec_format(¶ms
);
1981 static NTSTATUS
wow64_wg_parser_stream_enable(void *args
)
1985 wg_parser_stream_t stream
;
1988 struct wg_parser_stream_enable_params params
=
1990 .stream
= params32
->stream
,
1991 .format
= ULongToPtr(params32
->format
),
1994 return wg_parser_stream_enable(¶ms
);
1997 static NTSTATUS
wow64_wg_parser_stream_get_buffer(void *args
)
2002 wg_parser_stream_t stream
;
2005 struct wg_parser_stream_get_buffer_params params
=
2007 .parser
= params32
->parser
,
2008 .stream
= params32
->stream
,
2009 .buffer
= ULongToPtr(params32
->buffer
),
2011 return wg_parser_stream_get_buffer(¶ms
);
2014 static NTSTATUS
wow64_wg_parser_stream_copy_buffer(void *args
)
2018 wg_parser_stream_t stream
;
2023 struct wg_parser_stream_copy_buffer_params params
=
2025 .stream
= params32
->stream
,
2026 .data
= ULongToPtr(params32
->data
),
2027 .offset
= params32
->offset
,
2028 .size
= params32
->size
,
2030 return wg_parser_stream_copy_buffer(¶ms
);
2033 static NTSTATUS
wow64_wg_parser_stream_get_tag(void *args
)
2037 wg_parser_stream_t stream
;
2042 struct wg_parser_stream_get_tag_params params
=
2044 .stream
= params32
->stream
,
2045 .tag
= params32
->tag
,
2046 .buffer
= ULongToPtr(params32
->buffer
),
2047 .size
= ULongToPtr(params32
->size
),
2050 return wg_parser_stream_get_tag(¶ms
);
2053 NTSTATUS
wow64_wg_transform_create(void *args
)
2057 wg_transform_t transform
;
2059 PTR32 output_format
;
2062 struct wg_transform_create_params params
=
2064 .input_format
= ULongToPtr(params32
->input_format
),
2065 .output_format
= ULongToPtr(params32
->output_format
),
2066 .attrs
= ULongToPtr(params32
->attrs
),
2070 ret
= wg_transform_create(¶ms
);
2071 params32
->transform
= params
.transform
;
2075 NTSTATUS
wow64_wg_transform_set_output_format(void *args
)
2079 wg_transform_t transform
;
2082 struct wg_transform_set_output_format_params params
=
2084 .transform
= params32
->transform
,
2085 .format
= ULongToPtr(params32
->format
),
2087 return wg_transform_set_output_format(¶ms
);
2090 NTSTATUS
wow64_wg_transform_push_data(void *args
)
2094 wg_transform_t transform
;
2098 struct wg_transform_push_data_params params
=
2100 .transform
= params32
->transform
,
2101 .sample
= ULongToPtr(params32
->sample
),
2105 ret
= wg_transform_push_data(¶ms
);
2106 params32
->result
= params
.result
;
2110 NTSTATUS
wow64_wg_transform_read_data(void *args
)
2114 wg_transform_t transform
;
2119 struct wg_transform_read_data_params params
=
2121 .transform
= params32
->transform
,
2122 .sample
= ULongToPtr(params32
->sample
),
2123 .format
= ULongToPtr(params32
->format
),
2127 ret
= wg_transform_read_data(¶ms
);
2128 params32
->result
= params
.result
;
2132 NTSTATUS
wow64_wg_muxer_create(void *args
)
2139 struct wg_muxer_create_params params
=
2141 .format
= ULongToPtr(params32
->format
),
2145 ret
= wg_muxer_create(¶ms
);
2146 params32
->muxer
= params
.muxer
;
2150 NTSTATUS
wow64_wg_muxer_add_stream(void *args
)
2158 struct wg_muxer_add_stream_params params
=
2160 .muxer
= params32
->muxer
,
2161 .stream_id
= params32
->stream_id
,
2162 .format
= ULongToPtr(params32
->format
),
2164 return wg_muxer_add_stream(¶ms
);
2167 NTSTATUS
wow64_wg_muxer_push_sample(void *args
)
2175 struct wg_muxer_push_sample_params params
=
2177 .muxer
= params32
->muxer
,
2178 .sample
= ULongToPtr(params32
->sample
),
2179 .stream_id
= params32
->stream_id
,
2181 return wg_muxer_push_sample(¶ms
);
2184 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
2186 #define X64(name) [unix_ ## name] = wow64_ ## name
2187 X(wg_init_gstreamer
),
2189 X(wg_parser_create
),
2190 X(wg_parser_destroy
),
2192 X(wg_parser_connect
),
2193 X(wg_parser_disconnect
),
2195 X(wg_parser_get_next_read_offset
),
2196 X64(wg_parser_push_data
),
2198 X(wg_parser_get_stream_count
),
2199 X(wg_parser_get_stream
),
2201 X64(wg_parser_stream_get_preferred_format
),
2202 X64(wg_parser_stream_get_codec_format
),
2203 X64(wg_parser_stream_enable
),
2204 X(wg_parser_stream_disable
),
2206 X64(wg_parser_stream_get_buffer
),
2207 X64(wg_parser_stream_copy_buffer
),
2208 X(wg_parser_stream_release_buffer
),
2209 X(wg_parser_stream_notify_qos
),
2211 X(wg_parser_stream_get_duration
),
2212 X64(wg_parser_stream_get_tag
),
2213 X(wg_parser_stream_seek
),
2215 X64(wg_transform_create
),
2216 X(wg_transform_destroy
),
2217 X64(wg_transform_set_output_format
),
2219 X64(wg_transform_push_data
),
2220 X64(wg_transform_read_data
),
2221 X(wg_transform_get_status
),
2222 X(wg_transform_drain
),
2223 X(wg_transform_flush
),
2225 X64(wg_muxer_create
),
2226 X(wg_muxer_destroy
),
2227 X64(wg_muxer_add_stream
),
2229 X64(wg_muxer_push_sample
),
2232 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_wg_funcs_count
);