head 1.3; access; symbols pkgsrc-2014Q1:1.1.0.2 pkgsrc-2014Q1-base:1.1; locks; strict; comment @// @; 1.3 date 2014.06.11.00.40.59; author ryoon; state dead; branches; next 1.2; commitid QTw894DEf2Let2Ex; 1.2 date 2014.04.30.15.07.18; author ryoon; state Exp; branches; next 1.1; commitid BxErbE5mH8g3CIyx; 1.1 date 2014.03.20.21.02.00; author ryoon; state Exp; branches; next ; commitid 7yTA4yPlY6RyTttx; desc @@ 1.3 log @Update to 30.0 * debug build is broken Changelog: New Sidebars button in browser chrome enables faster access to social, bookmark, & history sidebars New Mac OS X command-E sets find term to selected text New Support for GStreamer 1.0 Changed Disallow calling WebIDL constructors as functions on the web Developer With the exception of those bundled inside an extension or ones that are whitelisted, plugins will no longer be activated by default (see blog post) Developer Fixes to box-shadow and other visual overflow (see bug 480888) Developer Mute and volume available per window when using WebAudio Developer background-blend-mode enabled by default Developer Use of line-height allowed for Developer ES6 array and generator comprehensions implemented (read docs for more details) Developer Error stack now contains column number Developer Support for alpha option in canvas context options (feature description) Fixed Ignore autocomplete="off" when offering to save passwords via the password manager (see 956906) Fixed TypedArrays don't support new named properties (see 695438) Fixed Various security fixes Fixed in Firefox 30 MFSA 2014-54 Buffer overflow in Gamepad API MFSA 2014-53 Buffer overflow in Web Audio Speex resampler MFSA 2014-52 Use-after-free with SMIL Animation Controller MFSA 2014-51 Use-after-free in Event Listener Manager MFSA 2014-50 Clickjacking through cursor invisability after Flash interaction MFSA 2014-49 Use-after-free and out of bounds issues found using Address Sanitizer MFSA 2014-48 Miscellaneous memory safety hazards (rv:30.0 / rv:24.6) @ text @$NetBSD: patch-content_media_gstreamer_GStreamerReader.cpp,v 1.2 2014/04/30 15:07:18 ryoon Exp $ --- content/media/gstreamer/GStreamerReader.cpp.orig 2014-04-18 02:02:42.000000000 +0000 +++ content/media/gstreamer/GStreamerReader.cpp @@@@ -10,8 +10,10 @@@@ #include "AbstractMediaDecoder.h" #include "MediaResource.h" #include "GStreamerReader.h" +#if GST_VERSION_MAJOR >= 1 +#include "GStreamerAllocator.h" +#endif #include "GStreamerFormatHelper.h" -#include "GStreamerMozVideoBuffer.h" #include "VideoUtils.h" #include "mozilla/dom/TimeRanges.h" #include "mozilla/Preferences.h" @@@@ -33,14 +35,16 @@@@ extern PRLogModuleInfo* gMediaDecoderLog #define LOG(type, msg, ...) #endif -extern bool -IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane, - const VideoData::YCbCrBuffer::Plane& aCbPlane, - const VideoData::YCbCrBuffer::Plane& aCrPlane); - +#if DEBUG static const unsigned int MAX_CHANNELS = 4; -// Let the demuxer work in pull mode for short files -static const int SHORT_FILE_SIZE = 1024 * 1024; +#endif +// Let the demuxer work in pull mode for short files. This used to be a micro +// optimization to have more accurate durations for ogg files in mochitests. +// Since as of today we aren't using gstreamer to demux ogg, and having demuxers +// work in pull mode over http makes them slower (since they really assume +// near-zero latency in pull mode) set the constant to 0 for now, which +// effectively disables it. +static const int SHORT_FILE_SIZE = 0; // The default resource->Read() size when working in push mode static const int DEFAULT_SOURCE_READ_SIZE = 50 * 1024; @@@@ -62,6 +66,10 @@@@ GStreamerReader::GStreamerReader(Abstrac : MediaDecoderReader(aDecoder), mMP3FrameParser(aDecoder->GetResource()->GetLength()), mUseParserDuration(false), +#if GST_VERSION_MAJOR >= 1 + mAllocator(nullptr), + mBufferPool(nullptr), +#endif mPlayBin(nullptr), mBus(nullptr), mSource(nullptr), @@@@ -74,6 +82,9 @@@@ GStreamerReader::GStreamerReader(Abstrac mAudioSinkBufferCount(0), mGstThreadsMonitor("media.gst.threads"), mReachedEos(false), +#if GST_VERSION_MAJOR >= 1 + mConfigureAlignment(true), +#endif fpsNum(0), fpsDen(0) { @@@@ -85,8 +96,12 @@@@ GStreamerReader::GStreamerReader(Abstrac mSinkCallbacks.eos = GStreamerReader::EosCb; mSinkCallbacks.new_preroll = GStreamerReader::NewPrerollCb; +#if GST_VERSION_MAJOR >= 1 + mSinkCallbacks.new_sample = GStreamerReader::NewBufferCb; +#else mSinkCallbacks.new_buffer = GStreamerReader::NewBufferCb; mSinkCallbacks.new_buffer_list = nullptr; +#endif gst_segment_init(&mVideoSegment, GST_FORMAT_UNDEFINED); gst_segment_init(&mAudioSegment, GST_FORMAT_UNDEFINED); @@@@ -110,65 +125,59 @@@@ GStreamerReader::~GStreamerReader() mAudioAppSink = nullptr; gst_object_unref(mBus); mBus = nullptr; +#if GST_VERSION_MAJOR >= 1 + g_object_unref(mAllocator); + g_object_unref(mBufferPool); +#endif } } nsresult GStreamerReader::Init(MediaDecoderReader* aCloneDonor) { - GError* error = nullptr; - if (!gst_init_check(0, 0, &error)) { - LOG(PR_LOG_ERROR, "gst initialization failed: %s", error->message); - g_error_free(error); - return NS_ERROR_FAILURE; - } + GStreamerFormatHelper::Instance(); + +#if GST_VERSION_MAJOR >= 1 + mAllocator = static_cast(g_object_new(GST_TYPE_MOZ_GFX_MEMORY_ALLOCATOR, nullptr)); + moz_gfx_memory_allocator_set_reader(mAllocator, this); + + mBufferPool = static_cast(g_object_new(GST_TYPE_MOZ_GFX_BUFFER_POOL, nullptr)); +#endif +#if GST_VERSION_MAJOR >= 1 + mPlayBin = gst_element_factory_make("playbin", nullptr); +#else mPlayBin = gst_element_factory_make("playbin2", nullptr); +#endif if (!mPlayBin) { - LOG(PR_LOG_ERROR, "couldn't create playbin2"); + LOG(PR_LOG_ERROR, "couldn't create playbin"); return NS_ERROR_FAILURE; } g_object_set(mPlayBin, "buffer-size", 0, nullptr); mBus = gst_pipeline_get_bus(GST_PIPELINE(mPlayBin)); mVideoSink = gst_parse_bin_from_description("capsfilter name=filter ! " - "appsink name=videosink sync=true max-buffers=1 " + "appsink name=videosink sync=false max-buffers=1 " +#if GST_VERSION_MAJOR >= 1 + "caps=video/x-raw,format=I420" +#else "caps=video/x-raw-yuv,format=(fourcc)I420" +#endif , TRUE, nullptr); mVideoAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mVideoSink), "videosink")); - gst_app_sink_set_callbacks(mVideoAppSink, &mSinkCallbacks, - (gpointer) this, nullptr); - GstPad* sinkpad = gst_element_get_pad(GST_ELEMENT(mVideoAppSink), "sink"); - gst_pad_add_event_probe(sinkpad, - G_CALLBACK(&GStreamerReader::EventProbeCb), this); - gst_object_unref(sinkpad); - gst_pad_set_bufferalloc_function(sinkpad, GStreamerReader::AllocateVideoBufferCb); - gst_pad_set_element_private(sinkpad, this); - mAudioSink = gst_parse_bin_from_description("capsfilter name=filter ! " -#ifdef MOZ_SAMPLE_TYPE_FLOAT32 - "appsink name=audiosink max-buffers=2 sync=false caps=audio/x-raw-float," -#ifdef IS_LITTLE_ENDIAN - "channels={1,2},width=32,endianness=1234", TRUE, nullptr); -#else - "channels={1,2},width=32,endianness=4321", TRUE, nullptr); -#endif -#else - "appsink name=audiosink max-buffers=2 sync=false caps=audio/x-raw-int," -#ifdef IS_LITTLE_ENDIAN - "channels={1,2},width=16,endianness=1234", TRUE, nullptr); -#else - "channels={1,2},width=16,endianness=4321", TRUE, nullptr); -#endif -#endif + "appsink name=audiosink sync=false max-buffers=1", TRUE, nullptr); mAudioAppSink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(mAudioSink), "audiosink")); + GstCaps* caps = BuildAudioSinkCaps(); + g_object_set(mAudioAppSink, "caps", caps, nullptr); + gst_caps_unref(caps); + + gst_app_sink_set_callbacks(mVideoAppSink, &mSinkCallbacks, + (gpointer) this, nullptr); gst_app_sink_set_callbacks(mAudioAppSink, &mSinkCallbacks, (gpointer) this, nullptr); - sinkpad = gst_element_get_pad(GST_ELEMENT(mAudioAppSink), "sink"); - gst_pad_add_event_probe(sinkpad, - G_CALLBACK(&GStreamerReader::EventProbeCb), this); - gst_object_unref(sinkpad); + InstallPadCallbacks(); g_object_set(mPlayBin, "uri", "appsrc://", "video-sink", mVideoSink, @@@@ -331,13 +340,12 @@@@ nsresult GStreamerReader::ReadMetadata(M /* Little trick: set the target caps to "skip" so that playbin2 fails to * find a decoder for the stream we want to skip. */ - GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr); + GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr, nullptr); g_object_set(filter, "caps", filterCaps, nullptr); gst_caps_unref(filterCaps); gst_object_unref(filter); } - /* start the pipeline */ LOG(PR_LOG_DEBUG, "starting metadata pipeline"); gst_element_set_state(mPlayBin, GST_STATE_PAUSED); @@@@ -358,6 +366,7 @@@@ nsresult GStreamerReader::ReadMetadata(M gst_message_unref(message); ret = NS_ERROR_FAILURE; } else { + LOG(PR_LOG_DEBUG, "read metadata pipeline prerolled"); gst_message_unref(message); ret = NS_OK; break; @@@@ -371,23 +380,8 @@@@ nsresult GStreamerReader::ReadMetadata(M /* we couldn't get this to play */ return ret; - /* FIXME: workaround for a bug in matroskademux. This seek makes matroskademux - * parse the index */ - if (gst_element_seek_simple(mPlayBin, GST_FORMAT_TIME, - GST_SEEK_FLAG_FLUSH, 0)) { - /* after a seek we need to wait again for ASYNC_DONE */ - message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, - (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR)); - if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { - gst_element_set_state(mPlayBin, GST_STATE_NULL); - gst_message_unref(message); - return NS_ERROR_FAILURE; - } - } - /* report the duration */ gint64 duration; - GstFormat format = GST_FORMAT_TIME; if (isMP3 && mMP3FrameParser.IsMP3()) { // The MP3FrameParser has reported a duration; use that over the gstreamer @@@@ -396,17 +390,25 @@@@ nsresult GStreamerReader::ReadMetadata(M mUseParserDuration = true; mLastParserDuration = mMP3FrameParser.GetDuration(); mDecoder->SetMediaDuration(mLastParserDuration); - - } else if (gst_element_query_duration(GST_ELEMENT(mPlayBin), - &format, &duration) && format == GST_FORMAT_TIME) { - // Otherwise use the gstreamer duration. - ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - LOG(PR_LOG_DEBUG, "returning duration %" GST_TIME_FORMAT, GST_TIME_ARGS(duration)); - duration = GST_TIME_AS_USECONDS (duration); - mDecoder->SetMediaDuration(duration); - } else { - mDecoder->SetMediaSeekable(false); + LOG(PR_LOG_DEBUG, "querying duration"); + // Otherwise use the gstreamer duration. +#if GST_VERSION_MAJOR >= 1 + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), + GST_FORMAT_TIME, &duration)) { +#else + GstFormat format = GST_FORMAT_TIME; + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), + &format, &duration) && format == GST_FORMAT_TIME) { +#endif + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + LOG(PR_LOG_DEBUG, "have duration %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration)); + duration = GST_TIME_AS_USECONDS (duration); + mDecoder->SetMediaDuration(duration); + } else { + mDecoder->SetMediaSeekable(false); + } } int n_video = 0, n_audio = 0; @@@@ -419,7 +421,11 @@@@ nsresult GStreamerReader::ReadMetadata(M *aTags = nullptr; // Watch the pipeline for fatal errors +#if GST_VERSION_MAJOR >= 1 + gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this, nullptr); +#else gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this); +#endif /* set the pipeline to PLAYING so that it starts decoding and queueing data in * the appsinks */ @@@@ -433,19 +439,35 @@@@ nsresult GStreamerReader::CheckSupported bool done = false; bool unsupported = false; - GstIterator *it = gst_bin_iterate_recurse(GST_BIN(mPlayBin)); + GstIterator* it = gst_bin_iterate_recurse(GST_BIN(mPlayBin)); while (!done) { + GstIteratorResult res; GstElement* element; - GstIteratorResult res = gst_iterator_next(it, (void **)&element); + +#if GST_VERSION_MAJOR >= 1 + GValue value = {0,}; + res = gst_iterator_next(it, &value); +#else + res = gst_iterator_next(it, (void **) &element); +#endif switch(res) { case GST_ITERATOR_OK: { +#if GST_VERSION_MAJOR >= 1 + element = GST_ELEMENT (g_value_get_object (&value)); +#endif GstElementFactory* factory = gst_element_get_factory(element); if (factory) { const char* klass = gst_element_factory_get_klass(factory); - GstPad* pad = gst_element_get_pad(element, "sink"); + GstPad* pad = gst_element_get_static_pad(element, "sink"); if (pad) { - GstCaps* caps = gst_pad_get_negotiated_caps(pad); + GstCaps* caps; + +#if GST_VERSION_MAJOR >= 1 + caps = gst_pad_get_current_caps(pad); +#else + caps = gst_pad_get_negotiated_caps(pad); +#endif if (caps) { /* check for demuxers but ignore elements like id3demux */ @@@@ -460,7 +482,11 @@@@ nsresult GStreamerReader::CheckSupported } } +#if GST_VERSION_MAJOR >= 1 + g_value_unset (&value); +#else gst_object_unref(element); +#endif done = unsupported; break; } @@@@ -484,6 +510,8 @@@@ nsresult GStreamerReader::ResetDecode() { nsresult res = NS_OK; + LOG(PR_LOG_DEBUG, "reset decode"); + if (NS_FAILED(MediaDecoderReader::ResetDecode())) { res = NS_ERROR_FAILURE; } @@@@ -494,6 +522,11 @@@@ nsresult GStreamerReader::ResetDecode() mVideoSinkBufferCount = 0; mAudioSinkBufferCount = 0; mReachedEos = false; +#if GST_VERSION_MAJOR >= 1 + mConfigureAlignment = true; +#endif + + LOG(PR_LOG_DEBUG, "reset decode done"); return res; } @@@@ -517,11 +550,11 @@@@ bool GStreamerReader::DecodeAudioData() /* We have nothing decoded so it makes no sense to return to the state machine * as it will call us back immediately, we'll return again and so on, wasting * CPU cycles for no job done. So, block here until there is either video or - * audio data available + * audio data available */ mon.Wait(); if (!mAudioSinkBufferCount) { - /* There is still no audio data available, so either there is video data or + /* There is still no audio data available, so either there is video data or * something else has happened (Eos, etc...). Return to the state machine * to process it. */ @@@@ -533,24 +566,44 @@@@ bool GStreamerReader::DecodeAudioData() } } +#if GST_VERSION_MAJOR >= 1 + GstSample *sample = gst_app_sink_pull_sample(mAudioAppSink); + buffer = gst_buffer_ref(gst_sample_get_buffer(sample)); + gst_sample_unref(sample); +#else buffer = gst_app_sink_pull_buffer(mAudioAppSink); +#endif + mAudioSinkBufferCount--; } int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); timestamp = gst_segment_to_stream_time(&mAudioSegment, GST_FORMAT_TIME, timestamp); + timestamp = GST_TIME_AS_USECONDS(timestamp); + int64_t duration = 0; if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer))) duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer)); int64_t offset = GST_BUFFER_OFFSET(buffer); +#if GST_VERSION_MAJOR >= 1 + GstMapInfo info; + gst_buffer_map(buffer, &info, GST_MAP_READ); + unsigned int size = info.size; +#else unsigned int size = GST_BUFFER_SIZE(buffer); +#endif int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels; ssize_t outSize = static_cast(size / sizeof(AudioDataValue)); nsAutoArrayPtr data(new AudioDataValue[outSize]); +#if GST_VERSION_MAJOR >= 1 + memcpy(data, info.data, info.size); + gst_buffer_unmap(buffer, &info); +#else memcpy(data, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); +#endif AudioData* audio = new AudioData(offset, timestamp, duration, frames, data.forget(), mInfo.mAudio.mChannels); @@@@ -561,7 +614,7 @@@@ bool GStreamerReader::DecodeAudioData() } bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, - int64_t aTimeThreshold) + int64_t aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); @@@@ -580,11 +633,11 @@@@ bool GStreamerReader::DecodeVideoFrame(b /* We have nothing decoded so it makes no sense to return to the state machine * as it will call us back immediately, we'll return again and so on, wasting * CPU cycles for no job done. So, block here until there is either video or - * audio data available + * audio data available */ mon.Wait(); if (!mVideoSinkBufferCount) { - /* There is still no video data available, so either there is audio data or + /* There is still no video data available, so either there is audio data or * something else has happened (Eos, etc...). Return to the state machine * to process it */ @@@@ -598,11 +651,17 @@@@ bool GStreamerReader::DecodeVideoFrame(b mDecoder->NotifyDecodedFrames(0, 1); +#if GST_VERSION_MAJOR >= 1 + GstSample *sample = gst_app_sink_pull_sample(mVideoAppSink); + buffer = gst_buffer_ref(gst_sample_get_buffer(sample)); + gst_sample_unref(sample); +#else buffer = gst_app_sink_pull_buffer(mVideoAppSink); +#endif mVideoSinkBufferCount--; } - bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT); + bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); if ((aKeyFrameSkip && !isKeyframe)) { gst_buffer_unref(buffer); return true; @@@@ -618,10 +677,18 @@@@ bool GStreamerReader::DecodeVideoFrame(b "frame has invalid timestamp"); timestamp = GST_TIME_AS_USECONDS(timestamp); + int64_t duration; + if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer))) + duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer)); + else if (fpsNum && fpsDen) + /* add 1-frame duration */ + duration = gst_util_uint64_scale(GST_USECOND, fpsDen, fpsNum); + if (timestamp < aTimeThreshold) { LOG(PR_LOG_DEBUG, "skipping frame %" GST_TIME_FORMAT " threshold %" GST_TIME_FORMAT, - GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold)); + GST_TIME_ARGS(timestamp * 1000), + GST_TIME_ARGS(aTimeThreshold * 1000)); gst_buffer_unref(buffer); return true; } @@@@ -630,61 +697,36 @@@@ bool GStreamerReader::DecodeVideoFrame(b /* no more frames */ return false; - int64_t duration = 0; - if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer))) - duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer)); - else if (fpsNum && fpsDen) - /* 1-frame duration */ - duration = gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen); - - nsRefPtr image; - GstMozVideoBufferData* bufferdata = reinterpret_cast - GST_IS_MOZ_VIDEO_BUFFER(buffer)?gst_moz_video_buffer_get_data(GST_MOZ_VIDEO_BUFFER(buffer)):nullptr; - - if(bufferdata) - image = bufferdata->mImage; +#if GST_VERSION_MAJOR >= 1 + if (mConfigureAlignment && buffer->pool) { + GstStructure *config = gst_buffer_pool_get_config(buffer->pool); + GstVideoAlignment align; + if (gst_buffer_pool_config_get_video_alignment(config, &align)) + gst_video_info_align(&mVideoInfo, &align); + gst_structure_free(config); + mConfigureAlignment = false; + } +#endif + nsRefPtr image = GetImageFromBuffer(buffer); if (!image) { /* Ugh, upstream is not calling gst_pad_alloc_buffer(). Fallback to * allocating a PlanarYCbCrImage backed GstBuffer here and memcpy. */ GstBuffer* tmp = nullptr; - AllocateVideoBufferFull(nullptr, GST_BUFFER_OFFSET(buffer), - GST_BUFFER_SIZE(buffer), nullptr, &tmp, image); - - /* copy */ - gst_buffer_copy_metadata(tmp, buffer, (GstBufferCopyFlags)GST_BUFFER_COPY_ALL); - memcpy(GST_BUFFER_DATA(tmp), GST_BUFFER_DATA(buffer), - GST_BUFFER_SIZE(tmp)); + CopyIntoImageBuffer(buffer, &tmp, image); gst_buffer_unref(buffer); buffer = tmp; } - guint8* data = GST_BUFFER_DATA(buffer); - - int width = mPicture.width; - int height = mPicture.height; - GstVideoFormat format = mFormat; - - VideoData::YCbCrBuffer b; - for(int i = 0; i < 3; i++) { - b.mPlanes[i].mData = data + gst_video_format_get_component_offset(format, i, - width, height); - b.mPlanes[i].mStride = gst_video_format_get_row_stride(format, i, width); - b.mPlanes[i].mHeight = gst_video_format_get_component_height(format, - i, height); - b.mPlanes[i].mWidth = gst_video_format_get_component_width(format, - i, width); - b.mPlanes[i].mOffset = 0; - b.mPlanes[i].mSkip = 0; - } - - isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); int64_t offset = mDecoder->GetResource()->Tell(); // Estimate location in media. - VideoData* video = VideoData::Create(mInfo.mVideo, image, offset, - timestamp, duration, b, - isKeyframe, -1, mPicture); + VideoData* video = VideoData::CreateFromImage(mInfo.mVideo, + mDecoder->GetImageContainer(), + offset, timestamp, duration, + static_cast(image.get()), + isKeyframe, -1, mPicture); mVideoQueue.Push(video); + gst_buffer_unref(buffer); return true; @@@@ -707,6 +749,10 @@@@ nsresult GStreamerReader::Seek(int64_t a return NS_ERROR_FAILURE; } LOG(PR_LOG_DEBUG, "seek succeeded"); + GstMessage* message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, + (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR)); + gst_message_unref(message); + LOG(PR_LOG_DEBUG, "seek completed"); return DecodeToTarget(aTarget); } @@@@ -718,7 +764,9 @@@@ nsresult GStreamerReader::GetBuffered(do return NS_OK; } +#if GST_VERSION_MAJOR == 0 GstFormat format = GST_FORMAT_TIME; +#endif MediaResource* resource = mDecoder->GetResource(); nsTArray ranges; resource->GetCachedRanges(ranges); @@@@ -740,12 +788,21 @@@@ nsresult GStreamerReader::GetBuffered(do int64_t endOffset = ranges[index].mEnd; gint64 startTime, endTime; +#if GST_VERSION_MAJOR >= 1 + if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, + startOffset, GST_FORMAT_TIME, &startTime)) + continue; + if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, + endOffset, GST_FORMAT_TIME, &endTime)) + continue; +#else if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, startOffset, &format, &startTime) || format != GST_FORMAT_TIME) continue; if (!gst_element_query_convert(GST_ELEMENT(mPlayBin), GST_FORMAT_BYTES, endOffset, &format, &endTime) || format != GST_FORMAT_TIME) continue; +#endif double start = (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND; double end = (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND; @@@@ -766,7 +823,13 @@@@ void GStreamerReader::ReadAndPushData(gu nsresult rv = NS_OK; GstBuffer* buffer = gst_buffer_new_and_alloc(aLength); +#if GST_VERSION_MAJOR >= 1 + GstMapInfo info; + gst_buffer_map(buffer, &info, GST_MAP_WRITE); + guint8 *data = info.data; +#else guint8* data = GST_BUFFER_DATA(buffer); +#endif uint32_t size = 0, bytesRead = 0; while(bytesRead < aLength) { rv = resource->Read(reinterpret_cast(data + bytesRead), @@@@ -780,7 +843,12 @@@@ void GStreamerReader::ReadAndPushData(gu int64_t offset2 = resource->Tell(); unused << offset2; +#if GST_VERSION_MAJOR >= 1 + gst_buffer_unmap(buffer, &info); + gst_buffer_set_size(buffer, bytesRead); +#else GST_BUFFER_SIZE(buffer) = bytesRead; +#endif GstFlowReturn ret = gst_app_src_push_buffer(mSource, gst_buffer_ref(buffer)); if (ret != GST_FLOW_OK) { @@@@ -813,8 +881,13 @@@@ int64_t GStreamerReader::QueryDuration() gint64 duration = 0; GstFormat format = GST_FORMAT_TIME; +#if GST_VERSION_MAJOR >= 1 + if (gst_element_query_duration(GST_ELEMENT(mPlayBin), + format, &duration)) { +#else if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration)) { +#endif if (format == GST_FORMAT_TIME) { LOG(PR_LOG_DEBUG, "pipeline duration %" GST_TIME_FORMAT, GST_TIME_ARGS (duration)); @@@@ -893,109 +966,6 @@@@ gboolean GStreamerReader::SeekData(GstAp return NS_SUCCEEDED(rv); } -gboolean GStreamerReader::EventProbeCb(GstPad* aPad, - GstEvent* aEvent, - gpointer aUserData) -{ - GStreamerReader* reader = reinterpret_cast(aUserData); - return reader->EventProbe(aPad, aEvent); -} - -gboolean GStreamerReader::EventProbe(GstPad* aPad, GstEvent* aEvent) -{ - GstElement* parent = GST_ELEMENT(gst_pad_get_parent(aPad)); - switch(GST_EVENT_TYPE(aEvent)) { - case GST_EVENT_NEWSEGMENT: - { - gboolean update; - gdouble rate; - GstFormat format; - gint64 start, stop, position; - GstSegment* segment; - - /* Store the segments so we can convert timestamps to stream time, which - * is what the upper layers sync on. - */ - ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); - gst_event_parse_new_segment(aEvent, &update, &rate, &format, - &start, &stop, &position); - if (parent == GST_ELEMENT(mVideoAppSink)) - segment = &mVideoSegment; - else - segment = &mAudioSegment; - gst_segment_set_newsegment(segment, update, rate, format, - start, stop, position); - break; - } - case GST_EVENT_FLUSH_STOP: - /* Reset on seeks */ - ResetDecode(); - break; - default: - break; - } - gst_object_unref(parent); - - return TRUE; -} - -GstFlowReturn GStreamerReader::AllocateVideoBufferFull(GstPad* aPad, - guint64 aOffset, - guint aSize, - GstCaps* aCaps, - GstBuffer** aBuf, - nsRefPtr& aImage) -{ - /* allocate an image using the container */ - ImageContainer* container = mDecoder->GetImageContainer(); - if (!container) { - // We don't have an ImageContainer. We probably belong to an