|
1 # HG changeset patch |
|
2 # Parent 0559be6b60075e1a708ca90e874f922ff200c462 |
|
3 # User Mike Gorse <mgorse@suse.com> |
|
4 |
|
5 Bug 806917 - support GStreamer 1.0 |
|
6 |
|
7 diff --git a/configure.in b/configure.in |
|
8 --- a/configure.in |
|
9 +++ b/configure.in |
|
10 @@ -5758,28 +5758,36 @@ fi |
|
11 |
|
12 AC_SUBST(MOZ_PULSEAUDIO) |
|
13 AC_SUBST(MOZ_PULSEAUDIO_CFLAGS) |
|
14 AC_SUBST(MOZ_PULSEAUDIO_LIBS) |
|
15 |
|
16 dnl ======================================================== |
|
17 dnl = Enable GStreamer |
|
18 dnl ======================================================== |
|
19 -MOZ_ARG_ENABLE_BOOL(gstreamer, |
|
20 -[ --enable-gstreamer Enable GStreamer support], |
|
21 -MOZ_GSTREAMER=1, |
|
22 -MOZ_GSTREAMER=) |
|
23 +MOZ_ARG_ENABLE_STRING(gstreamer, |
|
24 +[ --enable-gstreamer[=1.0] Enable GStreamer support], |
|
25 +[ MOZ_GSTREAMER=1 |
|
26 + # API version, eg 0.10, 1.0 etc |
|
27 + if test -n "$enableval" ]; then |
|
28 + GST_API_VERSION=$enableval |
|
29 + else |
|
30 + GST_API_VERSION=0.10 |
|
31 + fi] |
|
32 +[ MOZ_GSTREAMER=]) |
|
33 |
|
34 if test "$MOZ_GSTREAMER"; then |
|
35 - # API version, eg 0.10, 1.0 etc |
|
36 - GST_API_VERSION=0.10 |
|
37 # core/base release number |
|
38 # depend on >= 0.10.33 as that's when the playbin2 source-setup signal was |
|
39 # introduced |
|
40 - GST_VERSION=0.10.33 |
|
41 + if test "$GST_API_VERSION" = "1.0"; then |
|
42 + GST_VERSION=1.0 |
|
43 + else |
|
44 + GST_VERSION=0.10.33 |
|
45 + fi |
|
46 PKG_CHECK_MODULES(GSTREAMER, |
|
47 gstreamer-$GST_API_VERSION >= $GST_VERSION |
|
48 gstreamer-app-$GST_API_VERSION |
|
49 gstreamer-plugins-base-$GST_API_VERSION) |
|
50 if test -n "$GSTREAMER_LIBS"; then |
|
51 _SAVE_LDFLAGS=$LDFLAGS |
|
52 LDFLAGS="$LDFLAGS $GSTREAMER_LIBS -lgstvideo-$GST_API_VERSION" |
|
53 AC_TRY_LINK(,[return 0;],_HAVE_LIBGSTVIDEO=1,_HAVE_LIBGSTVIDEO=) |
|
54 diff --git a/content/media/gstreamer/GStreamerFormatHelper.cpp b/content/media/gstreamer/GStreamerFormatHelper.cpp |
|
55 --- a/content/media/gstreamer/GStreamerFormatHelper.cpp |
|
56 +++ b/content/media/gstreamer/GStreamerFormatHelper.cpp |
|
57 @@ -141,17 +141,21 @@ bool GStreamerFormatHelper::HaveElements |
|
58 } |
|
59 g_list_free(list); |
|
60 } |
|
61 |
|
62 return true; |
|
63 } |
|
64 |
|
65 GList* GStreamerFormatHelper::GetFactories() { |
|
66 +#if GST_VERSION_MAJOR == 1 |
|
67 + uint32_t cookie = gst_registry_get_feature_list_cookie(gst_registry_get()); |
|
68 +#else |
|
69 uint32_t cookie = gst_default_registry_get_feature_list_cookie (); |
|
70 +#endif |
|
71 if (cookie != mCookie) { |
|
72 g_list_free(mFactories); |
|
73 mFactories = gst_element_factory_list_get_elements |
|
74 (GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_DECODER, |
|
75 GST_RANK_MARGINAL); |
|
76 mCookie = cookie; |
|
77 } |
|
78 |
|
79 diff --git a/content/media/gstreamer/GStreamerReader.cpp b/content/media/gstreamer/GStreamerReader.cpp |
|
80 --- a/content/media/gstreamer/GStreamerReader.cpp |
|
81 +++ b/content/media/gstreamer/GStreamerReader.cpp |
|
82 @@ -69,18 +69,22 @@ GStreamerReader::GStreamerReader(Abstrac |
|
83 MOZ_COUNT_CTOR(GStreamerReader); |
|
84 |
|
85 mSrcCallbacks.need_data = GStreamerReader::NeedDataCb; |
|
86 mSrcCallbacks.enough_data = GStreamerReader::EnoughDataCb; |
|
87 mSrcCallbacks.seek_data = GStreamerReader::SeekDataCb; |
|
88 |
|
89 mSinkCallbacks.eos = GStreamerReader::EosCb; |
|
90 mSinkCallbacks.new_preroll = GStreamerReader::NewPrerollCb; |
|
91 +#if GST_VERSION_MAJOR == 1 |
|
92 + mSinkCallbacks.new_sample = GStreamerReader::NewBufferCb; |
|
93 +#else |
|
94 mSinkCallbacks.new_buffer = GStreamerReader::NewBufferCb; |
|
95 mSinkCallbacks.new_buffer_list = NULL; |
|
96 +#endif |
|
97 |
|
98 gst_segment_init(&mVideoSegment, GST_FORMAT_UNDEFINED); |
|
99 gst_segment_init(&mAudioSegment, GST_FORMAT_UNDEFINED); |
|
100 } |
|
101 |
|
102 GStreamerReader::~GStreamerReader() |
|
103 { |
|
104 MOZ_COUNT_DTOR(GStreamerReader); |
|
105 @@ -120,19 +124,26 @@ nsresult GStreamerReader::Init(MediaDeco |
|
106 mVideoSink = gst_parse_bin_from_description("capsfilter name=filter ! " |
|
107 "appsink name=videosink sync=true max-buffers=1 " |
|
108 "caps=video/x-raw-yuv,format=(fourcc)I420" |
|
109 , TRUE, NULL); |
|
110 mVideoAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mVideoSink), |
|
111 "videosink")); |
|
112 gst_app_sink_set_callbacks(mVideoAppSink, &mSinkCallbacks, |
|
113 (gpointer) this, NULL); |
|
114 - GstPad *sinkpad = gst_element_get_pad(GST_ELEMENT(mVideoAppSink), "sink"); |
|
115 + GstPad *sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink"); |
|
116 +#if GST_VERSION_MAJOR == 1 |
|
117 + // TODO: Figure out whether we need UPSTREAM or DOWNSTREAM, or both |
|
118 + gst_pad_add_probe(sinkpad, |
|
119 + (GstPadProbeType) (GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_UPSTREAM), |
|
120 + &GStreamerReader::EventProbeCb, this, NULL); |
|
121 +#else |
|
122 gst_pad_add_event_probe(sinkpad, |
|
123 G_CALLBACK(&GStreamerReader::EventProbeCb), this); |
|
124 +#endif |
|
125 gst_object_unref(sinkpad); |
|
126 |
|
127 mAudioSink = gst_parse_bin_from_description("capsfilter name=filter ! " |
|
128 #ifdef MOZ_SAMPLE_TYPE_FLOAT32 |
|
129 "appsink name=audiosink sync=true caps=audio/x-raw-float," |
|
130 #ifdef IS_LITTLE_ENDIAN |
|
131 "channels={1,2},rate=44100,width=32,endianness=1234", TRUE, NULL); |
|
132 #else |
|
133 @@ -145,19 +156,25 @@ nsresult GStreamerReader::Init(MediaDeco |
|
134 #else |
|
135 "channels={1,2},rate=48000,width=16,endianness=4321", TRUE, NULL); |
|
136 #endif |
|
137 #endif |
|
138 mAudioAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mAudioSink), |
|
139 "audiosink")); |
|
140 gst_app_sink_set_callbacks(mAudioAppSink, &mSinkCallbacks, |
|
141 (gpointer) this, NULL); |
|
142 - sinkpad = gst_element_get_pad(GST_ELEMENT(mAudioAppSink), "sink"); |
|
143 + sinkpad = gst_element_get_static_pad(GST_ELEMENT(mAudioAppSink), "sink"); |
|
144 +#if GST_VERSION_MAJOR == 1 |
|
145 + gst_pad_add_probe(sinkpad, |
|
146 + (GstPadProbeType) (GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_EVENT_UPSTREAM), |
|
147 + &GStreamerReader::EventProbeCb, this, NULL); |
|
148 +#else |
|
149 gst_pad_add_event_probe(sinkpad, |
|
150 G_CALLBACK(&GStreamerReader::EventProbeCb), this); |
|
151 +#endif |
|
152 gst_object_unref(sinkpad); |
|
153 |
|
154 g_object_set(mPlayBin, "uri", "appsrc://", |
|
155 "video-sink", mVideoSink, |
|
156 "audio-sink", mAudioSink, |
|
157 NULL); |
|
158 |
|
159 g_object_connect(mPlayBin, "signal::source-setup", |
|
160 @@ -231,17 +248,17 @@ nsresult GStreamerReader::ReadMetadata(V |
|
161 filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter"); |
|
162 else if (!(current_flags & GST_PLAY_FLAG_VIDEO)) |
|
163 filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter"); |
|
164 |
|
165 if (filter) { |
|
166 /* Little trick: set the target caps to "skip" so that playbin2 fails to |
|
167 * find a decoder for the stream we want to skip. |
|
168 */ |
|
169 - GstCaps *filterCaps = gst_caps_new_simple ("skip", NULL); |
|
170 + GstCaps *filterCaps = gst_caps_new_simple ("skip", NULL, NULL); |
|
171 g_object_set(filter, "caps", filterCaps, NULL); |
|
172 gst_caps_unref(filterCaps); |
|
173 gst_object_unref(filter); |
|
174 } |
|
175 |
|
176 /* start the pipeline */ |
|
177 gst_element_set_state(mPlayBin, GST_STATE_PAUSED); |
|
178 |
|
179 @@ -284,19 +301,24 @@ nsresult GStreamerReader::ReadMetadata(V |
|
180 gst_element_set_state(mPlayBin, GST_STATE_NULL); |
|
181 gst_message_unref(message); |
|
182 return NS_ERROR_FAILURE; |
|
183 } |
|
184 } |
|
185 |
|
186 /* report the duration */ |
|
187 gint64 duration; |
|
188 +#if GST_VERSION_MAJOR == 1 |
|
189 + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), |
|
190 + GST_FORMAT_TIME, &duration)) { |
|
191 +#else |
|
192 GstFormat format = GST_FORMAT_TIME; |
|
193 if (gst_element_query_duration(GST_ELEMENT(mPlayBin), |
|
194 &format, &duration) && format == GST_FORMAT_TIME) { |
|
195 +#endif |
|
196 ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); |
|
197 LOG(PR_LOG_DEBUG, ("returning duration %" GST_TIME_FORMAT, |
|
198 GST_TIME_ARGS (duration))); |
|
199 duration = GST_TIME_AS_USECONDS (duration); |
|
200 mDecoder->SetMediaDuration(duration); |
|
201 } |
|
202 |
|
203 int n_video = 0, n_audio = 0; |
|
204 @@ -365,59 +387,87 @@ bool GStreamerReader::DecodeAudioData() |
|
205 { |
|
206 NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
|
207 |
|
208 if (!WaitForDecodedData(&mAudioSinkBufferCount)) { |
|
209 mAudioQueue.Finish(); |
|
210 return false; |
|
211 } |
|
212 |
|
213 +#if GST_VERSION_MAJOR == 1 |
|
214 + GstSample *sample = gst_app_sink_pull_sample(mAudioAppSink); |
|
215 + GstBuffer *buffer = gst_sample_get_buffer(sample); |
|
216 +#else |
|
217 GstBuffer *buffer = gst_app_sink_pull_buffer(mAudioAppSink); |
|
218 +#endif |
|
219 int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); |
|
220 timestamp = gst_segment_to_stream_time(&mAudioSegment, |
|
221 GST_FORMAT_TIME, timestamp); |
|
222 timestamp = GST_TIME_AS_USECONDS(timestamp); |
|
223 int64_t duration = 0; |
|
224 if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer))) |
|
225 duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer)); |
|
226 |
|
227 int64_t offset = GST_BUFFER_OFFSET(buffer); |
|
228 +#if GST_VERSION_MAJOR == 1 |
|
229 + GstMapInfo info; |
|
230 + gst_buffer_map(buffer, &info, GST_MAP_READ); |
|
231 + unsigned int size = info.size; |
|
232 +#else |
|
233 unsigned int size = GST_BUFFER_SIZE(buffer); |
|
234 +#endif |
|
235 int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudioChannels; |
|
236 ssize_t outSize = static_cast<size_t>(size / sizeof(AudioDataValue)); |
|
237 nsAutoArrayPtr<AudioDataValue> data(new AudioDataValue[outSize]); |
|
238 +#if GST_VERSION_MAJOR == 1 |
|
239 + memcpy(data, info.data, info.size); |
|
240 + gst_buffer_unmap(buffer, &info); |
|
241 +#else |
|
242 memcpy(data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); |
|
243 +#endif |
|
244 AudioData *audio = new AudioData(offset, timestamp, duration, |
|
245 frames, data.forget(), mInfo.mAudioChannels); |
|
246 |
|
247 mAudioQueue.Push(audio); |
|
248 gst_buffer_unref(buffer); |
|
249 |
|
250 return true; |
|
251 } |
|
252 |
|
253 bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, |
|
254 int64_t aTimeThreshold) |
|
255 { |
|
256 NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); |
|
257 |
|
258 +#if GST_VERSION_MAJOR == 1 |
|
259 + GstSample *sample = NULL; |
|
260 +#endif |
|
261 GstBuffer *buffer = NULL; |
|
262 int64_t timestamp, nextTimestamp; |
|
263 while (true) |
|
264 { |
|
265 if (!WaitForDecodedData(&mVideoSinkBufferCount)) { |
|
266 mVideoQueue.Finish(); |
|
267 break; |
|
268 } |
|
269 mDecoder->NotifyDecodedFrames(0, 1); |
|
270 |
|
271 +#if GST_VERSION_MAJOR == 1 |
|
272 + sample = gst_app_sink_pull_sample(mVideoAppSink); |
|
273 + buffer = gst_sample_get_buffer(sample); |
|
274 +#else |
|
275 buffer = gst_app_sink_pull_buffer(mVideoAppSink); |
|
276 +#endif |
|
277 bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT); |
|
278 if ((aKeyFrameSkip && !isKeyframe)) { |
|
279 +#if GST_VERSION_MAJOR == 1 |
|
280 + gst_sample_unref(sample); |
|
281 +#else |
|
282 gst_buffer_unref(buffer); |
|
283 +#endif |
|
284 buffer = NULL; |
|
285 continue; |
|
286 } |
|
287 |
|
288 timestamp = GST_BUFFER_TIMESTAMP(buffer); |
|
289 { |
|
290 ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); |
|
291 timestamp = gst_segment_to_stream_time(&mVideoSegment, |
|
292 @@ -431,62 +481,90 @@ bool GStreamerReader::DecodeVideoFrame(b |
|
293 else if (fpsNum && fpsDen) |
|
294 /* add 1-frame duration */ |
|
295 nextTimestamp += gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen); |
|
296 |
|
297 if (timestamp < aTimeThreshold) { |
|
298 LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT |
|
299 " threshold %" GST_TIME_FORMAT, |
|
300 GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold))); |
|
301 +#if GST_VERSION_MAJOR == 1 |
|
302 + gst_sample_unref(sample); |
|
303 +#else |
|
304 gst_buffer_unref(buffer); |
|
305 +#endif |
|
306 buffer = NULL; |
|
307 continue; |
|
308 } |
|
309 |
|
310 break; |
|
311 } |
|
312 |
|
313 if (buffer == NULL) |
|
314 /* no more frames */ |
|
315 return false; |
|
316 |
|
317 +#if GST_VERSION_MAJOR == 1 |
|
318 + GstMapInfo info; |
|
319 + gst_buffer_map(buffer, &info, GST_MAP_READ); |
|
320 + guint8 *data = info.data; |
|
321 +#else |
|
322 guint8 *data = GST_BUFFER_DATA(buffer); |
|
323 +#endif |
|
324 |
|
325 int width = mPicture.width; |
|
326 int height = mPicture.height; |
|
327 GstVideoFormat format = mFormat; |
|
328 |
|
329 VideoData::YCbCrBuffer b; |
|
330 +#if GST_VERSION_MAJOR == 1 |
|
331 + GstVideoInfo *video_info; |
|
332 + gst_video_info_set_format(video_info, format, width, height); |
|
333 + for(int i = 0; i < 3; i++) { |
|
334 + b.mPlanes[i].mData = data + GST_VIDEO_INFO_COMP_OFFSET(video_info, i); |
|
335 + b.mPlanes[i].mStride = GST_VIDEO_INFO_COMP_STRIDE(video_info, i); |
|
336 + b.mPlanes[i].mHeight = GST_VIDEO_INFO_COMP_HEIGHT(video_info, i); |
|
337 + b.mPlanes[i].mWidth = GST_VIDEO_INFO_COMP_WIDTH(video_info, i); |
|
338 + b.mPlanes[i].mOffset = 0; |
|
339 + b.mPlanes[i].mSkip = 0; |
|
340 + } |
|
341 +#else |
|
342 for(int i = 0; i < 3; i++) { |
|
343 b.mPlanes[i].mData = data + gst_video_format_get_component_offset(format, i, |
|
344 width, height); |
|
345 b.mPlanes[i].mStride = gst_video_format_get_row_stride(format, i, width); |
|
346 b.mPlanes[i].mHeight = gst_video_format_get_component_height(format, |
|
347 i, height); |
|
348 b.mPlanes[i].mWidth = gst_video_format_get_component_width(format, |
|
349 i, width); |
|
350 b.mPlanes[i].mOffset = 0; |
|
351 b.mPlanes[i].mSkip = 0; |
|
352 } |
|
353 +#endif |
|
354 |
|
355 bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, |
|
356 GST_BUFFER_FLAG_DELTA_UNIT); |
|
357 /* XXX ? */ |
|
358 int64_t offset = 0; |
|
359 VideoData *video = VideoData::Create(mInfo, |
|
360 mDecoder->GetImageContainer(), |
|
361 offset, |
|
362 timestamp, |
|
363 nextTimestamp, |
|
364 b, |
|
365 isKeyframe, |
|
366 -1, |
|
367 mPicture); |
|
368 mVideoQueue.Push(video); |
|
369 +#if GST_VERSION_MAJOR == 1 |
|
370 + gst_buffer_unmap(buffer, &info); |
|
371 + gst_sample_unref(sample); |
|
372 +#else |
|
373 gst_buffer_unref(buffer); |
|
374 +#endif |
|
375 |
|
376 return true; |
|
377 } |
|
378 |
|
379 nsresult GStreamerReader::Seek(int64_t aTarget, |
|
380 int64_t aStartTime, |
|
381 int64_t aEndTime, |
|
382 int64_t aCurrentTime) |
|
383 @@ -509,52 +587,62 @@ nsresult GStreamerReader::Seek(int64_t a |
|
384 |
|
385 nsresult GStreamerReader::GetBuffered(nsTimeRanges* aBuffered, |
|
386 int64_t aStartTime) |
|
387 { |
|
388 if (!mInfo.mHasVideo && !mInfo.mHasAudio) { |
|
389 return NS_OK; |
|
390 } |
|
391 |
|
392 - GstFormat format = GST_FORMAT_TIME; |
|
393 +#if GST_VERSION_MAJOR == 0 |
|
394 + GstFormat format = GST_FORMAT_TIME; |
|
395 +#endif |
|
396 + |
|
397 MediaResource* resource = mDecoder->GetResource(); |
|
398 gint64 resourceLength = resource->GetLength(); |
|
399 nsTArray<MediaByteRange> ranges; |
|
400 resource->GetCachedRanges(ranges); |
|
401 |
|
402 if (mDecoder->OnStateMachineThread()) |
|
403 /* Report the position from here while buffering as we can't report it from |
|
404 * the gstreamer threads that are actually reading from the resource |
|
405 */ |
|
406 NotifyBytesConsumed(); |
|
407 |
|
408 if (resource->IsDataCachedToEndOfResource(0)) { |
|
409 /* fast path for local or completely cached files */ |
|
410 gint64 duration = 0; |
|
411 - GstFormat format = GST_FORMAT_TIME; |
|
412 - |
|
413 duration = QueryDuration(); |
|
414 double end = (double) duration / GST_MSECOND; |
|
415 LOG(PR_LOG_DEBUG, ("complete range [0, %f] for [0, %li]", |
|
416 end, resourceLength)); |
|
417 aBuffered->Add(0, end); |
|
418 return NS_OK; |
|
419 } |
|
420 |
|
421 for(uint32_t index = 0; index < ranges.Length(); index++) { |
|
422 int64_t startOffset = ranges[index].mStart; |
|
423 int64_t endOffset = ranges[index].mEnd; |
|
424 gint64 startTime, endTime; |
|
425 |
|
426 +#if GST_VERSION_MAJOR == 1 |
|
427 + if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, |
|
428 + startOffset, GST_FORMAT_TIME, &startTime)) |
|
429 + continue; |
|
430 + if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, |
|
431 + endOffset, GST_FORMAT_TIME, &endTime)) |
|
432 + continue; |
|
433 +#else |
|
434 if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, |
|
435 startOffset, &format, &startTime) || format != GST_FORMAT_TIME) |
|
436 continue; |
|
437 if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, |
|
438 endOffset, &format, &endTime) || format != GST_FORMAT_TIME) |
|
439 continue; |
|
440 +#endif |
|
441 |
|
442 double start = start = (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND; |
|
443 double end = (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND; |
|
444 LOG(PR_LOG_DEBUG, ("adding range [%f, %f] for [%li %li] size %li", |
|
445 start, end, startOffset, endOffset, resourceLength)); |
|
446 aBuffered->Add(start, end); |
|
447 } |
|
448 |
|
449 @@ -563,48 +651,64 @@ nsresult GStreamerReader::GetBuffered(ns |
|
450 |
|
451 void GStreamerReader::ReadAndPushData(guint aLength) |
|
452 { |
|
453 MediaResource* resource = mDecoder->GetResource(); |
|
454 NS_ASSERTION(resource, "Decoder has no media resource"); |
|
455 nsresult rv = NS_OK; |
|
456 |
|
457 GstBuffer *buffer = gst_buffer_new_and_alloc(aLength); |
|
458 +#if GST_VERSION_MAJOR == 1 |
|
459 + GstMapInfo info; |
|
460 + gst_buffer_map(buffer, &info, GST_MAP_WRITE); |
|
461 + guint8 *data = info.data; |
|
462 +#else |
|
463 guint8 *data = GST_BUFFER_DATA(buffer); |
|
464 +#endif |
|
465 uint32_t size = 0, bytesRead = 0; |
|
466 while(bytesRead < aLength) { |
|
467 rv = resource->Read(reinterpret_cast<char*>(data + bytesRead), |
|
468 aLength - bytesRead, &size); |
|
469 if (NS_FAILED(rv) || size == 0) |
|
470 break; |
|
471 |
|
472 bytesRead += size; |
|
473 } |
|
474 |
|
475 +#if GST_VERSION_MAJOR == 1 |
|
476 + info.size = bytesRead; |
|
477 + gst_buffer_unmap(buffer, &info); |
|
478 +#else |
|
479 GST_BUFFER_SIZE(buffer) = bytesRead; |
|
480 +#endif |
|
481 mByteOffset += bytesRead; |
|
482 |
|
483 GstFlowReturn ret = gst_app_src_push_buffer(mSource, gst_buffer_ref(buffer)); |
|
484 if (ret != GST_FLOW_OK) |
|
485 LOG(PR_LOG_ERROR, ("ReadAndPushData push ret %s", gst_flow_get_name(ret))); |
|
486 |
|
487 - if (GST_BUFFER_SIZE (buffer) < aLength) |
|
488 + if (bytesRead < aLength) |
|
489 /* If we read less than what we wanted, we reached the end */ |
|
490 gst_app_src_end_of_stream(mSource); |
|
491 |
|
492 gst_buffer_unref(buffer); |
|
493 } |
|
494 |
|
495 int64_t GStreamerReader::QueryDuration() |
|
496 { |
|
497 gint64 duration = 0; |
|
498 GstFormat format = GST_FORMAT_TIME; |
|
499 |
|
500 +#if GST_VERSION_MAJOR == 1 |
|
501 + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), |
|
502 + format, &duration)) { |
|
503 +#else |
|
504 if (gst_element_query_duration(GST_ELEMENT(mPlayBin), |
|
505 &format, &duration)) { |
|
506 +#endif |
|
507 if (format == GST_FORMAT_TIME) { |
|
508 LOG(PR_LOG_DEBUG, ("pipeline duration %" GST_TIME_FORMAT, |
|
509 GST_TIME_ARGS (duration))); |
|
510 duration = GST_TIME_AS_USECONDS (duration); |
|
511 } |
|
512 } |
|
513 |
|
514 /*if (mDecoder->mDuration != -1 && |
|
515 @@ -668,60 +772,95 @@ gboolean GStreamerReader::SeekData(GstAp |
|
516 if (NS_SUCCEEDED(rv)) |
|
517 mByteOffset = mLastReportedByteOffset = aOffset; |
|
518 else |
|
519 LOG(PR_LOG_ERROR, ("seek at %lu failed", aOffset)); |
|
520 |
|
521 return NS_SUCCEEDED(rv); |
|
522 } |
|
523 |
|
524 +#if GST_VERSION_MAJOR == 1 |
|
525 +GstPadProbeReturn GStreamerReader::EventProbeCb(GstPad *aPad, |
|
526 + GstPadProbeInfo *aInfo, |
|
527 + gpointer aUserData) |
|
528 +{ |
|
529 + GStreamerReader *reader = (GStreamerReader *) aUserData; |
|
530 + GstEvent *aEvent = (GstEvent *)aInfo->data; |
|
531 + return reader->EventProbe(aPad, aEvent); |
|
532 +} |
|
533 +#else |
|
534 gboolean GStreamerReader::EventProbeCb(GstPad *aPad, |
|
535 GstEvent *aEvent, |
|
536 gpointer aUserData) |
|
537 { |
|
538 GStreamerReader *reader = (GStreamerReader *) aUserData; |
|
539 return reader->EventProbe(aPad, aEvent); |
|
540 } |
|
541 +#endif |
|
542 |
|
543 +#if GST_VERSION_MAJOR == 1 |
|
544 +GstPadProbeReturn GStreamerReader::EventProbe(GstPad *aPad, GstEvent *aEvent) |
|
545 +#else |
|
546 gboolean GStreamerReader::EventProbe(GstPad *aPad, GstEvent *aEvent) |
|
547 +#endif |
|
548 { |
|
549 GstElement *parent = GST_ELEMENT(gst_pad_get_parent(aPad)); |
|
550 switch(GST_EVENT_TYPE(aEvent)) { |
|
551 +#if GST_VERSION_MAJOR == 1 |
|
552 + case GST_EVENT_SEGMENT: |
|
553 +#else |
|
554 case GST_EVENT_NEWSEGMENT: |
|
555 +#endif |
|
556 { |
|
557 +#if GST_VERSION_MAJOR == 1 |
|
558 + const GstSegment *newSegment; |
|
559 +#else |
|
560 gboolean update; |
|
561 gdouble rate; |
|
562 GstFormat format; |
|
563 gint64 start, stop, position; |
|
564 +#endif |
|
565 GstSegment *segment; |
|
566 |
|
567 /* Store the segments so we can convert timestamps to stream time, which |
|
568 * is what the upper layers sync on. |
|
569 */ |
|
570 ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); |
|
571 +#if GST_VERSION_MAJOR == 1 |
|
572 + gst_event_parse_segment(aEvent, &newSegment); |
|
573 +#else |
|
574 gst_event_parse_new_segment(aEvent, &update, &rate, &format, |
|
575 &start, &stop, &position); |
|
576 +#endif |
|
577 if (parent == GST_ELEMENT(mVideoAppSink)) |
|
578 segment = &mVideoSegment; |
|
579 else |
|
580 segment = &mAudioSegment; |
|
581 +#if GST_VERSION_MAJOR == 1 |
|
582 + gst_segment_copy_into (newSegment, segment); |
|
583 +#else |
|
584 gst_segment_set_newsegment(segment, update, rate, format, |
|
585 start, stop, position); |
|
586 +#endif |
|
587 break; |
|
588 } |
|
589 case GST_EVENT_FLUSH_STOP: |
|
590 /* Reset on seeks */ |
|
591 ResetDecode(); |
|
592 break; |
|
593 default: |
|
594 break; |
|
595 } |
|
596 gst_object_unref(parent); |
|
597 |
|
598 +#if GST_VERSION_MAJOR == 1 |
|
599 + return GST_PAD_PROBE_OK; |
|
600 +#else |
|
601 return TRUE; |
|
602 +#endif |
|
603 } |
|
604 |
|
605 GstFlowReturn GStreamerReader::NewPrerollCb(GstAppSink *aSink, |
|
606 gpointer aUserData) |
|
607 { |
|
608 GStreamerReader *reader = (GStreamerReader *) aUserData; |
|
609 |
|
610 if (aSink == reader->mVideoAppSink) |
|
611 @@ -730,18 +869,22 @@ GstFlowReturn GStreamerReader::NewPrerol |
|
612 reader->AudioPreroll(); |
|
613 return GST_FLOW_OK; |
|
614 } |
|
615 |
|
616 void GStreamerReader::AudioPreroll() |
|
617 { |
|
618 /* The first audio buffer has reached the audio sink. Get rate and channels */ |
|
619 LOG(PR_LOG_DEBUG, ("Audio preroll")); |
|
620 - GstPad *sinkpad = gst_element_get_pad(GST_ELEMENT(mAudioAppSink), "sink"); |
|
621 + GstPad *sinkpad = gst_element_get_static_pad(GST_ELEMENT(mAudioAppSink), "sink"); |
|
622 +#if GST_VERSION_MAJOR == 1 |
|
623 + GstCaps *caps = gst_pad_get_current_caps(sinkpad); |
|
624 +#else |
|
625 GstCaps *caps = gst_pad_get_negotiated_caps(sinkpad); |
|
626 +#endif |
|
627 GstStructure *s = gst_caps_get_structure(caps, 0); |
|
628 mInfo.mAudioRate = mInfo.mAudioChannels = 0; |
|
629 gst_structure_get_int(s, "rate", (gint *) &mInfo.mAudioRate); |
|
630 gst_structure_get_int(s, "channels", (gint *) &mInfo.mAudioChannels); |
|
631 NS_ASSERTION(mInfo.mAudioRate != 0, ("audio rate is zero")); |
|
632 NS_ASSERTION(mInfo.mAudioChannels != 0, ("audio channels is zero")); |
|
633 NS_ASSERTION(mInfo.mAudioChannels > 0 && mInfo.mAudioChannels <= MAX_CHANNELS, |
|
634 "invalid audio channels number"); |
|
635 @@ -749,19 +892,29 @@ void GStreamerReader::AudioPreroll() |
|
636 gst_caps_unref(caps); |
|
637 gst_object_unref(sinkpad); |
|
638 } |
|
639 |
|
640 void GStreamerReader::VideoPreroll() |
|
641 { |
|
642 /* The first video buffer has reached the video sink. Get width and height */ |
|
643 LOG(PR_LOG_DEBUG, ("Video preroll")); |
|
644 - GstPad *sinkpad = gst_element_get_pad(GST_ELEMENT(mVideoAppSink), "sink"); |
|
645 + GstPad *sinkpad = gst_element_get_static_pad(GST_ELEMENT(mVideoAppSink), "sink"); |
|
646 +#if GST_VERSION_MAJOR == 1 |
|
647 + GstCaps *caps = gst_pad_get_current_caps(sinkpad); |
|
648 + GstVideoInfo info; |
|
649 + memset (&info, 0, sizeof (info)); |
|
650 + gst_video_info_from_caps(&info, caps); |
|
651 + mFormat = info.finfo->format; |
|
652 + mPicture.width = info.width; |
|
653 + mPicture.height = info.height; |
|
654 +#else |
|
655 GstCaps *caps = gst_pad_get_negotiated_caps(sinkpad); |
|
656 gst_video_format_parse_caps(caps, &mFormat, &mPicture.width, &mPicture.height); |
|
657 +#endif |
|
658 GstStructure *structure = gst_caps_get_structure(caps, 0); |
|
659 gst_structure_get_fraction(structure, "framerate", &fpsNum, &fpsDen); |
|
660 NS_ASSERTION(mPicture.width && mPicture.height, "invalid video resolution"); |
|
661 mInfo.mDisplay = nsIntSize(mPicture.width, mPicture.height); |
|
662 mInfo.mHasVideo = true; |
|
663 gst_caps_unref(caps); |
|
664 gst_object_unref(sinkpad); |
|
665 } |
|
666 diff --git a/content/media/gstreamer/GStreamerReader.h b/content/media/gstreamer/GStreamerReader.h |
|
667 --- a/content/media/gstreamer/GStreamerReader.h |
|
668 +++ b/content/media/gstreamer/GStreamerReader.h |
|
669 @@ -71,18 +71,23 @@ private: |
|
670 |
|
671 /* Called when a seek is issued on the pipeline */ |
|
672 static gboolean SeekDataCb(GstAppSrc *aSrc, |
|
673 guint64 aOffset, |
|
674 gpointer aUserData); |
|
675 gboolean SeekData(GstAppSrc *aSrc, guint64 aOffset); |
|
676 |
|
677 /* Called when events reach the sinks. See inline comments */ |
|
678 +#if GST_VERSION_MAJOR == 1 |
|
679 + static GstPadProbeReturn EventProbeCb(GstPad *aPad, GstPadProbeInfo *aInfo, gpointer aUserData); |
|
680 + GstPadProbeReturn EventProbe(GstPad *aPad, GstEvent *aEvent); |
|
681 +#else |
|
682 static gboolean EventProbeCb(GstPad *aPad, GstEvent *aEvent, gpointer aUserData); |
|
683 gboolean EventProbe(GstPad *aPad, GstEvent *aEvent); |
|
684 +#endif |
|
685 |
|
686 /* Called when the pipeline is prerolled, that is when at start or after a |
|
687 * seek, the first audio and video buffers are queued in the sinks. |
|
688 */ |
|
689 static GstFlowReturn NewPrerollCb(GstAppSink *aSink, gpointer aUserData); |
|
690 void VideoPreroll(); |
|
691 void AudioPreroll(); |
|
692 |