Bug 970774 - Add display width/height for track encoder. r=rillian
authorBenjamin Chen <bechen@mozilla.com>
Fri, 21 Feb 2014 14:27:41 +0800
changeset 188880 838a38c416bd1817c71b39e28fbf561fbbeb5770
parent 188879 2cb3948fb588ecb1a06aff98e8319d5f213797ae
child 188881 896d64c59638f5f172fabe70dc33b645dc8e2b6d
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs970774
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 970774 - Add display width/height for track encoder. r=rillian
content/media/encoder/OmxTrackEncoder.cpp
content/media/encoder/OmxTrackEncoder.h
content/media/encoder/TrackEncoder.cpp
content/media/encoder/TrackEncoder.h
content/media/encoder/VP8TrackEncoder.cpp
content/media/encoder/VP8TrackEncoder.h
content/media/webm/EbmlComposer.cpp
content/media/webm/EbmlComposer.h
content/media/webm/WebMWriter.cpp
content/media/webm/WebMWriter.h
media/libmkv/WebMElement.c
media/libmkv/WebMElement.h
media/libmkv/bug970774.patch
media/libmkv/update.sh
--- a/content/media/encoder/OmxTrackEncoder.cpp
+++ b/content/media/encoder/OmxTrackEncoder.cpp
@@ -21,21 +21,24 @@
 using namespace android;
 
 namespace mozilla {
 
 #define ENCODER_CONFIG_FRAME_RATE 30 // fps
 #define GET_ENCODED_VIDEO_FRAME_TIMEOUT 100000 // microseconds
 
 nsresult
-OmxVideoTrackEncoder::Init(int aWidth, int aHeight, TrackRate aTrackRate)
+OmxVideoTrackEncoder::Init(int aWidth, int aHeight, int aDisplayWidth,
+                           int aDisplayHeight, TrackRate aTrackRate)
 {
   mFrameWidth = aWidth;
   mFrameHeight = aHeight;
   mTrackRate = aTrackRate;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
 
   mEncoder = OMXCodecWrapper::CreateAVCEncoder();
   NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
 
   nsresult rv = mEncoder->Configure(mFrameWidth, mFrameHeight,
                                     ENCODER_CONFIG_FRAME_RATE);
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
--- a/content/media/encoder/OmxTrackEncoder.h
+++ b/content/media/encoder/OmxTrackEncoder.h
@@ -30,17 +30,19 @@ public:
     : VideoTrackEncoder()
   {}
 
   already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
 
 protected:
-  nsresult Init(int aWidth, int aHeight, TrackRate aTrackRate) MOZ_OVERRIDE;
+  nsresult Init(int aWidth, int aHeight,
+                int aDisplayWidth, int aDisplayHeight,
+                TrackRate aTrackRate) MOZ_OVERRIDE;
 
 private:
   nsAutoPtr<android::OMXVideoEncoder> mEncoder;
 };
 
 class OmxAudioTrackEncoder MOZ_FINAL : public AudioTrackEncoder
 {
 public:
--- a/content/media/encoder/TrackEncoder.cpp
+++ b/content/media/encoder/TrackEncoder.cpp
@@ -158,17 +158,20 @@ VideoTrackEncoder::NotifyQueuedTrackChan
 
    // Check and initialize parameters for codec encoder.
   if (!mInitialized) {
     VideoSegment::ChunkIterator iter(const_cast<VideoSegment&>(video));
     while (!iter.IsEnded()) {
       VideoChunk chunk = *iter;
       if (!chunk.IsNull()) {
         gfx::IntSize imgsize = chunk.mFrame.GetImage()->GetSize();
-        nsresult rv = Init(imgsize.width, imgsize.height, aTrackRate);
+        gfxIntSize intrinsicSize = chunk.mFrame.GetIntrinsicSize();
+        nsresult rv = Init(imgsize.width, imgsize.height,
+                           intrinsicSize.width, intrinsicSize.height,
+                           aTrackRate);
         if (NS_FAILED(rv)) {
           LOG("[VideoTrackEncoder]: Fail to initialize the encoder!");
           NotifyCancel();
         }
         break;
       }
 
       iter.Next();
@@ -209,17 +212,18 @@ VideoTrackEncoder::AppendVideoSegment(co
 }
 
 void
 VideoTrackEncoder::NotifyEndOfStream()
 {
   // If source video track is muted till the end of encoding, initialize the
   // encoder with default frame width, frame height, and track rate.
   if (!mCanceled && !mInitialized) {
-    Init(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, DEFAULT_TRACK_RATE);
+    Init(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT,
+         DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, DEFAULT_TRACK_RATE);
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   mEndOfStream = true;
   mReentrantMonitor.NotifyAll();
 }
 
 void
--- a/content/media/encoder/TrackEncoder.h
+++ b/content/media/encoder/TrackEncoder.h
@@ -217,16 +217,18 @@ protected:
 
 class VideoTrackEncoder : public TrackEncoder
 {
 public:
   VideoTrackEncoder()
     : TrackEncoder()
     , mFrameWidth(0)
     , mFrameHeight(0)
+    , mDisplayWidth(0)
+    , mDisplayHeight(0)
     , mTrackRate(0)
     , mTotalFrameDuration(0)
   {}
 
   /**
    * Notified by the same callbcak of MediaEncoder when it has received a track
    * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
    */
@@ -239,17 +241,18 @@ public:
 protected:
   /**
    * Initialized the video encoder. In order to collect the value of width and
    * height of source frames, this initialization is delayed until we have
    * received the first valid video frame from MediaStreamGraph;
    * mReentrantMonitor will be notified after it has successfully initialized,
    * and this method is called on the MediaStramGraph thread.
    */
-  virtual nsresult Init(int aWidth, int aHeight, TrackRate aTrackRate) = 0;
+  virtual nsresult Init(int aWidth, int aHeight, int aDisplayWidth,
+                        int aDisplayHeight, TrackRate aTrackRate) = 0;
 
   /**
    * Appends source video frames to mRawSegment. We only append the source chunk
    * if it is unique to mLastChunk. Called on the MediaStreamGraph thread.
    */
   nsresult AppendVideoSegment(const VideoSegment& aSegment);
 
   /**
@@ -271,16 +274,26 @@ protected:
   int mFrameWidth;
 
   /**
    * The height of source video frame, ceiled if the source height is odd.
    */
   int mFrameHeight;
 
   /**
+   * The display width of source video frame.
+   */
+  int mDisplayWidth;
+
+  /**
+   * The display height of source video frame.
+   */
+  int mDisplayHeight;
+
+  /**
    * The track rate of source video.
    */
   TrackRate mTrackRate;
 
   /**
    * The total duration of frames in encoded video in TrackTicks, kept track of
    * in subclasses.
    */
--- a/content/media/encoder/VP8TrackEncoder.cpp
+++ b/content/media/encoder/VP8TrackEncoder.cpp
@@ -48,29 +48,33 @@ VP8TrackEncoder::~VP8TrackEncoder()
 
   if (mVPXImageWrapper) {
     vpx_img_free(mVPXImageWrapper);
   }
   MOZ_COUNT_DTOR(VP8TrackEncoder);
 }
 
 nsresult
-VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, TrackRate aTrackRate)
+VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth,
+                      int32_t aDisplayHeight,TrackRate aTrackRate)
 {
-  if (aWidth < 1 || aHeight < 1 || aTrackRate <= 0) {
+  if (aWidth < 1 || aHeight < 1 || aDisplayWidth < 1 || aDisplayHeight < 1
+      || aTrackRate <= 0) {
     return NS_ERROR_FAILURE;
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   mTrackRate = aTrackRate;
   mEncodedFrameRate = DEFAULT_ENCODE_FRAMERATE;
   mEncodedFrameDuration = mTrackRate / mEncodedFrameRate;
   mFrameWidth = aWidth;
   mFrameHeight = aHeight;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
 
   // Encoder configuration structure.
   vpx_codec_enc_cfg_t config;
   memset(&config, 0, sizeof(vpx_codec_enc_cfg_t));
   if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config, 0)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -148,16 +152,18 @@ VP8TrackEncoder::GetMetadata()
 
   if (mCanceled || mEncodingComplete) {
     return nullptr;
   }
 
   nsRefPtr<VP8Metadata> meta = new VP8Metadata();
   meta->mWidth = mFrameWidth;
   meta->mHeight = mFrameHeight;
+  meta->mDisplayWidth = mDisplayWidth;
+  meta->mDisplayHeight = mDisplayHeight;
   meta->mEncodedFrameRate = mEncodedFrameRate;
 
   return meta.forget();
 }
 
 nsresult
 VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
 {
--- a/content/media/encoder/VP8TrackEncoder.h
+++ b/content/media/encoder/VP8TrackEncoder.h
@@ -33,16 +33,17 @@ public:
   virtual ~VP8TrackEncoder();
 
   already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_FINAL MOZ_OVERRIDE;
 
   nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_FINAL MOZ_OVERRIDE;
 
 protected:
   nsresult Init(int32_t aWidth, int32_t aHeight,
+                int32_t aDisplayWidth, int32_t aDisplayHeight,
                 TrackRate aTrackRate) MOZ_FINAL MOZ_OVERRIDE;
 
 private:
   // Calculate the target frame's encoded duration.
   TrackTicks CalculateEncodedDuration(TrackTicks aDurationCopied);
 
   // Calculate the mRemainingTicks for next target frame.
   TrackTicks CalculateRemainingTicks(TrackTicks aDurationCopied,
--- a/content/media/webm/EbmlComposer.cpp
+++ b/content/media/webm/EbmlComposer.cpp
@@ -36,17 +36,18 @@ void EbmlComposer::GenerateHeader()
       writeSegmentInformation(&ebml, &ebmlLoc, TIME_CODE_SCALE, 0);
       {
         EbmlLoc trackLoc;
         Ebml_StartSubElement(&ebml, &trackLoc, Tracks);
         {
           // Video
           if (mWidth > 0 && mHeight > 0) {
             writeVideoTrack(&ebml, 0x1, 0, "V_VP8",
-                            mWidth, mHeight, mFrameRate);
+                            mWidth, mHeight,
+                            mDisplayWidth, mDisplayHeight, mFrameRate);
           }
           // Audio
           if (mCodecPrivateData.Length() > 0) {
             writeAudioTrack(&ebml, 0x2, 0x0, "A_VORBIS", mSampleFreq,
                             mChannels, mCodecPrivateData.Elements(),
                             mCodecPrivateData.Length());
           }
         }
@@ -118,23 +119,28 @@ EbmlComposer::WriteSimpleBlock(EncodedFr
   }
   MOZ_ASSERT_IF(ebml.offset > DEFAULT_HEADER_SIZE + aFrame->GetFrameData().Length(),
                 "write more data > EBML_BUFFER_SIZE");
   mClusterBuffs.LastElement().SetLength(ebml.offset);
 }
 
 void
 EbmlComposer::SetVideoConfig(uint32_t aWidth, uint32_t aHeight,
+                             uint32_t aDisplayWidth, uint32_t aDisplayHeight,
                              float aFrameRate)
 {
   MOZ_ASSERT(aWidth > 0, "Width should > 0");
   MOZ_ASSERT(aHeight > 0, "Height should > 0");
+  MOZ_ASSERT(aDisplayWidth > 0, "DisplayWidth should > 0");
+  MOZ_ASSERT(aDisplayHeight > 0, "DisplayHeight should > 0");
   MOZ_ASSERT(aFrameRate > 0, "FrameRate should > 0");
   mWidth = aWidth;
   mHeight = aHeight;
+  mDisplayWidth = aDisplayWidth;
+  mDisplayHeight = aDisplayHeight;
   mFrameRate = aFrameRate;
 }
 
 void
 EbmlComposer::SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
                              uint32_t aBitDepth)
 {
   MOZ_ASSERT(aSampleFreq > 0, "SampleFreq should > 0");
--- a/content/media/webm/EbmlComposer.h
+++ b/content/media/webm/EbmlComposer.h
@@ -14,17 +14,18 @@ namespace mozilla {
  * A WebM muxer helper for package the valid WebM format.
  */
 class EbmlComposer {
 public:
   EbmlComposer();
   /*
    * Assign the parameter which header required.
    */
-  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, float aFrameRate);
+  void SetVideoConfig(uint32_t aWidth, uint32_t aHeight, uint32_t aDisplayWidth,
+                      uint32_t aDisplayHeight, float aFrameRate);
 
   void SetAudioConfig(uint32_t aSampleFreq, uint32_t aChannels,
                       uint32_t bitDepth);
   /*
    * Set the CodecPrivateData for writing in header.
    */
   void SetAudioCodecPrivateData(nsTArray<uint8_t>& aBufs)
   {
@@ -59,16 +60,18 @@ private:
   nsTArray<uint8_t> mCodecPrivateData;
 
   // The timecode of the cluster.
   uint64_t mClusterTimecode;
 
   // Video configuration
   int mWidth;
   int mHeight;
+  int mDisplayWidth;
+  int mDisplayHeight;
   float mFrameRate;
   // Audio configuration
   float mSampleFreq;
   int mBitDepth;
   int mChannels;
 };
 
 }
--- a/content/media/webm/WebMWriter.cpp
+++ b/content/media/webm/WebMWriter.cpp
@@ -38,16 +38,17 @@ WebMWriter::GetContainerData(nsTArray<ns
 nsresult
 WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
 {
   MOZ_ASSERT(aMetadata);
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
     VP8Metadata* meta = static_cast<VP8Metadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
     mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
+                                  meta->mDisplayWidth, meta->mDisplayHeight,
                                   meta->mEncodedFrameRate);
     mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_VIDEO_TRACK;
   }
 
   if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
     VorbisMetadata* meta = static_cast<VorbisMetadata*>(aMetadata);
     MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
     mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels, meta->mBitDepth);
--- a/content/media/webm/WebMWriter.h
+++ b/content/media/webm/WebMWriter.h
@@ -24,16 +24,18 @@ public:
 };
 
 // VP8 meta data structure
 class VP8Metadata : public TrackMetadataBase
 {
 public:
   int32_t mWidth;
   int32_t mHeight;
+  int32_t mDisplayWidth;
+  int32_t mDisplayHeight;
   int32_t mEncodedFrameRate;
   MetadataKind GetKind() const MOZ_OVERRIDE { return METADATA_VP8; }
 };
 
 /**
  * WebM writer helper
  * This class accepts encoder to set audio or video meta data or
  * encoded data to ebml Composer, and get muxing data through GetContainerData.
--- a/media/libmkv/WebMElement.c
+++ b/media/libmkv/WebMElement.c
@@ -52,32 +52,39 @@ static UInt64 generateTrackID(unsigned i
   r = r << 32;
   r +=  rand();
 //  UInt64 rval = t ^ r;
   return t ^ r;
 }
 
 void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+                     unsigned int displayWidth, unsigned int displayHeight,
                      double frameRate) {
   EbmlLoc start;
   UInt64 trackID;
   Ebml_StartSubElement(glob, &start, TrackEntry);
   Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
   trackID = generateTrackID(trackNumber);
   Ebml_SerializeUnsigned(glob, TrackUID, trackID);
   Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
 
   Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
   Ebml_SerializeString(glob, CodecID, codecId);
   {
     EbmlLoc videoStart;
     Ebml_StartSubElement(glob, &videoStart, Video);
     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
+    if (pixelWidth != displayWidth) {
+      Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth);
+    }
+    if (pixelHeight != displayHeight) {
+      Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight);
+    }
     Ebml_SerializeFloat(glob, FrameRate, frameRate);
     Ebml_EndSubElement(glob, &videoStart); // Video
   }
   Ebml_EndSubElement(glob, &start); // Track Entry
 }
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      unsigned char *private, unsigned long privateSize) {
--- a/media/libmkv/WebMElement.h
+++ b/media/libmkv/WebMElement.h
@@ -16,16 +16,17 @@ extern "C" {
 #include "EbmlWriter.h"
 
 // these are helper functions
 void writeHeader(EbmlGlobal *ebml);
 void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
 // this function is a helper only, it assumes a lot of defaults
 void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
+                     unsigned int displayWidth, unsigned int displayHeight,
                      double frameRate);
 void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
                      const char *codecId, double samplingFrequency, unsigned int channels,
                      unsigned char *private_, unsigned long privateSize);
 
 void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
                       int isKeyframe, unsigned char lacingFlag, int discardable,
                       unsigned char *data, unsigned long dataLength);
new file mode 100644
--- /dev/null
+++ b/media/libmkv/bug970774.patch
@@ -0,0 +1,64 @@
+diff --git a/media/libmkv/WebMElement.c b/media/libmkv/WebMElement.c
+--- a/media/libmkv/WebMElement.c
++++ b/media/libmkv/WebMElement.c
+@@ -52,32 +52,39 @@ static UInt64 generateTrackID(unsigned i
+   r = r << 32;
+   r +=  rand();
+ //  UInt64 rval = t ^ r;
+   return t ^ r;
+ }
+ 
+ void writeVideoTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
++                     unsigned int displayWidth, unsigned int displayHeight,
+                      double frameRate) {
+   EbmlLoc start;
+   UInt64 trackID;
+   Ebml_StartSubElement(glob, &start, TrackEntry);
+   Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber);
+   trackID = generateTrackID(trackNumber);
+   Ebml_SerializeUnsigned(glob, TrackUID, trackID);
+   Ebml_SerializeString(glob, CodecName, "VP8");  // TODO shouldn't be fixed
+ 
+   Ebml_SerializeUnsigned(glob, TrackType, 1); // video is always 1
+   Ebml_SerializeString(glob, CodecID, codecId);
+   {
+     EbmlLoc videoStart;
+     Ebml_StartSubElement(glob, &videoStart, Video);
+     Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth);
+     Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight);
++    if (pixelWidth != displayWidth) {
++      Ebml_SerializeUnsigned(glob, DisplayWidth, displayWidth);
++    }
++    if (pixelHeight != displayHeight) {
++      Ebml_SerializeUnsigned(glob, DisplayHeight, displayHeight);
++    }
+     Ebml_SerializeFloat(glob, FrameRate, frameRate);
+     Ebml_EndSubElement(glob, &videoStart); // Video
+   }
+   Ebml_EndSubElement(glob, &start); // Track Entry
+ }
+ void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, double samplingFrequency, unsigned int channels,
+                      unsigned char *private, unsigned long privateSize) {
+diff --git a/media/libmkv/WebMElement.h b/media/libmkv/WebMElement.h
+--- a/media/libmkv/WebMElement.h
++++ b/media/libmkv/WebMElement.h
+@@ -16,16 +16,17 @@ extern "C" {
+ #include "EbmlWriter.h"
+ 
+ // these are helper functions
+ void writeHeader(EbmlGlobal *ebml);
+ void writeSegmentInformation(EbmlGlobal *ebml, EbmlLoc *startInfo, unsigned long timeCodeScale, double duration);
+ // this function is a helper only, it assumes a lot of defaults
+ void writeVideoTrack(EbmlGlobal *ebml, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, unsigned int pixelWidth, unsigned int pixelHeight,
++                     unsigned int displayWidth, unsigned int displayHeight,
+                      double frameRate);
+ void writeAudioTrack(EbmlGlobal *glob, unsigned int trackNumber, int flagLacing,
+                      const char *codecId, double samplingFrequency, unsigned int channels,
+                      unsigned char *private_, unsigned long privateSize);
+ 
+ void writeSimpleBlock(EbmlGlobal *ebml, unsigned char trackNumber, short timeCode,
+                       int isKeyframe, unsigned char lacingFlag, int discardable,
+                       unsigned char *data, unsigned long dataLength);
--- a/media/libmkv/update.sh
+++ b/media/libmkv/update.sh
@@ -30,8 +30,9 @@ else
   echo "Remember to update README_MOZILLA with the version details."
 fi
 
 # Apply any patches against upstream here.
 patch -p1 < source_fix.patch
 patch -p1 < gecko_fix.patch
 patch -p1 < const_fix.patch
 patch -p3 < bock_fix.patch
+patch -p3 < bug970774.patch