Bug 977089 - Don't pass ID3 headers to GStreamer. r=cpearce, a=lsblakk
authorEdwin Flores <eflores@mozilla.com>
Thu, 08 May 2014 15:49:31 +1200
changeset 192255 e414a4798c7c
parent 192254 5b3bfd0a529a
child 192256 d27918134b3d
push id3547
push userryanvm@gmail.com
push date2014-05-12 23:13 +0000
treeherdermozilla-beta@d27918134b3d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, lsblakk
bugs977089
milestone30.0
Bug 977089 - Don't pass ID3 headers to GStreamer. r=cpearce, a=lsblakk
content/media/gstreamer/GStreamerReader.cpp
content/media/gstreamer/GStreamerReader.h
--- a/content/media/gstreamer/GStreamerReader.cpp
+++ b/content/media/gstreamer/GStreamerReader.cpp
@@ -63,16 +63,17 @@ typedef enum {
   GST_PLAY_FLAG_BUFFERING     = (1 << 8),
   GST_PLAY_FLAG_DEINTERLACE   = (1 << 9),
   GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
 } PlayFlags;
 
 GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder)
   : MediaDecoderReader(aDecoder),
   mMP3FrameParser(aDecoder->GetResource()->GetLength()),
+  mDataOffset(0),
   mUseParserDuration(false),
 #if GST_VERSION_MAJOR >= 1
   mAllocator(nullptr),
   mBufferPool(nullptr),
 #endif
   mPlayBin(nullptr),
   mBus(nullptr),
   mSource(nullptr),
@@ -233,17 +234,17 @@ void GStreamerReader::PlayBinSourceSetup
    * returns something meaningful and not -1
    */
   char buf[512];
   unsigned int size = 0;
   resource->Read(buf, sizeof(buf), &size);
   resource->Seek(SEEK_SET, 0);
 
   /* now we should have a length */
-  int64_t resourceLength = resource->GetLength();
+  int64_t resourceLength = GetDataLength();
   gst_app_src_set_size(mSource, resourceLength);
   if (resource->IsDataCachedToEndOfResource(0) ||
       (resourceLength != -1 && resourceLength <= SHORT_FILE_SIZE)) {
     /* let the demuxer work in pull mode for local files (or very short files)
      * so that we get optimal seeking accuracy/performance
      */
     LOG(PR_LOG_DEBUG, "configuring random access, len %lld", resourceLength);
     gst_app_src_set_stream_type(mSource, GST_APP_STREAM_TYPE_RANDOM_ACCESS);
@@ -282,21 +283,38 @@ nsresult GStreamerReader::ParseMP3Header
     NS_ENSURE_TRUE(bytesRead, NS_ERROR_FAILURE);
 
     mMP3FrameParser.Parse(bytes, bytesRead, offset);
     offset += bytesRead;
   } while (!mMP3FrameParser.ParsedHeaders());
 
   if (mMP3FrameParser.IsMP3()) {
     mLastParserDuration = mMP3FrameParser.GetDuration();
+    mDataOffset = mMP3FrameParser.GetMP3Offset();
+
+    // Update GStreamer's stream length in case we found any ID3 headers to
+    // ignore.
+    gst_app_src_set_size(mSource, GetDataLength());
   }
 
   return NS_OK;
 }
 
+int64_t
+GStreamerReader::GetDataLength()
+{
+  int64_t streamLen = mDecoder->GetResource()->GetLength();
+
+  if (streamLen < 0) {
+    return streamLen;
+  }
+
+  return streamLen - mDataOffset;
+}
+
 nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
                                        MetadataTags** aTags)
 {
   NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
   nsresult ret = NS_OK;
 
   /*
    * Parse MP3 headers before we kick off the GStreamer pipeline otherwise there
@@ -792,17 +810,17 @@ nsresult GStreamerReader::GetBuffered(do
 
     {
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
       duration = mDecoder->GetMediaDuration();
     }
 
     double end = (double) duration / GST_MSECOND;
     LOG(PR_LOG_DEBUG, "complete range [0, %f] for [0, %li]",
-          end, resource->GetLength());
+          end, GetDataLength());
     aBuffered->Add(0, end);
     return NS_OK;
   }
 
   for(uint32_t index = 0; index < ranges.Length(); index++) {
     int64_t startOffset = ranges[index].mStart;
     int64_t endOffset = ranges[index].mEnd;
     gint64 startTime, endTime;
@@ -821,17 +839,17 @@ nsresult GStreamerReader::GetBuffered(do
     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;
     LOG(PR_LOG_DEBUG, "adding range [%f, %f] for [%li %li] size %li",
-          start, end, startOffset, endOffset, resource->GetLength());
+          start, end, startOffset, endOffset, GetDataLength());
     aBuffered->Add(start, end);
   }
 
   return NS_OK;
 }
 
 void GStreamerReader::ReadAndPushData(guint aLength)
 {
@@ -925,25 +943,27 @@ gboolean GStreamerReader::SeekDataCb(Gst
                                      gpointer aUserData)
 {
   GStreamerReader* reader = reinterpret_cast<GStreamerReader*>(aUserData);
   return reader->SeekData(aSrc, aOffset);
 }
 
 gboolean GStreamerReader::SeekData(GstAppSrc* aSrc, guint64 aOffset)
 {
+  aOffset += mDataOffset;
+
   ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
   MediaResource* resource = mDecoder->GetResource();
   int64_t resourceLength = resource->GetLength();
 
   if (gst_app_src_get_size(mSource) == -1) {
     /* It's possible that we didn't know the length when we initialized mSource
      * but maybe we do now
      */
-    gst_app_src_set_size(mSource, resourceLength);
+    gst_app_src_set_size(mSource, GetDataLength());
   }
 
   nsresult rv = NS_ERROR_FAILURE;
   if (aOffset < static_cast<guint64>(resourceLength)) {
     rv = resource->Seek(SEEK_SET, aOffset);
   }
 
   if (NS_FAILED(rv)) {
--- a/content/media/gstreamer/GStreamerReader.h
+++ b/content/media/gstreamer/GStreamerReader.h
@@ -173,19 +173,27 @@ private:
    */
   static GValueArray* AutoplugSortCb(GstElement* aElement,
                                      GstPad* aPad, GstCaps* aCaps,
                                      GValueArray* aFactories);
 
   // Try to find MP3 headers in this stream using our MP3 frame parser.
   nsresult ParseMP3Headers();
 
+  // Get the length of the stream, excluding any metadata we have ignored at the
+  // start of the stream: ID3 headers, for example.
+  int64_t GetDataLength();
+
   // Use our own MP3 parser here, largely for consistency with other platforms.
   MP3FrameParser mMP3FrameParser;
 
+  // The byte position in the stream where the actual media (ignoring, for
+  // example, ID3 tags) starts.
+  uint64_t mDataOffset;
+
   // 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;