Motown: Improvements to packet definition
- Removed duration field
- Renamed various "PresentationTime" things to "Pts"
- Now implementing Packet accessors in the base class.
- Improved the way ffmpeg AVFrame and AVPacket structures are managed.

R=johngro@google.com

Review URL: https://codereview.chromium.org/1814553002 .
diff --git a/mojo/dart/packages/mojo_services/lib/mojo/media/media_transport.mojom.dart b/mojo/dart/packages/mojo_services/lib/mojo/media/media_transport.mojom.dart
index b36f0f5..c8ffc41 100644
--- a/mojo/dart/packages/mojo_services/lib/mojo/media/media_transport.mojom.dart
+++ b/mojo/dart/packages/mojo_services/lib/mojo/media/media_transport.mojom.dart
@@ -100,11 +100,10 @@
 
 class MediaPacket extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
-    const bindings.StructDataHeader(48, 0)
+    const bindings.StructDataHeader(40, 0)
   ];
   static const int kNoTimestamp = 9223372036854775807;
   int pts = 9223372036854775807;
-  int duration = 0;
   bool endOfStream = false;
   MediaPacketRegion payload = null;
   List<MediaPacketRegion> extraPayload = null;
@@ -150,20 +149,16 @@
     }
     if (mainDataHeader.version >= 0) {
       
-      result.duration = decoder0.decodeUint64(16);
+      result.endOfStream = decoder0.decodeBool(16, 0);
     }
     if (mainDataHeader.version >= 0) {
       
-      result.endOfStream = decoder0.decodeBool(24, 0);
-    }
-    if (mainDataHeader.version >= 0) {
-      
-      var decoder1 = decoder0.decodePointer(32, false);
+      var decoder1 = decoder0.decodePointer(24, false);
       result.payload = MediaPacketRegion.decode(decoder1);
     }
     if (mainDataHeader.version >= 0) {
       
-      var decoder1 = decoder0.decodePointer(40, true);
+      var decoder1 = decoder0.decodePointer(32, true);
       if (decoder1 == null) {
         result.extraPayload = null;
       } else {
@@ -189,21 +184,14 @@
       rethrow;
     }
     try {
-      encoder0.encodeUint64(duration, 16);
-    } on bindings.MojoCodecError catch(e) {
-      e.message = "Error encountered while encoding field "
-          "duration of struct MediaPacket: $e";
-      rethrow;
-    }
-    try {
-      encoder0.encodeBool(endOfStream, 24, 0);
+      encoder0.encodeBool(endOfStream, 16, 0);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
           "endOfStream of struct MediaPacket: $e";
       rethrow;
     }
     try {
-      encoder0.encodeStruct(payload, 32, false);
+      encoder0.encodeStruct(payload, 24, false);
     } on bindings.MojoCodecError catch(e) {
       e.message = "Error encountered while encoding field "
           "payload of struct MediaPacket: $e";
@@ -211,9 +199,9 @@
     }
     try {
       if (extraPayload == null) {
-        encoder0.encodeNullPointer(40, true);
+        encoder0.encodeNullPointer(32, true);
       } else {
-        var encoder1 = encoder0.encodePointerArray(extraPayload.length, 40, bindings.kUnspecifiedArrayLength);
+        var encoder1 = encoder0.encodePointerArray(extraPayload.length, 32, bindings.kUnspecifiedArrayLength);
         for (int i0 = 0; i0 < extraPayload.length; ++i0) {
           encoder1.encodeStruct(extraPayload[i0], bindings.ArrayDataHeader.kHeaderSize + bindings.kPointerSize * i0, false);
         }
@@ -228,7 +216,6 @@
   String toString() {
     return "MediaPacket("
            "pts: $pts" ", "
-           "duration: $duration" ", "
            "endOfStream: $endOfStream" ", "
            "payload: $payload" ", "
            "extraPayload: $extraPayload" ")";
@@ -237,7 +224,6 @@
   Map toJson() {
     Map map = new Map();
     map["pts"] = pts;
-    map["duration"] = duration;
     map["endOfStream"] = endOfStream;
     map["payload"] = payload;
     map["extraPayload"] = extraPayload;
diff --git a/mojo/services/media/common/interfaces/media_transport.mojom b/mojo/services/media/common/interfaces/media_transport.mojom
index b8d5ac4..da31dfd 100644
--- a/mojo/services/media/common/interfaces/media_transport.mojom
+++ b/mojo/services/media/common/interfaces/media_transport.mojom
@@ -30,9 +30,6 @@
   // according to the media timeline.
   int64 pts = kNoTimestamp;
 
-  // Duration represented by the packet.
-  uint64 duration;
-
   // Indicates whether this is the last packet in the stream.
   bool end_of_stream;
 
diff --git a/services/media/factory_service/media_sink_impl.cc b/services/media/factory_service/media_sink_impl.cc
index 36b3a22..b32121e 100644
--- a/services/media/factory_service/media_sink_impl.cc
+++ b/services/media/factory_service/media_sink_impl.cc
@@ -240,12 +240,11 @@
   // The media time corresponding to start_local_time.
   int64_t start_media_time;
   if (flushed_ &&
-      producer_->GetFirstPresentationTimeSinceFlush() !=
-          Packet::kUnknownPresentationTime) {
+      producer_->GetFirstPtsSinceFlush() != Packet::kUnknownPts) {
     // We're getting started initially or after a flush/prime, so the media
     // time corresponding to start_local_time should be the PTS of
     // the first packet.
-    start_media_time = producer_->GetFirstPresentationTimeSinceFlush();
+    start_media_time = producer_->GetFirstPtsSinceFlush();
   } else {
     // We're resuming, so the media time corresponding to start_local_time can
     // be calculated using the existing transform.
diff --git a/services/media/framework/formatting.cc b/services/media/framework/formatting.cc
index cea3aaa..26c50bd 100644
--- a/services/media/framework/formatting.cc
+++ b/services/media/framework/formatting.cc
@@ -57,8 +57,7 @@
   }
 
   os << "&" << std::hex << uint64_t(value.get()) << std::dec;
-  os << "/pts:" << value->presentation_time();
-  os << "/dur:" << value->duration();
+  os << "/pts:" << value->pts();
   os << "/eos:" << (value->end_of_stream() ? "t" : "f");
   os << "/size:" << value->size();
   os << "/payload:" << std::hex << uint64_t(value->payload()) << std::dec;
diff --git a/services/media/framework/packet.cc b/services/media/framework/packet.cc
index 32204bc..e6b9155 100644
--- a/services/media/framework/packet.cc
+++ b/services/media/framework/packet.cc
@@ -9,66 +9,57 @@
 namespace mojo {
 namespace media {
 
+Packet::Packet(
+    int64_t pts,
+    bool end_of_stream,
+    size_t size,
+    void* payload) :
+    pts_(pts),
+    end_of_stream_(end_of_stream),
+    size_(size),
+    payload_(payload) {
+  DCHECK((size == 0) == (payload == nullptr));
+}
+
 class PacketImpl : public Packet {
  public:
   PacketImpl(
-      int64_t presentation_time,
-      uint64_t duration,
+      int64_t pts,
       bool end_of_stream,
       size_t size,
       void* payload,
       PayloadAllocator* allocator) :
-      presentation_time_(presentation_time),
-      duration_(duration),
-      end_of_stream_(end_of_stream),
-      size_(size),
-      payload_(payload),
-      allocator_(allocator) {
-    DCHECK((size == 0) == (payload == nullptr));
-  }
-
-  ~PacketImpl() override {};
-
-  int64_t presentation_time() const override { return presentation_time_; }
-
-  uint64_t duration() const override { return duration_; }
-
-  bool end_of_stream() const override { return end_of_stream_; }
-
-  size_t size() const override { return size_; }
-
-  void* payload() const override { return payload_; }
+      Packet(pts, end_of_stream, size, payload),
+      allocator_(allocator) {}
 
  protected:
+  ~PacketImpl() override {};
+
   void Release() override {
-    if (payload_ != nullptr && allocator_ != nullptr) {
-      DCHECK(allocator_);
-      allocator_->ReleasePayloadBuffer(size_, payload_);
+    // In the default implementation, payload() will be nullptr if and only if
+    // allocator_ is nullptr. Subclasses have the option of having a non-null
+    // payload() and handling deallocation themselves, so allocator_ can be
+    // nullptr even when payload() is not.
+    if (payload() != nullptr && allocator_ != nullptr) {
+      allocator_->ReleasePayloadBuffer(size(), payload());
     }
     delete this;
   }
 
  private:
-  int64_t presentation_time_;
-  uint64_t duration_;
-  bool end_of_stream_;
-  size_t size_;
-  void* payload_;
   PayloadAllocator* allocator_;
 };
 
 // static
 PacketPtr Packet::Create(
-    int64_t presentation_time,
-    uint64_t duration,
+    int64_t pts,
     bool end_of_stream,
     size_t size,
     void* payload,
     PayloadAllocator* allocator) {
   DCHECK(payload == nullptr || allocator != nullptr);
   return PacketPtr(new PacketImpl(
-      presentation_time,
-      duration,
+      pts,
       end_of_stream,
       size,
       payload,
@@ -77,14 +68,12 @@
 
 // static
 PacketPtr Packet::CreateNoAllocator(
-    int64_t presentation_time,
-    uint64_t duration,
+    int64_t pts,
     bool end_of_stream,
     size_t size,
     void* payload) {
   return PacketPtr(new PacketImpl(
-      presentation_time,
-      duration,
+      pts,
       end_of_stream,
       size,
       payload,
@@ -92,10 +81,9 @@
 }
 
 // static
-PacketPtr Packet::CreateEndOfStream(int64_t presentation_time) {
+PacketPtr Packet::CreateEndOfStream(int64_t pts) {
   return PacketPtr(new PacketImpl(
-      presentation_time,
-      0, // duration
+      pts,
       true, // end_of_stream
       0, // size
       nullptr, // payload
diff --git a/services/media/framework/packet.h b/services/media/framework/packet.h
index d89d68b..952383c 100644
--- a/services/media/framework/packet.h
+++ b/services/media/framework/packet.h
@@ -32,14 +32,12 @@
 // 2) The relationship to the allocator could be clearer.
 class Packet {
  public:
-  static const int64_t kUnknownPresentationTime =
-      std::numeric_limits<int64_t>::min();
+  static const int64_t kUnknownPts = std::numeric_limits<int64_t>::min();
 
   // Creates a packet. If size is 0, payload must be nullptr and vice-versa.
   // If payload is not nullptr, an allocator must be provided.
   static PacketPtr Create(
-      int64_t presentation_time,
-      uint64_t duration,
+      int64_t pts,
       bool end_of_stream,
       size_t size,
       void* payload,
@@ -49,30 +47,39 @@
   // No allocator is provided, and the payload will not be released when the
   // packet is released.
   static PacketPtr CreateNoAllocator(
-      int64_t presentation_time,
-      uint64_t duration,
+      int64_t pts,
       bool end_of_stream,
       size_t size,
       void* payload);
 
   // Creates an end-of-stream packet with no payload.
-  static PacketPtr CreateEndOfStream(int64_t presentation_time);
+  static PacketPtr CreateEndOfStream(int64_t pts);
 
-  virtual int64_t presentation_time() const = 0;
+  int64_t pts() const { return pts_; }
 
-  virtual uint64_t duration() const = 0;
+  bool end_of_stream() const { return end_of_stream_; }
 
-  virtual bool end_of_stream() const = 0;
+  size_t size() const { return size_; }
 
-  virtual size_t size() const = 0;
-
-  virtual void* payload() const = 0;
+  void* payload() const { return payload_; }
 
  protected:
+  Packet(
+      int64_t pts,
+      bool end_of_stream,
+      size_t size,
+      void* payload);
+
   virtual ~Packet() {}
 
   virtual void Release() = 0;
 
+ private:
+  int64_t pts_;
+  bool end_of_stream_;
+  size_t size_;
+  void* payload_;
+
   friend PacketDeleter;
 };
 
diff --git a/services/media/framework/parts/lpcm_reformatter.cc b/services/media/framework/parts/lpcm_reformatter.cc
index 91c86f2..79b5458 100644
--- a/services/media/framework/parts/lpcm_reformatter.cc
+++ b/services/media/framework/parts/lpcm_reformatter.cc
@@ -249,8 +249,7 @@
   if (in_size == 0) {
     // Zero-sized input packet. Make a copy.
     *output = Packet::Create(
-        input->presentation_time(),
-        input->duration(),
+        input->pts(),
         input->end_of_stream(),
         0,
         nullptr,
@@ -258,7 +257,7 @@
     return true;
   }
 
-  size_t frame_count = input->duration();
+  size_t frame_count = in_type_.frame_count(in_size);
   uint64_t out_size = out_type_.min_buffer_size(frame_count);
 
   void* buffer = allocator->AllocatePayloadBuffer(out_size);
@@ -285,8 +284,7 @@
   }
 
   *output = Packet::Create(
-      input->presentation_time(),
-      frame_count,
+      input->pts(),
       input->end_of_stream(),
       out_size,
       buffer,
diff --git a/services/media/framework/stages/output.cc b/services/media/framework/stages/output.cc
index e64d913..1180cf8 100644
--- a/services/media/framework/stages/output.cc
+++ b/services/media/framework/stages/output.cc
@@ -65,8 +65,7 @@
     }
 
     packet = Packet::Create(
-        packet->presentation_time(),
-        packet->duration(),
+        packet->pts(),
         packet->end_of_stream(),
         size,
         buffer,
diff --git a/services/media/framework/stream_type.h b/services/media/framework/stream_type.h
index aaa3136..31021e2 100644
--- a/services/media/framework/stream_type.h
+++ b/services/media/framework/stream_type.h
@@ -271,7 +271,13 @@
   }
 
   uint64_t min_buffer_size(uint64_t frame_count) const {
-    return frame_count * sample_size_ * channels_;
+    return frame_count * bytes_per_frame();
+  }
+
+  uint64_t frame_count(uint64_t size) const {
+    DCHECK(bytes_per_frame() != 0);
+    DCHECK(size % bytes_per_frame() == 0);
+    return size / bytes_per_frame();
   }
 
   static uint32_t SampleSizeFromFormat(SampleFormat sample_format);
diff --git a/services/media/framework_ffmpeg/BUILD.gn b/services/media/framework_ffmpeg/BUILD.gn
index 8934bc5..0bb2492 100644
--- a/services/media/framework_ffmpeg/BUILD.gn
+++ b/services/media/framework_ffmpeg/BUILD.gn
@@ -21,6 +21,8 @@
 
 source_set("framework_ffmpeg") {
   sources = [
+    "av_frame.h",
+    "av_packet.h",
     "ffmpeg_audio_decoder.cc",
     "ffmpeg_audio_decoder.h",
     "ffmpeg_decoder.cc",
diff --git a/services/media/framework_ffmpeg/av_frame.h b/services/media/framework_ffmpeg/av_frame.h
new file mode 100644
index 0000000..8b02b66
--- /dev/null
+++ b/services/media/framework_ffmpeg/av_frame.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_FRAME_H_
+#define SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_FRAME_H_
+
+extern "C" {
+#include "third_party/ffmpeg/libavutil/frame.h"
+}
+
+namespace mojo {
+namespace media {
+namespace ffmpeg {
+
+struct AVFrameDeleter {
+  inline void operator()(AVFrame* ptr) const {
+    av_frame_free(&ptr);
+  }
+};
+
+using AvFramePtr = std::unique_ptr<AVFrame, AVFrameDeleter>;
+
+struct AvFrame{
+  static AvFramePtr Create() {
+    return AvFramePtr(av_frame_alloc());
+  }
+};
+
+}  // namespace ffmpeg
+}  // namespace media
+}  // namespace mojo
+
+#endif // SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_FRAME_H_
diff --git a/services/media/framework_ffmpeg/av_packet.h b/services/media/framework_ffmpeg/av_packet.h
new file mode 100644
index 0000000..f1d51b8
--- /dev/null
+++ b/services/media/framework_ffmpeg/av_packet.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_PACKET_H_
+#define SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_PACKET_H_
+
+extern "C" {
+#include "third_party/ffmpeg/libavcodec/avcodec.h"
+#include "third_party/ffmpeg/libavformat/avformat.h"
+}
+
+namespace mojo {
+namespace media {
+namespace ffmpeg {
+
+struct AVPacketDeleter {
+  inline void operator()(AVPacket* ptr) const {
+    av_free_packet(ptr);
+  }
+};
+
+using AvPacketPtr = std::unique_ptr<AVPacket, AVPacketDeleter>;
+
+struct AvPacket{
+  static AvPacketPtr Create() {
+    AVPacket* av_packet = new AVPacket();
+    av_init_packet(av_packet);
+    return AvPacketPtr(av_packet);
+  }
+};
+
+}  // namespace ffmpeg
+}  // namespace media
+}  // namespace mojo
+
+#endif // SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_PACKET_H_
diff --git a/services/media/framework_ffmpeg/ffmpeg_audio_decoder.cc b/services/media/framework_ffmpeg/ffmpeg_audio_decoder.cc
index 11e2679..0d854c1 100644
--- a/services/media/framework_ffmpeg/ffmpeg_audio_decoder.cc
+++ b/services/media/framework_ffmpeg/ffmpeg_audio_decoder.cc
@@ -28,12 +28,12 @@
 
 void FfmpegAudioDecoder::Flush() {
   FfmpegDecoderBase::Flush();
-  next_presentation_time_= Packet::kUnknownPresentationTime;
+  next_pts_= Packet::kUnknownPts;
 }
 
 int FfmpegAudioDecoder::Decode(
     const AVPacket& av_packet,
-    const AvFramePtr& av_frame_ptr,
+    const ffmpeg::AvFramePtr& av_frame_ptr,
     PayloadAllocator* allocator,
     bool* frame_decoded_out) {
   DCHECK(allocator);
@@ -41,11 +41,11 @@
   DCHECK(context());
   DCHECK(av_frame_ptr);
 
-  if (next_presentation_time_ == Packet::kUnknownPresentationTime) {
+  if (next_pts_ == Packet::kUnknownPts) {
     if (av_packet.pts == AV_NOPTS_VALUE) {
-      next_presentation_time_ = 0;
+      next_pts_ = 0;
     } else {
-      next_presentation_time_ = av_packet.pts;
+      next_pts_ = av_packet.pts;
     }
   }
 
@@ -74,10 +74,10 @@
     PayloadAllocator* allocator) {
   DCHECK(allocator);
 
-  int64_t presentation_time = av_frame.pts;
-  if (presentation_time == AV_NOPTS_VALUE) {
-    presentation_time = next_presentation_time_;
-    next_presentation_time_ += av_frame.nb_samples;
+  int64_t pts = av_frame.pts;
+  if (pts == AV_NOPTS_VALUE) {
+    pts = next_pts_;
+    next_pts_ += av_frame.nb_samples;
   }
 
   uint64_t payload_size;
@@ -110,8 +110,7 @@
   }
 
   return Packet::Create(
-      presentation_time,
-      av_frame.nb_samples,
+      pts,
       false, // The base class is responsible for end-of-stream.
       payload_size,
       payload_buffer,
@@ -119,7 +118,7 @@
 }
 
 PacketPtr FfmpegAudioDecoder::CreateOutputEndOfStreamPacket() {
-  return Packet::CreateEndOfStream(next_presentation_time_);
+  return Packet::CreateEndOfStream(next_pts_);
 }
 
 int FfmpegAudioDecoder::AllocateBufferForAvFrame(
diff --git a/services/media/framework_ffmpeg/ffmpeg_audio_decoder.h b/services/media/framework_ffmpeg/ffmpeg_audio_decoder.h
index 48503e6..9a8d6dc 100644
--- a/services/media/framework_ffmpeg/ffmpeg_audio_decoder.h
+++ b/services/media/framework_ffmpeg/ffmpeg_audio_decoder.h
@@ -24,7 +24,7 @@
 
   int Decode(
       const AVPacket& av_packet,
-      const AvFramePtr& av_frame_ptr,
+      const ffmpeg::AvFramePtr& av_frame_ptr,
       PayloadAllocator* allocator,
       bool* frame_decoded_out) override;
 
@@ -112,7 +112,7 @@
   std::unique_ptr<StreamType> stream_type_;
 
   // Used to supply missing PTS.
-  int64_t next_presentation_time_= Packet::kUnknownPresentationTime;
+  int64_t next_pts_= Packet::kUnknownPts;
 };
 
 }  // namespace media
diff --git a/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc b/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc
index 8af9730..80bbe4f 100644
--- a/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc
+++ b/services/media/framework_ffmpeg/ffmpeg_decoder_base.cc
@@ -76,7 +76,7 @@
   av_init_packet(&av_packet_);
   av_packet_.data = reinterpret_cast<uint8_t*>(input->payload());
   av_packet_.size = input->size();
-  av_packet_.pts = input->presentation_time();
+  av_packet_.pts = input->pts();
 }
 
 bool FfmpegDecoderBase::UnprepareInputPacket(
diff --git a/services/media/framework_ffmpeg/ffmpeg_decoder_base.h b/services/media/framework_ffmpeg/ffmpeg_decoder_base.h
index 69faca7..ce3935b 100644
--- a/services/media/framework_ffmpeg/ffmpeg_decoder_base.h
+++ b/services/media/framework_ffmpeg/ffmpeg_decoder_base.h
@@ -6,6 +6,8 @@
 #define SERVICES_MEDIA_FRAMEWORK_FFMPEG_FFMPEG_DECODER_BASE_H_
 
 #include "services/media/framework/parts/decoder.h"
+#include "services/media/framework_ffmpeg/av_frame.h"
+#include "services/media/framework_ffmpeg/av_packet.h"
 #include "services/media/framework_ffmpeg/ffmpeg_type_converters.h"
 extern "C" {
 #include "third_party/ffmpeg/libavcodec/avcodec.h"
@@ -34,20 +36,12 @@
       PacketPtr* output) override;
 
  protected:
-  struct AVFrameDeleter {
-    inline void operator()(AVFrame* ptr) const {
-      av_frame_free(&ptr);
-    }
-  };
-
-  using AvFramePtr = std::unique_ptr<AVFrame, AVFrameDeleter>;
-
   // Decodes from av_packet into av_frame_ptr. The result indicates how many
   // bytes were consumed from av_packet_. *frame_decoded_out indicates whether
   // av_frame_ptr contains a complete frame.
   virtual int Decode(
       const AVPacket& av_packet,
-      const AvFramePtr& av_frame_ptr,
+      const ffmpeg::AvFramePtr& av_frame_ptr,
       PayloadAllocator* allocator,
       bool* frame_decoded_out) = 0;
 
@@ -75,7 +69,7 @@
 
   AvCodecContextPtr av_codec_context_;
   AVPacket av_packet_;
-  AvFramePtr av_frame_ptr_;
+  ffmpeg::AvFramePtr av_frame_ptr_;
 };
 
 }  // namespace media
diff --git a/services/media/framework_ffmpeg/ffmpeg_demux.cc b/services/media/framework_ffmpeg/ffmpeg_demux.cc
index b882588..e71ebfa 100644
--- a/services/media/framework_ffmpeg/ffmpeg_demux.cc
+++ b/services/media/framework_ffmpeg/ffmpeg_demux.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "services/media/framework/safe_clone.h"
+#include "services/media/framework_ffmpeg/av_packet.h"
 #include "services/media/framework_ffmpeg/ffmpeg_demux.h"
 #include "services/media/framework_ffmpeg/ffmpeg_io.h"
 #include "services/media/framework_ffmpeg/ffmpeg_type_converters.h"
@@ -54,36 +55,31 @@
   // Specialized packet implementation.
   class DemuxPacket : public Packet {
    public:
-    DemuxPacket() {
-      av_init_packet(&av_packet_);
-    }
-
-    // Packet implementation.
-    int64_t presentation_time() const override { return av_packet_.pts; };
-
-    uint64_t duration() const override { return av_packet_.duration; };
-
-    bool end_of_stream() const override { return false; }
-
-    size_t size() const override { return size_t(av_packet_.size); }
-
-    void* payload() const override {
-      return reinterpret_cast<void*>(av_packet_.data);
+    static PacketPtr Create(ffmpeg::AvPacketPtr av_packet) {
+      return PacketPtr(new DemuxPacket(std::move(av_packet)));
     }
 
     AVPacket& av_packet() {
-      return av_packet_;
+      return *av_packet_;
     }
 
    protected:
-    ~DemuxPacket() override {
-      av_free_packet(&av_packet_);
-    }
+    ~DemuxPacket() override {}
 
     void Release() override { delete this; }
 
-  private:
-    AVPacket av_packet_;
+   private:
+    DemuxPacket(ffmpeg::AvPacketPtr av_packet) :
+        Packet(
+            (av_packet->pts == AV_NOPTS_VALUE) ? kUnknownPts : av_packet->pts,
+            false,
+            static_cast<size_t>(av_packet->size),
+            av_packet->data),
+        av_packet_(std::move(av_packet)) {
+      DCHECK(av_packet->size >= 0);
+    }
+
+    ffmpeg::AvPacketPtr av_packet_;
   };
 
   struct AVFormatContextDeleter {
@@ -105,7 +101,7 @@
   AvioContextPtr io_context_;
   std::vector<DemuxStream*> streams_;
   std::unique_ptr<Metadata> metadata_;
-  int64_t next_presentation_time_;
+  int64_t next_pts_;
   int next_stream_to_end_ = -1; // -1: don't end, streams_.size(): stop.
 };
 
@@ -199,26 +195,23 @@
     return PullEndOfStreamPacket(stream_index_out);
   }
 
-  FfmpegDemuxImpl::DemuxPacket* demux_packet =
-      new FfmpegDemuxImpl::DemuxPacket();
+  ffmpeg::AvPacketPtr av_packet = ffmpeg::AvPacket::Create();
 
-  demux_packet->av_packet().data = nullptr;
-  demux_packet->av_packet().size = 0;
+  av_packet->data = nullptr;
+  av_packet->size = 0;
 
-  if (av_read_frame(format_context_.get(), &demux_packet->av_packet()) < 0) {
+  if (av_read_frame(format_context_.get(), av_packet.get()) < 0) {
     // End of stream. Start producing end-of-stream packets for all the streams.
-    PacketPtr(demux_packet); // Deletes demux_packet.
     next_stream_to_end_ = 0;
     return PullEndOfStreamPacket(stream_index_out);
   }
 
   *stream_index_out =
-      static_cast<size_t>(demux_packet->av_packet().stream_index);
+      static_cast<size_t>(av_packet->stream_index);
   // TODO(dalesat): What if the packet has no PTS or duration?
-  next_presentation_time_ =
-      demux_packet->presentation_time() + demux_packet->duration();
+  next_pts_ = av_packet->pts + av_packet->duration;
 
-  return PacketPtr(demux_packet);
+  return DemuxPacket::Create(std::move(av_packet));
 }
 
 PacketPtr FfmpegDemuxImpl::PullEndOfStreamPacket(size_t* stream_index_out) {
@@ -230,7 +223,7 @@
   }
 
   *stream_index_out = next_stream_to_end_++;
-  return Packet::CreateEndOfStream(next_presentation_time_);
+  return Packet::CreateEndOfStream(next_pts_);
 }
 
 void FfmpegDemuxImpl::CopyMetadata(
diff --git a/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc b/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc
index 8e84fb6..73fe12e 100644
--- a/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc
+++ b/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc
@@ -17,7 +17,7 @@
 
 int FfmpegVideoDecoder::Decode(
     const AVPacket& av_packet,
-    const AvFramePtr& av_frame_ptr,
+    const ffmpeg::AvFramePtr& av_frame_ptr,
     PayloadAllocator* allocator,
     bool* frame_decoded_out) {
   DCHECK(av_frame_ptr);
@@ -45,7 +45,6 @@
   // TODO(dalesat): This is just a copy of the audio version.
   return Packet::Create(
       av_frame.pts,
-      av_frame.pkt_duration,
       false,
       packet_size_,
       av_frame.data[0],
diff --git a/services/media/framework_ffmpeg/ffmpeg_video_decoder.h b/services/media/framework_ffmpeg/ffmpeg_video_decoder.h
index e192804..3d3d4f7 100644
--- a/services/media/framework_ffmpeg/ffmpeg_video_decoder.h
+++ b/services/media/framework_ffmpeg/ffmpeg_video_decoder.h
@@ -22,7 +22,7 @@
   // FfmpegDecoderBase overrides.
   int Decode(
       const AVPacket& av_packet,
-      const AvFramePtr& av_frame_ptr,
+      const ffmpeg::AvFramePtr& av_frame_ptr,
       PayloadAllocator* allocator,
       bool* frame_decoded_out) override;
 
diff --git a/services/media/framework_mojo/mojo_consumer.cc b/services/media/framework_mojo/mojo_consumer.cc
index 5c9d2c8..2efb5e3 100644
--- a/services/media/framework_mojo/mojo_consumer.cc
+++ b/services/media/framework_mojo/mojo_consumer.cc
@@ -46,6 +46,7 @@
 void MojoConsumer::SendPacket(
     MediaPacketPtr media_packet,
     const SendPacketCallback& callback) {
+  DCHECK(media_packet);
   DCHECK(supply_callback_);
   supply_callback_(PacketImpl::Create(
       media_packet.Pass(),
@@ -77,7 +78,7 @@
 }
 
 void MojoConsumer::set_allocator(PayloadAllocator* allocator) {
-  NOTREACHED();
+  LOG(ERROR) << "set_allocator called on MojoConsumer";
 }
 
 void MojoConsumer::SetSupplyCallback(const SupplyCallback& supply_callback) {
@@ -91,10 +92,16 @@
     const SendPacketCallback& callback,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     const MappedSharedBuffer& buffer) :
+    Packet(
+        media_packet->pts,
+        media_packet->end_of_stream,
+        media_packet->payload->length,
+        media_packet->payload->length == 0 ?
+            nullptr :
+            buffer.PtrFromOffset(media_packet->payload->offset)),
     media_packet_(media_packet.Pass()),
     callback_(callback),
-    task_runner_(task_runner),
-    payload_(buffer.PtrFromOffset(media_packet_->payload->offset)) {}
+    task_runner_(task_runner) {}
 
 MojoConsumer::PacketImpl::~PacketImpl() {}
 
diff --git a/services/media/framework_mojo/mojo_consumer.h b/services/media/framework_mojo/mojo_consumer.h
index f737405..076623e 100644
--- a/services/media/framework_mojo/mojo_consumer.h
+++ b/services/media/framework_mojo/mojo_consumer.h
@@ -89,25 +89,6 @@
           buffer));
     }
 
-    // Packet implementation.
-    int64_t presentation_time() const override {
-      return media_packet_->pts;
-    }
-
-    uint64_t duration() const override {
-      return media_packet_->duration;
-    }
-
-    bool end_of_stream() const override {
-      return media_packet_->end_of_stream;
-    }
-
-    size_t size() const override {
-      return media_packet_->payload->length;
-    }
-
-    void* payload() const override { return payload_; }
-
    protected:
     void Release() override;
 
@@ -125,7 +106,6 @@
     MediaPacketPtr media_packet_;
     const SendPacketCallback callback_;
     scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-    void* payload_;
   };
 
   BindingSet<MediaConsumer> bindings_;
diff --git a/services/media/framework_mojo/mojo_producer.cc b/services/media/framework_mojo/mojo_producer.cc
index 4554ae5..744feed 100644
--- a/services/media/framework_mojo/mojo_producer.cc
+++ b/services/media/framework_mojo/mojo_producer.cc
@@ -56,7 +56,7 @@
 
   DCHECK(consumer_.is_bound());
   consumer_->Flush(callback);
-  first_presentation_time_since_flush_ = Packet::kUnknownPresentationTime;
+  first_pts_since_flush_ = Packet::kUnknownPts;
   end_of_stream_= false;
 }
 
@@ -65,8 +65,8 @@
   status_callback_ = callback;
 }
 
-int64_t MojoProducer::GetFirstPresentationTimeSinceFlush() {
-  return first_presentation_time_since_flush_;
+int64_t MojoProducer::GetFirstPtsSinceFlush() {
+  return first_pts_since_flush_;
 }
 
 PayloadAllocator* MojoProducer::allocator() {
@@ -80,9 +80,8 @@
 Demand MojoProducer::SupplyPacket(PacketPtr packet) {
   DCHECK(packet);
 
-  if (first_presentation_time_since_flush_ ==
-      Packet::kUnknownPresentationTime) {
-    first_presentation_time_since_flush_ = packet->presentation_time();
+  if (first_pts_since_flush_ == Packet::kUnknownPts) {
+    first_pts_since_flush_ = packet->pts();
   }
 
   // If we're no longer connected, throw the packet away.
@@ -192,8 +191,7 @@
   region->length = packet->size();
 
   MediaPacketPtr media_packet = MediaPacket::New();
-  media_packet->pts = packet->presentation_time();
-  media_packet->duration = packet->duration();
+  media_packet->pts = packet->pts();
   media_packet->end_of_stream = packet->end_of_stream();
   media_packet->payload = region.Pass();
 
diff --git a/services/media/framework_mojo/mojo_producer.h b/services/media/framework_mojo/mojo_producer.h
index 2fb252e..5679b7c 100644
--- a/services/media/framework_mojo/mojo_producer.h
+++ b/services/media/framework_mojo/mojo_producer.h
@@ -45,7 +45,7 @@
 
   // Gets the first presentation time seen on any packet after the most recent
   // flush or, if there has never been a flush, the first packet supplied.
-  int64_t GetFirstPresentationTimeSinceFlush();
+  int64_t GetFirstPtsSinceFlush();
 
   // ActiveSink implementation.
   PayloadAllocator* allocator() override;
@@ -89,8 +89,7 @@
   bool end_of_stream_= false;
   DemandCallback demand_callback_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  int64_t first_presentation_time_since_flush_ =
-      Packet::kUnknownPresentationTime;
+  int64_t first_pts_since_flush_ = Packet::kUnknownPts;
   // TODO(dalesat): Base this logic on presentation time or duration.
   uint32_t max_pushes_outstanding_ = 0;
   uint32_t current_pushes_outstanding_ = 0;
diff --git a/services/media/framework_mojo/mojo_pull_mode_producer.cc b/services/media/framework_mojo/mojo_pull_mode_producer.cc
index 141d6e1..b2c7dc8 100644
--- a/services/media/framework_mojo/mojo_pull_mode_producer.cc
+++ b/services/media/framework_mojo/mojo_pull_mode_producer.cc
@@ -11,7 +11,7 @@
 MojoPullModeProducer::MojoPullModeProducer() :
     state_(MediaState::UNPREPARED),
     demand_(Demand::kNegative),
-    presentation_time_(0),
+    pts_(0),
     cached_packet_(nullptr) {}
 
 MojoPullModeProducer::~MojoPullModeProducer() {
@@ -157,7 +157,7 @@
     // At end-of-stream. Respond with empty end-of-stream packet.
     HandlePullWithPacketUnsafe(
         callback,
-        Packet::CreateEndOfStream(presentation_time_));
+        Packet::CreateEndOfStream(pts_));
     return true;
   }
 
@@ -190,11 +190,10 @@
   region->length = packet->size();
 
   MediaPacketPtr media_packet = MediaPacket::New();
-  media_packet->pts = packet->presentation_time();
-  media_packet->duration = packet->duration();
+  media_packet->pts = packet->pts();
   media_packet->end_of_stream = packet->end_of_stream();
   media_packet->payload = region.Pass();
-  presentation_time_ = packet->presentation_time() + packet->duration();
+  pts_ = packet->pts();
 
   return media_packet.Pass();
 }
diff --git a/services/media/framework_mojo/mojo_pull_mode_producer.h b/services/media/framework_mojo/mojo_pull_mode_producer.h
index 5ecf80e..8ba6fc6 100644
--- a/services/media/framework_mojo/mojo_pull_mode_producer.h
+++ b/services/media/framework_mojo/mojo_pull_mode_producer.h
@@ -78,7 +78,7 @@
   // THE FIELDS BELOW SHOULD ONLY BE ACCESSED WITH lock_ TAKEN.
   MediaState state_;
   Demand demand_;
-  int64_t presentation_time_;
+  int64_t pts_;
 
   // pending_pulls_ contains the callbacks for the pull requests that have yet
   // to be satisfied. unreleased_packets_ contains the packets that have been