2012-04-18 15:33:13 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2012-11-14 11:46:40 -08:00
|
|
|
#if !defined(GStreamerReader_h_)
|
|
|
|
#define GStreamerReader_h_
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
#include <gst/gst.h>
|
|
|
|
#include <gst/app/gstappsrc.h>
|
|
|
|
#include <gst/app/gstappsink.h>
|
|
|
|
#include <gst/video/video.h>
|
2013-03-13 13:11:15 -07:00
|
|
|
#include <map>
|
2012-11-14 11:46:40 -08:00
|
|
|
#include "MediaDecoderReader.h"
|
2012-04-18 15:33:13 -07:00
|
|
|
|
2012-11-14 11:45:33 -08:00
|
|
|
namespace mozilla {
|
|
|
|
|
2013-03-03 09:01:05 -08:00
|
|
|
namespace dom {
|
|
|
|
class TimeRanges;
|
|
|
|
}
|
|
|
|
|
2012-11-19 07:11:21 -08:00
|
|
|
class AbstractMediaDecoder;
|
2012-11-14 11:45:33 -08:00
|
|
|
|
2012-11-14 11:46:40 -08:00
|
|
|
class GStreamerReader : public MediaDecoderReader
|
2012-04-18 15:33:13 -07:00
|
|
|
{
|
|
|
|
public:
|
2012-11-19 07:11:21 -08:00
|
|
|
GStreamerReader(AbstractMediaDecoder* aDecoder);
|
2012-11-14 11:46:40 -08:00
|
|
|
virtual ~GStreamerReader();
|
2012-04-18 15:33:13 -07:00
|
|
|
|
2012-11-14 11:46:40 -08:00
|
|
|
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
|
2012-04-18 15:33:13 -07:00
|
|
|
virtual nsresult ResetDecode();
|
|
|
|
virtual bool DecodeAudioData();
|
|
|
|
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
|
2012-08-22 08:56:38 -07:00
|
|
|
int64_t aTimeThreshold);
|
2012-11-28 11:40:07 -08:00
|
|
|
virtual nsresult ReadMetadata(VideoInfo* aInfo,
|
2012-11-08 16:40:08 -08:00
|
|
|
MetadataTags** aTags);
|
2012-08-22 08:56:38 -07:00
|
|
|
virtual nsresult Seek(int64_t aTime,
|
|
|
|
int64_t aStartTime,
|
|
|
|
int64_t aEndTime,
|
|
|
|
int64_t aCurrentTime);
|
2013-03-03 10:27:36 -08:00
|
|
|
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
virtual bool HasAudio() {
|
|
|
|
return mInfo.mHasAudio;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool HasVideo() {
|
|
|
|
return mInfo.mHasVideo;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
void ReadAndPushData(guint aLength);
|
2013-03-13 13:11:15 -07:00
|
|
|
bool WaitForDecodedData(int* counter);
|
2012-04-18 15:33:13 -07:00
|
|
|
void NotifyBytesConsumed();
|
2012-08-22 08:56:38 -07:00
|
|
|
int64_t QueryDuration();
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Gst callbacks */
|
|
|
|
|
|
|
|
/* Called on the source-setup signal emitted by playbin. Used to
|
|
|
|
* configure appsrc .
|
|
|
|
*/
|
2013-03-13 13:11:15 -07:00
|
|
|
static void PlayBinSourceSetupCb(GstElement* aPlayBin,
|
|
|
|
GParamSpec* pspec,
|
2012-04-18 15:33:13 -07:00
|
|
|
gpointer aUserData);
|
2013-03-13 13:11:15 -07:00
|
|
|
void PlayBinSourceSetup(GstAppSrc* aSource);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Called from appsrc when we need to read more data from the resource */
|
2013-03-13 13:11:15 -07:00
|
|
|
static void NeedDataCb(GstAppSrc* aSrc, guint aLength, gpointer aUserData);
|
|
|
|
void NeedData(GstAppSrc* aSrc, guint aLength);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Called when appsrc has enough data and we can stop reading */
|
2013-03-13 13:11:15 -07:00
|
|
|
static void EnoughDataCb(GstAppSrc* aSrc, gpointer aUserData);
|
|
|
|
void EnoughData(GstAppSrc* aSrc);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Called when a seek is issued on the pipeline */
|
2013-03-13 13:11:15 -07:00
|
|
|
static gboolean SeekDataCb(GstAppSrc* aSrc,
|
2012-04-18 15:33:13 -07:00
|
|
|
guint64 aOffset,
|
|
|
|
gpointer aUserData);
|
2013-03-13 13:11:15 -07:00
|
|
|
gboolean SeekData(GstAppSrc* aSrc, guint64 aOffset);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Called when events reach the sinks. See inline comments */
|
2013-03-13 13:11:15 -07:00
|
|
|
static gboolean EventProbeCb(GstPad* aPad, GstEvent* aEvent, gpointer aUserData);
|
|
|
|
gboolean EventProbe(GstPad* aPad, GstEvent* aEvent);
|
|
|
|
|
|
|
|
/* Called when elements in the video branch of the pipeline call
|
|
|
|
* gst_pad_alloc_buffer(). Used to provide PlanarYCbCrImage backed GstBuffers
|
|
|
|
* to the pipeline so that a memory copy can be avoided when handling YUV
|
|
|
|
* buffers from the pipeline to the gfx side.
|
|
|
|
*/
|
|
|
|
static GstFlowReturn AllocateVideoBufferCb(GstPad* aPad, guint64 aOffset, guint aSize,
|
|
|
|
GstCaps* aCaps, GstBuffer** aBuf);
|
|
|
|
GstFlowReturn AllocateVideoBufferFull(GstPad* aPad, guint64 aOffset, guint aSize,
|
|
|
|
GstCaps* aCaps, GstBuffer** aBuf, nsRefPtr<layers::PlanarYCbCrImage>& aImage);
|
|
|
|
GstFlowReturn AllocateVideoBuffer(GstPad* aPad, guint64 aOffset, guint aSize,
|
|
|
|
GstCaps* aCaps, GstBuffer** aBuf);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
|
|
|
/* Called when the pipeline is prerolled, that is when at start or after a
|
|
|
|
* seek, the first audio and video buffers are queued in the sinks.
|
|
|
|
*/
|
2013-03-13 13:11:15 -07:00
|
|
|
static GstFlowReturn NewPrerollCb(GstAppSink* aSink, gpointer aUserData);
|
2012-04-18 15:33:13 -07:00
|
|
|
void VideoPreroll();
|
|
|
|
void AudioPreroll();
|
|
|
|
|
|
|
|
/* Called when buffers reach the sinks */
|
2013-03-13 13:11:15 -07:00
|
|
|
static GstFlowReturn NewBufferCb(GstAppSink* aSink, gpointer aUserData);
|
2012-04-18 15:33:13 -07:00
|
|
|
void NewVideoBuffer();
|
|
|
|
void NewAudioBuffer();
|
|
|
|
|
|
|
|
/* Called at end of stream, when decoding has finished */
|
2013-03-13 13:11:15 -07:00
|
|
|
static void EosCb(GstAppSink* aSink, gpointer aUserData);
|
|
|
|
void Eos(GstAppSink* aSink);
|
2012-04-18 15:33:13 -07:00
|
|
|
|
2013-03-13 13:11:15 -07:00
|
|
|
GstElement* mPlayBin;
|
|
|
|
GstBus* mBus;
|
|
|
|
GstAppSrc* mSource;
|
2012-04-18 15:33:13 -07:00
|
|
|
/* video sink bin */
|
2013-03-13 13:11:15 -07:00
|
|
|
GstElement* mVideoSink;
|
2012-04-18 15:33:13 -07:00
|
|
|
/* the actual video app sink */
|
2013-03-13 13:11:15 -07:00
|
|
|
GstAppSink* mVideoAppSink;
|
2012-04-18 15:33:13 -07:00
|
|
|
/* audio sink bin */
|
2013-03-13 13:11:15 -07:00
|
|
|
GstElement* mAudioSink;
|
2012-04-18 15:33:13 -07:00
|
|
|
/* the actual audio app sink */
|
2013-03-13 13:11:15 -07:00
|
|
|
GstAppSink* mAudioAppSink;
|
2012-04-18 15:33:13 -07:00
|
|
|
GstVideoFormat mFormat;
|
|
|
|
nsIntRect mPicture;
|
|
|
|
int mVideoSinkBufferCount;
|
|
|
|
int mAudioSinkBufferCount;
|
|
|
|
GstAppSrcCallbacks mSrcCallbacks;
|
|
|
|
GstAppSinkCallbacks mSinkCallbacks;
|
|
|
|
/* monitor used to synchronize access to shared state between gstreamer
|
|
|
|
* threads and other gecko threads */
|
2012-11-14 11:46:40 -08:00
|
|
|
ReentrantMonitor mGstThreadsMonitor;
|
2012-04-18 15:33:13 -07:00
|
|
|
/* video and audio segments we use to convert absolute timestamps to [0,
|
|
|
|
* stream_duration]. They're set when the pipeline is started or after a seek.
|
|
|
|
* Concurrent access guarded with mGstThreadsMonitor.
|
|
|
|
*/
|
|
|
|
GstSegment mVideoSegment;
|
|
|
|
GstSegment mAudioSegment;
|
|
|
|
/* bool used to signal when gst has detected the end of stream and
|
|
|
|
* DecodeAudioData and DecodeVideoFrame should not expect any more data
|
|
|
|
*/
|
|
|
|
bool mReachedEos;
|
|
|
|
/* offset we've reached reading from the source */
|
|
|
|
gint64 mByteOffset;
|
|
|
|
/* the last offset we reported with NotifyBytesConsumed */
|
|
|
|
gint64 mLastReportedByteOffset;
|
|
|
|
int fpsNum;
|
|
|
|
int fpsDen;
|
|
|
|
};
|
|
|
|
|
2013-03-13 13:11:15 -07:00
|
|
|
class BufferData {
|
|
|
|
public:
|
|
|
|
BufferData(layers::PlanarYCbCrImage* aImage) : mImage(aImage) {}
|
|
|
|
|
|
|
|
static void* Copy(void* aData) {
|
|
|
|
return new BufferData(reinterpret_cast<BufferData*>(aData)->mImage);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Free(void* aData) {
|
|
|
|
delete reinterpret_cast<BufferData*>(aData);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<layers::PlanarYCbCrImage> mImage;
|
|
|
|
};
|
|
|
|
|
2012-11-14 11:45:33 -08:00
|
|
|
} // namespace mozilla
|
|
|
|
|
2012-04-18 15:33:13 -07:00
|
|
|
#endif
|