1/*
2 * Copyright (C) 2016 Metrological Group B.V.
3 * Copyright (C) 2016 Igalia S.L
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * aint with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "MediaSourceClientGStreamerMSE.h"
23
24#include "AppendPipeline.h"
25#include "MediaPlayerPrivateGStreamerMSE.h"
26#include "PlaybackPipeline.h"
27#include "WebKitMediaSourceGStreamer.h"
28#include <gst/gst.h>
29
30GST_DEBUG_CATEGORY_EXTERN(webkit_mse_debug);
31#define GST_CAT_DEFAULT webkit_mse_debug
32
33#if ENABLE(VIDEO) && USE(GSTREAMER) && ENABLE(MEDIA_SOURCE)
34
35namespace WebCore {
36
37Ref<MediaSourceClientGStreamerMSE> MediaSourceClientGStreamerMSE::create(MediaPlayerPrivateGStreamerMSE& playerPrivate)
38{
39 ASSERT(WTF::isMainThread());
40
41 // No return adoptRef(new MediaSourceClientGStreamerMSE(playerPrivate)) because the ownership has already been transferred to MediaPlayerPrivateGStreamerMSE.
42 Ref<MediaSourceClientGStreamerMSE> client(adoptRef(*new MediaSourceClientGStreamerMSE(playerPrivate)));
43 playerPrivate.setMediaSourceClient(client.get());
44 return client;
45}
46
47MediaSourceClientGStreamerMSE::MediaSourceClientGStreamerMSE(MediaPlayerPrivateGStreamerMSE& playerPrivate)
48 : m_playerPrivate(playerPrivate)
49 , m_duration(MediaTime::invalidTime())
50{
51 ASSERT(WTF::isMainThread());
52}
53
54MediaSourceClientGStreamerMSE::~MediaSourceClientGStreamerMSE()
55{
56 ASSERT(WTF::isMainThread());
57}
58
59MediaSourcePrivate::AddStatus MediaSourceClientGStreamerMSE::addSourceBuffer(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate, const ContentType&)
60{
61 ASSERT(WTF::isMainThread());
62
63 ASSERT(m_playerPrivate.m_playbackPipeline);
64 ASSERT(sourceBufferPrivate);
65
66 RefPtr<AppendPipeline> appendPipeline = adoptRef(new AppendPipeline(*this, *sourceBufferPrivate, m_playerPrivate));
67 GST_TRACE("Adding SourceBuffer to AppendPipeline: this=%p sourceBuffer=%p appendPipeline=%p", this, sourceBufferPrivate.get(), appendPipeline.get());
68 m_playerPrivate.m_appendPipelinesMap.add(sourceBufferPrivate, appendPipeline);
69
70 return m_playerPrivate.m_playbackPipeline->addSourceBuffer(sourceBufferPrivate);
71}
72
73const MediaTime& MediaSourceClientGStreamerMSE::duration()
74{
75 ASSERT(WTF::isMainThread());
76
77 return m_duration;
78}
79
80void MediaSourceClientGStreamerMSE::durationChanged(const MediaTime& duration)
81{
82 ASSERT(WTF::isMainThread());
83
84 GST_TRACE("duration: %f", duration.toFloat());
85 if (!duration.isValid() || duration.isPositiveInfinite() || duration.isNegativeInfinite())
86 return;
87
88 m_duration = duration;
89 m_playerPrivate.durationChanged();
90}
91
92void MediaSourceClientGStreamerMSE::abort(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate)
93{
94 ASSERT(WTF::isMainThread());
95
96 GST_DEBUG("aborting");
97
98 RefPtr<AppendPipeline> appendPipeline = m_playerPrivate.m_appendPipelinesMap.get(sourceBufferPrivate);
99
100 ASSERT(appendPipeline);
101
102 appendPipeline->resetParserState();
103}
104
105void MediaSourceClientGStreamerMSE::resetParserState(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate)
106{
107 ASSERT(WTF::isMainThread());
108
109 GST_DEBUG("resetting parser state");
110
111 RefPtr<AppendPipeline> appendPipeline = m_playerPrivate.m_appendPipelinesMap.get(sourceBufferPrivate);
112
113 ASSERT(appendPipeline);
114
115 appendPipeline->resetParserState();
116}
117
118void MediaSourceClientGStreamerMSE::append(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate, Vector<unsigned char>&& data)
119{
120 ASSERT(WTF::isMainThread());
121
122 GST_DEBUG("Appending %zu bytes", data.size());
123
124 RefPtr<AppendPipeline> appendPipeline = m_playerPrivate.m_appendPipelinesMap.get(sourceBufferPrivate);
125
126 ASSERT(appendPipeline);
127
128 // Wrap the whole Vector object in case the data is stored in the inlined buffer.
129 auto* bufferData = data.data();
130 auto bufferLength = data.size();
131 GRefPtr<GstBuffer> buffer = adoptGRef(gst_buffer_new_wrapped_full(static_cast<GstMemoryFlags>(0), bufferData, bufferLength, 0, bufferLength, new Vector<unsigned char>(WTFMove(data)),
132 [](gpointer data)
133 {
134 delete static_cast<Vector<unsigned char>*>(data);
135 }));
136
137 appendPipeline->pushNewBuffer(WTFMove(buffer));
138}
139
140void MediaSourceClientGStreamerMSE::markEndOfStream(MediaSourcePrivate::EndOfStreamStatus status)
141{
142 ASSERT(WTF::isMainThread());
143
144 m_playerPrivate.markEndOfStream(status);
145}
146
147void MediaSourceClientGStreamerMSE::removedFromMediaSource(RefPtr<SourceBufferPrivateGStreamer> sourceBufferPrivate)
148{
149 ASSERT(WTF::isMainThread());
150
151 ASSERT(m_playerPrivate.m_playbackPipeline);
152
153 // Remove the AppendPipeline from the map. This should cause its destruction since there should be no alive
154 // references at this point.
155 ASSERT(m_playerPrivate.m_appendPipelinesMap.get(sourceBufferPrivate)->hasOneRef());
156 m_playerPrivate.m_appendPipelinesMap.remove(sourceBufferPrivate);
157
158 m_playerPrivate.m_playbackPipeline->removeSourceBuffer(sourceBufferPrivate);
159}
160
161void MediaSourceClientGStreamerMSE::flush(AtomicString trackId)
162{
163 ASSERT(WTF::isMainThread());
164
165 // This is only for on-the-fly reenqueues after appends. When seeking, the seek will do its own flush.
166 if (!m_playerPrivate.m_seeking)
167 m_playerPrivate.m_playbackPipeline->flush(trackId);
168}
169
170void MediaSourceClientGStreamerMSE::enqueueSample(Ref<MediaSample>&& sample)
171{
172 ASSERT(WTF::isMainThread());
173
174 m_playerPrivate.m_playbackPipeline->enqueueSample(WTFMove(sample));
175}
176
177void MediaSourceClientGStreamerMSE::allSamplesInTrackEnqueued(const AtomicString& trackId)
178{
179 ASSERT(WTF::isMainThread());
180
181 m_playerPrivate.m_playbackPipeline->allSamplesInTrackEnqueued(trackId);
182}
183
184GRefPtr<WebKitMediaSrc> MediaSourceClientGStreamerMSE::webKitMediaSrc()
185{
186 ASSERT(WTF::isMainThread());
187
188 WebKitMediaSrc* source = WEBKIT_MEDIA_SRC(m_playerPrivate.m_source.get());
189
190 ASSERT(WEBKIT_IS_MEDIA_SRC(source));
191
192 return source;
193}
194
195} // namespace WebCore.
196
197#endif // USE(GSTREAMER)
198