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