mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 918135 - Use MP3FrameParser in GStreamer backend for MP3 duration estimation r=cpearce
This patch adds support for our home-grown MP3 frame parser to the GStreamer backend so that our duration estimation is consistent across all platforms.
This commit is contained in:
parent
39b4d9dbec
commit
740ce45445
@ -5,6 +5,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsError.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "MediaResource.h"
|
||||
@ -57,6 +58,8 @@ typedef enum {
|
||||
|
||||
GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder),
|
||||
mMP3FrameParser(aDecoder->GetResource()->GetLength()),
|
||||
mUseParserDuration(false),
|
||||
mPlayBin(nullptr),
|
||||
mBus(nullptr),
|
||||
mSource(nullptr),
|
||||
@ -243,6 +246,35 @@ void GStreamerReader::PlayBinSourceSetup(GstAppSrc* aSource)
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this stream is an MP3, we want to parse the headers to estimate the
|
||||
* stream duration.
|
||||
*/
|
||||
nsresult GStreamerReader::ParseMP3Headers()
|
||||
{
|
||||
MediaResource *resource = mDecoder->GetResource();
|
||||
|
||||
const uint32_t MAX_READ_BYTES = 4096;
|
||||
|
||||
uint64_t offset = 0;
|
||||
char bytes[MAX_READ_BYTES];
|
||||
uint32_t bytesRead;
|
||||
do {
|
||||
nsresult rv = resource->ReadAt(offset, bytes, MAX_READ_BYTES, &bytesRead);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(bytesRead, NS_ERROR_FAILURE);
|
||||
|
||||
mMP3FrameParser.Parse(bytes, bytesRead, offset);
|
||||
offset += bytesRead;
|
||||
} while (!mMP3FrameParser.ParsedHeaders());
|
||||
|
||||
if (mMP3FrameParser.IsMP3()) {
|
||||
mLastParserDuration = mMP3FrameParser.GetDuration();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
@ -338,16 +370,32 @@ nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
}
|
||||
|
||||
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
|
||||
if (isMP3) {
|
||||
ParseMP3Headers();
|
||||
}
|
||||
|
||||
/* report the duration */
|
||||
gint64 duration;
|
||||
GstFormat format = GST_FORMAT_TIME;
|
||||
if (gst_element_query_duration(GST_ELEMENT(mPlayBin),
|
||||
|
||||
if (isMP3 && mMP3FrameParser.IsMP3()) {
|
||||
// The MP3FrameParser has reported a duration; use that over the gstreamer
|
||||
// reported duration for inter-platform consistency.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
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);
|
||||
}
|
||||
@ -1019,5 +1067,33 @@ void GStreamerReader::Eos()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is an MP3 stream, pass any new data we get to the MP3 frame parser
|
||||
* for duration estimation.
|
||||
*/
|
||||
void GStreamerReader::NotifyDataArrived(const char *aBuffer,
|
||||
uint32_t aLength,
|
||||
int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (HasVideo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mMP3FrameParser.NeedsData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mLastParserDuration && mUseParserDuration) {
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mLastParserDuration = duration;
|
||||
mDecoder->UpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#if !defined(GStreamerReader_h_)
|
||||
#define GStreamerReader_h_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/app/gstappsrc.h>
|
||||
#include <gst/app/gstappsink.h>
|
||||
@ -17,8 +19,9 @@
|
||||
#pragma GCC diagnostic ignored "-Wreserved-user-defined-literal"
|
||||
#include <gst/video/video.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#include <map>
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MP3FrameParser.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -52,6 +55,10 @@ public:
|
||||
int64_t aCurrentTime);
|
||||
virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime);
|
||||
|
||||
virtual void NotifyDataArrived(const char *aBuffer,
|
||||
uint32_t aLength,
|
||||
int64_t aOffset) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool HasAudio() {
|
||||
return mInfo.HasAudio();
|
||||
}
|
||||
@ -129,6 +136,20 @@ private:
|
||||
static void EosCb(GstAppSink* aSink, gpointer aUserData);
|
||||
void Eos();
|
||||
|
||||
// Try to find MP3 headers in this stream using our MP3 frame parser.
|
||||
nsresult ParseMP3Headers();
|
||||
|
||||
// Use our own MP3 parser here, largely for consistency with other platforms.
|
||||
MP3FrameParser mMP3FrameParser;
|
||||
|
||||
// We want to be able to decide in |ReadMetadata| whether or not we use the
|
||||
// duration from the MP3 frame parser, as this backend supports more than just
|
||||
// MP3. But |NotifyDataArrived| can update the duration and is often called
|
||||
// _before_ |ReadMetadata|. This flag stops the former from using the parser
|
||||
// duration until we are sure we want to.
|
||||
bool mUseParserDuration;
|
||||
int64_t mLastParserDuration;
|
||||
|
||||
GstElement* mPlayBin;
|
||||
GstBus* mBus;
|
||||
GstAppSrc* mSource;
|
||||
|
Loading…
Reference in New Issue
Block a user