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 171025 838a38c416bd1817c71b39e28fbf561fbbeb5770
parent 171024 2cb3948fb588ecb1a06aff98e8319d5f213797ae
child 171026 896d64c59638f5f172fabe70dc33b645dc8e2b6d
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersrillian
bugs970774
milestone30.0a1
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